public void CollideAxis(PhysicalObject obj, Vector2 startpos, Vector2 move, Axis axis) { float xcol = 0.05f; bool touch_u = false; bool touch_r = false; bool touch_d = false; bool touch_l = false; obj.on_ladder[(int)axis] = false; Vector2 feet = new Vector2(startpos.X, startpos.Y + obj.hitbox.Y); if (axis == Axis.X) { move = new Vector2(move.X, 0); //if the ground is a slope, include the Y-movement if (obj.surface_k != 0) if (move.X * -obj.surface_k < 0) move.Y = move.X * -obj.surface_k; } else move = new Vector2(0, move.Y); obj.pos += move; int index_x = (int)obj.pos.X; int index_y = (int)obj.pos.Y; //how many tiles can the object potentially collide with int width = (int)Math.Ceiling(obj.hitbox.X) + 1; int height = (int)Math.Ceiling(obj.hitbox.Y) + 1; //get a list of all those int[][] check = new int[width * height][]; int c = 0; for (int w = 0; w < width; w++) for (int h = 0; h < height; h++) { check[c] = new int[] { w + index_x, h + index_y }; c++; } for (int i = 0; i < check.Length; i++) { Vector4 playerHitBox = new Vector4(obj.pos.X, obj.pos.Y, obj.hitbox.X, obj.hitbox.Y); //todo: other blocktypes //upper left corner of the tile int x = check[i][0]; int y = check[i][1]; if (x >= 0 && x < map[0].Length && y >= 0 && y < map.Length) { //get the tile from map Tile tile = map[y][x]; //reusable variables Vector4 tileHitBox; switch (tile.tileType) { case Tile.TileType.scenery: break; case Tile.TileType.solid: if (tile.GetType() == typeof(Slope)) { //SLABS / HALF-BLOCKS Slope slope = tile as Slope; if (slope.side == Slope.Side.floor) tileHitBox = new Vector4(x, y + (1f - slope.leftY), 1, slope.leftY); else tileHitBox = new Vector4(x, y, 1, slope.leftY); } else tileHitBox = new Vector4(x, y, 1, 1);//Regular square //Does it collide? if (VectorIntersect(playerHitBox, tileHitBox)) { if (axis == Axis.X) { if (move.X > 0) { obj.pos.X = x - obj.hitbox.X; touch_r = true; //reset velocity obj.velocity.X = xcol; } else { obj.pos.X = x + 1; touch_l = true; obj.velocity.X = -xcol; } } else { if (playerHitBox.Y < tileHitBox.Y) { obj.pos.Y = tileHitBox.Y - obj.hitbox.Y;//tile y pos - player height touch_d = true; } else { obj.pos.Y = tileHitBox.Y + tileHitBox.W;//tile y pos + tile height touch_u = true; } //reset velocity obj.velocity.Y = 0; obj.surface_k = 0; } } break; case Tile.TileType.platform: if (axis == Axis.Y) { tileHitBox = new Vector4(x, y, 1, 1);//Regular square float slope_m; float slope_k = 0; float slope_x; bool was_above = false; Slope slope = new Slope(Tile.TileType.platform, Slope.Side.floor, 0f, 0f); if (tile.GetType() == typeof(Slope)) { //SLOPES //y = kx + m //m -> plat.Y //k -> plat.right - plat.left //x -> player.x - plat.x slope = tile as Slope; if (slope.leftY == slope.rightY)//slab { if (slope.side == Slope.Side.roof)//roof slab tileHitBox = new Vector4(x, y, 1, slope.leftY); else//floor slab tileHitBox = new Vector4(x, (float)y + (1f - slope.leftY), 1, slope.leftY); } else { if (slope.side == Slope.Side.floor) { slope_m = slope.leftY; slope_k = slope.rightY - slope.leftY; slope_x = playerHitBox.X + playerHitBox.Z / 2f - (float)x; float slopeheight = get_slopeheight(slope_k, x, slope_m, slope, obj.pos.X, obj.pos.X + obj.hitbox.X); float old_slopeheight = get_slopeheight(slope_k, x, slope_m, slope, feet.X, feet.X + obj.hitbox.X); tileHitBox = new Vector4(x, (float)y + (1f - slopeheight), 1, slopeheight); was_above = feet.Y <= (float)y + (1f - old_slopeheight) + 0.0001f; } } } if (VectorIntersect(playerHitBox, tileHitBox) && (feet.Y <= tileHitBox.Y || was_above)) { //do collision if (slope.side == Slope.Side.floor) { obj.pos.Y = tileHitBox.Y - obj.hitbox.Y;//tile y pos - player height touch_d = true; } else { obj.pos.Y = tileHitBox.Y + tileHitBox.W;//tile y pos + tile height touch_u = true; } obj.velocity.Y = 0; obj.surface_k = slope_k; } } break; case Tile.TileType.ladder: tileHitBox = new Vector4(x + 1f/3, y - 1f/3, 1f/2, 4f/3); //The hitbox is "squeezed" along the x-axis to avoid the ladder being grabbed with minimal overlap. if (VectorIntersect(tileHitBox, playerHitBox)) { obj.on_ladder[(int)axis] = true; } break; case Tile.TileType.death: break; case Tile.TileType.win: break; } } } //update the objects intel if (axis == Axis.X) { obj.touch_left.Update(touch_l); obj.touch_right.Update(touch_r); } else { obj.touch_down.Update(touch_d); obj.touch_up.Update(touch_u); } }
public bool Collides(PhysicalObject obj) { Vector4 rec1 = new Vector4(pos.X, pos.Y, hitbox.X, hitbox.Y); Vector4 rec2 = new Vector4(obj.pos.X, obj.pos.Y, obj.hitbox.X, obj.hitbox.Y); Vector2 pos1 = new Vector2(rec1.X + rec1.Z / 2f, rec1.Y + rec1.W / 2f); Vector2 pos2 = new Vector2(rec2.X + rec2.Z / 2f, rec2.Y + rec2.W / 2f); return (Math.Abs(pos1.X - pos2.X) < (rec1.Z + rec2.Z) / 2 //if ΔX < medelvärdet av width && Math.Abs(pos1.Y - pos2.Y) < (rec1.W + rec2.W) / 2); //if ΔY < medelvärdet av height }
public void UpdatePhysicalObject(PhysicalObject obj) { //store start position and velocity Vector2 pos = obj.pos; Vector2 vel = obj.velocity; //move on the X-axis CollideAxis(obj, pos, obj.velocity, Axis.X); //since the slope-movement (int the Y axis) is already included in the X-step if the ground is sloped, //remove the slopes' Y movement float correction = 0f; if (obj.surface_k != 0) if (vel.X * -obj.surface_k < 0) correction = vel.X * obj.surface_k; else correction += 0.1f;//make sure the character gets pushed down to the ground //reset surface obj.surface_k = 0; //move on the Y-axis CollideAxis(obj, pos, obj.velocity + new Vector2(0, correction), Axis.Y); }