本节课我们要学习的内容在地图上随机生成红色敌人玩家碰到敌人后进入战斗模式战斗胜利后敌人消失获得分数屏幕显示敌人数量using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Graphics;using Microsoft.Xna.Framework.Input;using System;using System.Collections.Generic;using System.IO;using FontStashSharp;namespace MY_FIRST_GAME{// ★ 游戏状态枚举public enum GameState{Exploring, // 探索模式Battling // 战斗模式}public class Game1 : Game{private GraphicsDeviceManager _graphics;private SpriteBatch _spriteBatch;// 玩家private Texture2D playerTexture;private Vector2 playerPosition;private float playerSpeed 200f;private int playerHp 100;private int playerMaxHp 100;private int playerAttack 15;// 金币private Texture2D coinTexture;private ListVector2 coins;private Random rng;private int score;// ★ 敌人private Texture2D enemyTexture;private ListEnemyData enemies;// 字体private SpriteFontBase font;// ★ 游戏状态private GameState state GameState.Exploring;// ★ 战斗相关private EnemyData? currentEnemy;private string battleMessage ;private float battleTimer 0f;private bool playerTurn true;public Game1(){_graphics new GraphicsDeviceManager(this);Content.RootDirectory Content;IsMouseVisible true;}protected override void Initialize(){_graphics.PreferredBackBufferWidth 800;_graphics.PreferredBackBufferHeight 600;_graphics.ApplyChanges();playerPosition new Vector2(400, 300);rng new Random();coins new ListVector2();enemies new ListEnemyData();score 0;SpawnCoins(5);SpawnEnemies(3);base.Initialize();}protected override void LoadContent(){_spriteBatch new SpriteBatch(GraphicsDevice);// 玩家图片using var stream File.OpenRead(Content/player.png);playerTexture Texture2D.FromStream(GraphicsDevice, stream);// 金币纹理coinTexture new Texture2D(GraphicsDevice, 32, 32);Color[] coinData new Color[32 * 32];for (int i 0; i coinData.Length; i)coinData[i] Color.Gold;coinTexture.SetData(coinData);// ★ 敌人纹理红色方块 48x48enemyTexture new Texture2D(GraphicsDevice, 48, 48);Color[] enemyData new Color[48 * 48];for (int i 0; i enemyData.Length; i)enemyData[i] Color.Red;enemyTexture.SetData(enemyData);// 字体var fontSystem new FontSystem();fontSystem.AddFont(File.ReadAllBytes(Content/consola.ttf));font fontSystem.GetFont(18);}// ★ 敌人数据结构private class EnemyData{public Vector2 Position;public int Hp;public int MaxHp;public int Attack;public bool IsAlive;public string Name;public EnemyData(Vector2 pos, string name, int hp, int attack){Position pos;Name name;Hp hp;MaxHp hp;Attack attack;IsAlive true;}}private void SpawnCoins(int count){for (int i 0; i count; i){float x rng.Next(50, 750);float y rng.Next(50, 550);coins.Add(new Vector2(x, y));}}private void SpawnEnemies(int count){for (int i 0; i count; i){float x rng.Next(80, 720);float y rng.Next(80, 520);enemies.Add(new EnemyData(new Vector2(x, y),史莱姆 (i 1),30 rng.Next(0, 20),8 rng.Next(0, 6)));}}protected override void Update(GameTime gameTime){KeyboardState keyboard Keyboard.GetState();float deltaTime (float)gameTime.ElapsedGameTime.TotalSeconds;// ★ 根据游戏状态分发更新if (state GameState.Exploring)UpdateExploring(keyboard, deltaTime);else if (state GameState.Battling)UpdateBattling(keyboard, deltaTime);if (keyboard.IsKeyDown(Keys.Escape))Exit();base.Update(gameTime);}// ★ 探索模式更新private void UpdateExploring(KeyboardState keyboard, float deltaTime){float speed playerSpeed * deltaTime;if (keyboard.IsKeyDown(Keys.W) || keyboard.IsKeyDown(Keys.Up))playerPosition.Y - speed;if (keyboard.IsKeyDown(Keys.S) || keyboard.IsKeyDown(Keys.Down))playerPosition.Y speed;if (keyboard.IsKeyDown(Keys.A) || keyboard.IsKeyDown(Keys.Left))playerPosition.X - speed;if (keyboard.IsKeyDown(Keys.D) || keyboard.IsKeyDown(Keys.Right))playerPosition.X speed;playerPosition.X Math.Clamp(playerPosition.X, 32, 768);playerPosition.Y Math.Clamp(playerPosition.Y, 32, 568);CheckCoinCollision();CheckEnemyCollision();if (coins.Count 0) SpawnCoins(5);if (enemies.Count 0) SpawnEnemies(3);}// ★ 战斗模式更新private void UpdateBattling(KeyboardState keyboard, float deltaTime){if (currentEnemy null || !currentEnemy.IsAlive){EndBattle(true);return;}if (playerHp 0){EndBattle(false);return;}// 按空格攻击if (playerTurn keyboard.IsKeyDown(Keys.Space)){// 玩家攻击currentEnemy.Hp - playerAttack;battleMessage $你对 {currentEnemy.Name} 造成了 {playerAttack} 点伤害;playerTurn false;}// 敌人回合简单延迟if (!playerTurn){battleTimer deltaTime;if (battleTimer 0.8f){battleTimer 0f;// 敌人攻击playerHp - currentEnemy.Attack;battleMessage ${currentEnemy.Name} 对你造成了 {currentEnemy.Attack} 点伤害;playerTurn true;}}}// ★ 结束战斗private void EndBattle(bool playerWon){if (playerWon currentEnemy ! null){score 50;currentEnemy.IsAlive false;enemies.Remove(currentEnemy);}currentEnemy null;battleMessage ;battleTimer 0f;playerTurn true;state GameState.Exploring;}// ★ 敌人碰撞检测private void CheckEnemyCollision(){Rectangle playerRect new Rectangle((int)playerPosition.X - 32,(int)playerPosition.Y - 32,64, 64);for (int i enemies.Count - 1; i 0; i--){Rectangle enemyRect new Rectangle((int)enemies[i].Position.X - 24,(int)enemies[i].Position.Y - 24,48, 48);if (playerRect.Intersects(enemyRect)){// 进入战斗currentEnemy enemies[i];state GameState.Battling;battleMessage $遭遇了 {currentEnemy.Name}按 空格 攻击;playerTurn true;battleTimer 0f;break;}}}// 金币碰撞private void CheckCoinCollision(){Rectangle playerRect new Rectangle((int)playerPosition.X - 32,(int)playerPosition.Y - 32,64, 64);for (int i coins.Count - 1; i 0; i--){Rectangle coinRect new Rectangle((int)coins[i].X, (int)coins[i].Y, 32, 32);if (playerRect.Intersects(coinRect)){coins.RemoveAt(i);score 10;}}}protected override void Draw(GameTime gameTime){GraphicsDevice.Clear(Color.CornflowerBlue);_spriteBatch.Begin();// 画金币foreach (Vector2 coinPos in coins)_spriteBatch.Draw(coinTexture, coinPos, Color.White);// ★ 画敌人foreach (EnemyData enemy in enemies){_spriteBatch.Draw(enemyTexture,enemy.Position,null,Color.White,0f,new Vector2(24, 24),1f,SpriteEffects.None,0f);}// 画玩家_spriteBatch.Draw(playerTexture,playerPosition,null,Color.White,0f,new Vector2(playerTexture.Width / 2, playerTexture.Height / 2),1f,SpriteEffects.None,0f);// UI 文字_spriteBatch.DrawString(font, $分数{score}, new Vector2(10, 10), Color.White);_spriteBatch.DrawString(font, $金币{coins.Count}, new Vector2(10, 35), Color.Gold);_spriteBatch.DrawString(font, $敌人{enemies.Count}, new Vector2(10, 60), Color.Red);_spriteBatch.DrawString(font, $HP{playerHp}/{playerMaxHp}, new Vector2(10, 85), Color.LimeGreen);// ★ 战斗界面if (state GameState.Battling currentEnemy ! null){// 半透明背景Texture2D overlay new Texture2D(GraphicsDevice, 1, 1);overlay.SetData(new[] { new Color(0, 0, 0, 180) });_spriteBatch.Draw(overlay, new Rectangle(0, 250, 800, 100), Color.White);_spriteBatch.DrawString(font, $⚔️ {currentEnemy.Name}, new Vector2(20, 260), Color.Red);_spriteBatch.DrawString(font, $敌人HP{currentEnemy.Hp}/{currentEnemy.MaxHp}, new Vector2(20, 285), Color.White);_spriteBatch.DrawString(font, $你的HP{playerHp}/{playerMaxHp}, new Vector2(20, 310), Color.LimeGreen);_spriteBatch.DrawString(font, battleMessage, new Vector2(20, 335), Color.Yellow);}_spriteBatch.DrawString(font, WASD移动 | 靠近敌人战斗 | 战斗中按空格攻击, new Vector2(10, 570), Color.LightGray);_spriteBatch.End();base.Draw(gameTime);}}} 核心新知识1. 游戏状态机public enum GameState { Exploring, Battling } if (state GameState.Exploring) UpdateExploring(...); else if (state GameState.Battling) UpdateBattling(...);这就是你在设计模式课学的状态模式的实际应用。探索和战斗是两个完全独立的逻辑分支。2. 战斗触发if (playerRect.Intersects(enemyRect)) { currentEnemy enemies[i]; state GameState.Battling; }. 战斗流程玩家回合按空格键攻击敌人回合等待 0.8 秒后自动反击战斗结束敌人死亡或玩家死亡回到探索模式
从零开发游戏需要学习的c#模块,第二十章(2D 敌人与战斗触发)
发布时间:2026/5/23 0:49:36
本节课我们要学习的内容在地图上随机生成红色敌人玩家碰到敌人后进入战斗模式战斗胜利后敌人消失获得分数屏幕显示敌人数量using Microsoft.Xna.Framework;using Microsoft.Xna.Framework.Graphics;using Microsoft.Xna.Framework.Input;using System;using System.Collections.Generic;using System.IO;using FontStashSharp;namespace MY_FIRST_GAME{// ★ 游戏状态枚举public enum GameState{Exploring, // 探索模式Battling // 战斗模式}public class Game1 : Game{private GraphicsDeviceManager _graphics;private SpriteBatch _spriteBatch;// 玩家private Texture2D playerTexture;private Vector2 playerPosition;private float playerSpeed 200f;private int playerHp 100;private int playerMaxHp 100;private int playerAttack 15;// 金币private Texture2D coinTexture;private ListVector2 coins;private Random rng;private int score;// ★ 敌人private Texture2D enemyTexture;private ListEnemyData enemies;// 字体private SpriteFontBase font;// ★ 游戏状态private GameState state GameState.Exploring;// ★ 战斗相关private EnemyData? currentEnemy;private string battleMessage ;private float battleTimer 0f;private bool playerTurn true;public Game1(){_graphics new GraphicsDeviceManager(this);Content.RootDirectory Content;IsMouseVisible true;}protected override void Initialize(){_graphics.PreferredBackBufferWidth 800;_graphics.PreferredBackBufferHeight 600;_graphics.ApplyChanges();playerPosition new Vector2(400, 300);rng new Random();coins new ListVector2();enemies new ListEnemyData();score 0;SpawnCoins(5);SpawnEnemies(3);base.Initialize();}protected override void LoadContent(){_spriteBatch new SpriteBatch(GraphicsDevice);// 玩家图片using var stream File.OpenRead(Content/player.png);playerTexture Texture2D.FromStream(GraphicsDevice, stream);// 金币纹理coinTexture new Texture2D(GraphicsDevice, 32, 32);Color[] coinData new Color[32 * 32];for (int i 0; i coinData.Length; i)coinData[i] Color.Gold;coinTexture.SetData(coinData);// ★ 敌人纹理红色方块 48x48enemyTexture new Texture2D(GraphicsDevice, 48, 48);Color[] enemyData new Color[48 * 48];for (int i 0; i enemyData.Length; i)enemyData[i] Color.Red;enemyTexture.SetData(enemyData);// 字体var fontSystem new FontSystem();fontSystem.AddFont(File.ReadAllBytes(Content/consola.ttf));font fontSystem.GetFont(18);}// ★ 敌人数据结构private class EnemyData{public Vector2 Position;public int Hp;public int MaxHp;public int Attack;public bool IsAlive;public string Name;public EnemyData(Vector2 pos, string name, int hp, int attack){Position pos;Name name;Hp hp;MaxHp hp;Attack attack;IsAlive true;}}private void SpawnCoins(int count){for (int i 0; i count; i){float x rng.Next(50, 750);float y rng.Next(50, 550);coins.Add(new Vector2(x, y));}}private void SpawnEnemies(int count){for (int i 0; i count; i){float x rng.Next(80, 720);float y rng.Next(80, 520);enemies.Add(new EnemyData(new Vector2(x, y),史莱姆 (i 1),30 rng.Next(0, 20),8 rng.Next(0, 6)));}}protected override void Update(GameTime gameTime){KeyboardState keyboard Keyboard.GetState();float deltaTime (float)gameTime.ElapsedGameTime.TotalSeconds;// ★ 根据游戏状态分发更新if (state GameState.Exploring)UpdateExploring(keyboard, deltaTime);else if (state GameState.Battling)UpdateBattling(keyboard, deltaTime);if (keyboard.IsKeyDown(Keys.Escape))Exit();base.Update(gameTime);}// ★ 探索模式更新private void UpdateExploring(KeyboardState keyboard, float deltaTime){float speed playerSpeed * deltaTime;if (keyboard.IsKeyDown(Keys.W) || keyboard.IsKeyDown(Keys.Up))playerPosition.Y - speed;if (keyboard.IsKeyDown(Keys.S) || keyboard.IsKeyDown(Keys.Down))playerPosition.Y speed;if (keyboard.IsKeyDown(Keys.A) || keyboard.IsKeyDown(Keys.Left))playerPosition.X - speed;if (keyboard.IsKeyDown(Keys.D) || keyboard.IsKeyDown(Keys.Right))playerPosition.X speed;playerPosition.X Math.Clamp(playerPosition.X, 32, 768);playerPosition.Y Math.Clamp(playerPosition.Y, 32, 568);CheckCoinCollision();CheckEnemyCollision();if (coins.Count 0) SpawnCoins(5);if (enemies.Count 0) SpawnEnemies(3);}// ★ 战斗模式更新private void UpdateBattling(KeyboardState keyboard, float deltaTime){if (currentEnemy null || !currentEnemy.IsAlive){EndBattle(true);return;}if (playerHp 0){EndBattle(false);return;}// 按空格攻击if (playerTurn keyboard.IsKeyDown(Keys.Space)){// 玩家攻击currentEnemy.Hp - playerAttack;battleMessage $你对 {currentEnemy.Name} 造成了 {playerAttack} 点伤害;playerTurn false;}// 敌人回合简单延迟if (!playerTurn){battleTimer deltaTime;if (battleTimer 0.8f){battleTimer 0f;// 敌人攻击playerHp - currentEnemy.Attack;battleMessage ${currentEnemy.Name} 对你造成了 {currentEnemy.Attack} 点伤害;playerTurn true;}}}// ★ 结束战斗private void EndBattle(bool playerWon){if (playerWon currentEnemy ! null){score 50;currentEnemy.IsAlive false;enemies.Remove(currentEnemy);}currentEnemy null;battleMessage ;battleTimer 0f;playerTurn true;state GameState.Exploring;}// ★ 敌人碰撞检测private void CheckEnemyCollision(){Rectangle playerRect new Rectangle((int)playerPosition.X - 32,(int)playerPosition.Y - 32,64, 64);for (int i enemies.Count - 1; i 0; i--){Rectangle enemyRect new Rectangle((int)enemies[i].Position.X - 24,(int)enemies[i].Position.Y - 24,48, 48);if (playerRect.Intersects(enemyRect)){// 进入战斗currentEnemy enemies[i];state GameState.Battling;battleMessage $遭遇了 {currentEnemy.Name}按 空格 攻击;playerTurn true;battleTimer 0f;break;}}}// 金币碰撞private void CheckCoinCollision(){Rectangle playerRect new Rectangle((int)playerPosition.X - 32,(int)playerPosition.Y - 32,64, 64);for (int i coins.Count - 1; i 0; i--){Rectangle coinRect new Rectangle((int)coins[i].X, (int)coins[i].Y, 32, 32);if (playerRect.Intersects(coinRect)){coins.RemoveAt(i);score 10;}}}protected override void Draw(GameTime gameTime){GraphicsDevice.Clear(Color.CornflowerBlue);_spriteBatch.Begin();// 画金币foreach (Vector2 coinPos in coins)_spriteBatch.Draw(coinTexture, coinPos, Color.White);// ★ 画敌人foreach (EnemyData enemy in enemies){_spriteBatch.Draw(enemyTexture,enemy.Position,null,Color.White,0f,new Vector2(24, 24),1f,SpriteEffects.None,0f);}// 画玩家_spriteBatch.Draw(playerTexture,playerPosition,null,Color.White,0f,new Vector2(playerTexture.Width / 2, playerTexture.Height / 2),1f,SpriteEffects.None,0f);// UI 文字_spriteBatch.DrawString(font, $分数{score}, new Vector2(10, 10), Color.White);_spriteBatch.DrawString(font, $金币{coins.Count}, new Vector2(10, 35), Color.Gold);_spriteBatch.DrawString(font, $敌人{enemies.Count}, new Vector2(10, 60), Color.Red);_spriteBatch.DrawString(font, $HP{playerHp}/{playerMaxHp}, new Vector2(10, 85), Color.LimeGreen);// ★ 战斗界面if (state GameState.Battling currentEnemy ! null){// 半透明背景Texture2D overlay new Texture2D(GraphicsDevice, 1, 1);overlay.SetData(new[] { new Color(0, 0, 0, 180) });_spriteBatch.Draw(overlay, new Rectangle(0, 250, 800, 100), Color.White);_spriteBatch.DrawString(font, $⚔️ {currentEnemy.Name}, new Vector2(20, 260), Color.Red);_spriteBatch.DrawString(font, $敌人HP{currentEnemy.Hp}/{currentEnemy.MaxHp}, new Vector2(20, 285), Color.White);_spriteBatch.DrawString(font, $你的HP{playerHp}/{playerMaxHp}, new Vector2(20, 310), Color.LimeGreen);_spriteBatch.DrawString(font, battleMessage, new Vector2(20, 335), Color.Yellow);}_spriteBatch.DrawString(font, WASD移动 | 靠近敌人战斗 | 战斗中按空格攻击, new Vector2(10, 570), Color.LightGray);_spriteBatch.End();base.Draw(gameTime);}}} 核心新知识1. 游戏状态机public enum GameState { Exploring, Battling } if (state GameState.Exploring) UpdateExploring(...); else if (state GameState.Battling) UpdateBattling(...);这就是你在设计模式课学的状态模式的实际应用。探索和战斗是两个完全独立的逻辑分支。2. 战斗触发if (playerRect.Intersects(enemyRect)) { currentEnemy enemies[i]; state GameState.Battling; }. 战斗流程玩家回合按空格键攻击敌人回合等待 0.8 秒后自动反击战斗结束敌人死亡或玩家死亡回到探索模式