Jump to content
  • Advertisement
Neon Warge

Stuck on implementing platformer collision

This topic is 386 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So I am trying to make a platformer for a promotional project. This platforming game is easy. Only static obstacles, some variations of platform levels such that the sprite can jump to the next platform and jump down to the previous platform (like the NES Contra). The games suppose to behave like Mario. The platforming/environment is not complicated. You can jump up and down to platform, jump across obstacle, jump to next elevation etc. Please do take note, there is a degree of a proper platforming scheme (similar to Mario). Its just that the game is very basic.

The problem is, if my sprite goes (1,1) direction (jumping and then falling forward), my sprite snaps to one of the corners of the obstacle's hitbox. I surmised probably it is because I set some collision detections on four vertices on the hitbox of my sprite and comparing this against other hitboxes of perceived platforms (which btw, are on different size), I made it similar with 'raycasting'. It appears my sprite shows up on a position overlapping the bounding box of the platform when code proxied and correct the position of the sprite. Causing it to jitter on such corner. Sometimes it even teleports on the other side of the obstacle.

My code is a bit crude. I wanted to make it simple without using too much physics (like Box2D). As I believe this game is a simple as it gets, I felt like simpler solution suits this project better. But the fact I encountered problem like this make me feel regrettable doing this.

Here is my code so far:

package nick.runnypants.entities;

import kit.Entity;
import kit.creator.SceneSprite;
import kit.input.KeyboardEvent;
import kit.creator.CreatorObject;
import kit.display.Sprite;
import kit.input.Key;
import kit.physics.PhysicsBody;
import kit.System;
import kit.physics.Box2D;

import box2d.dynamics.BodyType;
import box2d.common.math.Vec2;

import nick.runnypants.entities.Collider;
import nick.runnypants.utils.MathUtils;

