diff --git a/Shared/Player.cs b/Shared/Player.cs
index c3f702f..5124ffe 100644
--- a/Shared/Player.cs
+++ b/Shared/Player.cs
@@ -1,5 +1,6 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
+using System;
using System.Collections.Generic;
namespace SemiColinGames {
@@ -17,10 +18,12 @@ namespace SemiColinGames {
private const int gravity = 2400;
private const int spriteSize = 48;
+ // TODO: rename to spriteHalfWidth / spriteHalfHeight.
private const int spriteWidth = 7;
+ private const int spriteHeight = 13;
private readonly Texture2D texture;
- private Point position = new Point(64, 16 * 14);
+ private Point position = new Point(64, 16 * 10);
private int jumps = 0;
private Facing facing = Facing.Right;
private Pose pose = Pose.Jumping;
@@ -43,65 +46,89 @@ namespace SemiColinGames {
}
private Aabb Box(Point position, int yOffset) {
- return new Aabb(new Vector2(position.X, position.Y - 7 + 13 + yOffset),
- new Vector2(spriteWidth, 13));
+ return new Aabb(new Vector2(position.X, position.Y - 7 + spriteHeight + yOffset),
+ new Vector2(spriteWidth, spriteHeight));
}
public void Update(float modelTime, History input, Rectangle[] collisionTargets) {
- Point oldPosition = position;
Vector2 movement = HandleInput(modelTime, input);
- position = new Point((int) (oldPosition.X + movement.X), (int) (oldPosition.Y + movement.Y));
-
- Rectangle oldBbox = Bbox(oldPosition);
- Rectangle playerBbox = Bbox(position);
- bool standingOnGround = false;
// TODO: we shouldn't hardcode the tile sizes here.
Vector2 halfBoxSize = new Vector2(World.TileSize / 2, World.TileSize / 2);
- foreach (var rect in collisionTargets) {
- Aabb rectBox = new Aabb(
+ // Broad test: remove all collision targets nowhere near the player.
+ List candidates = new List();
+ // TODO: This is strictly larger than it needs to be. We could expand only in the actual
+ // direction of movement.
+ Aabb largeBox = new Aabb(
+ new Vector2(position.X, position.Y - 7 + spriteHeight), // current player position
+ new Vector2(spriteWidth + Math.Abs(movement.X), spriteHeight + Math.Abs(movement.Y)));
+ for (int i = 0; i < collisionTargets.Length; i++) {
+ Rectangle rect = collisionTargets[i];
+ Aabb box = new Aabb(
new Vector2(rect.X + World.TileSize / 2, rect.Y + World.TileSize / 2), halfBoxSize);
- Aabb playerBox = Box(position);
- playerBbox = Bbox(position);
+ if (box.Intersect(largeBox) != null) {
+ Debug.AddRect(box, Color.Green);
+ candidates.Add(rect);
+ }
+ }
- // first we check for left-right collisions...
- if (playerBox.Intersect(rectBox) != null) {
- if (oldBbox.Right <= rect.Left && playerBbox.Right > rect.Left) {
- position.X = rect.Left - spriteWidth;
+ Point[] movePoints = Line.Rasterize(0, 0, (int) movement.X, (int) movement.Y);
+ for (int i = 1; i < movePoints.Length; i++) {
+ int dx = movePoints[i].X - movePoints[i - 1].X;
+ int dy = movePoints[i].Y - movePoints[i - 1].Y;
+ if (dy != 0) {
+ Point newPosition = new Point(position.X, position.Y + dy);
+ Aabb player = Box(newPosition);
+ bool reject = false;
+ foreach (var rect in candidates) {
+ Aabb box = new Aabb(
+ new Vector2(rect.X + World.TileSize / 2, rect.Y + World.TileSize / 2), halfBoxSize);
+ if (box.Intersect(player) != null) {
+ reject = true;
+ break;
+ }
}
- if (oldBbox.Left >= rect.Right && playerBbox.Left < rect.Right) {
- position.X = rect.Right + spriteWidth;
+ if (!reject) {
+ position = newPosition;
}
- playerBox = Box(position);
}
- // after fixing that, we check for hitting our head or hitting the ground.
- if (playerBox.Intersect(rectBox) != null) {
- if (oldPosition.Y > position.Y) {
- int diff = playerBbox.Top - rect.Bottom;
- position.Y -= diff;
- // TODO: set ySpeed = 0 here so that bonking our head actually reduces hangtime?
- } else {
- standingOnGround = true;
- int diff = playerBbox.Bottom - rect.Top;
- position.Y -= diff;
+ if (dx != 0) {
+ Point newPosition = new Point(position.X + dx, position.Y);
+ Aabb player = Box(newPosition);
+ bool reject = false;
+ foreach (var rect in candidates) {
+ Aabb box = new Aabb(
+ new Vector2(rect.X + World.TileSize / 2, rect.Y + World.TileSize / 2), halfBoxSize);
+ if (box.Intersect(player) != null) {
+ reject = true;
+ break;
+ }
}
- } else {
- playerBox = Box(position, 1);
- if (playerBox.Intersect(rectBox) != null) {
- standingOnGround = true;
- Debug.AddRect(rect, Color.Cyan);
- } else {
- Debug.AddRect(rect, Color.Green);
+ if (!reject) {
+ position = newPosition;
}
}
}
+
+ bool standingOnGround = false;
+ Aabb groundIntersect = Box(position, 1);
+ foreach (var rect in candidates) {
+ Aabb box = new Aabb(
+ new Vector2(rect.X + World.TileSize / 2, rect.Y + World.TileSize / 2), halfBoxSize);
+ if (groundIntersect.Intersect(box) != null) {
+ standingOnGround = true;
+ Debug.AddRect(rect, Color.Cyan);
+ // break;
+ }
+ }
+
if (standingOnGround) {
jumps = 1;
- ySpeed = 0;
- Debug.AddRect(playerBbox, Color.Red);
+ ySpeed = -0.0001f;
+ // Debug.AddRect(playerBbox, Color.Red);
} else {
jumps = 0;
- Debug.AddRect(playerBbox, Color.Orange);
+ // Debug.AddRect(playerBbox, Color.Orange);
}
if (movement.X > 0) {