从零开发游戏需要学习的c#模块,第三十一章(技能冷却系统 —— 范围爆炸)

本节课目标

  1. 鼠标右键释放范围爆炸

  2. 爆炸有冷却时间(5秒)

  3. 屏幕显示冷却进度图标

  4. 爆炸范围内所有敌人受到大量伤害

  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 到 1,0=冷却好了)
public float GetSkillCooldownPercent()
{
    if (skillReady) return 0;
    return skillTimer / skillCooldown;
}

第二步:创建爆炸特效类

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

cs 复制代码
using 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. 添加字段:

csharp

复制代码
private List<Explosion> explosions = default!;

2. 在 InitializeGame 里初始化:

csharp

复制代码
explosions = new List<Explosion>();

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 里画爆炸:

csharp

复制代码
foreach (Explosion exp in explosions)
    exp.Draw(_spriteBatch, GraphicsDevice);

5. 替换 DrawGameUI 里添加技能冷却图标:

在 UI 最后加:

csharp

复制代码
// ★ 技能冷却图标
DrawSkillCooldown(_spriteBatch, 700, 500, 40);

6. 添加冷却图标绘制方法:

csharp

复制代码
private 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);
}

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

相关推荐
试剂界的爱马仕2 小时前
《古董局·终局5:潮生》第 4 章:藤田的棋局
人工智能·学习
王文?问2 小时前
ESP32-S3 实战教程:本地语音识别控制 Web 塔防游戏,从固件到前端完整跑通
前端·游戏·语音识别
searchforAI2 小时前
我的Obsidian知识库,现在可以自动剪藏笔记到本地了
人工智能·笔记·学习·音视频·ai工具·obsidian·视频总结
周末也要写八哥2 小时前
Visual C++6.0下载安装流程及PDF学习手册资源
c++·学习·pdf
a1117762 小时前
网页我的世界游戏 MC (html 开源)
游戏·开源·html
吴可可1232 小时前
ModelSpace常量正确用法解析
c#
坤坤藤椒牛肉面2 小时前
C++学习--类和对象
学习
影寂ldy2 小时前
C#List泛型集合
windows·c#·list
楼田莉子3 小时前
C++20新特性:Range库
开发语言·c++·后端·学习·c++20