从零开发游戏需要学习的c#模块,第三十章(掉落物品 —— 血包与能量)

本节课学习内容

  1. 敌人死亡时概率掉落血包或能量球

  2. 血包恢复血量

  3. 能量球暂时提升攻击力

  4. 掉落物有吸引动画(可选)

第一步:创建掉落物类

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

csharp

复制代码
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace MY_FIRST_GAME
{
    public enum PickupType
    {
        Health,   // 血包:恢复25点血量
        Power     // 能量球:5秒内攻击力翻倍
    }

    public class Pickup
    {
        public Vector2 Position;
        public PickupType Type;
        public bool IsAlive = true;
        public float Lifetime = 10f;  // 10秒后消失
        public int Value;

        private Texture2D texture;
        private float timer;
        private float floatOffset;
        private float floatSpeed = 0.5f;

        public Pickup(Vector2 position, PickupType type, GraphicsDevice graphicsDevice)
        {
            Position = position;
            Type = type;

            int size = 20;
            texture = new Texture2D(graphicsDevice, size, size);
            Color[] data = new Color[size * size];

            switch (type)
            {
                case PickupType.Health:
                    Value = 25;
                    // 红色十字
                    for (int y = 0; y < size; y++)
                        for (int x = 0; x < size; x++)
                        {
                            bool horizontal = (y >= size * 0.35f && y <= size * 0.65f);
                            bool vertical = (x >= size * 0.35f && x <= size * 0.65f);
                            if (horizontal || vertical)
                                data[y * size + x] = Color.Red;
                            else
                                data[y * size + x] = Color.Transparent;
                        }
                    break;

                case PickupType.Power:
                    Value = 5;  // 持续5秒
                    // 黄色闪电
                    for (int y = 0; y < size; y++)
                        for (int x = 0; x < size; x++)
                        {
                            float dx = x - size / 2f;
                            float dy = y - size / 2f;
                            if (dx * dx + dy * dy < (size / 2f) * (size / 2f))
                                data[y * size + x] = Color.Gold;
                            else
                                data[y * size + x] = Color.Transparent;
                        }
                    break;
            }
            texture.SetData(data);
        }

        public void Update(float deltaTime)
        {
            timer += deltaTime;
            floatOffset = (float)System.Math.Sin(timer * 3) * 5; // 上下浮动

            if (timer >= Lifetime)
                IsAlive = false;
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            Vector2 drawPos = Position + new Vector2(0, floatOffset);
            spriteBatch.Draw(texture, drawPos, null, Color.White,
                0f, new Vector2(texture.Width / 2, texture.Height / 2),
                1f, SpriteEffects.None, 0f);
        }

        public Rectangle GetBounds()
        {
            return new Rectangle(
                (int)(Position.X - texture.Width / 2),
                (int)(Position.Y - texture.Height / 2),
                texture.Width, texture.Height);
        }
    }
}

第二步:给 Player 类加 BUFF 系统

Player.cs 里添加:

cs 复制代码
// BUFF 相关
private bool isPoweredUp;
private float powerTimer;
private int originalAttack;

// 在构造函数里保存原始攻击力
// 在 Player 构造函数末尾加:originalAttack = Attack;

// 添加方法
public void ApplyPowerUp(float duration)
{
    if (!isPoweredUp)
    {
        originalAttack = Attack;
        isPoweredUp = true;
    }
    powerTimer = duration;
    Attack = originalAttack * 2;  // 攻击力翻倍
}

public void UpdateBuffs(float deltaTime)
{
    if (isPoweredUp)
    {
        powerTimer -= deltaTime;
        if (powerTimer <= 0)
        {
            isPoweredUp = false;
            Attack = originalAttack;  // 恢复
        }
    }
}

public bool HasPowerUp => isPoweredUp;
public float PowerUpTimeRemaining => powerTimer;

Player 的构造函数最后加一行:

csharp

复制代码
originalAttack = Attack;

第三步:改造 Game1.cs

只列出需要改的地方。

1. 添加字段:

csharp

