PDA

View Full Version : Ice Slick



C-Dawg
11-06-2006, 12:13 PM
I'm having a really frustrating time getting this script to work right.

GOAL: Design a script for an ice slick. If Link does not have any Winter Boots, the ice slick will make him slide uncontrolably until he exits the slick or hits a solid combo. Then he can choose to slide in another direction, but can never change direction unless he's off of the slick or against a solid combo. If Link has Level 1 Winter Boots, then he can move normally on the ice slick, but he will slip and slide in any direction he has momentum. Level 2 Winter Boots allow him to move normally on the ice slick.

PROBLEM: I can't get any stage of this ice slick to work correctly. First, I tried to code up the ice slick's behavior when Link has no Winter Boots.



// =============================================
// Ice_Slick: On a screen with this FFC, when Link
// steps inside of a rectangle defined by the four
// data coordinates, he will slip uncontrollably
// in that direction until he exits the rectangle or
// until he hits a solid object.
// Data is set up as follows:
// D0 - The north X coordinate of the ice slick
// D1 - The south X coordinate of the ice slick
// D2 - The west y coordinate of the ice slick
// D3 - The east y coordinate of the ice slick
// =============================================

ffc script ice_slick{

// VARIABLES

int state = 0; // Whether or not Link is slipping.
// 0 = Not slipping
// 1 = Slipping north
// 2 = Slipping south
// 3 = slipping east
// 4 = slipping west

void run(int north, int south, int west, int east){

while(true){

if (state == 1){

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west) &&
(canMove(Link->X, Link->Y - 16)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->Y = Link->Y - 1;
}
else { state = 0; }
} // end of state = 1


if (state == 2){

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west) &&
(canMove(Link->X, Link->Y + 16)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->Y = Link->Y + 1;
}
else { state = 0; }
} // end of state = 2


if (state == 3){

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west) &&
(canMove(Link->X + 16, Link->Y)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->X = Link->X + 1;
}
else { state = 0; }
} // end of state = 3

if (state == 4){

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west) &&
(canMove(Link->X - 16, Link->Y)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->X = Link->X - 1;
}
else { state = 0; }
} // end of state = 4


if (state == 0){

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west)){

if(Link->InputUp && canMove(Link->X, Link->Y-16))
{ state = 1; }
if(Link->InputDown && canMove(Link->X, Link->Y+16))
{ state = 2; }
if(Link->InputRight && canMove(Link->X+16, Link->Y))
{ state = 3; }
if(Link->InputLeft && canMove(Link->X-16, Link->Y))
{ state = 4; }
}
} // end of state 0

Waitframe();

} // end of while loop

} // end of run void


// Collision detection function
bool canMove(int x, int y)
{
if(x<0 || x>240 || y<0 || y>160)
return false;

return Screen->ComboS[ComboAt(x,y)] == 0;
}
}


This works, sort of. It compiles fine, but at runtime, Link will slide across the ice, come to rest somewhere, and usually then gets stuck. He can still move if pushed (for instance, drop a bomb and it will push him away) but the directional input is turned off. Yet Link is immobile. This seems IMPOSSIBLE given the script, which only terminates input in the same if{} statement that forces Link to slide across the ice.

I tried to fix the code by changing how Link would slide as follows:



// =============================================
// Ice_Slick: On a screen with this FFC, when Link
// steps inside of a rectangle defined by the four
// data coordinates, he will slip uncontrollably
// in that direction until he exits the rectangle or
// until he hits a solid object.
// Data is set up as follows:
// D0 - The north X coordinate of the ice slick
// D1 - The south X coordinate of the ice slick
// D2 - The west y coordinate of the ice slick
// D3 - The east y coordinate of the ice slick
// =============================================

ffc script ice_slick{

// VARIABLES

int state = 0; // Whether or not Link is slipping.
// 0 = Not slipping
// 1 = Slipping north
// 2 = Slipping south
// 3 = slipping east
// 4 = slipping west

void run(int north, int south, int west, int east){

while(true){

if (state == 1){


Link->Y = Link->Y - 1;

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west) &&
(canMove(Link->X, Link->Y - 16)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;
}
else { state = 0; }
} // end of state = 1


if (state == 2){

Link->Y = Link->Y + 1;

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west) &&
(canMove(Link->X, Link->Y + 16)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

}
else { state = 0; }
} // end of state = 2


if (state == 3){

Link->X = Link->X + 1;

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west) &&
(canMove(Link->X + 16, Link->Y)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

}
else { state = 0; }
} // end of state = 3

if (state == 4){

Link->X = Link->X - 1;

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west) &&
(canMove(Link->X - 16, Link->Y)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

}
else { state = 0; }
} // end of state = 4


if (state == 0){

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west)){

if(Link->InputUp && canMove(Link->X, Link->Y-16))
{ state = 1; }
if(Link->InputDown && canMove(Link->X, Link->Y+16))
{ state = 2; }
if(Link->InputRight && canMove(Link->X+16, Link->Y))
{ state = 3; }
if(Link->InputLeft && canMove(Link->X-16, Link->Y))
{ state = 4; }
}
} // end of state 0

Waitframe();

} // end of while loop

} // end of run void


// Collision detection function
bool canMove(int x, int y)
{
if(x<0 || x>240 || y<0 || y>160)
return false;

return Screen->ComboS[ComboAt(x,y)] == 0;
}
}


But alas, this had no effect on the bizzare behavior. Link would still become immobile and unable to move on the ice. Additionally, the collision detection is wonky; it will stop him two full combos away from solid blocks instead of right next to them, seemingly at random.

Since this didn't work, I tried to use secret flags. This would be, in theory, easier and more useful, since the ice slicks could be any shape at all. I came up with this:



// =============================================
// Ice_Slick: On a screen with this FFC, Link will
// slip on any tile that has Flag 16 (Secret Flag 0)
// on layer 0. When Link steps on such a tile, he
// will slip in that direction until he's next to
// a combo without that secret flag.
// =============================================

ffc script ice_slick{

// VARIABLES

int state = 0; // Whether or not Link is slipping.
// 0 = Not slipping
// 1 = Slipping north
// 2 = Slipping south
// 3 = slipping east
// 4 = slipping west

void run(){

while(true){

if (state == 0){

if ((Link->InputUp) &&
(Screen->ComboF[ComboAt(Link->X,Link->Y-16)] == 16)){
state == 1;
}
if ((Link->InputDown) &&
(Screen->ComboF[ComboAt(Link->X,Link->Y+16)] == 16)){
state == 2;
}
if ((Link->InputRight) &&
(Screen->ComboF[ComboAt(Link->X+16,Link->Y)] == 16)){
state == 3;
}
if ((Link->InputLeft) &&
(Screen->ComboF[ComboAt(Link->X-16,Link->Y)] == 16)){
state == 4;
}
} // end of state = 0

if (state == 1){

if (Screen->ComboF[ComboAt(Link->X,Link->Y-16)] == 16){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->Y = Link->Y - 1;
}
else{ state = 0;}

} // end of state = 1

if (state == 2){

if (Screen->ComboF[ComboAt(Link->X,Link->Y+16)] == 16){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->Y = Link->Y + 1;
}
else{ state = 0;}

} // end of state = 2


if (state == 3){

if (Screen->ComboF[ComboAt(Link->X+16,Link->Y)] == 16){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->Y = Link->Y + 1;
}
else{ state = 0;}

} // end of state = 3

if (state == 4){

if (Screen->ComboF[ComboAt(Link->X-16,Link->Y)] == 16){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->Y = Link->Y - 1;
}
else{ state = 0;}

} // end of state = 4

Waitframe();

} // end of while loop
} // end of void main
} // end of FFC Script