class Runner extends BoundedObject 
	public var moveSpeed : Float = 1550;
	public var jumpHeight : Float = 3;
	public var timeToJumpApex : Float = 0.35;
	public var showDebugLines : Bool = false;

	private var position : Vec2;
	private var velocity : Vec2;
	private var acceleration : Vec2;
	private var direction : Vec2;
	private var sprite : Sprite;
	private var sceneSprite : SceneSprite;
	private var jumpSpeed : Float;
	private var gravity : Float;
	private var isGrounded : Bool;
	private var keyPresses : Map<Key, Int>;
	private var perceivedPlatforms : Array<BoundedObject>;
	private var thisCollider : Collider;
	private var collisionInfo : CollisionInfo;

	public override function onStart() : Void
		perceivedPlatforms = new Array<BoundedObject>();
		sceneSprite = owner.getSceneSpriteFromParents();

		sprite = owner.getSprite();
	private function initPhysics()
		collisionInfo = new CollisionInfo();
		setBoundOffset(new Vec2(sprite.getNaturalWidth() / 2.0, sprite.getNaturalHeight() / 2.0));
		thisCollider = getCollider();

		position = new Vec2(sprite.x._, sprite.y._);
		acceleration = new Vec2(0, 0);
		velocity = new Vec2(0, 0);
		direction = new Vec2(0, 0);
		gravity = (2 * jumpHeight) / (timeToJumpApex * timeToJumpApex);
		jumpSpeed = gravity * timeToJumpApex;
	private function initControls()
		keyPresses = new Map<Key, Int>();
	public override function onUpdate(dt : Float) : Void
		direction = new Vec2(0, 0);


		velocity.x = direction.x * moveSpeed * dt;
		velocity.y = direction.y * moveSpeed * dt;
		// velocity.y += gravity * dt;

		if (collisionInfo.collideLeft || collisionInfo.collideRight)
			velocity.x = 0;
			direction.x = 0;
		if (collisionInfo.collideBottom)
			velocity.y = 0;
			direction.y = 0;
		position.x += MathUtils.lerp(velocity.x, moveSpeed * direction.x, dt);
		position.y += MathUtils.lerp(velocity.y, moveSpeed * direction.y, dt);
		sprite.x._ = position.x;
		sprite.y._ = position.y;
	private function resolveCollisions(velocity : Vec2)
		for (platform in perceivedPlatforms)
			var thatCollider = platform.getCollider();
			checkVerticalCollision(velocity, thatCollider);
			checkHorizontalCollision(velocity, thatCollider);
	private function checkVerticalCollision(velocity : Vec2, thatCollider : Collider)
		if (MathUtils.sign(velocity.y) == 1
			&& (MathUtils.isBetweenHorizontal(thisCollider.bottomLeft.x, thatCollider.topLeft, thatCollider.topRight)
			|| MathUtils.isBetweenHorizontal(thisCollider.bottomRight.x, thatCollider.topLeft, thatCollider.topRight)))
			var dist = thatCollider.topLeft.y - thisCollider.bottomLeft.y;
			if (dist <= 0 && thisCollider.topLeft.y < thatCollider.bottomLeft.y)
				position.y = thatCollider.topLeft.y - (sprite.getNaturalHeight() / 2.0);
				collisionInfo.collideBottom = true;
		else if (MathUtils.sign(velocity.y) == -1
			&& (MathUtils.isBetweenHorizontal(thisCollider.topLeft.x, thatCollider.bottomLeft, thatCollider.bottomRight)
			|| MathUtils.isBetweenHorizontal(thisCollider.topRight.x, thatCollider.bottomLeft, thatCollider.bottomLeft)))
			var dist = thisCollider.topLeft.y - thatCollider.bottomLeft.y;
			if (dist <= 0 && thisCollider.topLeft.y > thatCollider.topLeft.y)
				position.y = thatCollider.bottomLeft.y + (sprite.getNaturalHeight() / 2.0);
				collisionInfo.collideBottom = true;
	private function checkHorizontalCollision(velocity : Vec2, thatCollider : Collider)
		if (MathUtils.sign(velocity.x) == 1 
				&& (MathUtils.isBetweenVertical(thisCollider.bottomRight.y, thatCollider.topLeft, thatCollider.bottomLeft)
				|| MathUtils.isBetweenVertical(thisCollider.topRight.y, thatCollider.topLeft, thatCollider.bottomLeft)))
			var dist = thatCollider.topLeft.x - thisCollider.bottomRight.x;
			if (dist <= 0 && thisCollider.bottomRight.x < thatCollider.bottomRight.x) 
				position.x = thatCollider.topLeft.x - (sprite.getNaturalWidth() / 2.0);
				collisionInfo.collideRight = true;
		else if (MathUtils.sign(velocity.x) == -1 
			&& (MathUtils.isBetweenVertical(thisCollider.bottomLeft.y, thatCollider.topRight, thatCollider.bottomRight)
			|| MathUtils.isBetweenVertical(thisCollider.topLeft.y, thatCollider.topRight, thatCollider.bottomRight)))
			var dist = thisCollider.topLeft.x - thatCollider.bottomRight.x;
			if (dist <= 0 && thisCollider.bottomRight.x > thatCollider.bottomLeft.x)
				position.x = thatCollider.bottomRight.x + (sprite.getNaturalWidth() / 2.0);
				collisionInfo.collideLeft = true;
	private function perceivePlatforms()
		var platforms : Array<Entity> = sceneSprite.getObjectsByType(BoundedObject);
		for (e in platforms)
			perceivedPlatforms.insert(0, e.get(BoundedObject));
	private function updateInput() : Void
		if (keyPresses.get(Key.Left) != null || keyPresses.get(Key.A) != null)
			direction.x = -1;
		if (keyPresses.get(Key.Right) != null || keyPresses.get(Key.D) != null)
			direction.x = 1;
		if (keyPresses.get(Key.Up) != null || keyPresses.get(Key.W) != null)
			direction.y = -1;
		if (keyPresses.get(Key.Down) != null || keyPresses.get(Key.S) != null)
			direction.y = 1;
		//if (keyPresses.get(Key.Space) != null)
		//	jump();
	public function jump() : Void
		velocity.y = -jumpSpeed;
		isGrounded = false;
	public function onKeyDown(event : KeyboardEvent)
		keyPresses.set(event.key, event.id);
	public function onKeyUp(event : KeyboardEvent)

I disabled jumping/platforming mechanics and move the sprite on all directions. As you can see, if I move  diagonally towards  a particular obstacle, my sprite seems to collide a bit with platform's corner, and I had my code to correct its position. This doesn't look nice because, sometimes, the collision doesn't make sense and it looks jittery. Collision works well on a very strict movement, like coming from the left, right, top, bottom, but not combinations of those as my sprite teleports on the other side of the obstacle. 

I've been searching through the web and spent countless hour figuring this out and I can't seem to find any useful article. Though I came to know 'bullet through paper problem', 'SAT', 'Sweep'

etc. I am not totally sure if this is the solution to my problem, hence this post.

This is using 2dKit + Haxe language. 

I felt very dumb and I am really stuck.  Any help will be greatly appreciated.


Share this post

Link to post
Share on other sites

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!