当前位置: 首页 > news >正文

从零开发游戏需要学习的c#模块,第二十三章(粒子效果 —— 让游戏“活”起来本课目标)

本节课学习目标

  1. 创建粒子系统类

  2. 吃金币时生成金色星星粒子

  3. 碰敌人时生成红色火花粒子

  4. 粒子自动衰减、消失

第一步:创建粒子类

右键项目 →添加,文件名Particle.cs

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;

namespace MY_FIRST_GAME
{
public class Particle
{
public Vector2 Position;
public Vector2 Velocity; // 速度(方向和快慢)
public float Lifetime; // 剩余生命(秒)
public float MaxLifetime; // 最大生命(秒)
public Color Color;
public float Size; // 粒子大小
public float Rotation; // 旋转角度
public float RotationSpeed; // 旋转速度

public bool IsAlive => Lifetime > 0;

public Particle(Vector2 position, Vector2 velocity, float lifetime, Color color, float size)
{
Position = position;
Velocity = velocity;
Lifetime = lifetime;
MaxLifetime = lifetime;
Color = color;
Size = size;
Rotation = 0f;
RotationSpeed = (float)(new Random().NextDouble() * 10 - 5); // 随机旋转
}

public void Update(float deltaTime)
{
Lifetime -= deltaTime;
Position += Velocity * deltaTime;
Velocity *= 0.98f; // 速度衰减
Rotation += RotationSpeed * deltaTime;
}

// 透明度随生命值变化
public float Alpha => Math.Clamp(Lifetime / MaxLifetime, 0f, 1f);
}
}

第二步:创建粒子系统类

右键项目 →添加,文件名ParticleSystem.cs

