1

对不起所有的代码,但我对 Visual C# 和 XNA 完全陌生。

该程序脱离了 Aaron Reed 的 Learning XNA 4.0。我的教授修改了它应该做的一些事情(这本书涵盖了其中的一部分,但不是全部)。大部分代码都是从书中复制的。

这些是对成品的最低要求:

  1. 您可以使用任意 2 张图像代替 3 Rings 和 Skull ball(或者如果您愿意,您仍然可以使用相同的图像)——一张是玩家(3 枚戒指),另一张是参与者(也称为敌人)
  2. 玩家精灵只能使用箭头键移动(鼠标未激活)
  3. 参与者精灵是自动化的,它们可以自由移动(如果您愿意,可以随机移动)并且它们会从边界反弹(以您选择的任何方式)
  4. 游戏开始时有 1 个玩家和 5 个参与者精灵
  5. 游戏持续整整 120 秒,在游戏结束时,如果玩家精灵摧毁了所有参与者(敌人精灵),屏幕上会打印一条消息,指示玩家获胜;否则打印一条玩家输掉的消息
  6. 每 10 秒就会在任意位置出现一个新的敌方精灵化身
  7. 只有当敌方精灵发生碰撞并且同时按下“A”键时,玩家精灵才能摧毁敌方精灵。如果在没有碰撞的情况下按下“A”键,则会出现 2 个敌人的化身
  8. 敌人的精灵必须以合理的速度移动(我的意思不是很慢)才能使游戏有意义
  9. 你需要在你的程序中有一些声音——一个总是播放的背景声音,一个在敌人被摧毁时播放的声音,一个不同的声音,当玩家开火但敌人没有被摧毁,因为没有碰撞,当一个新的敌人出现(每 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);
    }
}
4

1 回答 1

1

对于您的碰撞代码:

    if (position.Y > clientBounds.Height - frameSize.Y ||
        position.Y < 0)
        speed *= -1;

你是在告诉精灵只走上去。基本上,当它在 y 上达到 -1 时,它会向正方向移动,直到它变为正方向,在这种情况下,它会向负方向移动。所以你一直在屏幕外的正面和负面之间切换。我的建议是将这些陈述分成两部分,这样当你不逃避时,你就会准确地从墙上反弹。

    if (position.X > clientBounds.Width - frameSize.X)
        speed *= -1;
    else if (position.X<=0)
        speed*=1;
    if (position.Y > ClientBounds.Height - frameSize.Y)
          speed *= -1;
    else if(position.Y > 0)
          speed *= 1;
于 2014-08-16T14:13:56.243 回答