This script didn't do ANYTHING. It was as if the secret flags weren't being detected. I tested both innate secret flags (assigned in the combo editor) and placed secret flags (assigned in the screen editor). Neither triggered any behavior.

So, last, I tried the second-level behavior of the ice slick. That is, giving Link momentum when he moves in a direction and making him slip in that direction. I came up with this:



// =============================================
// Ice_Slick: On a screen with this FFC, when Link
// steps inside of a rectangle defined by the four
// data coordinates, he will slip on the ice. The slipping
// is controlled by momentum variables that increase
// in the direction Link steps, and decrease in the direction
// he steps away from, as long as that direction is held.
// Data is set up as follows:
// D0 - The north X coordinate of the ice slick
// D1 - The south X coordinate of the ice slick
// D2 - The west y coordinate of the ice slick
// D3 - The east y coordinate of the ice slick
// =============================================

ffc script ice_slick{

// VARIABLES

int state = 0; // Whether or not Link is slipping.
// 0 = Not slipping
// 1 = Slipping north
// 2 = Slipping south
// 3 = slipping east
// 4 = slipping west

int slip_x; // Link's slipping factor
int slip_y;

void run(int north, int south, int west, int east){

while(true){

if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west) ){

if (Link->InputUp){slip_y = slip_y - 0.2;}
if (Link->InputDown){slip_y = slip_y + 0.2;}
if (Link->InputRight){slip_y = slip_x + 0.2;}
if (Link->InputLeft){slip_y = slip_x - 0.2;}

if(slip_y > 1) { slip_y = 1);
if(slip_y < -1) { slip_y = -1);
if(slip_x > 1) { slip_x = 1);
if(slip_x < -1) { slip_x = -1);

if(slip_y < 1 && !Link->InputUp){ Link->Y = Link->Y + slip_y); }
if(slip_y > 1 && !Link->InputDown){ Link->Y = Link->Y + slip_y); }
if(slip_x > 1 && !Link->InputRight){ Link->X = Link->X + slip_x); }
if(slip_x < 1 && !Link->InputLeft){ Link->X = Link->X + slip_x); }

Waitframe();

} // end of while loop
} // end of void run
} // end of ffc script


Which, as far as I can tell, also does NOTHING.

I'm going nuts here. Is this a compiler error, or are my algorithms missing something?

Saffith
11-07-2006, 12:15 AM
Focusing on the fourth version here...


int state = 0; // Whether or not Link is slipping.
// 0 = Not slipping
// 1 = Slipping north
// 2 = Slipping south
// 3 = slipping east
// 4 = slipping west

int slip_x; // Link's slipping factor
int slip_y;You never use that state, y'know. Perhaps you're planning to use it later, but I don't see that you'll need it. And be sure to initialize the slipping variables.



if( (Link->X < south) && (Link->X > north) &&
(Link->Y < east) && (Link->Y > west) )
You're getting X and Y mixed up. That should be more like:

if( (Link->X >= west) && (Link->X + 15 <= east) &&
(Link->Y >= north) && (Link->Y + 15 <= south) )


if (Link->InputUp){slip_y = slip_y - 0.2;}
if (Link->InputDown){slip_y = slip_y + 0.2;}
if (Link->InputRight){slip_y = slip_x + 0.2;}
if (Link->InputLeft){slip_y = slip_x - 0.2;}

if(slip_y > 1) { slip_y = 1);
if(slip_y < -1) { slip_y = -1);
if(slip_x > 1) { slip_x = 1);
if(slip_x < -1) { slip_x = -1);
You have a couple of misplaced parentheses there. Also, you used slip_y instead of slip_x a couple of times.
This could be shortened to half as many lines if you use slip_x=Max(slip_x+0.2, 1), etc.


