对不起所有的代码,但我对 Visual C# 和 XNA 完全陌生。
该程序脱离了 Aaron Reed 的 Learning XNA 4.0。我的教授修改了它应该做的一些事情(这本书涵盖了其中的一部分,但不是全部)。大部分代码都是从书中复制的。
这些是对成品的最低要求:
- 您可以使用任意 2 张图像代替 3 Rings 和 Skull ball(或者如果您愿意,您仍然可以使用相同的图像)——一张是玩家(3 枚戒指),另一张是参与者(也称为敌人)
- 玩家精灵只能使用箭头键移动(鼠标未激活)
- 参与者精灵是自动化的,它们可以自由移动(如果您愿意,可以随机移动)并且它们会从边界反弹(以您选择的任何方式)
- 游戏开始时有 1 个玩家和 5 个参与者精灵
- 游戏持续整整 120 秒,在游戏结束时,如果玩家精灵摧毁了所有参与者(敌人精灵),屏幕上会打印一条消息,指示玩家获胜;否则打印一条玩家输掉的消息
- 每 10 秒就会在任意位置出现一个新的敌方精灵化身
- 只有当敌方精灵发生碰撞并且同时按下“A”键时,玩家精灵才能摧毁敌方精灵。如果在没有碰撞的情况下按下“A”键,则会出现 2 个敌人的化身
- 敌人的精灵必须以合理的速度移动(我的意思不是很慢)才能使游戏有意义
- 你需要在你的程序中有一些声音——一个总是播放的背景声音,一个在敌人被摧毁时播放的声音,一个不同的声音,当玩家开火但敌人没有被摧毁,因为没有碰撞,当一个新的敌人出现(每 10 秒)
我试图让敌人(骷髅球)躲避玩家(三环),但敌人要么在所有方面都没有反应(玩家在右侧或左侧,并且敌人直到玩家在上方才会躲避或下),当敌人确实躲避时,他们会在屏幕外晃动消失(他们只是突然直线上升或下降,而且他们正在快速晃动。
当新敌人在 10 秒后生成时,从左上角开始,它会从底墙上弹起,然后在返回时消失在屏幕外。
10 秒后,头骨也不会在屏幕周围随机生成。
此外,我不知道如何在按下 A 按钮且没有碰撞的情况下再生成 2 个敌人。
精灵管理器.cs
namespace Assignment_2
{
public class SpriteManager : Microsoft.Xna.Framework.DrawableGameComponent
{
//SpriteBatch for drawing
SpriteBatch spriteBatch;
//A sprite for the player and a list of automated sprites
UserControlledSprite player;
List<Sprite> spriteList = new List<Sprite>();
int enemySpawnMinMilliseconds = 10000;
int enemySpawnMaxMilliseconds = 10000;
int enemyMinSpeed = 10;
int enemyMaxSpeed = 10;
int nextSpawnTime = 0;
public SpriteManager(Game game)
: base(game)
{
// TODO: Construct any child components here
}
public override void Initialize()
{
// TODO: Add your initialization code here
ResetSpawnTime();
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(Game.GraphicsDevice);
//Load the player sprite
player = new UserControlledSprite(
Game.Content.Load<Texture2D>(@"Images/threerings"),
Vector2.Zero, new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(6, 6));
//Load several different automated sprites into the list to test
//spriteList.Add(new AutomatedSprite(
// Game.Content.Load<Texture2D>(@"Images/skullball"),
// new Vector2(150, 150), new Point(75, 75), 10, new Point(0, 0),
// new Point(6, 8), new Vector2(3, 0), "skullcollision"));
//spriteList.Add(new AutomatedSprite(
// Game.Content.Load<Texture2D>(@"Images/skullball"),
// new Vector2(300, 150), new Point(75, 75), 10, new Point(0, 0),
// new Point(6, 8), new Vector2(-2, 0), "skullcollision"));
////spriteList.Add(new AutomatedSprite(
//// Game.Content.Load<Texture2D>(@"Images/skullball"),
//// new Vector2(150, 300), new Point(75, 75), 10, new Point(0, 0),
//// new Point(6, 8), new Vector2(3, 4), "skullcollision"));
////spriteList.Add(new AutomatedSprite(
//// Game.Content.Load<Texture2D>(@"Images/skullball"),
//// new Vector2(300, 400), new Point(75, 75), 10, new Point(0, 0),
//// new Point(6, 8), new Vector2(0, -3), "skullcollision"));
////spriteList.Add(new AutomatedSprite(
//// Game.Content.Load<Texture2D>(@"Images/skullball"),
//// new Vector2(200, 300), new Point(75, 75), 10, new Point(0, 0),
//// new Point(6, 8), new Vector2(-3, 7), "skullcollision"));
spriteList.Add(new EvadingSprite(
Game.Content.Load<Texture2D>(@"Images/skullball"),
new Vector2(150, 150), new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(3, 0), "skullcollision", this, .75f, 150));
spriteList.Add(new EvadingSprite(
Game.Content.Load<Texture2D>(@"Images/skullball"),
new Vector2(300, 150), new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(-2, 0), "skullcollision", this, .75f, 150));
spriteList.Add(new EvadingSprite(
Game.Content.Load<Texture2D>(@"Images/skullball"),
new Vector2(150, 300), new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(3, 4), "skullcollision", this, .75f, 150));
spriteList.Add(new EvadingSprite(
Game.Content.Load<Texture2D>(@"Images/skullball"),
new Vector2(300, 400), new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(0, -3), "skullcollision", this, .75f, 150));
spriteList.Add(new EvadingSprite(
Game.Content.Load<Texture2D>(@"Images/skullball"),
new Vector2(200, 300), new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(-3, 7), "skullcollision", this, .75f, 150));
base.LoadContent();
}
public override void Update(GameTime gameTime)
{
nextSpawnTime -= gameTime.ElapsedGameTime.Milliseconds;
if (nextSpawnTime < 0)
{
SpawnEnemy();
//reset spawn timer
ResetSpawnTime();
}
// Update player
player.Update(gameTime, Game.Window.ClientBounds);
// Update all sprites
for (int i = 0; i < spriteList.Count; ++i)
{
Sprite s = spriteList[i];
s.Update(gameTime, Game.Window.ClientBounds);
// Check for collisions
if (s.collisionRect.Intersects(player.collisionRect) && (Keyboard.GetState().IsKeyDown(Keys.A)))
{
// Play collision sound
if (s.collisionCueName != null)
((Game1)Game).PlayCue(s.collisionCueName);
// Remove collided sprite from the game
spriteList.RemoveAt(i);
--i;
}
}
base.Update(gameTime);
}
public override void Draw(GameTime gameTime)
{
spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
// Draw the player
player.Draw(gameTime, spriteBatch);
// Draw all sprites
foreach (Sprite s in spriteList)
s.Draw(gameTime, spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
// Return current position of the player sprite
public Vector2 GetPlayerPosition()
{
return player.GetPosition;
}
private void SpawnEnemy()
{
Vector2 speed = Vector2.Zero;
Vector2 position = Vector2.Zero;
// Default frame size
Point frameSize = new Point(75, 75);
// Create the sprite. NOTE: This sprite bounces off the bottom wall then goes back and disappears offscreen
spriteList.Add(
new EvadingSprite(Game.Content.Load<Texture2D>(@"images\skullball"),
position, new Point(75, 75), 10, new Point(0, 0),
new Point(6, 8), new Vector2(3, 4), "skullcollision", this, .75f, 150));
}
private void ResetSpawnTime()
{
nextSpawnTime = ((Game1)Game).rnd.Next(
enemySpawnMinMilliseconds,
enemySpawnMaxMilliseconds);
}
}
}
闪避精灵
class EvadingSprite : Sprite
{
// Save a reference to the sprite manager to
// use to get the player position
SpriteManager spriteManager;
// Variables to delay evasion until player is close
float evasionSpeedModifier;
int evasionRange;
bool evade = false;
public EvadingSprite(Texture2D textureImage, Vector2 position,
Point frameSize, int collisionOffset, Point currentFrame,
Point sheetSize, Vector2 speed, string collisionCueName,
SpriteManager spriteManager, float evasionSpeedModifier,
int evasionRange)
: base(textureImage, position, frameSize, collisionOffset,
currentFrame, sheetSize, speed, collisionCueName)
{
this.spriteManager = spriteManager;
this.evasionSpeedModifier = evasionSpeedModifier;
this.evasionRange = evasionRange;
}
public EvadingSprite(Texture2D textureImage, Vector2 position,
Point frameSize, int collisionOffset, Point currentFrame,
Point sheetSize, Vector2 speed, int millisecondsPerFrame,
string collisionCueName, SpriteManager spriteManager,
float evasionSpeedModifier, int evasionRange)
: base(textureImage, position, frameSize, collisionOffset,
currentFrame, sheetSize, speed, millisecondsPerFrame,
collisionCueName)
{
this.spriteManager = spriteManager;
this.evasionSpeedModifier = evasionSpeedModifier;
this.evasionRange = evasionRange;
}
public override Vector2 direction
{
get { return speed; }
}
public override void Update(GameTime gameTime, Rectangle clientBounds)
{
// First, move the sprite along its direction vector
position += speed;
// Use the player position to move the sprite closer in
// the X and/or Y directions
Vector2 player = spriteManager.GetPlayerPosition();
if (evade)
{
// Move away from the player horizontally
if (player.X < position.Y)
position.X += Math.Abs(speed.Y);
else if (player.X > position.X)
position.X -= Math.Abs(speed.Y);
// Move away from the player vertically
if (player.Y < position.Y)
position.Y += Math.Abs(speed.X);
else if (player.Y > position.Y)
position.Y -= Math.Abs(speed.X);
}
else
{
if (Vector2.Distance(position, player) < evasionRange)
{
// Player is within evasion range,
// reverse direction and modify speed
speed *= -evasionSpeedModifier;
evade = true;
}
}
//make them bounce off walls
if (position.X > clientBounds.Width - frameSize.X ||
position.X < 0)
speed *= -1;
if (position.Y > clientBounds.Height - frameSize.Y ||
position.Y < 0)
speed *= -1;
base.Update(gameTime, clientBounds);
}
}