Tile map Collision Detection

2020-07-29 18:17发布

问题:

I've been looking through the other questions but just can't seem to figure this out.. I'm using XNA in a custom tilemap loader. Here is the code. http://pastebin.com/cuatQHTb

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 Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace Pressure
{

    public class Game1 : Microsoft.Xna.Framework.Game
    {


        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D player;
        Vector2 pos = Vector2.Zero;
        Vector2 playersp = new Vector2(50.0f, 50.0f);
        Texture2D road1;
        Texture2D road2;
        Texture2D brickwall;
        Texture2D floor1;
        Texture2D floor2;
        Texture2D floor3;
        Texture2D grass;
        Texture2D sidewalk1;
        Texture2D wood;
        Texture2D road3;
        private Vector2 origin;
        KeyboardState currentState;
        Camera camera = new Camera();

        Vector2 motion;

        List<Texture2D> tiles = new List<Texture2D>();

        static int tileWidth = 64;
        static int tileHeight = 64;

        int tileMapWidth;
        int tileMapHeight;

        static int screenWidth;
        static int screenHeight;

        static int mapWidthInPixels;
        static int mapHeightInPixels;
        int[,] map = {
              {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 5, 6, 5, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 6, 5, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 8, 1, 1, 1, 2, 2, 1, 8, 7, 5, 6, 5, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 8, 1, 1, 1, 2, 2, 1, 8, 7, 5, 5, 5, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 8, 1, 1, 1, 1, 1, 1, 8, 7, 5, 5, 5, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 8, 1, 3, 3, 3, 1, 1, 8, 7, 5, 6, 5, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 8, 8, 1, 1, 8, 8, 8, 8, 7, 5, 6, 5, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 6, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,},
              {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,},
              {9, 9, 9, 5, 5, 9, 9, 9, 5, 5, 9, 9, 9, 5, 5, 5, 5, 5, 9, 9, 9, 5, 5, 9, 9, 9, 5, 5, 9,},
              {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,},
              {7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,},
              {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
              {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
                     };
        public static int ScreenWidth
        {
            get { return screenWidth; }
        }

        public static int ScreenHeight
        {
            get { return screenHeight; }
        }

        public static int MapWidthInPixels
        {
            get { return mapWidthInPixels; }
        }

        public static int MapHeightInPixels
        {
            get { return mapHeightInPixels; }
        }
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }


        protected override void Initialize()
        {

            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            player = Content.Load<Texture2D>("haz");
            origin.X = player.Width /2;
            origin.Y = player.Height /2;
            grass = Content.Load<Texture2D>("grass");
            floor1 = Content.Load<Texture2D>("floor1");
            floor2 = Content.Load<Texture2D>("floor2");
            floor3 = Content.Load<Texture2D>("floor3");
            wood = Content.Load<Texture2D>("wood");
            road1 = Content.Load<Texture2D>("road1");
            road2 = Content.Load<Texture2D>("road2");
            sidewalk1 = Content.Load<Texture2D>("sidewalk1");
            brickwall = Content.Load<Texture2D>("brickwall");
            road3 = Content.Load<Texture2D>("road3");
            tiles.Add(grass); //0
            tiles.Add(floor1);//1
            tiles.Add(floor2);//2
            tiles.Add(floor3);//3
            tiles.Add(wood);//4
            tiles.Add(road1);//5
            tiles.Add(road2);//6
            tiles.Add(sidewalk1);//7
            tiles.Add(brickwall);//8
            tiles.Add(road3);//9

            tileMapWidth = map.GetLength(1);
            tileMapHeight = map.GetLength(0);

            mapWidthInPixels = tileMapWidth * tileWidth;
            mapHeightInPixels = tileMapHeight * tileHeight;

            screenWidth = GraphicsDevice.Viewport.Width;
            screenHeight = GraphicsDevice.Viewport.Height;
           }


        protected override void UnloadContent()
        {
             }
        private float RotationAngle;
        private float oldx;
        private float oldy;

        protected override void Update(GameTime gameTime)
        {
            oldx = playersp.X;
            oldy = playersp.Y;
    currentState = Keyboard.GetState();
   pos = playersp;

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            IsMouseVisible = true;


            MouseState Mouses = Mouse.GetState();
            Vector2 mouseLook = new Vector2(Mouses.X, Mouses.Y);

            motion = Vector2.Zero;
            Vector2 direction = (playersp ) - mouseLook; 
            float angle = (float)(Math.Atan2(direction.Y, direction.X));

            RotationAngle = angle ; 
            if (currentState.IsKeyDown(Keys.W))
            {
                if (playersp.Y > screenHeight  /4)
                {
                    playersp.Y = playersp.Y - 1;

                }
                else
                {
                    ScrollUp();

                }
            }
            if (currentState.IsKeyDown(Keys.A))
            {
                if (playersp.X > screenWidth / 4)
                {

                        playersp.X = playersp.X - 1;

                }
                else
                {
                    ScrollLeft();


                }
            }
            if (currentState.IsKeyDown(Keys.S)) 
            {
                if (playersp.Y > screenHeight / 1.5f)
                {
                    ScrollDown();
                }else{
                    playersp.Y = playersp.Y + 1; 
                }

            }
            if (currentState.IsKeyDown( Keys.D))
            {

                if (playersp.X > screenWidth / 1.5f)
                {

                    ScrollRight();
                }
                else
                {
                    playersp.X = playersp.X + 1;

                }

            }
            if (motion != Vector2.Zero)
            {
                motion.Normalize();

                camera.Position += motion * camera.Speed;
            }

            base.Update(gameTime);
        }

        private void ScrollUp()
        {
            motion.Y = -0.5f;
        }

        private void ScrollRight()
        {
            motion.X = 0.5f;
        }

        private void ScrollDown()
        {
            motion.Y = 0.5f;
        }

        private void ScrollLeft()
        {
            motion.X = -0.5f;
        }

        private Point VectorToCell(Vector2 vector)
        {
            return new Point(
                        (int)(vector.X / tileWidth),
                        (int)(vector.Y / tileHeight));
        }

        private Vector2 ViewPortVector()
        {
            return new Vector2(
                    screenWidth + tileWidth,
                    screenHeight + tileHeight);
        }


        protected override void Draw(GameTime gameTime)
        {

            GraphicsDevice.Clear(Color.CornflowerBlue);
            DrawMap();




            base.Draw(gameTime);

        }

        private void DrawMap()
        {
            Point cameraPoint = VectorToCell(camera.Position);
            Point viewPoint = VectorToCell(camera.Position +
                                ViewPortVector());

            Point min = new Point();
            Point max = new Point();

            min.X = cameraPoint.X;
            min.Y = cameraPoint.Y;
            max.X = (int)Math.Min(viewPoint.X, map.GetLength(1));
            max.Y = (int)Math.Min(viewPoint.Y, map.GetLength(0));

            Rectangle tileRectangle = new Rectangle(
                    0,
                    0,
                    tileWidth,
                    tileHeight);

            spriteBatch.Begin();

            for (int y = min.Y; y < max.Y; y++)
            {
                for (int x = min.X; x < max.X; x++)
                {
                    tileRectangle.X = x * tileWidth - (int)camera.Position.X;
                    tileRectangle.Y = y * tileHeight - (int)camera.Position.Y;

                    spriteBatch.Draw(tiles[map[y, x]],
                        tileRectangle,
                        Color.White);
                    spriteBatch.Draw(player, pos, null, Color.White, RotationAngle,
      origin, 1.0f, SpriteEffects.None, 0f);
                }
            }

            spriteBatch.End();
        }

    }
}

How would I detect the tiles position and make sure the player doesn't enter that tile? thanks!

回答1:

You could do something like this:

private static float scalingFactor = 10;
private static float mapSizeX = 19;
private static float mapSizeY = 29;

in Update:

if (playersp.Y > screenHeight  /4) {
  int mapX = (int) (playersp.X / scalingFactor);
  int mapY = (int) (playersp.Y / scalingFactor) - 1;
  if (isMovable(mapX, mapY)) {
    playersp.Y = playersp.Y - scalingFactor;
  }
} else {
  ScrollUp();
}

and a new method:

public bool isMovable(int mapX, int mapY)
{
  if (mapX < 0 || mapX > 19 || mapY < 0 || mapY > 29) {
    return false;
  }

  int tile = map[mapX, mapY];
  if (tile == 4 || tile == 8) {
    return false;
  }

  return true;
}

Similarly for the other directions.

The above code calls the function isMovable to decide whether the player can move to the new location based on the type of tile stored in the map at that position. The decision is false (the player cannot move there) if it is wood or brick wall, otherwise it is true.

The scaling factor is to map between the screen position (captured in playersp) and the tile map. In this case each tile is equivalent to 10 screen "pixels" (You can break it into two separate scales if you want to: one for X dimention, the other for Y).

Note, you need to make sure the values mapSizeX and mapSizeY are correct.

It would be best if you introduced named constants for the type of tile instead of using the numbers -- it will make your code more readable (for you in the future and for others reading it).

EDIT: updated code & explanation