using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; using System.Collections.Generic; namespace MY_FIRST_GAME { public class ParticleSystem { private List<Particle> particles = new List<Particle>(); private Texture2D particleTexture; private Random rng = new Random(); public ParticleSystem(GraphicsDevice graphicsDevice) { // 创建圆形粒子纹理 int size = 16; particleTexture = new Texture2D(graphicsDevice, size, size); Color[] data = new Color[size * size]; for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { float dx = x - size / 2f; float dy = y - size / 2f; float dist = (float)Math.Sqrt(dx * dx + dy * dy); if (dist < size / 2f) { float alpha = 1f - (dist / (size / 2f)); data[y * size + x] = new Color(1f, 1f, 1f, alpha); } else { data[y * size + x] = Color.Transparent; } } } particleTexture.SetData(data); } // ★ 生成金币粒子(金色星星效果) public void EmitCoinParticles(Vector2 position, int count = 8) { for (int i = 0; i < count; i++) { float angle = (float)(rng.NextDouble() * Math.PI * 2); float speed = (float)(rng.NextDouble() * 150 + 50); Vector2 velocity = new Vector2( (float)Math.Cos(angle) * speed, (float)Math.Sin(angle) * speed - 80 // 稍微向上 ); float lifetime = (float)(rng.NextDouble() * 0.5 + 0.3); Color color = rng.Next(2) == 0 ? Color.Gold : Color.Yellow; particles.Add(new Particle(position, velocity, lifetime, color, 12)); } } // ★ 生成敌人碰撞粒子(红色火花效果) public void EmitHitParticles(Vector2 position, int count = 12) { for (int i = 0; i < count; i++) { float angle = (float)(rng.NextDouble() * Math.PI * 2); float speed = (float)(rng.NextDouble() * 200 + 80); Vector2 velocity = new Vector2( (float)Math.Cos(angle) * speed, (float)Math.Sin(angle) * speed ); float lifetime = (float)(rng.NextDouble() * 0.4 + 0.2); Color color = Color.Lerp(Color.Red, Color.Orange, (float)rng.NextDouble()); particles.Add(new Particle(position, velocity, lifetime, color, 10)); } } public void Update(float deltaTime) { for (int i = particles.Count - 1; i >= 0; i--) { particles[i].Update(deltaTime); if (!particles[i].IsAlive) particles.RemoveAt(i); } } public void Draw(SpriteBatch spriteBatch) { foreach (Particle p in particles) { spriteBatch.Draw( particleTexture, p.Position, null, p.Color * p.Alpha, p.Rotation, new Vector2(particleTexture.Width / 2, particleTexture.Height / 2), p.Size / particleTexture.Width, SpriteEffects.None, 0f ); } } public int ParticleCount => particles.Count; } }

第三步:集成到 Game1.cs

Game1.cs完整替换为:

using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Audio; 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 Player player = default!; private Texture2D playerSpriteSheet; private Texture2D coinTexture; private List<Vector2> coins; private Random rng; private int score; private Texture2D enemyTexture; private List<Vector2> enemies; private SpriteFontBase font; private GameState state = GameState.Exploring; // 音频 private SoundEffect coinSound = default!; private SoundEffect hitSound = default!; // ★ 粒子系统 private ParticleSystem particleSystem = default!; public Game1() { _graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; IsMouseVisible = true; } protected override void Initialize() { _graphics.PreferredBackBufferWidth = 800; _graphics.PreferredBackBufferHeight = 600; _graphics.ApplyChanges(); rng = new Random(); coins = new List<Vector2>(); enemies = new List<Vector2>(); score = 0; SpawnCoins(5); SpawnEnemies(3); // ★ 初始化粒子系统 particleSystem = new ParticleSystem(GraphicsDevice); base.Initialize(); } protected override void LoadContent() { _spriteBatch = new SpriteBatch(GraphicsDevice); // 玩家 using var stream = File.OpenRead("Content/player_spritesheet.png"); playerSpriteSheet = Texture2D.FromStream(GraphicsDevice, stream); player = new Player(playerSpriteSheet, new Vector2(400, 300)); // 金币 coinTexture = new Texture2D(GraphicsDevice, 24, 24); Color[] coinData = new Color[24 * 24]; for (int i = 0; i < coinData.Length; i++) coinData[i] = Color.Gold; coinTexture.SetData(coinData); // 敌人 enemyTexture = new Texture2D(GraphicsDevice, 40, 40); Color[] enemyData = new Color[40 * 40]; 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); // 音效 try { using var coinStream = File.OpenRead("Content/coin.wav"); coinSound = SoundEffect.FromStream(coinStream); using var hitStream = File.OpenRead("Content/hit.wav"); hitSound = SoundEffect.FromStream(hitStream); } catch { } } private void SpawnCoins(int count) { for (int i = 0; i < count; i++) coins.Add(new Vector2(rng.Next(50, 750), rng.Next(50, 550))); } private void SpawnEnemies(int count) { for (int i = 0; i < count; i++) enemies.Add(new Vector2(rng.Next(80, 720), rng.Next(80, 520))); } protected override void Update(GameTime gameTime) { float deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; KeyboardState keyboard = Keyboard.GetState(); if (state == GameState.Exploring) { player.Update(deltaTime); CheckCoinCollision(); CheckEnemyCollision(); if (coins.Count == 0) SpawnCoins(5); if (enemies.Count == 0) SpawnEnemies(3); } // ★ 更新粒子 particleSystem.Update(deltaTime); if (keyboard.IsKeyDown(Keys.M)) SoundEffect.MasterVolume = SoundEffect.MasterVolume > 0 ? 0f : 1f; if (keyboard.IsKeyDown(Keys.Escape)) Exit(); base.Update(gameTime); } private void CheckCoinCollision() { Rectangle playerRect = player.GetBounds(); for (int i = coins.Count - 1; i >= 0; i--) { Rectangle coinRect = new Rectangle((int)coins[i].X, (int)coins[i].Y, 24, 24); if (playerRect.Intersects(coinRect)) { Vector2 coinPos = coins[i]; coins.RemoveAt(i); score += 10; // ★ 生成金币粒子 particleSystem.EmitCoinParticles(coinPos); try { coinSound?.Play(); } catch { } } } } private void CheckEnemyCollision() { Rectangle playerRect = player.GetBounds(); for (int i = enemies.Count - 1; i >= 0; i--) { Rectangle enemyRect = new Rectangle( (int)enemies[i].X - 20, (int)enemies[i].Y - 20, 40, 40); if (playerRect.Intersects(enemyRect)) { Vector2 enemyPos = enemies[i]; enemies.RemoveAt(i); score += 50; // ★ 生成碰撞粒子 particleSystem.EmitHitParticles(enemyPos); try { hitSound?.Play(); } catch { } } } } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); _spriteBatch.Begin(); // 金币 foreach (Vector2 coinPos in coins) _spriteBatch.Draw(coinTexture, coinPos, Color.White); // 敌人 foreach (Vector2 enemyPos in enemies) _spriteBatch.Draw(enemyTexture, enemyPos, null, Color.White, 0f, new Vector2(20, 20), 1f, SpriteEffects.None, 0f); // ★ 粒子(画在玩家下面) particleSystem.Draw(_spriteBatch); // 玩家 player.Draw(_spriteBatch); // 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, $"粒子:{particleSystem.ParticleCount}", new Vector2(10, 85), Color.Cyan); _spriteBatch.DrawString(font, "WASD移动 | M静音 | ESC退出", new Vector2(10, 570), Color.LightGray); _spriteBatch.End(); base.Draw(gameTime); } } }

本节课新知识

1. 粒子物理

csharp

Position += Velocity * deltaTime; // 按速度移动 Velocity *= 0.98f; // 速度逐渐衰减 Lifetime -= deltaTime; // 生命倒计时
2. 圆形纹理生成

csharp

float dist = sqrt(dx² + dy²); if (dist < radius) alpha = 1 - (dist / radius); // 边缘透明
3. 随机发射方向

csharp

float angle = random * PI * 2; Vector2 velocity = (cos(angle) * speed, sin(angle) * speed);
4. 颜色混合

csharp

Color.Lerp(Color.Red, Color.Orange, random); // 红橙之间随机 p.Color * p.Alpha // 颜色 × 透明度

本节课学习内容到此结束,我叫魔法阵维护师,关注我,下期更精彩!

http://www.jsqmd.com/news/876410/

相关文章:

  • 从ANOVA到回归模型:深入理解F检验在机器学习模型评估中的双重角色
  • 快速掌握qmc-decoder:终极QQ音乐加密音频解密转换指南
  • MiGPT终极指南:零代码将小爱音箱改造成AI语音助手
  • 2026年探秘武夷山!国家公园一号风景道包车之旅等你来开启 - GrowthUME
  • 如何高效移除Unity游戏马赛克:UniversalUnityDemosaics实战指南
  • 机器学习公平性:程序公平与分配公平的权衡与实现路径
  • Playwright国内安装失败原因与镜像配置全指南
  • 如何快速安装Windows包管理器:Winget一键安装完整指南
  • 用Node.js重写Frida CLI:告别Python依赖的轻量级动态分析方案
  • DDR指标:量化数据质量,评估模型鲁棒性的新方法
  • 猫抓浏览器插件终极指南:三步快速获取网页视频音频资源
  • 终极Zotero中文文献管理指南:茉莉花插件三招解决90%难题
  • 5分钟极速上手:Windows平台PDF处理工具完全部署指南
  • 东莞不锈钢编织带金属屏蔽网厂家2026解析,提供高性价比产品 - GrowthUME
  • 量子机器学习中噪声鲁棒观测量的原理、学习框架与应用
  • 阴阳师自动化脚本终极指南:如何用智能工具解放你的游戏时间
  • IDA Pro JSON-RPC接口实战:构建可编程逆向工程服务
  • 狄拉克方程信号处理:统一节点与边信号的拓扑机器学习新范式
  • 网盘下载新革命:LinkSwift直链助手让你的下载速度飞起来
  • 终极指南:如何用ncmdumpGUI快速解密网易云音乐NCM文件
  • 长春包装制品,纸壳包装,托盘,空运纸壳包装等优选商家推荐 - GrowthUME
  • 鸣潮自动化脚本:解放双手的智能游戏助手终极指南
  • Steam创意工坊模组下载终极指南:WorkshopDL跨平台模组自由教程
  • JMeter接口测试深度指南:协议、数据、断言与压测避坑全解析
  • 5分钟解锁PS4手柄在Windows的终极玩法:DS4Windows完全指南
  • Thorium浏览器:基于Chromium的终极性能优化与隐私保护深度解析
  • 如何让老款Mac焕发新生:OpenCore Legacy Patcher终极适配指南
  • 如何让Chromium浏览器性能提升3倍:Thorium项目的编译优化实战指南
  • 中国车牌生成器技术深度解析:从算法原理到AI数据增强实战
  • 三分钟掌握专业AI换脸:roop-unleashed零门槛视频制作指南