if(slip_y < 1 && !Link->InputUp){ Link->Y = Link->Y + slip_y); }
if(slip_y > 1 && !Link->InputDown){ Link->Y = Link->Y + slip_y); }
if(slip_x > 1 && !Link->InputRight){ Link->X = Link->X + slip_x); }
if(slip_x < 1 && !Link->InputLeft){ Link->X = Link->X + slip_x); }
You probably mean to be comparing those to 0 instead of 1.
You might want to change the conditions a bit so that Link's position is affected as long as he's not walking in the same direction he's slipping. As it is, he'll slip if he stops moving in one direction, but he'll be able to start walking the opposite direction with no difficulty.

A more subtle problem: Link's position is strictly integral. This'll be adjusting his position by one pixel per frame when it moves him at all. You need your own variables to keep track of it more precisely. Something like this:

realLinkX -= lastFramesLinkX;
realLinkY -= lastFramesLinkY;

realLinkX += Link->X;
realLinkY += Link->Y;

// Modify realLinkX and realLinkY

Link->X = realLinkX;
Link->Y = realLinkY;

lastFramesLinkX = Link->X;
lastFramesLinkY = Link->Y;




It's obviously not complete yet, but all that should at least get it working as far as it goes.


By the way, I finally got around to working out a pixel-perfect solidity testing function.

bool walkableAt(int x, int y)
{
if(x<0 || x>255 || y<0 || y>175)
return false;

int mask=1111b;

if(x%16<8)
mask&=0011b;
else
mask&=1100b;

if(y%16<8)
mask&=0101b;
else
mask&=1010b;

return ((Screen->ComboS[ComboAt(x, y)]&mask)==0);
}

C-Dawg
11-07-2006, 10:17 AM
Thanks for the edits. I'm embarassed that I mixed up the X and Y coordinates; I suppose it looked like it worked because, often, they were interchangable on a square of the screen.

I'll try using your solidity testing function and see if that cures the problems I'm having with the first versions of the Ice Slick.

Any clue why the flag-based test isn't working at all? (Other than repeats of the errors you've already noted?)

C-Dawg
11-07-2006, 10:20 AM
You might want to change the conditions a bit so that Link's position is affected as long as he's not walking in the same direction he's slipping.


That's actually what the part of the code that goes

if(slip_y > 0 && !Link->InputDown){ Link->Y = Link->Y + slip_y); } etc

is supposed to do. Not working that way...?




A more subtle problem: Link's position is strictly integral. This'll be adjusting his position by one pixel per frame when it moves him at all. You need your own variables to keep track of it more precisely. Something like this:

realLinkX -= lastFramesLinkX;
realLinkY -= lastFramesLinkY;

realLinkX += Link->X;
realLinkY += Link->Y;

// Modify realLinkX and realLinkY

Link->X = realLinkX;
Link->Y = realLinkY;

lastFramesLinkX = Link->X;
lastFramesLinkY = Link->Y;


I'm not sure I understand what you're saying here or why this is necessary. How does Link's position being "strictly integral" cause problems with moving him one pixel per frame?

Saffith
11-07-2006, 02:28 PM
That's actually what the part of the code that goes

if(slip_y > 0 && !Link->InputDown){ Link->Y = Link->Y + slip_y); } etc

is supposed to do. Not working that way...?Sorry, I wasn't thinking about it quite right. That does appear to be correct.


I'm not sure I understand what you're saying here or why this is necessary. How does Link's position being "strictly integral" cause problems with moving him one pixel per frame?What I mean is that when you adjust Link's position, the decimal part of the number you add is truncated. Link->X+=1.5 does the same thing as Link->X+=1. Link->X+=0.8 doesn't do anything at all; do it a hundred times a frame, and he still won't move a pixel. Since your slip variables are capped at 1, they won't have any effect until they're maxed out.

C-Dawg
11-07-2006, 02:45 PM
Ooooh, I get it. That does make sense. Still, it will make the slipping a little less precise, since I really don't want Link to slip much faster than he walks. I'll go back and re-work that section.

C-Dawg
11-10-2006, 11:24 AM
UPDATE: I'm going to have a god damn seizure. This fucking code just doesn't work. I've implemented the improvements to the collision detection function, and I've fixed the north/west south/east mixup for all states. Yet Link STILL gets stuck on the ice. I have no clue how this behavior is even possible.

Link's input is ONLY turned off if the code goes into the "if" statements inside states 1 - 4. Right? Right. And in those same if statements, Link is pushed ahead by 1 pixel per frame. There should be no possible way for Link's input to turn off yet Link to not move!

I wondered if it was a problem with the one-pixel-per-frame movement, but increasing it to 2 doesn't fix the problem.

Any ideas, or is this some sort of bizzare bug?

Saffith
11-10-2006, 01:47 PM
Can you post what you've got now? That sounds quite odd.

C-Dawg
11-10-2006, 02:18 PM
Yo.



// =============================================
// Ice_Slick: On a screen with this FFC, when Link
// steps inside of a rectangle defined by the four
// data coordinates, he will slip uncontrollably
// in that direction until he exits the rectangle or
// until he hits a solid object.
// Data is set up as follows:
// D0 - The west X coordinate of the ice slick
// D1 - The east X coordinate of the ice slick
// D2 - The north y coordinate of the ice slick
// D3 - The south y coordinate of the ice slick
// =============================================

