从零开发游戏需要学习的c#模块,第三十章(掉落物品 —— 血包与能量)
本节课学习内容
敌人死亡时概率掉落血包或能量球
血包恢复血量
能量球暂时提升攻击力
掉落物有吸引动画(可选)
第一步:创建掉落物类
右键项目 →添加→类,文件名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里添加:
// 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); }好了,本节课学习内容到此结束,关注我,下期更精彩!
