)
本节课目标用二维数组定义地图根据数组绘制墙壁和地面玩家碰到墙壁会停下来金币和敌人不生成在墙壁上第一步创建地图类右键项目 →添加→类文件名TileMap.cscsharpusing Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System.Collections.Generic; namespace MY_FIRST_GAME { public class TileMap { // 瓦片类型 public enum TileType { Empty 0, // 空地 Wall 1, // 墙壁 } public int TileSize { get; private set; } 40; public int Width { get; private set; } public int Height { get; private set; } public TileType[,] Tiles; private Texture2D wallTexture; private Texture2D floorTexture; // ★ 地图数据0空地, 1墙壁 // 可以手动编辑这个数组来设计地图 private int[,] mapData new int[,] { {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, }; public TileMap(GraphicsDevice graphicsDevice) { Height mapData.GetLength(0); Width mapData.GetLength(1); Tiles new TileType[Width, Height]; // 转换地图数据 for (int y 0; y Height; y) for (int x 0; x Width; x) Tiles[x, y] (TileType)mapData[y, x]; // 创建墙壁纹理 wallTexture new Texture2D(graphicsDevice, TileSize, TileSize); Color[] wallData new Color[TileSize * TileSize]; for (int i 0; i wallData.Length; i) wallData[i] Color.DarkSlateGray; wallTexture.SetData(wallData); // 创建地板纹理 floorTexture new Texture2D(graphicsDevice, TileSize, TileSize); Color[] floorData new Color[TileSize * TileSize]; for (int i 0; i floorData.Length; i) floorData[i] new Color(30, 30, 30); floorTexture.SetData(floorData); } public void Draw(SpriteBatch spriteBatch) { for (int x 0; x Width; x) { for (int y 0; y Height; y) { Vector2 position new Vector2(x * TileSize, y * TileSize); if (Tiles[x, y] TileType.Wall) spriteBatch.Draw(wallTexture, position, Color.White); else spriteBatch.Draw(floorTexture, position, Color.White); } } } // 检查某个像素位置是否是墙壁 public bool IsWall(Vector2 position) { int tileX (int)(position.X / TileSize); int tileY (int)(position.Y / TileSize); if (tileX 0 || tileX Width || tileY 0 || tileY Height) return true; // 地图外也算墙 return Tiles[tileX, tileY] TileType.Wall; } // 检查矩形是否碰到墙壁 public bool CollidesWithWall(Rectangle bounds) { int left bounds.Left / TileSize; int right bounds.Right / TileSize; int top bounds.Top / TileSize; int bottom bounds.Bottom / TileSize; for (int x left; x right; x) { for (int y top; y bottom; y) { if (x 0 || x Width || y 0 || y Height) return true; if (Tiles[x, y] TileType.Wall) return true; } } return false; } // 获取地图上的随机空地 public Vector2 GetRandomEmptyPosition(Random rng, int margin 1) { while (true) { int x rng.Next(margin, Width - margin); int y rng.Next(margin, Height - margin); if (Tiles[x, y] TileType.Empty) return new Vector2(x * TileSize TileSize / 2, y * TileSize TileSize / 2); } } } }第二步改造 Player 类以支持墙壁碰撞把Player.cs的Update方法替换为// 在 Player 类顶部添加字段 private TileMap tileMap; // 修改构造函数接收 TileMap public Player(Texture2D spriteSheet, Vector2 startPosition, TileMap map) { Position startPosition; texture spriteSheet; tileMap map; idleAnimation new Animation(texture, 1, 0f, true); walkAnimation new Animation(texture, 4, 0.15f, true); currentAnimation idleAnimation; } // 替换 Update 方法 public void Update(float deltaTime) { KeyboardState keyboard Keyboard.GetState(); Vector2 newPosition Position; bool isMovingNow false; if (keyboard.IsKeyDown(Keys.W) || keyboard.IsKeyDown(Keys.Up)) { newPosition.Y - Speed * deltaTime; isMovingNow true; } if (keyboard.IsKeyDown(Keys.S) || keyboard.IsKeyDown(Keys.Down)) { newPosition.Y Speed * deltaTime; isMovingNow true; } if (keyboard.IsKeyDown(Keys.A) || keyboard.IsKeyDown(Keys.Left)) { newPosition.X - Speed * deltaTime; isMovingNow true; } if (keyboard.IsKeyDown(Keys.D) || keyboard.IsKeyDown(Keys.Right)) { newPosition.X Speed * deltaTime; isMovingNow true; } isMoving isMovingNow; // ★ 碰撞检测分别检测 X 和 Y 轴 Rectangle newBounds GetBoundsAt(newPosition); // 先试 X 轴 Rectangle xBounds new Rectangle( newBounds.X, GetBounds().Y, newBounds.Width, GetBounds().Height ); if (!tileMap.CollidesWithWall(xBounds)) Position new Vector2(newPosition.X, Position.Y); // 再试 Y 轴 Rectangle yBounds new Rectangle( GetBounds().X, newBounds.Y, GetBounds().Width, newBounds.Height ); if (!tileMap.CollidesWithWall(yBounds)) Position new Vector2(Position.X, newPosition.Y); // 切换动画 if (isMoving) { if (currentAnimation ! walkAnimation) { walkAnimation.Reset(); currentAnimation walkAnimation; } } else { currentAnimation idleAnimation; } currentAnimation.Update(deltaTime); } // 添加辅助方法 private Rectangle GetBoundsAt(Vector2 pos) { Rectangle sourceRect currentAnimation.GetSourceRectangle(); return new Rectangle( (int)(pos.X - sourceRect.Width / 2), (int)(pos.Y - sourceRect.Height / 2), sourceRect.Width, sourceRect.Height ); }第三步改造Game1.cs把Game1.cs里关于TileMap的部分加上。只改以下三个地方1. 添加字段csharpprivate TileMap tileMap default!;2. 在InitializeGame()里初始化地图csharptileMap new TileMap(GraphicsDevice);3. 修改玩家创建两处csharp// LoadContent 里 player new Player(playerSpriteSheet, tileMap.GetRandomEmptyPosition(rng), tileMap); // 标题画面开始新游戏时 player new Player(playerSpriteSheet, tileMap.GetRandomEmptyPosition(rng), tileMap);4. 在SpawnCoins和SpawnEnemies里使用地图随机空地csharpprivate void SpawnCoins(int count) { for (int i 0; i count; i) coins.Add(tileMap.GetRandomEmptyPosition(rng)); } private void SpawnEnemies(int count) { for (int i 0; i count; i) enemies.Add(tileMap.GetRandomEmptyPosition(rng)); }5. 在DrawGame()最前面画地图csharptileMap.Draw(_spriteBatch);本节课学习到此结束我是魔法阵维护师关注我下期更精彩