从零开发游戏需要学习的c#模块,第十八章(2D 碰撞检测与金币收集)

这节课我们将要学习

  1. 在地图上随机生成金币(黄色方块代替)

  2. 玩家碰到金币后,金币消失,分数增加

  3. 屏幕左上角显示实时分数

将game1替换为

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Graphics;

using Microsoft.Xna.Framework.Input;

using System;

using System.Collections.Generic;

namespace MY_FIRST_GAME

{

public class Game1 : Game

{

private GraphicsDeviceManager _graphics;

private SpriteBatch _spriteBatch;

// 玩家

private Texture2D playerTexture;

private Vector2 playerPosition;

private float playerSpeed = 200f;

// ★ 金币

private Texture2D coinTexture;

private List<Vector2> coins;

private Random rng;

private int score;

// 字体(显示分数用)

private SpriteFont font;

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 List<Vector2>();

score = 0;

// 生成 5 个金币

SpawnCoins(5);

base.Initialize();

}

protected override void LoadContent()

{

_spriteBatch = new SpriteBatch(GraphicsDevice);

// 加载玩家图片

using var stream = System.IO.File.OpenRead("Content/player.png");

playerTexture = Texture2D.FromStream(GraphicsDevice, stream);

// ★ 创建金币纹理(黄色 32x32 方块)

coinTexture = new Texture2D(GraphicsDevice, 32, 32);

Color\[\] data = new Color32 \* 32;

for (int i = 0; i < data.Length; i++)

datai = Color.Gold;

coinTexture.SetData(data);

// ★ 加载字体(需要先创建字体文件,见下方说明)

// font = Content.Load<SpriteFont>("font");

}

// ★ 生成金币

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));

}

}

protected override void Update(GameTime gameTime)

{

KeyboardState keyboard = Keyboard.GetState();

float speed = playerSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;

float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

// 移动

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();

// ★ 金币捡完了重新生成

if (coins.Count == 0)

SpawnCoins(5);

if (keyboard.IsKeyDown(Keys.Escape))

Exit();

base.Update(gameTime);

}

// ★ 碰撞检测

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)coinsi.X, (int)coinsi.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);

}

// 画玩家(以图片中心为锚点)

_spriteBatch.Draw(

playerTexture,

playerPosition,

null,

Color.White,

0f,

new Vector2(playerTexture.Width / 2, playerTexture.Height / 2),

1f,

SpriteEffects.None,

0f

);

// ★ 画分数(暂时用窗口标题栏显示)

Window.Title = $"分数:{score} | 剩余金币:{coins.Count}";

_spriteBatch.End();

base.Draw(gameTime);

}

}

}

本节课学习的新内容

1. 碰撞检测:Rectangle.Intersects()
cs 复制代码
Rectangle playerRect = new Rectangle(玩家左上角X, 玩家左上角Y, 宽度, 高度);
Rectangle coinRect = new Rectangle(金币X, 金币Y, 32, 32);

if (playerRect.Intersects(coinRect))
{
    // 碰撞了!
}
2. 以图片中心为锚点画图
cs 复制代码
_spriteBatch.Draw(
    playerTexture,          // 纹理
    playerPosition,         // 位置
    null,                   // 不裁剪
    Color.White,            // 颜色
    0f,                     // 不旋转
    new Vector2(width/2, height/2),  // ★ 锚点设为中心
    1f,                     // 不缩放
    SpriteEffects.None,     // 不翻转
    0f                      // 深度
);
3. Math.Clamp 限制范围
cs 复制代码
playerPosition.X = Math.Clamp(playerPosition.X, 最小值, 最大值);

好了这节课就此结束,关注我,下期更精彩

相关推荐
samble5 小时前
从零搭建灌装监控系统(十七):LiveCharts 实时温度曲线
c#·wpf·mvvm·modbus·工业控制
别动我齐刘海6 小时前
C++ 工程化学习
java·linux·前端·c++·学习·机器学习·机器人
甲维斯8 小时前
我用AI做了一款「三国吃鸡」,开局孔明灯,落地青龙刀 !
人工智能·游戏·游戏开发
gjf05_059 小时前
人该怎样活着呢?版本75.8
学习
li星野11 小时前
【学习记录】PCB与PCBA核心知识全解析:从设计到制造的关键细节
学习·制造
卿卿的产品经理日记11 小时前
【AI产品经理实战】Day 35|从“沉迷工具“到回归 AI 底层:Skill 收官、系统复盘与下一个 13 天
人工智能·学习·产品经理
myshare202212 小时前
Dungeon Saga 常用词中英文对照表(阵营 / 品质 / 部位 / 套装 / 属性 / 套装效果)
游戏·dungeon saga·链游攻略
一条泥憨鱼12 小时前
【从0开始学习计算机网络】| ARP 协议:地址解析,ARP 欺骗,链路层寻址
网络·后端·学习·计算机网络
薛定谔的猫-菜鸟程序员12 小时前
上传试卷、打Boss,玩游戏:我用 TextIn xParse 做了一套“会解析试卷的刷题游戏“
人工智能·游戏·大模型·textin·ai数据层基础设施
HY小宝F13 小时前
树莓派智能摄像头系统 30 天重学计划之 Day 04 · HTTP / API:控制链入口 —— 学习总结
网络协议·学习·http