XNA碰撞检测

时间:2012-12-30 12:14:08

标签: xna collision-detection collision

对于学校我需要在XNA制作这个游戏项目我选择制作基于马里奥的游戏。 但是我现在已经进行了几天的碰撞检测,但我仍然找不到问题。

以下是该项目的链接: ProjectMario

Oke所以这就是它的作用。 enter image description here

这是我的代码

TileManager

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace mariospeed.ManagerClasses
{
    class TileManager
    {
        int[,] tilemap;
        int tilesize;
        int mapSizeX;
        int mapSizeY;
        int tileindex;
        Texture2D tex;
        List<Texture2D> texlis;
        public List<Rectangle> blocks;
        public List<Rectangle> blocksTop;
        public List<Rectangle> blocksLeft;
        public List<Rectangle> blocksRight;
        public List<Rectangle> tile;
        public int mapX;
        public int MapW;



        public TileManager()
        {
            tilemap = new int[,]
            {
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,1,0,1,1,1,1,1,1,1,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
                {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
            };


            tilesize = 28;
            texlis = new List<Texture2D>();
            mapSizeX = tilemap.GetLength(1);
            mapSizeY = tilemap.GetLength(0);
            blocks = new List<Rectangle>();
            blocksTop = new List<Rectangle>();
            blocksLeft = new List<Rectangle>();
            blocksRight = new List<Rectangle>();
            tile = new List<Rectangle>();
            mapX = 0;



            for (int x = 0; x < mapSizeX; x++)
            {
                for (int y = 0; y < mapSizeY; y++)
                {
                    if (tilemap[y, x] == 1)
                    {
                        blocks.Add(new Rectangle(x * tilesize - mapX, y * tilesize, 28, 30));

                    }
                }
            }

            foreach (Rectangle block in blocks)
            {
                blocksTop.Add(new Rectangle(block.Center.X, block.Top, block.Width, block.Height));
            }
            foreach (Rectangle block in blocks)
            {
                blocksLeft.Add(new Rectangle(block.Left, block.Y, 1, block.Height));
            }
            foreach (Rectangle block in blocks)
            {
                blocksRight.Add(new Rectangle(block.Right, block.Y, block.Width / 2, block.Height));
            }


            for (int x = 0; x < mapSizeX; x++)
            {
                for (int y = 0; y < mapSizeY; y++)
                {
                    tile.Add(new Rectangle(x * tilesize, y * tilesize, 28, 30));
                }
            }

            MapW = tilesize * mapSizeX;


        }
            //

        public void LoadContent(Texture2D tex1, Texture2D tex2)
        {
            texlis.Add(tex1);
            texlis.Add(tex2);

        }

        public void Draw(SpriteBatch sp)
        {

            for (int i = 0; i < mapSizeX; i++)
            {
                for (int j = 0; j < mapSizeY; j++)
                {
                    tileindex = tilemap[j, i];
                    tex = texlis[tileindex];


                    sp.Draw(tex, new Rectangle(i * 28 - mapX, j * 30, 28, 30), Color.White);

                }

            }

        }

    }
}

Mario Class

    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;
using mariospeed.GameScenes;


namespace mariospeed.GameComponents
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Mario : Microsoft.Xna.Framework.DrawableGameComponent
    {

        Texture2D texture2;
        public Vector2 cameraPosition;
        public Vector2 worldPosition;
        public Rectangle rectangle;
        public Rectangle footBounds;
        public Rectangle leftRec;
        public Rectangle rightRec;
        KeyboardState keystate;
        KeyboardState oldkeys;
        public string facing;
        public string state;
        public bool jump;
        float jumpSpeed;
        public float gravity;

        public float speed;
        float time;
        public string prevstate;
        Point frameSize;
        Point sheetSize;
        Point currentFrame;
        public Rectangle source;
        float interval;
        //
        Texture2D charr;
        Vector2 charPos;
        bool jumping; //Is the character jumping?
        public float startY, jumpspeed = 0; //startY to tell us //where it lands, jumpspeed to see how fast it jumps
        protected Texture2D texture;
        protected Vector2 position = new Vector2();

        protected const int WIDTH = 64;
        protected const int HEIGHT = 80;

        protected Rectangle screenBounds;

        protected List<Rectangle> frames;    // hierin de grenzen v/d frames
        private int activeFrame;
        public Mario(Game game, Texture2D texture)
            : base(game)
        {
            this.texture = texture;
            screenBounds = new Rectangle(0, 0,
               Game.Window.ClientBounds.Width, Game.Window.ClientBounds.Height);

            frames = new List<Rectangle>();

            CreateFrames();
            activeFrame = 0;
            PutInStartPosition();

            charr = texture; //Load image
            charPos = new Vector2(230, 450);//Char loc, X/Y
            startY = charPos.Y;//Starting position
            jumping = false;//Init jumping to false
            jumpspeed = 0;//Default no speed

            //
            cameraPosition = new Vector2(0, 0);
            worldPosition = new Vector2(40, 0);
            startY = worldPosition.Y;
            facing = "right";
            prevstate = state;
            state = "stand";
            jump = false;
            gravity = 0f;
            speed = 5f;
            frameSize = new Point(28, 30);
            sheetSize = new Point(6, 7);
            currentFrame = new Point(0, 0);
            time = 0f;
            interval = 100f;
            //
        }
        public void PutInStartPosition()
        {
            position.X = 10;
            position.Y = (screenBounds.Height - (texture.Height+18));

        }

        public Vector2 marioPosition()
        {
            return position;
        }
        public void CreateFrames()
        {

            frames.Add(new Rectangle(0, 0, WIDTH, HEIGHT));
            frames.Add(new Rectangle(WIDTH, 0, WIDTH, HEIGHT));
            frames.Add(new Rectangle(2*WIDTH, 0, WIDTH, HEIGHT));
           // frames.Add(new Rectangle(3*WIDTH, 0, WIDTH, HEIGHT));

        }




        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            time += (float)gameTime.ElapsedGameTime.TotalSeconds;
            oldkeys = keystate;
            keystate = Keyboard.GetState();
            cameraPosition.Y += gravity;
            worldPosition.Y += gravity;
            if (keystate.IsKeyDown(Keys.Right))
            {
                cameraPosition.X += speed;
                worldPosition.X += speed;

                facing = "right";


            }
            if (keystate.IsKeyDown(Keys.Left))
            {
                cameraPosition.X -= speed;
                worldPosition.X -= speed;

                facing = "left";


            }
            if (oldkeys.IsKeyDown(Keys.Left) && !keystate.IsKeyDown(Keys.Left))
            {
                state = "stand";
            }

            if (oldkeys.IsKeyDown(Keys.Right) && !keystate.IsKeyDown(Keys.Right))
            {
                state = "stand";
            }



            if (state == "stand")
            {

                if (keystate.IsKeyDown(Keys.Left))
                {
                    state = "walk";
                     MoveAnimation(gameTime);
                }
                if (keystate.IsKeyDown(Keys.Right))
                {
                    state = "walk";
                    MoveAnimation(gameTime);
                }
            }

            if (state == "walk")
            {
                activeFrame = (activeFrame + 1) % frames.Count;
                gravity = 5f;

            }
            if (state == "stand")
            {
                activeFrame = 0;
                gravity = 5f;
                 StandAnimation();
            }

            //

            if (jump)
            {
                state = "jump";
                cameraPosition.Y += jumpSpeed;
                worldPosition.Y += jumpSpeed;
                jumpSpeed += 1f;
                if (jumpSpeed == 0)
                {
                    jumpSpeed = 0;
                    jump = false;
                    state = "fall";
                }

            }
            else
            {
                if (worldPosition.Y == startY)
                {
                    if (keystate.IsKeyDown(Keys.Space) && !oldkeys.IsKeyDown(Keys.Space))
                    {
                        jumpSpeed -= 18f;
                        jump = true;
                        gravity = 0f;
                    }
                }
            }

            if (state == "fall")
            {
                gravity = 5f;
                JumpAnimation();
            }
            if (state == "jump")
            {
                JumpAnimation();
            }
            if (worldPosition.Y > startY)
            {
                state = "fall";

            }



            rectangle = new Rectangle((int)worldPosition.X, (int)worldPosition.Y, WIDTH, HEIGHT);
            footBounds = new Rectangle(rectangle.Center.X, rectangle.Center.Y, rectangle.Width, 1);
            rightRec = new Rectangle(rectangle.Center.X, rectangle.Y, rectangle.Width / 2, rectangle.Height);
            leftRec = new Rectangle(rectangle.Left, rectangle.Y, 1, rectangle.Height);



            base.Update(gameTime);

        }
        public override void Draw(GameTime gameTime)
        {
            SpriteBatch sBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
            if (facing == "right")
            {
                sBatch.Draw(texture, cameraPosition, frames[activeFrame], Color.White, 0f, new Vector2(rectangle.Width / 2, rectangle.Height / 2), 1.0f, SpriteEffects.None, 0);
                    }

            if (facing == "left")
            {
                sBatch.Draw(texture, cameraPosition, frames[activeFrame], Color.White, 0f, new Vector2(rectangle.Width / 2, rectangle.Height / 2), 1.0f, SpriteEffects.FlipHorizontally, 0);

            }
            //sBatch.Draw(texture, position, frames[activeFrame], Color.White);

            base.Draw(gameTime);
        }

        public void MoveAnimation(GameTime gt)
        {

            time += (float)gt.ElapsedGameTime.TotalMilliseconds;
            currentFrame.Y = 3;

            frameSize = new Point(33, 33);
            if (time > interval)
            {
                currentFrame.X++;
                if (currentFrame.X > 4)
                {
                    currentFrame.X = 1;
                }
                source = new Rectangle(currentFrame.X * frameSize.X, currentFrame.Y * 25, frameSize.X, frameSize.Y);
                time = 0f;
            }
        }

        public void JumpAnimation()
        {

            currentFrame.Y = 5;
            currentFrame.X = 1;
            frameSize = new Point(33, 33);
            source = new Rectangle(currentFrame.X * frameSize.X, currentFrame.Y * frameSize.Y, frameSize.X, frameSize.Y);

        }

        public void FallAnimation()
        {
            currentFrame.X = 5;
            currentFrame.X = 2;
            frameSize = new Point(33, 33);
            source = new Rectangle(currentFrame.X * frameSize.X, currentFrame.Y * frameSize.Y, frameSize.X, frameSize.Y);
        }
        public void StandAnimation()
        {
            currentFrame.X = 1;
            currentFrame.Y = 2;
            frameSize = new Point(33, 33);
            source = new Rectangle(currentFrame.X * frameSize.X, currentFrame.Y * 19, frameSize.X, frameSize.Y);

        }

    }
}

