XNA游戏:Bizzy Bees蜜蜂警官游戏
先来看一下游戏的界面
游戏的思路差不多像俄罗斯方块一样,上面的花一直往下掉,然后你就需要选中一只蜜蜂来吃上面的花,当蜜蜂的颜色和花的颜色一样或者花是彩色的花的时候,花就会被蜜蜂给吃掉,这时候这只蜜蜂也会被随机生成一只新的蜜蜂。当吃掉一朵彩色的花的时候,会增加一分,当花落到了底下的时候游戏结束。
看一下下面的代码:
花的对象
Flower.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DemoGame { class Flower { public int Color;//颜色 public float X;//X轴坐标 public float Y;//Y轴坐标 public Flower(int color, float x, float y) { this.Color = color; this.X = x; this.Y = y; } } }
花的列容器
Column.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content; namespace DemoGame { class Column { const int columnTop = 150;//列头高度,当花移动出这个高度后将开始新增新花 const int numberOfFlowerColors = 6;//花颜色的数量 const int rainbowFlowerColor = 6; //彩虹花的颜色 const int flowerDeltaY = 80; const int flowerWidth = 72;//花的宽度 const int flowerHeight = 72;//花的高度 const int columnBottom = 620;//列的高度 用来判断花是否移动到底了 private List<Flower> flowers = null;//花的集合 private SpriteBatch spriteBatch;//绘制花 private float x;//花的X轴,X轴的坐标是固定的 private Random r; private Texture2D flowerMap;//花的纹理 public float Velocity = 0.4f;//速度 /// <summary> /// 判断是否有花移动到底 /// </summary> public bool ReachedBottom { get { if (flowers.Count != 0 && flowers[0].Y >= columnBottom) return true; else return false; } } /// <summary> /// 初始化一列 /// </summary> /// <param name="content">当前的ContentManager</param> /// <param name="spriteBatch">当前的SpriteBatch</param> /// <param name="x"></param> /// <param name="seed"></param> public Column(ContentManager content, SpriteBatch spriteBatch, float x, int seed) { this.spriteBatch = spriteBatch; this.x = x; this.flowers = new List<Flower>(); this.r = new Random(seed); this.flowerMap = content.Load<Texture2D>("flowermap"); //初始化 添加3朵花 AddRandomFlower(x, columnTop + 2 * flowerDeltaY); AddRandomFlower(x, columnTop + flowerDeltaY); AddRandomFlower(x, columnTop); } /// <summary> /// 随机添加一朵花 /// </summary> /// <param name="x"></param> /// <param name="y"></param> private void AddRandomFlower(float x, int y) { int color = r.Next(numberOfFlowerColors+1); flowers.Add(new Flower(color, x, y)); } /// <summary> /// 在spriteBatch中绘制花精灵 /// </summary> public void Draw() { foreach (Flower flower in flowers) { spriteBatch.Draw(flowerMap, new Vector2(flower.X, flower.Y), new Rectangle(flower.Color * flowerWidth, 0, flowerWidth, flowerHeight), Color.White); } } /// <summary> /// 更新列 /// </summary> public void Update() { foreach (Flower f in flowers) { f.Y += Velocity;//增加Y轴的偏移量,表示正在向下移动 } //如果最上面的花已经全部离开顶部,则需要随机生成新的花从上面下来 if (flowers.Count == 0 || flowers[flowers.Count - 1].Y > columnTop) AddRandomFlower(x, columnTop - flowerDeltaY); } /// <summary> /// 获取最底下的一朵花 /// </summary> /// <returns></returns> public Flower GetBottomFlower() { if (flowers.Count > 0) return flowers[0]; else return null; } /// <summary> /// 移走最底下的一朵花 /// </summary> internal void RemoveBottomFlower() { if (flowers.Count > 0) flowers.RemoveAt(0); } } }
蜜蜂对象
Bee.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DemoGame { class Bee { public int Color;//蜜蜂颜色 public bool IsSelected = false;//是否选中 public Bee(int color) { this.Color = color; } } }
蜜蜂容器
BeePicker.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework; namespace DemoGame { class BeePicker { const int beeDeltaX = 96; const int beeStartX = 5; const int beeStartY = 700; const int numberOfBeeColors = 5;//蜜蜂颜色的数量 private List<Bee> bees = null;//蜜蜂集合 private SpriteBatch spriteBatch; private Texture2D beeMap; private Random r; public BeePicker(ContentManager content, SpriteBatch spriteBatch, int seed) { beeMap = content.Load<Texture2D>("beemap"); this.spriteBatch = spriteBatch; bees = new List<Bee>(); r = new Random(seed); for (int i = 0; i < 5; i++) { AddRandomBee(); } } /// <summary> /// 添加一只蜜蜂 /// </summary> private void AddRandomBee() { bees.Add(new Bee(r.Next(numberOfBeeColors + 1))); } /// <summary> /// 绘制蜜蜂 /// </summary> public void Draw() { for (int i = 0; i < 5; i++) { if(bees[i].IsSelected) spriteBatch.Draw(beeMap, new Vector2(beeStartX + i * beeDeltaX, beeStartY), new Rectangle(bees[i].Color * 91, 0, 91, 91), Color.DimGray); else spriteBatch.Draw(beeMap, new Vector2(beeStartX + i * beeDeltaX, beeStartY), new Rectangle(bees[i].Color * 91, 0, 91, 91), Color.White); } } /// <summary> /// 选中一只蜜蜂 /// </summary> /// <param name="x"></param> public void MarkSelectedBee(float x) { GetSelectedBee(x).IsSelected = true; } /// <summary> /// 获取选中的蜜蜂 /// </summary> /// <param name="x"></param> /// <returns></returns> public Bee GetSelectedBee(float x) { int index = (int)(x / beeDeltaX); return bees[index]; } /// <summary> /// 移除和替换蜜蜂 /// </summary> /// <param name="selectedBee"></param> /// <param name="availableFlowers"></param> public void RemoveAndReplaceBee(Bee selectedBee, List<int> availableFlowers) { int beeIndex = bees.IndexOf(selectedBee); //check if we already have a bee that matches the available flowers //remember to skip over the selectedBee since it will be removed in a moment bool match = false; int rainbowColor = 6; //if there is a rainbow flower it will always match if (availableFlowers.Contains(rainbowColor)) match = true; else { for (int i = 0; i < bees.Count; i++) { if(i != beeIndex && availableFlowers.Contains(bees[i].Color)){ match = true; break; } } } int color; if(match){ //we already have a match, just add a random colored bee color = r.Next(numberOfBeeColors + 1 ); } else{ //we have no match so we must pick a color from the available colors color = availableFlowers[r.Next(availableFlowers.Count)]; } //set the selected bee to the new color to "create" a new bee bees[beeIndex].Color = color; } internal void DeselectAll() { foreach (Bee bee in bees) bee.IsSelected = false; } } }
游戏主程序
Game1.cs
using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Input.Touch; using Microsoft.Xna.Framework.Media; namespace DemoGame { /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; //纹理 Texture2D backgroundTexture; Texture2D foregroundTexture; Texture2D hudTexture; Texture2D flowerMapTexture; //分数 int score = 0; //字体 SpriteFont largeFont; SpriteFont mediumFont; SpriteFont smallFont; List<Column> columns;//列集合 bool gameOver = false;//标记游戏是否结束 BeePicker beePicker = null;//蜜蜂处理类 Bee selectedBee = null;//蜜蜂 public Game1() { graphics = new GraphicsDeviceManager(this); //设置游戏图像的宽和高 graphics.PreferredBackBufferHeight = 800; graphics.PreferredBackBufferWidth = 480; Content.RootDirectory = "Content"; // Frame rate is 30 fps by default for Windows Phone. TargetElapsedTime = TimeSpan.FromTicks(333333); // Extend battery life under lock. InactiveSleepTime = TimeSpan.FromSeconds(1); } /// <summary> /// 初始化 /// </summary> protected override void Initialize() { // TODO: Add your initialization logic here //添加触摸事件 TouchPanel.EnabledGestures = GestureType.Tap; base.Initialize(); } /// <summary> /// 加载资源 /// </summary> protected override void LoadContent() { //创建一个新的SpriteBatch用来绘制纹理 spriteBatch = new SpriteBatch(GraphicsDevice); //加载纹理 backgroundTexture = Content.Load<Texture2D>("GameScreenBackground"); foregroundTexture = Content.Load<Texture2D>("GameScreenForeground"); hudTexture = Content.Load<Texture2D>("HUDBackground"); flowerMapTexture = Content.Load<Texture2D>("flowermap"); //加载字体资源 largeFont = Content.Load<SpriteFont>("LargeMenuFont"); mediumFont = Content.Load<SpriteFont>("MediumMenuFont"); smallFont = Content.Load<SpriteFont>("SmallMenuFont"); //初始化列 InitializeColumns(); beePicker = new BeePicker(Content, spriteBatch, System.DateTime.Now.Millisecond); } /// <summary> /// 初始化列 /// </summary> private void InitializeColumns() { columns = new List<Column>(); int seed = System.DateTime.Now.Millisecond; //初始化6列 for (int i = 0; i < 5; i++) { columns.Add(new Column(Content, spriteBatch, i * 92 + 22, seed + i)); } } /// <summary> /// UnloadContent will be called once per game and is the place to unload /// all content. /// </summary> protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } /// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { // 退出游戏 if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); // 添加更新的逻辑 if (!gameOver) { //处理用户的操作 while (TouchPanel.IsGestureAvailable)//是否触摸到屏幕 { GestureSample gesture = TouchPanel.ReadGesture();//获取手势 if (gesture.GestureType == GestureType.Tap)//点击操作 { HandleInput(gesture.Position);//传入点击的位置,处理点击操作 } } //更新花的状态,即不停地往下移动 foreach (Column c in columns) { c.Update(); if (c.ReachedBottom)//花到达底部,游戏结束 { gameOver = true; break; } } } base.Update(gameTime); } /// <summary> /// 点击输入操作处理 /// </summary> /// <param name="position"></param> private void HandleInput(Vector2 position) { if (position.X > 0 && position.X < 480 && position.Y > 700 && position.Y < 800)//点种了蜜蜂的位置 HandleBeeSelection(position.X); else if (selectedBee != null)//选中了蜜蜂 HandleFlowerSelection(position.X, position.Y); } /// <summary> /// 处理选中花的操作 /// </summary> /// <param name="x"></param> /// <param name="y"></param> private void HandleFlowerSelection(float x, float y) { //判断是否点中了列的位置 if (x > 10 && x < 470 && y > 100 && y < 700) { int rainbowColor = 6; int selectedColumnIndex = (int)((x - 10) / 92); //获取点中的列 Column selectedColumn = columns[selectedColumnIndex]; //获取点中的列底部的花 Flower selectedFlower = selectedColumn.GetBottomFlower(); //判断是否点中了底部的花,并且花的颜色和蜜蜂的颜色要相等,或者花是彩色的花 if(selectedFlower != null && (selectedFlower.Color == selectedBee.Color || selectedFlower.Color == rainbowColor)) { //移除花 selectedColumn.RemoveBottomFlower(); //替换另外一只蜜蜂,并且要保证至少要有一只蜜蜂可以和最底层的花可以匹配得上 List<int> availableFlowers = GetAvailableFlowers(); beePicker.RemoveAndReplaceBee(selectedBee, availableFlowers); //取消对蜜蜂的选中状态 beePicker.DeselectAll(); selectedBee = null;//设置选中的蜜蜂为null //如果蜜蜂吃掉的是彩色的花则增加一分 if (selectedFlower.Color == rainbowColor) { score++; //如果分数达到10, 20, 30... 则不断地增加花下落的Y轴偏移量速度 if ((score % 10) == 0) { foreach (Column c in columns) c.Velocity += 0.1f; } } } } } /// <summary> /// 获取最底下花的颜色,用来作为随机生成蜜蜂的一个条件 /// </summary> /// <returns></returns> private List<int> GetAvailableFlowers() { List<int> flowerColors = new List<int>(); foreach (Column c in columns) { Flower f = c.GetBottomFlower(); if (f != null) flowerColors.Add(f.Color); } return flowerColors; } /// <summary> /// 处理选中蜜蜂操作 /// </summary> /// <param name="x"></param> private void HandleBeeSelection(float x) { //first de-select any previously selected bee if (selectedBee != null) { selectedBee.IsSelected = false; selectedBee = null; } //Mark and select the new bee beePicker.MarkSelectedBee(x); selectedBee = beePicker.GetSelectedBee(x); } /// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); //画游戏背景 spriteBatch.Draw(backgroundTexture, Vector2.Zero, Color.White); //判断游戏是否结束 if (!gameOver) { //绘制花精灵 foreach (Column c in columns) c.Draw(); //绘制蜜蜂精灵 beePicker.Draw(); } else { spriteBatch.DrawString(largeFont, "GAME OVER", new Vector2(150, 400), Color.Red); } spriteBatch.Draw(foregroundTexture, Vector2.Zero, Color.White); DrawHUD(); spriteBatch.End(); base.Draw(gameTime); } /// <summary> /// 初始化屏幕 /// </summary> private void DrawHUD() { spriteBatch.Draw(hudTexture, new Vector2(7, 7), Color.White); //Print out game score and level spriteBatch.DrawString(mediumFont, "Marathon", new Vector2(40, 10), Color.Blue); spriteBatch.DrawString(largeFont, score.ToString(), new Vector2(127, 45), Color.Yellow); //TODO: Draw a flower on the HUD spriteBatch.Draw(flowerMapTexture, new Vector2(40, 45), new Rectangle(6*72, 0, 72, 72), Color.White, 0, Vector2.Zero, 0.5f, SpriteEffects.None, 0f); //Print out instructions spriteBatch.DrawString(smallFont, "Match flowers and bees", new Vector2(210, 10), Color.Yellow); spriteBatch.DrawString(smallFont, "Rainbow flowers match", new Vector2(206, 30), Color.Yellow); spriteBatch.DrawString(smallFont, "with all bees", new Vector2(260, 50), Color.Yellow); //Print out goal message spriteBatch.DrawString(largeFont, "Collect Rainbow Flowers", new Vector2(50, 115), Color.Blue); } } }
游戏的项目结构
参考文章: