PDA

View Full Version : The Wall-Hugger Doesn't Work



C-Dawg
10-19-2006, 10:00 AM
I'm having some difficulty getting my wall-hugger to work. Here's the code:

--------------------------------------------------------------------

ffc script wall_hugger {

void run() {

// CONSTANTS (use to change FFC behavior without modifying code)
int speed = 1; // The wall-hugger's speed
int direction = 0; // The wall-hugger's direction
// 0 = Clockwise
// 1 = Counter-clockwise

// VARIABLES (used by the code; do not change)
int state = 0; // Determines the direction of travel
// 0 = North
// 1 = East
// 2 = South
// 3 = West

while(true){
// Check for changes in direction

if (state == 0){
if (direction == 0){ //Clockwise behavior
if (!canMove(this->X, this->Y - 16)){state = 3;}
if (canMove(this->X + 16, this->Y)){state = 1;}
}
else{ // Counter-clockwise behavior
if (!canMove(this->X, this->Y - 16)){state = 1;}
if (canMove(this->X - 16, this->Y)){state = 3;}
}
}

if (state == 1){
if (direction == 0){ //Clockwise behavior
if (!canMove(this->X + 16, this->Y)){state = 0;}
if (canMove(this->X, this->Y+16)){state = 2;}
}
else{ // Counter-clockwise behavior
if (!canMove(this->X + 16, this->Y)){state = 2;}
if (canMove(this->X, this->Y - 16)){state = 0;}
}
}

if (state == 2){
if (direction == 0){ //Clockwise behavior
if (!canMove(this->X, this->Y+16)){state = 1;}
if (canMove(this->X - 16, this->Y)){state = 3;}
}
else{ // Counter-clockwise behavior
if (!canMove(this->X, this->Y + 16)){state = 3;}
if (canMove(this->X + 16, this->Y)){state = 1;}
}
}

if (state == 3){
if (direction == 0){ //Clockwise behavior
if (!canMove(this->X - 16, this->Y)){state = 2;}
if (canMove(this->X, this->Y - 16)){state = 0;}
}
else{ // Counter-clockwise behavior
if (!canMove(this->X - 16, this->Y)){state = 0;}
if (canMove(this->X, this->Y + 16)){state = 2;}
}
}

// After determining direction, move.

if (state == 0) { this->Vy = -speed; }
if (state == 1) { this->Vy = speed; }
if (state == 2) { this->Vy = speed; }
if (state == 3) { this->Vx = -speed; }

Waitframe();
} //end of while loop
} //end of void run()

// Collision detection function
bool canMove(int x, int y){

if(x<0 || x>240 || y<0 || y>160)

return false;

return Screen->ComboS[y+(x>>4)]==0;
} // end of bool canMove

} // end of ffc script

-------------------------------------------------

Instead of acting like it should, the wall-hugger will act, well, unpredictably. If there is an unwalkable combo north of it, it will vibrate widely and then wander off the screen to the left. If there is not, it will vibrate and stay in one place. I can't figure out what's wrong with the logic in the code.

Essentially what the little guy is supposed to do is start facing north. Each tic he is supposed to first check if there is a block in front of him, and then check if there is an opening to his right or left, depending on whether he's going to prefer moving clockwise or counterclockwise. If there's a block in front of him, he'll go around it, but he'll prefer to go into openings that match his rotation.

Anyone see a problem here?

I

Dark Nation
10-19-2006, 11:20 AM
Try using this code:


ffc script wall_hugger {

void run() {

// CONSTANTS (use to change FFC behavior without modifying code)
int speed = 1; // The wall-hugger's speed
int direction = 0; // The wall-hugger's direction
// 0 = Clockwise
// 1 = Counter-clockwise

// VARIABLES (used by the code; do not change)
int state = 0; // Determines the direction of travel
// 0 = North
// 1 = East
// 2 = South
// 3 = West

while(true){
// Check for changes in direction

Trace(state);
Trace(direction);
Trace(1000);
if (state == 0){
Trace(1100);
if (direction == 0){ //Clockwise behavior
Trace(1110);
if (!canMove(this->X, this->Y - 16)){Trace(1111); state = 3;}
Trace(1120);
if (canMove(this->X + 16, this->Y)){Trace(1121); state = 1;}
}
else{ // Counter-clockwise behavior
Trace(1210);
if (!canMove(this->X, this->Y - 16)){Trace(1211); state = 1;}
Trace(1220);
if (canMove(this->X - 16, this->Y)){Trace(1221); state = 3;}
}
}

Trace(state);
Trace(direction);
Trace(2000);
if (state == 1){
Trace(2100);
if (direction == 0){ //Clockwise behavior
Trace(2110);
if (!canMove(this->X + 16, this->Y)){Trace(2111); state = 0;}
Trace(1120);
if (canMove(this->X, this->Y+16)){Trace(2121); state = 2;}
}
else{ // Counter-clockwise behavior
Trace(2210);
if (!canMove(this->X + 16, this->Y)){Trace(2211); state = 2;}
Trace(2220);
if (canMove(this->X, this->Y - 16)){Trace(2221); state = 0;}
}
}

Trace(state);
Trace(direction);
Trace(3000);
if (state == 2){
Trace(3100);
if (direction == 0){ //Clockwise behavior
Trace(3110);
if (!canMove(this->X, this->Y+16)){Trace(3111); state = 1;}
Trace(3120);
if (canMove(this->X - 16, this->Y)){Trace(3121); state = 3;}
}
else{ // Counter-clockwise behavior
Trace(3210);
if (!canMove(this->X, this->Y + 16)){Trace(3211); state = 3;}
Trace(3220);
if (canMove(this->X + 16, this->Y)){Trace(3221); state = 1;}
}
}

Trace(state);
Trace(direction);
Trace(4000);
if (state == 3){
Trace(4100);
if (direction == 0){ //Clockwise behavior
Trace(4110);
if (!canMove(this->X - 16, this->Y)){Trace(4111); state = 2;}
Trace(4120);
if (canMove(this->X, this->Y - 16)){Trace(4121); state = 0;}
}
else{ // Counter-clockwise behavior
Trace(4210);
if (!canMove(this->X - 16, this->Y)){Trace(4211); state = 0;}
Trace(4220);
if (canMove(this->X, this->Y + 16)){Trace(4221); state = 2;}
}
}

Trace(state);
Trace(direction);
Trace(5000);
// After determining direction, move.

if (state == 0) { this->Vy = -speed; }
if (state == 1) { this->Vy = speed; }
if (state == 2) { this->Vy = speed; }
if (state == 3) { this->Vx = -speed; }
Trace(6000);

Waitframe();
} //end of while loop
} //end of void run()

// Collision detection function
bool canMove(int x, int y){

if(x<0 || x>240 || y<0 || y>160)

return false;

return Screen->ComboS[y+(x>>4)]==0;
} // end of bool canMove

} // end of ffc script


It's the same code you had except with a bunch of trace statements in there so you can follow the flow of the code. I noticed that on my test, the state basically went through this sequence: 0, 1, 2, waitframe, 3, 0, waitframe, 1, 2, waitframe, 3, 0, waitframe, etc. Hope that helps.

C-Dawg
10-19-2006, 11:23 AM
I think I see part of the problem already, just based on your trace. Once it gets loose from the wall, the wall_hugger wants to turn in all four directions because there is an opening to all sides... and since state 3 is the final state, thats where it ends up going each tic.

Alright, let's see how to solve that.

EDIT - Do we have a Switch function in ZScript yet?

Dark Nation
10-19-2006, 11:56 AM
No. You'll have to use else's for now, I think.

Wall-hugging code is somewhat similar to maze-solving code. From looking at the problem for a few moments, I came up with the following thoughts...

If the sprite is not touching any solid combos, it should continue travelling in its current direction. (So it can find a wall).
otherwise...
The sprite should check each of the 4 directions for a combo with walk flags, starting with the direction that is opposite of its rotation. So, if the sprite is travelling clockwise, it should check the direction counterclockwise from its current direction. So, if it's travelling clockwise up, it should look left first. It should travel in the first open direction it comes to.

C-Dawg
10-19-2006, 03:11 PM
I don't think that'll work. Suppose a clockwise wall-hugger is travelling North and there is one block to its immediate East. With your algorithm, it will look West first (which is counter-clockwise), find nothing there, and then zoom off to the West, away from the wall. And there's no provision for what happens when it runs into an interior corner (travelling North, there are blocks to the North and East).

So long as the hugger is next to a block, I think it needs to determine a direction and continue in that direction until it either (1) it runs into a block directly in its path, which means it has reached an interior corner, or (2) There is a hole in the in the blocks on the hugger's right (for clockwise movement) or left (for counterclockwise movement), which means it has reached an exterior corner.

Dark Nation
10-19-2006, 04:06 PM
I don't think that'll work. Suppose a clockwise wall-hugger is travelling North and there is one block to its immediate East. With your algorithm, it will look West first (which is counter-clockwise), find nothing there, and then zoom off to the West, away from the wall. And there's no provision for what happens when it runs into an interior corner (travelling North, there are blocks to the North and East).Just as it should. If it is travelling north and going clockwise, it will be hugging the wall on it's left, not it's right. If there is no wall there, it has reached an exterior corner and needs to head left (turn the corner).

C-Dawg
10-19-2006, 06:09 PM
Ahhh, I think we're talking cross purposes. You're thinking of walls as in the four edges of the screen. I'm thinking of walls as in a series of four blocks around which the thing moves. Interior versus exterior.

Maybe this is exactly the conceptual problem with my algorithm...