碰撞检测,带有地图块的播放器
Collision Detection, Player with tiles of the map
我如何用我的播放器与地图上的方块发生碰撞?
动画class:
public class Animation
{
public float speed = 2.5f;
protected string currentAnimatie;
public Texture2D sTexture;
public Vector2 sPosition;
private int FrameIndex;
private double TimeElapse;
private double TimeToUpdate;
public Vector2 sDirection = Vector2.Zero;
public Rectangle BoxRondCharachter
{
get
{
return new Rectangle((int)sPosition.X, (int)sPosition.Y, 50, 41);
}
}
public int FramesPerSec
{
set { TimeToUpdate = (1f / value); }
}
public Animation(Vector2 pos)
{
sPosition = pos;
}
public void Update(GameTime gametime)
{
TimeElapse += gametime.ElapsedGameTime.TotalSeconds;
if (TimeElapse > TimeToUpdate)
{
TimeElapse -= TimeToUpdate;
if (FrameIndex < sAnimatie[currentAnimatie].Length - 1)
{
FrameIndex++;
}
else
{
FrameIndex = 0;
}
TimeElapse = 0;
}
sPosition += sDirection;
sDirection = Vector2.Zero;
}
public void AddAnimatie(int frames, double yPos, int xStart, string naam, int width, int height, Vector2 offset)
{
Rectangle[] Rectangles = new Rectangle[frames];
///neemt de spritesheet en het verdeelt zich
for (int i = 0; i < frames; i++)
{
Rectangles[i] = new Rectangle((i + xStart) * width, (int)yPos, width, height);
}
sAnimatie.Add(naam, Rectangles);
}
public void Draw(SpriteBatch sprite)
{
sprite.Draw(sTexture, sPosition, sAnimatie[currentAnimatie [FrameIndex], Color.White);
}
public void AnimatieAfspelen(string animatieNaam)
{
if (currentAnimatie != animatieNaam)
{
currentAnimatie = animatieNaam;
FrameIndex = 0;
}
}
public void LaadContent(ContentManager content)
{
sTexture = content.Load<Texture2D>("char");
}
}
地图引擎Class:
class MapEngine
{
private List<CollisionTiles> collisionTiles = new List<CollisionTiles>();
public List<CollisionTiles> CollisionTiles
{
get { return collisionTiles; }
}
private int width, height;
public int Width
{
get { return width; }
}
public int Height
{
get { return height; }
}
public MapEngine()
{
}
public void Generate(int[,] map, int size)
{
for (int x = 0; x < map.GetLength(1); x++)
{
for (int y = 0; y < map.GetLength(0); y++)
{
int number = map[y, x];
if (number > 0)
{
collisionTiles.Add(new CollisionTiles(number, new Rectangle(x * size, y * size, size, size)));
width = (x + 1) * size;
height = (y + 1) * size;
}
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
foreach (CollisionTiles tile in collisionTiles)
{
tile.Draw(spriteBatch);
}
}
}
地图class:
class Map : MapEngine
{
public void ShowMap(ContentManager Content)
{
Tiles.Content = Content;
Generate(new int[,]{
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,},
{2,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,2,2,},
{2,2,1,1,1,0,0,0,0,1,1,1,2,2,2,1,0,0,0,0,2,2,},
{2,2,0,0,0,0,0,0,1,2,2,2,2,2,2,2,1,0,0,0,2,2,},
{2,0,0,0,0,0,1,1,2,2,2,2,2,2,2,2,2,1,1,1,2,2,},
{2,0,0,0,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,},
{2,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,}
}, 74);
}
}
英雄class:
public class Hero
{
private Vector2 position = new Vector2(54, 485);
public Vector2 Position
{
get { return position; }
}
public int Width { get; set; }
public int Height { get; set; }
private Animation _animation;
private Inputs inputH = new Inputs();
public bool LinkseStand = false;
private Rectangle collisionRectangle;
public Rectangle CollisionRectangle
{
get => collisionRectangle;
set => collisionRectangle = value;
}
public Hero()
{
_animation = new Animation(position);
_animation.AddAnimatie(4, 0, 0, "RechteIdle", 50, 35, new Vector2(0, 0));
_animation.AddAnimatie(4, 34, 0, "LinkseIdle", 50, 35, new Vector2(0, 0));
_animation.AddAnimatie(6, 72, 0, "Right", 50, 34, new Vector2(0, 0));
_animation.AddAnimatie(6, 107, 0, "Left", 50, 40, new Vector2(0, 0));
_animation.AddAnimatie(9, 144, 0, "Jump", 46, 41, new Vector2(0, 0));
_animation.AddAnimatie(4, 220, 0, "Crouch", 50, 32, new Vector2(0, 0));
_animation.AddAnimatie(7, 255, 0, "FirstAttack", 50, 45, new Vector2(0, 0));
_animation.AddAnimatie(14, 300, 0, "ComboAttack", 50, 41, new Vector2(0, 0));
_animation.AddAnimatie(5, 300, 0, "Dood", 50, 41, new Vector2(0, 0));
_animation.AnimatieAfspelen("RechteIdle");
_animation.FramesPerSec = 8;
}
public void Draw(SpriteBatch spritebatch)
{
_animation.Draw(spritebatch);
}
public void laadContent(ContentManager content)
{
_animation.LaadContent(content);
}
public void Update(GameTime gameTime)
{
_animation.Update(gameTime);
position += _animation.sDirection;
CollisionRectangle = new Rectangle((int)_animation.sPosition.X, (int)_animation.sPosition.Y, 50, 41);
inputH.update();
Move(gameTime);
}
private void Move(GameTime gameTime)
{
if (inputH.Right)
{
_animation.AnimatieAfspelen("Right");
_animation.sDirection.X = _animation.speed;
LinkseStand = false;
}
else if (inputH.Left)
{
_animation.AnimatieAfspelen("Left");
_animation.sDirection.X -= _animation.speed;
LinkseStand = true;
}
else if (inputH.Up)
{
_animation.AnimatieAfspelen("Jump");
_animation.sDirection.Y -= _animation.speed;
}
else if (inputH.NormalAttack)
{
_animation.AnimatieAfspelen("FirstAttack");
}
else if (inputH.ComboAttack)
{
_animation.AnimatieAfspelen("ComboAttack");
}
else
{
if (LinkseStand == true)
_animation.AnimatieAfspelen("LinkseIdle");
else
_animation.AnimatieAfspelen("RechteIdle");
}
}
}
碰撞方块class:
class CollisionTiles : Tiles
{
public CollisionTiles(int i, Rectangle newRect)
{
texture = Content.Load<Texture2D>("Tile" + i); //loads the tile (tile1, tile2)
Rectangle = newRect;
}
}
游戏 1 class:
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D background;
Vector2 backPos;
Animation _ani;
Hero _hero;
Map map;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1000; // set this value to the desired width of your window
graphics.PreferredBackBufferHeight = 590; // set this value to the desired height of your window
graphics.ApplyChanges();
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
map = new Map();
_hero = new Hero();
_ani = new Animation(_hero.Position);
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);
background = Content.Load<Texture2D>("background1");
backPos = new Vector2(0, 0);
map.ShowMap(Content);
//_heroTexture = Content.Load<Texture2D>("idleStand");
_hero.laadContent(Content);
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// game-specific 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)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
_hero.Update(gameTime);
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.Cyan);
// TODO: Add your drawing code here
spriteBatch.Begin();
spriteBatch.Draw(background, backPos, Color.White);
map.Draw(spriteBatch);
_hero.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
可以在Game1的Update方法中将Map实例传给Hero:
_hero.Update(gameTime, map);
并使用它来遍历 map.CollisionTiles
列表,检查 Hero class:
中的重叠
public void Update(GameTime gameTime, Map map)
{
_animation.Update(gameTime);
position += _animation.sDirection;
CollisionRectangle = new Rectangle((int)_animation.sPosition.X, (int)_animation.sPosition.Y, 50, 41);
// Check for collision with any of the CollisionTiles:
foreach(var item in map.CollisionTiles)
if(item.Rectangle.Intersects(CollisionRectangle))
// ^^^^^^^^^ needs to be public in the tile class.
{
position -= _animation.sDirection; // Collided with a tile undo move
break; //prevent moving backwards if colliding with more than one tile
}
inputH.update();
Move(gameTime);
}
在此代码中,Hero 无法移动到任何 CollisionTile。
我如何用我的播放器与地图上的方块发生碰撞?
动画class:
public class Animation
{
public float speed = 2.5f;
protected string currentAnimatie;
public Texture2D sTexture;
public Vector2 sPosition;
private int FrameIndex;
private double TimeElapse;
private double TimeToUpdate;
public Vector2 sDirection = Vector2.Zero;
public Rectangle BoxRondCharachter
{
get
{
return new Rectangle((int)sPosition.X, (int)sPosition.Y, 50, 41);
}
}
public int FramesPerSec
{
set { TimeToUpdate = (1f / value); }
}
public Animation(Vector2 pos)
{
sPosition = pos;
}
public void Update(GameTime gametime)
{
TimeElapse += gametime.ElapsedGameTime.TotalSeconds;
if (TimeElapse > TimeToUpdate)
{
TimeElapse -= TimeToUpdate;
if (FrameIndex < sAnimatie[currentAnimatie].Length - 1)
{
FrameIndex++;
}
else
{
FrameIndex = 0;
}
TimeElapse = 0;
}
sPosition += sDirection;
sDirection = Vector2.Zero;
}
public void AddAnimatie(int frames, double yPos, int xStart, string naam, int width, int height, Vector2 offset)
{
Rectangle[] Rectangles = new Rectangle[frames];
///neemt de spritesheet en het verdeelt zich
for (int i = 0; i < frames; i++)
{
Rectangles[i] = new Rectangle((i + xStart) * width, (int)yPos, width, height);
}
sAnimatie.Add(naam, Rectangles);
}
public void Draw(SpriteBatch sprite)
{
sprite.Draw(sTexture, sPosition, sAnimatie[currentAnimatie [FrameIndex], Color.White);
}
public void AnimatieAfspelen(string animatieNaam)
{
if (currentAnimatie != animatieNaam)
{
currentAnimatie = animatieNaam;
FrameIndex = 0;
}
}
public void LaadContent(ContentManager content)
{
sTexture = content.Load<Texture2D>("char");
}
}
地图引擎Class:
class MapEngine
{
private List<CollisionTiles> collisionTiles = new List<CollisionTiles>();
public List<CollisionTiles> CollisionTiles
{
get { return collisionTiles; }
}
private int width, height;
public int Width
{
get { return width; }
}
public int Height
{
get { return height; }
}
public MapEngine()
{
}
public void Generate(int[,] map, int size)
{
for (int x = 0; x < map.GetLength(1); x++)
{
for (int y = 0; y < map.GetLength(0); y++)
{
int number = map[y, x];
if (number > 0)
{
collisionTiles.Add(new CollisionTiles(number, new Rectangle(x * size, y * size, size, size)));
width = (x + 1) * size;
height = (y + 1) * size;
}
}
}
}
public void Draw(SpriteBatch spriteBatch)
{
foreach (CollisionTiles tile in collisionTiles)
{
tile.Draw(spriteBatch);
}
}
}
地图class:
class Map : MapEngine
{
public void ShowMap(ContentManager Content)
{
Tiles.Content = Content;
Generate(new int[,]{
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,},
{2,1,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,1,1,2,2,},
{2,2,1,1,1,0,0,0,0,1,1,1,2,2,2,1,0,0,0,0,2,2,},
{2,2,0,0,0,0,0,0,1,2,2,2,2,2,2,2,1,0,0,0,2,2,},
{2,0,0,0,0,0,1,1,2,2,2,2,2,2,2,2,2,1,1,1,2,2,},
{2,0,0,0,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,},
{2,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,}
}, 74);
}
}
英雄class:
public class Hero
{
private Vector2 position = new Vector2(54, 485);
public Vector2 Position
{
get { return position; }
}
public int Width { get; set; }
public int Height { get; set; }
private Animation _animation;
private Inputs inputH = new Inputs();
public bool LinkseStand = false;
private Rectangle collisionRectangle;
public Rectangle CollisionRectangle
{
get => collisionRectangle;
set => collisionRectangle = value;
}
public Hero()
{
_animation = new Animation(position);
_animation.AddAnimatie(4, 0, 0, "RechteIdle", 50, 35, new Vector2(0, 0));
_animation.AddAnimatie(4, 34, 0, "LinkseIdle", 50, 35, new Vector2(0, 0));
_animation.AddAnimatie(6, 72, 0, "Right", 50, 34, new Vector2(0, 0));
_animation.AddAnimatie(6, 107, 0, "Left", 50, 40, new Vector2(0, 0));
_animation.AddAnimatie(9, 144, 0, "Jump", 46, 41, new Vector2(0, 0));
_animation.AddAnimatie(4, 220, 0, "Crouch", 50, 32, new Vector2(0, 0));
_animation.AddAnimatie(7, 255, 0, "FirstAttack", 50, 45, new Vector2(0, 0));
_animation.AddAnimatie(14, 300, 0, "ComboAttack", 50, 41, new Vector2(0, 0));
_animation.AddAnimatie(5, 300, 0, "Dood", 50, 41, new Vector2(0, 0));
_animation.AnimatieAfspelen("RechteIdle");
_animation.FramesPerSec = 8;
}
public void Draw(SpriteBatch spritebatch)
{
_animation.Draw(spritebatch);
}
public void laadContent(ContentManager content)
{
_animation.LaadContent(content);
}
public void Update(GameTime gameTime)
{
_animation.Update(gameTime);
position += _animation.sDirection;
CollisionRectangle = new Rectangle((int)_animation.sPosition.X, (int)_animation.sPosition.Y, 50, 41);
inputH.update();
Move(gameTime);
}
private void Move(GameTime gameTime)
{
if (inputH.Right)
{
_animation.AnimatieAfspelen("Right");
_animation.sDirection.X = _animation.speed;
LinkseStand = false;
}
else if (inputH.Left)
{
_animation.AnimatieAfspelen("Left");
_animation.sDirection.X -= _animation.speed;
LinkseStand = true;
}
else if (inputH.Up)
{
_animation.AnimatieAfspelen("Jump");
_animation.sDirection.Y -= _animation.speed;
}
else if (inputH.NormalAttack)
{
_animation.AnimatieAfspelen("FirstAttack");
}
else if (inputH.ComboAttack)
{
_animation.AnimatieAfspelen("ComboAttack");
}
else
{
if (LinkseStand == true)
_animation.AnimatieAfspelen("LinkseIdle");
else
_animation.AnimatieAfspelen("RechteIdle");
}
}
}
碰撞方块class:
class CollisionTiles : Tiles
{
public CollisionTiles(int i, Rectangle newRect)
{
texture = Content.Load<Texture2D>("Tile" + i); //loads the tile (tile1, tile2)
Rectangle = newRect;
}
}
游戏 1 class:
public class Game1 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D background;
Vector2 backPos;
Animation _ani;
Hero _hero;
Map map;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1000; // set this value to the desired width of your window
graphics.PreferredBackBufferHeight = 590; // set this value to the desired height of your window
graphics.ApplyChanges();
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
map = new Map();
_hero = new Hero();
_ani = new Animation(_hero.Position);
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);
background = Content.Load<Texture2D>("background1");
backPos = new Vector2(0, 0);
map.ShowMap(Content);
//_heroTexture = Content.Load<Texture2D>("idleStand");
_hero.laadContent(Content);
}
/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// game-specific 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)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
_hero.Update(gameTime);
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.Cyan);
// TODO: Add your drawing code here
spriteBatch.Begin();
spriteBatch.Draw(background, backPos, Color.White);
map.Draw(spriteBatch);
_hero.Draw(spriteBatch);
spriteBatch.End();
base.Draw(gameTime);
}
}
可以在Game1的Update方法中将Map实例传给Hero:
_hero.Update(gameTime, map);
并使用它来遍历 map.CollisionTiles
列表,检查 Hero class:
public void Update(GameTime gameTime, Map map)
{
_animation.Update(gameTime);
position += _animation.sDirection;
CollisionRectangle = new Rectangle((int)_animation.sPosition.X, (int)_animation.sPosition.Y, 50, 41);
// Check for collision with any of the CollisionTiles:
foreach(var item in map.CollisionTiles)
if(item.Rectangle.Intersects(CollisionRectangle))
// ^^^^^^^^^ needs to be public in the tile class.
{
position -= _animation.sDirection; // Collided with a tile undo move
break; //prevent moving backwards if colliding with more than one tile
}
inputH.update();
Move(gameTime);
}
在此代码中,Hero 无法移动到任何 CollisionTile。