And The Collision Detection Method

    public void Collision()
        {


            foreach (Rectangle top in map.blocksTop)
            {
                if (top.Intersects(mario.footBounds))
                {
                    mario.gravity = 0f;
                    mario.state = "stand";
                    mario.startY = mario.worldPosition.Y;
                }
            }

            foreach (Rectangle left in map.blocksLeft)
            {
                if (left.Intersects(mario.rightRec))
                {
                    if (mario.footBounds.Y >= left.Y)
                    {

                        mario.worldPosition.X -= 5f;
                        mario.cameraPosition.X -= 5f;
                    }
                }
            }

            foreach (Rectangle right in map.blocksRight)
            {
                if (right.Intersects(mario.leftRec))
                {
                    if (mario.footBounds.Y >= right.Y)
                    {
                        mario.worldPosition.X += 5f;
                        mario.cameraPosition.X += 5f;
                    }
                }
            }

        }

有人能告诉我我做错了吗?

亲切的问候 Trustos

2 个答案:

答案 0 :(得分:0)

您可以使用构建碰撞功能,该功能基本上适用于游戏中的方形对象或构建bool函数,如果您的对象位于其他对象的同一位置或尝试移动它,则返回true。或者尝试使用youtube进行学习教程或者一些物理学:)。

答案 1 :(得分:0)

这是一种为侧滚动执行切片碰撞的简单方法。如果角色真的很快,这将无效。假设您的游戏以60 fps运行以获得更好的结果。

在两个轴上分开测试。从Y开始。如果目的地的图块被占用,请将Y夹在顶部或底部。

然后以相同的方式做X.它非常基本,但适用于这种情况。

Tile tileY = GetTileAt(Position.X, Position.Y + Velocity.Y);

if (tileY.IsOccupied)
{
    if (Velocity.Y >= 0) // Player is falling down
    {
        // Set position (feet) on top of the tile
        Position.Y = tileY.Y;
    }
    else
    {
        // Set position bellow the tile
        Position.Y = tileY.Y + TILE_HEIGHT + CHARACTER_HEIGHT;
    }
}

// Similar for X, but use the update Y position to fetch the tile
Tile tileX = GetTileAt(Position.X + Velocity.X, Position.Y);
if (tileX.IsOccupied)
{
    if (Velocity.X >= 0) // Player is going right
    {
        Position.X = tileX.X - (CHARACTER_WIDTH / 2);
    }
    else
    {
        Position.X = tileX.X + TILE_WIDTH + (CHARACTER_WIDTH / 2);
    }
}