ffc script ice_slick{

// VARIABLES

int state = 0; // Whether or not Link is slipping.
// 0 = Not slipping
// 1 = Slipping north
// 2 = Slipping south
// 3 = slipping east
// 4 = slipping west

void run(int west, int east, int north, int south){

while(true){

if (state == 0){

if( (Link->X <= east) && (Link->X >= west) &&
(Link->Y <= south) && (Link->Y >= north)){

if(Link->InputUp && canMove(Link->X, Link->Y-16))
{ state = 1; }
if(Link->InputDown && canMove(Link->X, Link->Y+16))
{ state = 2; }
if(Link->InputRight && canMove(Link->X+16, Link->Y))
{ state = 3; }
if(Link->InputLeft && canMove(Link->X-16, Link->Y))
{ state = 4; }
}
} // end of state 0

if (state == 1){

if( (Link->X <= east) && (Link->X >= west) &&
(Link->Y <= south) && (Link->Y >= north) &&
(canMove(Link->X, Link->Y - 16)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->Y = Link->Y - 1;
}
else { state = 0; }
} // end of state = 1


if (state == 2){

if( (Link->X <= east) && (Link->X >= west) &&
(Link->Y <= south) && (Link->Y >= north) &&
(canMove(Link->X, Link->Y - 16)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->Y = Link->Y + 1;
}
else { state = 0; }
} // end of state = 2


if (state == 3){

if( (Link->X <= east) && (Link->X >= west) &&
(Link->Y <= south) && (Link->Y >= north) &&
(canMove(Link->X, Link->Y - 16)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->X = Link->X + 1;
}
else { state = 0; }
} // end of state = 3

if (state == 4){

if( (Link->X <= east) && (Link->X >= west) &&
(Link->Y <= south) && (Link->Y >= north) &&
(canMove(Link->X, Link->Y - 16)) ){

Link->InputUp = false;
Link->InputDown = false;
Link->InputRight = false;
Link->InputLeft = false;

Link->X = Link->X - 1;
}
else { state = 0; }
} // end of state = 4

Waitframe();

} // end of while loop

} // end of run void


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

if(x<0 || x>255 || y<0 || y>175) {return false;}

int mask=1111b;

if(x%16<8){mask&=0011b;}

else {mask&=1100b;}

if(y%16<8) {mask&=0101b;}

else {mask&=1010b;}

return ((Screen->ComboS[ComboAt(x, y)]&mask)==0);
} // end of bool canMove
} // end of FFC script


Try it out. You'll find that if you slide back and forth on a normal square, Link will sometimes get stuck on the border of the square. If you put solid obstacles on the ice, he'll get stuck next to them or one tile away.

Saffith
11-10-2006, 02:54 PM
That's not the same problem I'm having, actually. I'm finding him sliding right through obstacles and sometimes failing to slide at all. Must just be set up differently.
I think the problem is that you have canMove(Link->X, Link->Y - 16) in the if statement for all four directions. Try using canMove(Link->X, Link->Y - 1) for north, canMove(Link->X, Link->Y + 16) for south, canMove(Link->X + 16, Link->Y) for east, and canMove(Link->X - 1, Link->Y) for west. That should be a bit closer, at least.

C-Dawg
11-10-2006, 04:25 PM
Why would making north -1 instead of -16 have an effect?

I'm also interested to know why you're not having a freezing problem, because it is really prevelant for me. What sort of setup are you using?

Saffith
11-10-2006, 06:20 PM
Why would making north -1 instead of -16 have an effect?http://img469.imageshack.us/img469/6117/yminus16am1.png
See that red pixel at the bottom-left corner of the block? That's Link->X, Link->Y-16. Clearly, Link can move north a bit, but canMove(Link->X, Link->Y-16) will return false.


What sort of setup are you using?http://img149.imageshack.us/img149/135/screentm3.png
The pinkish rectangle is the ice area.
West: 32
East: 128
North: 32
South: 96
Z3-style movement enabled.

That armos is the FFC running the script.

C-Dawg
11-11-2006, 11:42 AM
http://img469.imageshack.us/img469/6117/yminus16am1.png
See that red pixel at the bottom-left corner of the block? That's Link->X, Link->Y-16. Clearly, Link can move north a bit, but canMove(Link->X, Link->Y-16) will return false.

http://img149.imageshack.us/img149/135/screentm3.png
The pinkish rectangle is the ice area.
West: 32
East: 128
North: 32
South: 96
Z3-style movement enabled.

That armos is the FFC running the script.

Fuckin' no-go. I'm getting the same problem. Saffith, give me your e-mail and I'll shoot you a copy of the Quest file I'm playing with so you can check out the problem(s) first hand.

Im still completely bewildered how the code could freeze link and then ignore the instruction to move him one pixel at a time.

Saffith
11-11-2006, 11:35 PM
Saffith, give me your e-mail and I'll shoot you a copy of the Quest file I'm playing with so you can check out the problem(s) first hand.Your PM box is full, y'know.
Well, I guess you could send it to [email protected]. Not one I normally use, but I'll watch for it.

Saffith
11-12-2006, 02:20 PM
Ah, now I see...
It's not a problem with the script, exactly. Try enabling Z3-style movement. I believe you'll then find Link quite mobile indeed.

The thing is, without Z3-style movement, the script sometimes forces Link off of his grid, and the game simply can't handle it. It's not an insurmountable problem; you just have to adjust his position along one axis before sliding him along the other.

C-Dawg
11-12-2006, 04:57 PM
Really? What is Link's grid, and how do you guard against pushing him off of it?

Saffith
11-12-2006, 06:40 PM
You've noticed, no doubt, that if you walk up or down a bit, then start walking left or right, Link may walk up or down a few pixels farther before changing direction so that he's centered, essentially rounding his vertical position to the nearest half tile.
Basically, Link's movement is such that he'll only move left or right if Link->Y%8=0, and he'll only move up or down if Link->X%8=0. If you try to walk somewhere in between, he'll shift his position so that he stays on that grid.
You just have to imitate that yourself. When Link starts moving, be sure he's centered properly, and shift him along the perpendicular axis if he's not.

C-Dawg
11-12-2006, 07:49 PM
You've noticed, no doubt, that if you walk up or down a bit, then start walking left or right, Link may walk up or down a few pixels farther before changing direction so that he's centered, essentially rounding his vertical position to the nearest half tile.
Basically, Link's movement is such that he'll only move left or right if Link->Y%8=0, and he'll only move up or down if Link->X%8=0. If you try to walk somewhere in between, he'll shift his position so that he stays on that grid.
You just have to imitate that yourself. When Link starts moving, be sure he's centered properly, and shift him along the perpendicular axis if he's not.

So, essentially, if his X coordinates are not divisible by 8, he shouldn't be moving north or sourth, and if his Y coordinates are not divisible by 8, he shouldn't be moving east or west. Got it!

But there's a new problem. The collision detection is such that Link will sometimes stop against a block he should not. This happens when he's not completely centered on the 16x16 grid, so it'll be a problem even without Z3 movement. I think I'll change the collision detection to only check Link's BOTTOM half; that way, even if he's standing on the top of the tile, he won't stop against blocks above him.

But to do this, I need to better understand your collision detection function. Right now, I dont have a clue what it does. Can you break down how your collision detection function works?

Saffith
11-12-2006, 09:17 PM
Sure.

bool walkableAt(int x, int y)
{
if(x<0 || x>255 || y<0 || y>175)
return false;

int mask=1111b;

if(x%16<8)
mask&=0011b;
else
mask&=1100b;

if(y%16<8)
mask&=0101b;
else
mask&=1010b;

return ((Screen->ComboS[ComboAt(x, y)]&mask)==0);
}
Well, first, of course, is to make sure the given pixel is on the screen.
After that, it defines a 4-bit mask to use to find the correct bit in the result of ComboS. Screen->ComboS gives you a 4-bit number in which each bit corresponds to one quarter of the combo:
http://img135.imageshack.us/img135/7959/quartersdm2.png
The bit is 1 if that area is solid, 0 if it's walkable.
So, if you AND the bit mask and ComboS, the result is 0 if that pixel is walkable.


By way of example, consider walkableAt(23, 130) on this screen:
http://img241.imageshack.us/img241/7232/screenoe7.png
23, 130 is at the center of that tiny red X near the bottom-left. That falls here on the combo:
http://img241.imageshack.us/img241/1702/comboei5.png
That's just barely in the solid region, so the function should return false.
So...

bool walkableAt(int x, int y)
{
// x=23, y=130
// Obviously in range...
if(x<0 || x>255 || y<0 || y>175)
return false;

int mask=1111b;

// x % 16 = 7, so
// mask = 1111 & 0011 = 0011
if(x%16<8)
mask&=0011b;
else
mask&=1100b;

// y % 16 = 2, so
// mask = 0011 & 0101 = 0001
if(y%16<8)
mask&=0101b;
else
mask&=1010b;

// All but the top-right quarter of the combo is solid, so ComboS = 1011
// mask & ComboS = 0001 & 1011 = 0001
// The result wasn't 0, so return false
return ((Screen->ComboS[ComboAt(x, y)]&mask)==0);
}

C-Dawg
11-14-2006, 07:16 PM
Link->X and Link->Y return the location of the pixel in the upper left corner of the Link sprite, correct? So if you wanted to test walkability of tiles just around Link's feet, I'm thinking you'd just test the walkability of the following pixels:

For walkability north:
Link->X, Link->Y+8

For walkability south:
Link->X, Link->Y+16

For walkability east:
Link->X+16, Link->Y

For walkability west:
Link->X -1 Link->Y

Does that look about right?

Once I get this part perfected, I'll move on to integrating it with the second "slipping" stage of the ice, and include a reference to one of the spare Z items as the Winter Boots.

Saffith
11-14-2006, 07:58 PM
Pretty close. For north, use Y+7 instead of Y+8.
Also, be sure to check both the left and right sides if he's moving north or south.

If you decide to use Z3-style movement, you'll probably want to check two points for horizontal movement and three for vertical, to take into account that he may not be lined up with the solid areas