如何防止玩家对象在二维环境中穿过墙壁

时间:2013-01-09 02:25:21

标签: c# xna 2d

播放器盒以不希望的方式继续穿过墙壁,我尝试制作它以便玩家一次以0.1f(u)的增量移动,但这严重降低了游戏的性能。有什么方法我可以检测到玩家是否正在撞墙,他们在哪一侧击中它以及如何防止它们被撞到墙上?

这是我正在运行的代码(当然这是极简主义的)

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace Platformer
{

    public class Player
    {
        double terminalVelocity;
        //AnimatedTexture texture;
        public Texture2D texture;
        public Vector2 Position, Velocity;
        public Rectangle boundingBox;
        public Player(Texture2D tex, Vector2 pos, Vector2 vel, Rectangle bb)
        {
            texture = tex;
            Position = pos;
            Velocity = vel;
            boundingBox = bb;
            terminalVelocity = Math.Sqrt((2*bb.Width*bb.Height*Game1.gravity)/-9.8*2);
        }

        public void updateBoundingBoxes()
        {
            boundingBox.X = (int)Position.X;
            boundingBox.Y = (int)Position.Y;
        }

        public void onUpdate()  
        {
            updateBoundingBoxes();
            Position.X += Velocity.X;
            Position.Y += Velocity.Y;
            //Velocity = Vector2.Zero;
            Velocity.Y += Game1.gravity / 60;
            Velocity.X /= 1.2f;
        }

        public void Draw(SpriteBatch sb)
        {
            updateBoundingBoxes();
            sb.Begin();
                sb.Draw(texture,boundingBox,GameLighting.currentColour());
            sb.End();
        }

    }

    public enum GameLightingState
    {
        Red, Dark, Orange, Blue, White
    }

    public class Platform : Object
    {

        Texture2D text;
        public Rectangle rect;
        public Platform(Texture2D t, Vector2 p, int sizeX, int sizeY)
        {

            text = t;
            rect = new Rectangle((int)p.X, (int)p.Y, sizeX, sizeY);


        }

        public void onPlayerCollision(Player p)
        {
            p.Velocity.X = -p.Velocity.X / 2;
            p.Velocity.Y = -p.Velocity.Y / 2;
        }

        public void Draw(SpriteBatch sb)
        {
            sb.Begin();
               sb.Draw(text, rect, GameLighting.currentColour());
            sb.End();
        }

        public void onUpdate()
        {

        }

    }

    public class GameLighting
    {
        public static Color currentColour()
        {
            return eToColour(Game1.currentLightingState);
        }

        public static Color eToColour(GameLightingState gls)
        {
            switch (gls)
            {
                case(GameLightingState.Red):
                    return Color.Red;
                case (GameLightingState.Blue):
                    return Color.Blue;
                case (GameLightingState.Orange):
                    return Color.Orange;
                case (GameLightingState.Dark):
                    return Color.DarkGray;
                case (GameLightingState.White):
                    return Color.White;
            }
            return Color.White;
        }
    }


    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        public static float gravity = 9.80665f;
        public static GameLightingState currentLightingState;
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        List<Platform> platforms;
        List<Player> players;
        int controlledPlayerIndex = 0;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            currentLightingState = GameLightingState.White;
            platforms = new List<Platform>();
            players = new List<Player>();
            players.Add(new Player(this.Content.Load<Texture2D>("Images/dirt"), new Vector2(300,0), new Vector2(0,0), new Rectangle(300,0,20,20)));
            platforms.Add(new Platform(this.Content.Load<Texture2D>("Images/dirt"),new Vector2(300,450),200,20));
            platforms.Add(new Platform(this.Content.Load<Texture2D>("Images/dirt"), new Vector2(20,20), 20, 200));
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            foreach (Player p in players)
            {
                Boolean intersects = false;
                Rectangle tempRectangle = new Rectangle((int)(p.Position.X + p.Velocity.X),(int) (p.Position.Y + p.Velocity.Y), p.boundingBox.Width, p.boundingBox.Height);
                foreach (Platform pl in platforms)
                {
                    intersects = intersects || tempRectangle.Intersects(pl.rect);
                }
                if (!intersects)
                {
                    p.onUpdate();


                }
            }

            if (Keyboard.GetState().IsKeyDown(Keys.Space))
            {
                players[controlledPlayerIndex].Velocity.Y -= 0.75f;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.A)) 
            {
                players[controlledPlayerIndex].Velocity.X -= 0.75f;
            }
            if (Keyboard.GetState().IsKeyDown(Keys.D))
            {
                players[controlledPlayerIndex].Velocity.X += 0.75f;
            }

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here

            foreach (Platform p in platforms)
            {
                p.Draw(spriteBatch);
            }
            foreach (Player p in players)
            {
               p.Draw(spriteBatch);
            }
            base.Draw(gameTime);
        }
    }
}

*根据第一条评论更新了源代码

关于这段代码的一个注意事项,你需要在XNA中运行它并在一个名为Images的文件夹中使用一个名为dirt.png的图标,它与图片的外观无关,你只需要它就可以完全理解它是什么发生

1 个答案:

答案 0 :(得分:1)

最近我自己也遇到过类似的问题。这就是我所做的。

//variables needed
public bool follow = true;
public Vector2D startpoint;

//puts the startpoint value equal
//to the inital location of the player
public Player()
{
    startpoint.X = rectangle.X;
    startpoint.Y = rectangle.Y;
}

//if any of the collision tests fail
if(collision occurs)
{
    collision();
}
//else update startpoint to new valid location
else 
{
    startpoint.X = rectangle.X;
    startpoint.Y = rectangle.Y;
    follow = true;
}
if(follow == true)
{
    //movement commands occur
}
else
{
    follow = true;
}

//if a condition fails set player
//too last valid location
public void collision()
{
    rectangle.X = startpoint.X;
    rectangle.Y = startpoint.Y;
    follow = false;
}

这对我来说效果很好,希望它有所帮助。