复制代码
private List<Pickup> pickups = default!;

2. 在 InitializeGame 里初始化:

csharp

复制代码
pickups = new List<Pickup>();

3. 在击杀敌人的地方加掉落逻辑:

CheckBulletEnemyCollision 击杀分支里:

csharp

复制代码
if (enemies[j].Hp <= 0)
{
    // ...原有代码...

    // ★ 掉落判定
    float dropChance = (float)rng.NextDouble();
    if (dropChance < 0.4f)  // 40%概率掉落
    {
        if (dropChance < 0.25f)  // 25%血包
            pickups.Add(new Pickup(enemies[j].Position, PickupType.Health, GraphicsDevice));
        else  // 15%能量球
            pickups.Add(new Pickup(enemies[j].Position, PickupType.Power, GraphicsDevice));
    }
}

4. 在 Update 的 Game 状态里更新掉落物:

csharp

复制代码
// 更新掉落物
foreach (Pickup pickup in pickups)
    pickup.Update(deltaTime);
pickups.RemoveAll(p => !p.IsAlive);

// 更新玩家 BUFF
player.UpdateBuffs(deltaTime);

// 检测玩家和掉落物碰撞
CheckPickupCollision();

5. 添加碰撞检测方法:

csharp

复制代码
private void CheckPickupCollision()
{
    Rectangle playerRect = player.GetBounds();
    for (int i = pickups.Count - 1; i >= 0; i--)
    {
        if (pickups[i].GetBounds().Intersects(playerRect))
        {
            Pickup pickup = pickups[i];
            pickups.RemoveAt(i);

            switch (pickup.Type)
            {
                case PickupType.Health:
                    player.Hp = Math.Min(player.Hp + pickup.Value, player.MaxHp);
                    floatingTexts.Add(new FloatingText(pickup.Position, $"+{pickup.Value} HP", Color.Red));
                    break;
                case PickupType.Power:
                    player.ApplyPowerUp(pickup.Value);
                    floatingTexts.Add(new FloatingText(pickup.Position, "攻击力UP!", Color.Gold));
                    break;
            }
        }
    }
}

6. 在 DrawGameWorld 里画掉落物:

csharp

复制代码
foreach (Pickup pickup in pickups)
    pickup.Draw(_spriteBatch);

7. 在 DrawGameUI 里加 BUFF 提示:

在 UI 最后加:

csharp

复制代码
if (player.HasPowerUp)
{
    _spriteBatch.DrawString(font,
        $"⚡ 攻击力UP:{player.PowerUpTimeRemaining:F1}秒",
        new Vector2(600, 30), Color.Gold);
}

好了,本节课学习内容到此结束,关注我,下期更精彩!

相关推荐
落寞的星星5 小时前
这个对象就包含了已经转换好的DFA和各种词法分析器运转所需要的参数。下一步,我们就可以用ScannerInfo对象创建出Scanner对象,请看下面的代码:
开发语言·c#
聪慧的水蜜桃8 小时前
【YFIOs】用C#开发硬件之设备上云
开发语言·c#
星幻元宇VR10 小时前
公共安全实训展厅设备【人防知识学习系统】
科技·学习·安全
心中有国也有家13 小时前
AtomGit Flutter 鸿蒙客户端:情绪日记的时间线实现
学习·flutter·华为·harmonyos
hixiong12313 小时前
TensorRT转换工具分享
人工智能·计算机视觉·ai·c#
百里香酚兰14 小时前
【python学习笔记】pyttsx3库疑似只播报一次语音
笔记·python·学习
恣逍信点14 小时前
《凌微经》助读:本体论根基——“无之自悖”与“形性一体”
人工智能·科技·学习·程序人生·生活·交友·哲学
莫生灬灬15 小时前
DY联系人聊天Web面板支持获取联系人/聊天记录/发送消息
前端·chrome·websocket·c#
vivo互联网技术15 小时前
当 AI 进入推荐系统:从“推什么”到“怎么选”
人工智能·游戏·产品
chh56316 小时前
C++--string
java·开发语言·网络·c++·学习