P5.js movement logic — detective stops unexpectedly at corners in maze game

Hi everyone,

I’m working on a p5.js project where a detective character follows a fixed path through a “Vice City”-style maze to catch a criminal named Fox. The movement is controlled by conditional statements that update the detective’s speedX and speedY based on his locationX and locationY.

My issue is that the detective gets stuck at a corner — specifically around x: 703, y: 272 — and stops moving. The message “You let Fox get away. Better luck next time.” appears, meaning he’s not considered to be on the road anymore.

Here’s a simplified version of my code:

/*
402 - The case of the Why Gang ruby heist
Stage 4 - Fox

Officer: 5809203
CaseNum: 402-3-40231670-5809203

This final Why gang member Fox is the boss of the gang. Fox is particularly cunning and has hidden herself down this twisted network of alleys known as vice city. Head into vice city to find her but don’t get lost!

- Write if statements in the draw loop to set the direction for the detective
- Do this using the properties of the detective object, speedX and speedY. 
	- For example, to go north you would write the following code:
		det.speedX = 0; 
		det.speedY = -1;

- There are many ways to complete this task but you should only use the following commands and operators:
	if(){}
	else if
	>
	<
	&&

- You will need to make careful use of `else if` and the && operator for this task. Join all conditionals with "else if" and use at least one && operator for each condition.

*/

var currentRoad;
var direction;
var mapImage;
var overlayImage;

//the detective object
var det = {
	speedX: 0,
	speedY: 0,
	locationX: 199,
	locationY: 10,
	currentStreet: undefined,
	image: './det.png'
};

function preload()
{
	perp.image = loadImage(perp.image);
	det.image = loadImage(det.image);
	mapImage = loadImage("./map.png");
	overlayImage = loadImage("./overlay.png")
}

function setup()
{
	createCanvas(1024, 768);
}

function draw()
{

	///////////////////ADD YOUR CODE HERE///////////////////
	
	if (det.locationY < 135 && det.locationX < 210) {
		det.speedX = 0;
		det.speedY = 1;
	}
	else if (det.locationY >= 135 && det.locationY < 138 && det.locationX < 702) {
		det.speedX = 1;
		det.speedY = 0;
	}
	else if (det.locationX >= 702 && det.locationY < 260) {
		det.speedX = 0;
		det.speedY = 1;
	}
	else if (det.locationY >= 260 && det.locationX > 268) {
		det.speedX = -1;
		det.speedY = 0;
	}
	else if (det.locationX <= 270 && det.locationY < 445) {
		det.speedX = 0;
		det.speedY = 1;
	}
else if (det.locationY >= 445 && det.locationX < 826) {
		det.speedX = 1;
		det.speedY = 0;
	}
	
	///////////////DO NOT CHANGE CODE BELOW THIS POINT///////////////////

	background(50);

	if (perp.caught === 0)
	{
		det.locationX += det.speedX;
		det.locationY += det.speedY;
	}

	//draw the images of the map perp and the detective
	image(mapImage, 0, 0);
	image(overlayImage, 0, 0);
	image(perp.image, perp.locationX - roadWidth, perp.locationY - roadWidth, roadWidth * 2, roadWidth * 2);

	push();
	translate(det.locationX, det.locationY);
	if (det.speedX != 0) rotate((det.speedX - 1.5) * PI);
	else if (det.speedY < 0) rotate(PI);
	image(det.image, -roadWidth, -roadWidth, roadWidth * 2, roadWidth * 2);
	pop();

	push();
	textAlign(CENTER);
	textSize(32);
	noStroke();

	//the perp has been caught
	if (dist(det.locationX, det.locationY, perp.locationX, perp.locationY) < roadWidth / 2)
	{
		//display message to the player
		fill(0, 220, 0);
		text("Just in the nick of time! \nYou caught " + perp.name, width / 2, height / 2);
		perp.caught = 1;
	}

	//not on any roads, therefore the game is lost.
	if (!getOnRoad() || (det.speedX == 0 && det.speedY == 0))
	{
		fill(255, 0, 0);
		text("You let " + perp.name + " get away.\n Better luck next time.", width / 2, height / 2);
		perp.caught = -1;
	}

	pop();

	hud();

	fill(255);
	text(`${mouseX},${mouseY}`, mouseX, mouseY);
}

function hud()
{
	push();
	fill(250);
	noStroke();
	textAlign(LEFT, TOP);
	text("detective location - x: " + det.locationX + " y: " + det.locationY, 5, 5);
	pop();
}

function getOnRoad()
{

	if (mapImage.get(det.locationX, det.locationY)[0] == bckgrndColour)
	{
		return false;
	}

	return true;
}

var roadWidth = 25;
var bckgrndColour = 50;
var perp = {
	caught: 0,
	name: 'Fox',
	image: './perp.png',
	locationX: 763,
	locationY: 696
};
I've tried adjusting the corner conditions, including using `<=` or `>=`, adding more tolerance to the `locationX`/`locationY` values, and printing coordinates — but nothing seems to work.

When it says: else if (det.locationY >= 445 && det.locationX < 826) {
det.speedX = 1;
det.speedY = 0;
}

The character doesn’t turn right.

What I need help with:

  • How to write better boundary conditions for path-following logic like this
  • Why the character gets stuck on exact coordinates (like x=703), even though conditions look correct
  • Any suggestions on how to approach this type of logic more robustly?

Welcome to the forum, and thanks for your first post!

I moved it to a more relevant category so others can find it more easily. I also formatted the code to make it easier to read. You can check out this short guide or the animation below for tips on formatting code in future posts.

Glad to have you here!

Raphaël

A screen recording showing how to format code on Discourse

Hi welcome to the forum.

First thing to say is that based on the comments in the code this looks like an academic assignment in which case you should add the Homework tag to your original question.

If I understand your code correctly then the if-else statements at the beginning of the draw method are used to ‘turn’ the detective. There are 2 problems with this approach

  1. The turn positions are hard wired so will only work with one maze configuration.
  2. When using a cascade of if-then-else it is almost impossible to avoid logic errors and even harder to debug, which is what you need to do here.

The solution is to find an alternative approach :grin:

Let us assume that the detective in the middle of a road at position [pX, pY] and the current direction of travel is given by [dirX, dirY] and the road width in pixels is rw.

So if we test the pixel color at position [pX + dirX * rw/2, pY + dirY * rw/2] then there are two possibilities

  1. it matches the road color then we can continue in the same direction.
  2. it does not match the road color then we have reached the end of the road and need to change direction. To find the direction to turn test the colors in the four cardinal directions i.e.
  • North: [pX, pY - rw]
  • South: [pX, pY + rw]
  • East: [pX + rw, pY]
  • West: [pX - rw, pY]

This will tell us the direction of all roads from the detective, including the one he is currently on. Based on this information and the current direction of travel it is easy to determine the road he should take.

NOTE: I use rw instead of rw / 2 for this part to avoid possible ‘road edge’ issues.

2 Likes