本节课目标按鼠标右键释放范围爆炸爆炸有冷却时间5秒屏幕显示冷却进度图标爆炸范围内所有敌人受到大量伤害爆炸有视觉特效第一步给 Player 类加技能打开Player.cs添加以下内容1. 添加字段csharp// 技能系统 private float skillCooldown 5f; private float skillTimer 0f; private bool skillReady true;2. 添加方法csharp// 尝试释放技能返回是否成功 public bool TryUseSkill(float deltaTime) { if (!skillReady) { skillTimer - deltaTime; if (skillTimer 0) { skillReady true; skillTimer 0; } return false; } return true; } public void UseSkill() { skillReady false; skillTimer skillCooldown; } // 技能冷却百分比0 到 10冷却好了 public float GetSkillCooldownPercent() { if (skillReady) return 0; return skillTimer / skillCooldown; }第二步创建爆炸特效类右键项目 →添加→类文件名Explosion.csusing Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; namespace MY_FIRST_GAME { public class Explosion { public Vector2 Position; public float Radius; public float MaxRadius; public float Duration; public float Timer; public bool IsAlive Timer Duration; public int Damage; public Explosion(Vector2 position, float radius, float duration, int damage) { Position position; Radius 0; MaxRadius radius; Duration duration; Damage damage; Timer 0; } public void Update(float deltaTime) { Timer deltaTime; float progress Timer / Duration; Radius MaxRadius * progress; // 半径逐渐扩大 // 伤害在爆炸瞬间判定progress 0.1 时 } public void Draw(SpriteBatch spriteBatch, GraphicsDevice graphicsDevice) { float alpha 1f - (Timer / Duration); // 逐渐透明 // 画扩散圆环 int segments 32; float angleStep MathF.PI * 2 / segments; for (int i 0; i segments; i) { float angle1 i * angleStep; float angle2 (i 1) * angleStep; float x1 Position.X MathF.Cos(angle1) * Radius; float y1 Position.Y MathF.Sin(angle1) * Radius; float x2 Position.X MathF.Cos(angle2) * Radius; float y2 Position.Y MathF.Sin(angle2) * Radius; // 简单的线段绘制用 1x1 像素 DrawLine(spriteBatch, graphicsDevice, new Vector2(x1, y1), new Vector2(x2, y2), Color.Orange * alpha, 3); } } private void DrawLine(SpriteBatch spriteBatch, GraphicsDevice device, Vector2 start, Vector2 end, Color color, int thickness) { Texture2D pixel new Texture2D(device, 1, 1); pixel.SetData(new[] { Color.White }); float distance Vector2.Distance(start, end); float angle MathF.Atan2(end.Y - start.Y, end.X - start.X); spriteBatch.Draw(pixel, start, null, color, angle, Vector2.Zero, new Vector2(distance, thickness), SpriteEffects.None, 0); } public bool Intersects(Vector2 target, float targetRadius) { float dist Vector2.Distance(Position, target); return dist Radius targetRadius; } } }第三步改造Game1.cs以下是需要改动的地方1. 添加字段csharpprivate ListExplosion explosions default!;2. 在InitializeGame里初始化csharpexplosions new ListExplosion();3. 在Update的 Game 状态里添加技能触发和爆炸更新在子弹发射的代码后面加csharp// ★ 右键释放技能 if (currentMouse.RightButton ButtonState.Pressed previousMouse.RightButton ButtonState.Released) { if (player.TryUseSkill(deltaTime)) { player.UseSkill(); Vector2 mouseWorld camera.ScreenToWorld( new Vector2(currentMouse.X, currentMouse.Y)); explosions.Add(new Explosion(mouseWorld, 120f, 0.5f, 60)); try { shootSound?.Play(); } catch { } // 可换成爆炸音效 } }在粒子更新后面加csharp// 更新爆炸 foreach (Explosion exp in explosions) exp.Update(deltaTime); // ★ 爆炸伤害判定 for (int i explosions.Count - 1; i 0; i--) { if (explosions[i].Timer 0.1f) // 只在爆炸初期判定一次 { for (int j enemies.Count - 1; j 0; j--) { if (explosions[i].Intersects(enemies[j].Position, 20)) { enemies[j].Hp - explosions[i].Damage; if (enemies[j].Hp 0) { enemies[j].IsAlive false; score enemies[j].ScoreValue; enemiesDefeatedThisGame; particleSystem.EmitHitParticles(enemies[j].Position); // 加经验和掉落判定... } } } } } explosions.RemoveAll(e !e.IsAlive);4. 在DrawGameWorld里画爆炸csharpforeach (Explosion exp in explosions) exp.Draw(_spriteBatch, GraphicsDevice);5. 替换DrawGameUI里添加技能冷却图标在 UI 最后加csharp// ★ 技能冷却图标 DrawSkillCooldown(_spriteBatch, 700, 500, 40);6. 添加冷却图标绘制方法csharpprivate void DrawSkillCooldown(SpriteBatch spriteBatch, int x, int y, int size) { Texture2D pixel new Texture2D(GraphicsDevice, 1, 1); pixel.SetData(new[] { Color.White }); // 背景 spriteBatch.Draw(pixel, new Rectangle(x, y, size, size), Color.DarkSlateGray); spriteBatch.Draw(pixel, new Rectangle(x 2, y 2, size - 4, size - 4), Color.Black); // 冷却覆盖从下往上 float cooldownPercent player.GetSkillCooldownPercent(); if (cooldownPercent 0) { int coverHeight (int)((size - 4) * cooldownPercent); spriteBatch.Draw(pixel, new Rectangle(x 2, y 2, size - 4, coverHeight), Color.DarkBlue * 0.7f); } // 图标文字 _spriteBatch.DrawString(font, ⚡, new Vector2(x 8, y 6), Color.Gold); _spriteBatch.DrawString(font, 右键, new Vector2(x - 15, y size 5), Color.LightGray); }好了本节课学习就此结束我叫魔法阵维护师关注我下期更精彩
从零开发游戏需要学习的c#模块,第三十一章(技能冷却系统 —— 范围爆炸)
本节课目标按鼠标右键释放范围爆炸爆炸有冷却时间5秒屏幕显示冷却进度图标爆炸范围内所有敌人受到大量伤害爆炸有视觉特效第一步给 Player 类加技能打开Player.cs添加以下内容1. 添加字段csharp// 技能系统 private float skillCooldown 5f; private float skillTimer 0f; private bool skillReady true;2. 添加方法csharp// 尝试释放技能返回是否成功 public bool TryUseSkill(float deltaTime) { if (!skillReady) { skillTimer - deltaTime; if (skillTimer 0) { skillReady true; skillTimer 0; } return false; } return true; } public void UseSkill() { skillReady false; skillTimer skillCooldown; } // 技能冷却百分比0 到 10冷却好了 public float GetSkillCooldownPercent() { if (skillReady) return 0; return skillTimer / skillCooldown; }第二步创建爆炸特效类右键项目 →添加→类文件名Explosion.csusing Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; namespace MY_FIRST_GAME { public class Explosion { public Vector2 Position; public float Radius; public float MaxRadius; public float Duration; public float Timer; public bool IsAlive Timer Duration; public int Damage; public Explosion(Vector2 position, float radius, float duration, int damage) { Position position; Radius 0; MaxRadius radius; Duration duration; Damage damage; Timer 0; } public void Update(float deltaTime) { Timer deltaTime; float progress Timer / Duration; Radius MaxRadius * progress; // 半径逐渐扩大 // 伤害在爆炸瞬间判定progress 0.1 时 } public void Draw(SpriteBatch spriteBatch, GraphicsDevice graphicsDevice) { float alpha 1f - (Timer / Duration); // 逐渐透明 // 画扩散圆环 int segments 32; float angleStep MathF.PI * 2 / segments; for (int i 0; i segments; i) { float angle1 i * angleStep; float angle2 (i 1) * angleStep; float x1 Position.X MathF.Cos(angle1) * Radius; float y1 Position.Y MathF.Sin(angle1) * Radius; float x2 Position.X MathF.Cos(angle2) * Radius; float y2 Position.Y MathF.Sin(angle2) * Radius; // 简单的线段绘制用 1x1 像素 DrawLine(spriteBatch, graphicsDevice, new Vector2(x1, y1), new Vector2(x2, y2), Color.Orange * alpha, 3); } } private void DrawLine(SpriteBatch spriteBatch, GraphicsDevice device, Vector2 start, Vector2 end, Color color, int thickness) { Texture2D pixel new Texture2D(device, 1, 1); pixel.SetData(new[] { Color.White }); float distance Vector2.Distance(start, end); float angle MathF.Atan2(end.Y - start.Y, end.X - start.X); spriteBatch.Draw(pixel, start, null, color, angle, Vector2.Zero, new Vector2(distance, thickness), SpriteEffects.None, 0); } public bool Intersects(Vector2 target, float targetRadius) { float dist Vector2.Distance(Position, target); return dist Radius targetRadius; } } }第三步改造Game1.cs以下是需要改动的地方1. 添加字段csharpprivate ListExplosion explosions default!;2. 在InitializeGame里初始化csharpexplosions new ListExplosion();3. 在Update的 Game 状态里添加技能触发和爆炸更新在子弹发射的代码后面加csharp// ★ 右键释放技能 if (currentMouse.RightButton ButtonState.Pressed previousMouse.RightButton ButtonState.Released) { if (player.TryUseSkill(deltaTime)) { player.UseSkill(); Vector2 mouseWorld camera.ScreenToWorld( new Vector2(currentMouse.X, currentMouse.Y)); explosions.Add(new Explosion(mouseWorld, 120f, 0.5f, 60)); try { shootSound?.Play(); } catch { } // 可换成爆炸音效 } }在粒子更新后面加csharp// 更新爆炸 foreach (Explosion exp in explosions) exp.Update(deltaTime); // ★ 爆炸伤害判定 for (int i explosions.Count - 1; i 0; i--) { if (explosions[i].Timer 0.1f) // 只在爆炸初期判定一次 { for (int j enemies.Count - 1; j 0; j--) { if (explosions[i].Intersects(enemies[j].Position, 20)) { enemies[j].Hp - explosions[i].Damage; if (enemies[j].Hp 0) { enemies[j].IsAlive false; score enemies[j].ScoreValue; enemiesDefeatedThisGame; particleSystem.EmitHitParticles(enemies[j].Position); // 加经验和掉落判定... } } } } } explosions.RemoveAll(e !e.IsAlive);4. 在DrawGameWorld里画爆炸csharpforeach (Explosion exp in explosions) exp.Draw(_spriteBatch, GraphicsDevice);5. 替换DrawGameUI里添加技能冷却图标在 UI 最后加csharp// ★ 技能冷却图标 DrawSkillCooldown(_spriteBatch, 700, 500, 40);6. 添加冷却图标绘制方法csharpprivate void DrawSkillCooldown(SpriteBatch spriteBatch, int x, int y, int size) { Texture2D pixel new Texture2D(GraphicsDevice, 1, 1); pixel.SetData(new[] { Color.White }); // 背景 spriteBatch.Draw(pixel, new Rectangle(x, y, size, size), Color.DarkSlateGray); spriteBatch.Draw(pixel, new Rectangle(x 2, y 2, size - 4, size - 4), Color.Black); // 冷却覆盖从下往上 float cooldownPercent player.GetSkillCooldownPercent(); if (cooldownPercent 0) { int coverHeight (int)((size - 4) * cooldownPercent); spriteBatch.Draw(pixel, new Rectangle(x 2, y 2, size - 4, coverHeight), Color.DarkBlue * 0.7f); } // 图标文字 _spriteBatch.DrawString(font, ⚡, new Vector2(x 8, y 6), Color.Gold); _spriteBatch.DrawString(font, 右键, new Vector2(x - 15, y size 5), Color.LightGray); }好了本节课学习就此结束我叫魔法阵维护师关注我下期更精彩