Collision Detection for tiled map via cross products?

Alright, so I’m having some trouble with collision for a top down Zelda-like game. So far I have a collision box on my player that has to change shape based on his direction or he gets stuck, and while I’m sure I could get this down after a while it would be really ugly, and baddly coded. I had a thought: What if I could use cross products to get my desired collision detection like I did that one time in my 3d game (Thanks to a JGO user who showed me how).

So what I want is this. If the player is going up and left, and hits the bottom of a tile, he continues to go left. Same for right, Down/Left, and Down/Right. All the while using a collision box that is always the same size, and shape (a square).

My question right now isn’t HOW to do this, but rather where I should start, or if it’s even possible/worth it.

I found this tutorial, but it’s based on poly to poly collision (http://www.wildbunny.co.uk/blog/2011/04/20/collision-detection-for-dummies/) Should I use this? Or is there a simpler way to achieve what I want?

edit:-------------------------------------------------------------------------

Alright, so I tried something in Slick real quick, and it works kinda, but it only sends you one way, regardless of what your angle was (I.E. when hitting the bottom of a wall going Up/Left it sends you right).

here is the source so far:

package cypri.games.crosscol;

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Vector2f;

public class CrossCol extends BasicGame{

	Vector2f playerPos;
	int size = 32;
	float speed = 2.5f;
	Rectangle tile;
	
	public CrossCol(String title) {
		super(title);
	}
	
	public void move(float angle){
		Vector2f momentum = new Vector2f((float) (Math.sin(Math.toRadians(angle)) * speed),(float) -( Math.cos(Math.toRadians(angle)) * speed));
		Vector2f npos = playerPos.copy();
		npos.add(momentum);
		
		Rectangle r = new Rectangle(npos.x, npos.y, size, size);
		if(r.intersects(tile)){
			momentum = momentum.getPerpendicular();
		}
		
		playerPos.add(momentum);
	}

	@Override
	public void render(GameContainer gc, Graphics g) throws SlickException {
		g.setColor(Color.white);
		g.fillRect(0, 0, 800, 600);
		
		g.setColor(Color.red);
		g.fill(tile);
		
		g.setColor(Color.cyan);
		g.fillRect(playerPos.x,  playerPos.y, size,  size);
		
	}

	@Override
	public void init(GameContainer gc) throws SlickException {
		playerPos = new Vector2f(300,300);
		tile = new Rectangle(200,200,size, size);
	}

	@Override
	public void update(GameContainer gc, int delta) throws SlickException {
		Input input = gc.getInput();
		
		if(input.isKeyDown(Input.KEY_F4)) System.exit(0);
		
		if(input.isKeyDown(Input.KEY_UP)) move(0);
		if(input.isKeyDown(Input.KEY_DOWN)) move(180);
		if(input.isKeyDown(Input.KEY_LEFT)) move(270);
		if(input.isKeyDown(Input.KEY_RIGHT)) move(90);
		
	}
	
	public static void main(String[] args)
			throws SlickException
    {
         AppGameContainer app =
			new AppGameContainer(new CrossCol("Test"));
         app.setDisplayMode(800, 600, false);
         app.setTargetFrameRate(60);
         app.start();
    }

}

well, with your current setup it might be a little tricky. This is something I’ve seen very commonly with people using Slick.

Instead of checking each time which keys are down for movement, you could respond to the events keyPressed and keyReleased, and then set a velocity for your sprite (rectangular form), and then if you run into a wall going up, you just set your y component to zero which won’t affect your x component at all.

Does that make sense?

This may annoy you being so simple. ;D

All you have to do is move by axis.

That means checking x+movex, y
After that, check x, y+movey
(Or vice versa)

Basically what this does is do 2 separate movements (one for each axis) allowing the wall-sliding effect you want.

Thanks for the replies, guys. I think I got it ;D

package cypri.games.crosscol;

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Rectangle;
import org.newdawn.slick.geom.Vector2f;

public class CrossCol extends BasicGame{

	Vector2f playerPos;
	int size = 32;
	float speed = 2.5f;
	Rectangle tile;
	
	public CrossCol(String title) {
		super(title);
	}
	
	public void move(float val, boolean vertical){
		Vector2f momentum = new Vector2f(0,0);
		
		if(!vertical) momentum.x = val;
		else momentum.y = val;
		
		System.out.println("momentum: " + momentum.x + " --- " + momentum.y);
		Vector2f npos = playerPos.copy();
		npos.add(momentum);
		
		Rectangle r = new Rectangle(npos.x, npos.y, size, size);
		if(r.intersects(tile)){
			Vector2f perp = momentum.getPerpendicular();
			Vector2f oldMomentum = momentum.copy();
			
			if(oldMomentum.x < 0) momentum.x = -perp.x;
			else if(oldMomentum.x > 0) momentum.x = perp.x;
			else momentum.x = 0;
			
			if(oldMomentum.y < 0) momentum.y = -perp.y;
			else if(oldMomentum.y > 0) momentum.y = perp.y;
			else momentum.y = 0;
			
		}
		
		playerPos.add(momentum);
	}

	@Override
	public void render(GameContainer gc, Graphics g) throws SlickException {
		g.setColor(Color.white);
		g.fillRect(0, 0, 800, 600);
		
		g.setColor(Color.red);
		g.fill(tile);
		
		g.setColor(Color.cyan);
		g.fillRect(playerPos.x,  playerPos.y, size,  size);
		
	}

	@Override
	public void init(GameContainer gc) throws SlickException {
		playerPos = new Vector2f(300,300);
		tile = new Rectangle(200,200,size, size);
	}

	@Override
	public void update(GameContainer gc, int delta) throws SlickException {
		Input input = gc.getInput();
		
		if(input.isKeyDown(Input.KEY_F4)) System.exit(0);
		
		if(input.isKeyDown(Input.KEY_UP)) move(-2.5f, true);
		if(input.isKeyDown(Input.KEY_DOWN)) move(2.5f, true);
		if(input.isKeyDown(Input.KEY_LEFT)) move(-2.5f, false);
		if(input.isKeyDown(Input.KEY_RIGHT)) move(2.5f, false);
		
	}
	
	public static void main(String[] args)
			throws SlickException
    {
         AppGameContainer app =
			new AppGameContainer(new CrossCol("Test"));
         app.setDisplayMode(800, 600, false);
         app.setTargetFrameRate(60);
         app.start();
    }

}