This old code is back for yet another appearance.
#define DIR_DISTANCE 10000
#define DIR_DOWN_LEFT 1
#define DIR_DOWN 2
#define DIR_DOWN_RIGHT 3
#define DIR_LEFT 4
#define DIR_STOP 5
#define DIR_RIGHT 6
#define DIR_UP_LEFT 7
#define DIR_UP 8
#define DIR_UP_RIGHT 9
In repeatedly execute:
if (IsGamePaused()==0) {
Ã,Â
if ((IsKeyPressed (371) > 0) || (IsKeyPressed (55) > 0) || ((IsKeyPressed (372) > 0) && (IsKeyPressed (375) > 0))) Direct = DIR_UP_LEFT;
else if ((IsKeyPressed (373) > 0) || (IsKeyPressed (57) > 0) || ((IsKeyPressed (372) > 0) && (IsKeyPressed (377) > 0))) Direct = DIR_UP_RIGHT;
else if ((IsKeyPressed (379) > 0) || (IsKeyPressed (49) > 0) || ((IsKeyPressed (380) > 0) && (IsKeyPressed (375) > 0))) Direct = DIR_DOWN_LEFT;
else if ((IsKeyPressed (381) > 0) || (IsKeyPressed (51) > 0) || ((IsKeyPressed (380) > 0) && (IsKeyPressed (377) > 0))) Direct =DIR_DOWN_RIGHT;
else if ((IsKeyPressed (372) > 0) || (IsKeyPressed (56) > 0)) Direct = DIR_UP;
else if ((IsKeyPressed (375) > 0) || (IsKeyPressed (52) > 0)) Direct = DIR_LEFT;
else if ((IsKeyPressed (376) > 0) || (IsKeyPressed (53) > 0)) Direct = DIR_STOP;
else if ((IsKeyPressed (377) > 0) || (IsKeyPressed (54) > 0)) Direct = DIR_RIGHT;
else if ((IsKeyPressed (380) > 0) || (IsKeyPressed (50) > 0)) Direct = DIR_DOWN;
else Direct = DIR_STOP;
if (IsKeyPressed(keya)==1) { //RUNNING - 'A' button held down
Ã, Ã, if (isRunning==0) {
Ã, Ã, Ã, StopMoving(GetPlayerCharacter());
Ã, Ã, Ã, SetCharacterSpeed(GetPlayerCharacter(), 12);
Ã, Ã, Ã, isRunning = 1;
Ã, Ã, Ã, ReleaseCharacterView(EGO);
Ã, Ã, Ã, ChangeCharacterView(EGO, 33);
Ã, Ã, Ã, Direct = DIR_STOP;
Ã, Ã, }
}
Ã, else {
Ã, Ã, if (isRunning==1) {
Ã, Ã, Ã, StopMoving(GetPlayerCharacter());
Ã, Ã, Ã, SetCharacterSpeed(GetPlayerCharacter(), 6);
Ã, Ã, Ã, isRunning = 0;
Ã, Ã, Ã, ReleaseCharacterView(EGO);
Ã, Ã, Ã, ChangeCharacterView(EGO, 1);
Ã, Ã, Ã, Direct = DIR_STOP;
Ã, Ã, }
}
if ((PrevDirection != Direct) || (character[EGO].walking == 0)) {
PrevDirection = Direct;
CharId = GetPlayerCharacter ();
if (Direct == DIR_STOP) StopMoving (CharId); // 5 Stop (numeric pad)
else {
if (Direct == DIR_UP_LEFT) {
dx = -DIR_DISTANCE; dy = -DIR_DISTANCE;
StrCopy (direct, "ul");
} // 7 Home (numeric pad)
else if (Direct == DIR_UP) {
dx = 0; dy = -DIR_DISTANCE;
StrCopy (direct, "u");
} // 8 Up arrow
else if (Direct == DIR_UP_RIGHT) {
dx = DIR_DISTANCE; dy = -DIR_DISTANCE;
StrCopy (direct, "ur");
} // 9 PgUp (numeric pad)
else if (Direct == DIR_LEFT) {
dx = -DIR_DISTANCE; dy = 0;
StrCopy (direct, "l");
} // 4 Left arrow
else if (Direct == DIR_RIGHT) {
dx = DIR_DISTANCE; dy = 0;
StrCopy (direct, "r");
} // 6 Right arrow
else if (Direct == DIR_DOWN_LEFT) {
dx = -DIR_DISTANCE; dy = DIR_DISTANCE;
StrCopy (direct, "dl");
} // 1 End (numeric pad)
else if (Direct == DIR_DOWN) {
dx = 0; dy = DIR_DISTANCE;
StrCopy (direct, "d");
} // 2 Down arrow
else if (Direct == DIR_DOWN_RIGHT) {
dx = DIR_DISTANCE; dy = DIR_DISTANCE;
StrCopy (direct, "dr");
} // 3 PgDn (numeric pad)
MoveCharacterStraight (CharId, character [CharId].x + dx, character [CharId].y + dy);
}
}
}
At the moment, the code works -great-. I love it. Responds perfectly to keyboard control. There's another feature I'd like to add though.
Basically, when a character is walking along, say, left... if he hits an edge, he stops. Fair enough, but if I then, while holding left still, hold down the 'up' key, he still won't move. In a typical RPG, what would happen is that the character would start moving up along the edge (while still facing left) until it either hit a spot where it could go left/up-left or in neither direction anymore.
Also, even if the character is against an edge, I'd like him to keep "walking" on the spot if I have the key pressed.
One other thing is that if the character is against an edge and I hit a direction key (not hold it down necessarilly) facing that edge, the character won't move because, well, it's an edge. I'd like him to face that direction still, even if there's no walkable area.
I've written down all sorts of basic code ideas but when I try to think practically about how to adjust the above code, I just end up with a headache. Can anyone at least point me in the right direction? I don't know how to ask the game if it's a possibility to walk when I hit a key. It's not as simple as just checking if a certain coordinate is a walkable area or not because the next pixel over isn't necessarilly where the character would move given his speed and that it changes between walking and running.
I've been thinking about this for days and I just can't get my head around it.
I think it's going to be difficult to tweak your "old code" to do what you want.
Here's how I'd do it instead.
You'll need to know how many pixels the character moves every frame (every time repeatedly execute is run, in other words).
Use that to predict where the character will be next frame. Then break down the movement into pixels and see if there is walkable ground at each pixel. If so, move; if not, and you are moving diagonally, try the corresponding straight moves.
Then, animate the character independent of how it actually moves.
For the movements, you'll need to use floats to store character's position and the per frame movement.
//PSEUDOCODE (i.e. I haven't tested it :):
float characterX;
float characterY;
float animFrame = 0.0;
// character walks 30 = 0.75*GetGameSpeed() pixels per second
// (obviously assumes GetGameSpeed() is the default 40)
#define DIR_DISTANCE 0.75
// character changes animation frame every other game frame
#define ANIM_SPEED 0.5
// in player enters room:
// start in the middle of the pixel
characterX = IntToFloat(player.x) + 0.5;
characterY = IntToFloat(player.y) + 0.5;
int oldDirect = DIR_STOP;
// free functions
function TryDiagonalMove(float dist, int dir, int dx, int dy, int slideDirX, int slideDirY)
{
Ã, int newDir = dir;
Ã, // test that direction
Ã, float delta = 0.7071*dist;
Ã, float dxf = IntToFloat(dx);
Ã, float dyf = IntToFloat(dy);
Ã, float newCharacterX = characterX + dxf*delta;
Ã, int pixelMove = FloatToInt(newCharacterX) - FloatToInt(characterX);
Ã, if (pixelMove != 0)
Ã, {
Ã, Ã, // check the diagonal move
Ã, Ã, if (GetWalkableAreaAt(player.x + dx, player.y + dy) != 0)
Ã, Ã, {
Ã, Ã, Ã, // can move that way
Ã, Ã, Ã, float maxDelta = delta;
Ã, Ã, Ã, if (maxDelta > 1.0)
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, maxDelta = 1.0;
Ã, Ã, Ã, Ã, dist -= 1.414;
Ã, Ã, Ã, }
Ã, Ã, Ã, else
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, dist = 0.0;
Ã, Ã, Ã, }
Ã, Ã, Ã, characterX += dxf*maxDelta;
Ã, Ã, Ã, characterY += dyf*maxDelta;
Ã, Ã, }
Ã, Ã, else
Ã, Ã, {
Ã, Ã, Ã, // round off the position
Ã, Ã, Ã, characterX = IntToFloat(FloatToInt(characterX)) + 0.5;
Ã, Ã, Ã, characterY = IntToFloat(FloatToInt(characterY)) + 0.5;
Ã, Ã, Ã, if (GetWalkableAreaAt(player.x + dx, player.y) != 0)
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, newDir = slideDirX;
Ã, Ã, Ã, }
Ã, Ã, Ã, else
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, newDir = slideDirY;
Ã, Ã, Ã, }
Ã, Ã, }
Ã, }
Ã, else
Ã, {
Ã, Ã, // pixelMove == 0
Ã, Ã, // didn't change pixel so just move within the pixel
Ã, Ã, characterX = characterX + dxf*delta;
Ã, Ã, characterY = characterY + dyf*delta;
Ã, Ã, // stop
Ã, Ã, dist = 0.0;
Ã, }
Ã,Â
Ã, return newDir;
}
function TryStraightMove(float dist, int dx, int dy)
{
Ã, float delta = dist;
Ã, float dxf = IntToFloat(dx);
Ã, float dyf = IntToFloat(dy);
Ã, float newCharacterX = characterX + dxf*delta;
Ã, float newCharacterY = characterY + dyf*delta;
Ã, int pixelMoveX = FloatToInt(newCharacterX) - FloatToInt(characterX);
Ã, int pixelMoveY = FloatToInt(newCharacterY) - FloatToInt(characterY);
Ã, if (pixelMoveX != 0 || pixelMoveY != 0)
Ã, {
Ã, Ã, // check the move
Ã, Ã, if (GetWalkableAreaAt(player.x + dx, player.y + dy) != 0)
Ã, Ã, {
Ã, Ã, Ã, // can move that way
Ã, Ã, Ã, float maxDelta = delta;
Ã, Ã, Ã, if (maxDelta > 1.0)
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, maxDelta = 1.0;
Ã, Ã, Ã, Ã, dist -= 1.0;
Ã, Ã, Ã, }
Ã, Ã, Ã, else
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, dist = 0.0;
Ã, Ã, Ã, }
Ã, Ã, Ã, characterX += dxf*maxDelta;
Ã, Ã, Ã, characterY += dyf*maxDelta;
Ã, Ã, }
Ã, Ã, else
Ã, Ã, {
Ã, Ã, Ã, // round off the position
Ã, Ã, Ã, characterX = IntToFloat(FloatToInt(characterX)) + 0.5;
Ã, Ã, Ã, characterY = IntToFloat(FloatToInt(characterY)) + 0.5;
Ã, Ã, Ã, // stop moving
Ã, Ã, Ã, dist = 0.0;
Ã, Ã, }
Ã, }
Ã, else
Ã, {
Ã, Ã, // pixelMove == 0
Ã, Ã, // didn't change pixel so just move within the pixel
Ã, Ã, characterX = characterX + dxf*delta;
Ã, Ã, characterY = characterY + dyf*delta;
Ã, Ã, // stop
Ã, Ã, dist = 0.0;
Ã, }Ã,Â
}
// in repeatedly execute:
Direct = DirectionFromKeyPresses(); // as before
if (Direct != oldDirect)
{
Ã, // changing direction, so reset these
Ã, characterX = IntToFloat(player.x) + 0.5;
Ã, characterY = IntToFloat(player.y) + 0.5;
}
if (Direct != DIR_STOP)
{
Ã, float dist = DIR_DISTANCE;
Ã, if (IsKeyPressed(keya))
Ã, {
Ã, Ã, // running
Ã, Ã, dist = 2.0*DIR_DISTANCE;
Ã, }
Ã, int newDir = Direct;
Ã, while (dist > 0.0)
Ã, {
Ã, Ã, if (newDir == DIR_DOWN_LEFT)
Ã, Ã, {
Ã, Ã, Ã, newDir = TryDiagonalMove(dist, newDir, -1, 1, DIR_LEFT, DIR_DOWN);
Ã, Ã, }
Ã, Ã, else if (newDir == DIR_DOWN_RIGHT)
Ã, Ã, {
Ã, Ã, Ã, newDir = TryDiagonalMove(dist, newDir, 1, 1, DIR_RIGHT, DIR_DOWN);
Ã, Ã, }
Ã, Ã, else if (newDir == DIR_UP_LEFT)
Ã, Ã, {
Ã, Ã, Ã, newDir = TryDiagonalMove(dist, newDir, -1, -1, DIR_LEFT, DIR_UP);
Ã, Ã, }
Ã, Ã, else if (newDir == DIR_UP_RIGHT)
Ã, Ã, {
Ã, Ã, Ã, newDir = TryDiagonalMove(dist, newDir, 1, -1, DIR_RIGHT, DIR_UP);
Ã, Ã, }
Ã, Ã, else if (newDir == DIR_LEFT)
Ã, Ã, {
Ã, Ã, Ã, TryStraightMove(dist, -1, 0);
Ã, Ã, }
Ã, Ã, else if (newDir == DIR_RIGHT)
Ã, Ã, {
Ã, Ã, Ã, TryStraightMove(dist, 1, 0);
Ã, Ã, }
Ã, Ã, else if (newDir == DIR_UP)
Ã, Ã, {
Ã, Ã, Ã, TryStraightMove(dist, 0, -1);
Ã, Ã, }
Ã, Ã, else if (newDir == DIR_DOWN)
Ã, Ã, {
Ã, Ã, Ã, TryStraightMove(dist, 0, 1);
Ã, Ã, }
Ã, }
Ã,Â
Ã, // now animate the character
Ã, animFrame += ANIM_SPEED;
Ã, int animFrameInt = FloatToInt(animFrame);
Ã, if (animFrameInt > NUM_FRAMES) animFrameInt = 0;
Ã, // TODO: set the player loop and frame depending on Direct and animFrameInt
}
else
{
// TODO: set the standing frame based on oldDirect
}
player.x = FloatToInt(characterX);
player.y = FloatToInt(characterY);
oldDirect = Direct;
Sorry it's a bit long.
It might have been better using some lookup tables, but AGS doesn't lend itself to setting those up.
Remind me if we ever meet that I'm buying you a drink Steve. I don't mind at all if it's long, as long as it works.
I haven't got time to test it right now 'cause I have to scoot out for a bit but my gamespeed is actually 80, and (I might be understanding you wrong here but) do I have to put some of the code in a room script? This is the way the character will be moving throughout the entire game (hundreds of room).
No, it should all work from the global repeatedly_execute.
[EDIT - apart from that bit I said had to be in the room. Ugh. It should work pretty well without it though.]
Please send drinks to:
Creation of Adventures Studio Haven
Boat "The Onion Ring"
Ocho Rios Harbour
Jamaica
(Turns out I don't have to scoot out yet so I'm giving the code a go)
I'm getting an error with the "DirectionFromKeyPresses()" line. It's an undefinied symbol.
You were supposed to substitute your block of code that finds the direction from key presses there.
function DirectionFromKeyPresses()
{
int Direct = DIR_NONE;
if ((IsKeyPressed (371) > 0) || (IsKeyPressed (55) > 0) || ((IsKeyPressed (372) > 0) && (IsKeyPressed (375) > 0))) Direct = DIR_UP_LEFT;
else if ((IsKeyPressed (373) > 0) || (IsKeyPressed (57) > 0) || ((IsKeyPressed (372) > 0) && (IsKeyPressed (377) > 0))) Direct = DIR_UP_RIGHT;
else if ((IsKeyPressed (379) > 0) || (IsKeyPressed (49) > 0) || ((IsKeyPressed (380) > 0) && (IsKeyPressed (375) > 0))) Direct = DIR_DOWN_LEFT;
else if ((IsKeyPressed (381) > 0) || (IsKeyPressed (51) > 0) || ((IsKeyPressed (380) > 0) && (IsKeyPressed (377) > 0))) Direct =DIR_DOWN_RIGHT;
else if ((IsKeyPressed (372) > 0) || (IsKeyPressed (56) > 0)) Direct = DIR_UP;
else if ((IsKeyPressed (375) > 0) || (IsKeyPressed (52) > 0)) Direct = DIR_LEFT;
else if ((IsKeyPressed (376) > 0) || (IsKeyPressed (53) > 0)) Direct = DIR_STOP;
else if ((IsKeyPressed (377) > 0) || (IsKeyPressed (54) > 0)) Direct = DIR_RIGHT;
else if ((IsKeyPressed (380) > 0) || (IsKeyPressed (50) > 0)) Direct = DIR_DOWN;
return Direct;
}
You'll probably want to wrap the whole thing in a "IsGamePaused()", and I didn't look up the proper expression for testing the walkable area so that might be wrong too.
Also, I didn't write the code to animate the character. You'll need to do something about that.
Good luck!
No problem, thanks ^_^ Sorry I misunderstood before. The code has always been wrapped in an IsGamePaused() line so no problem there.
EDIT: "Cannot convert int to float" -> float dist = DIR_DISTANCE;
I'm not even sure what a float is so...
Quote from: Kinoko on Tue 05/07/2005 14:25:01
EDIT: "Cannot convert int to float" ->Ã, Ã, float dist = DIR_DISTANCE;
Damn. I'm surprised that didn't work.
Try this instead:
float dist = 0.75;
if (IsKeyPressed(keya))
{
Ã, // running, so go twice the distance
Ã, dist = 1.5;
}
0.75 and 1.5 are how far in pixels the player will move per frame. You'll need to tweak these.
A float is just a "real" number, as opposed to an integer, if you remember that from maths class. (It's short for floating-point number.)
Now I'm getting undefined symbol with ANIM_SPEED and NUM_FRAMES
ANIM_SPEED should have given you the same problem as DIR_DISTANCE.
Just comment those lines out for now - you'll need to come up with good values for ANIM_SPEED (maybe 0.1, i.e. advance an animation frame every 10 game frames) and NUM_FRAMES (4 if the walk cycle is 4 frames) that correspond to the main character running/walking.
Phew, we're getting there...
Okay, for clarification, I have this:
#define DIR_DISTANCE 10000
#define DIR_DOWN_LEFT 1
#define DIR_DOWN 2
#define DIR_DOWN_RIGHT 3
#define DIR_LEFT 4
#define DIR_STOP 5
#define DIR_RIGHT 6
#define DIR_UP_LEFT 7
#define DIR_UP 8
#define DIR_UP_RIGHT 9
#define DIR_NONE 0
int PrevDirection;
int isRunning = 0;
int CharId;
int Direct;
int oldDirect;
int newdir;
float characterX;
float characterY;
float animFrame = 0.0;
and:
function TryDiagonalMove(float dist, int dir, int dx, int dy, int slideDirX, int slideDirY)
{
int newDir = dir;
// test that direction
float delta = 0.7071*dist;
float dxf = IntToFloat(dx);
float dyf = IntToFloat(dy);
float newCharacterX = characterX + dxf*delta;
int pixelMove = FloatToInt(newCharacterX) - FloatToInt(characterX);
if (pixelMove != 0)
{
// check the diagonal move
if (GetWalkableAreaAt(player.x + dx, player.y + dy) != 0)
{
// can move that way
float maxDelta = delta;
if (maxDelta > 1.0)
{
maxDelta = 1.0;
dist -= 1.414;
}
else
{
dist = 0.0;
}
characterX += dxf*maxDelta;
characterY += dyf*maxDelta;
}
else
{
// round off the position
characterX = IntToFloat(FloatToInt(characterX)) + 0.5;
characterY = IntToFloat(FloatToInt(characterY)) + 0.5;
if (GetWalkableAreaAt(player.x + dx, player.y) != 0)
{
newDir = slideDirX;
}
else
{
newDir = slideDirY;
}
}
}
else
{
// pixelMove == 0
// didn't change pixel so just move within the pixel
characterX = characterX + dxf*delta;
characterY = characterY + dyf*delta;
// stop
dist = 0.0;
}
return newDir;
}
function TryStraightMove(float dist, int dx, int dy)
{
float delta = dist;
float dxf = IntToFloat(dx);
float dyf = IntToFloat(dy);
float newCharacterX = characterX + dxf*delta;
float newCharacterY = characterY + dyf*delta;
int pixelMoveX = FloatToInt(newCharacterX) - FloatToInt(characterX);
int pixelMoveY = FloatToInt(newCharacterY) - FloatToInt(characterY);
if (pixelMoveX != 0 || pixelMoveY != 0)
{
// check the move
if (GetWalkableAreaAt(player.x + dx, player.y + dy) != 0)
{
// can move that way
float maxDelta = delta;
if (maxDelta > 1.0)
{
maxDelta = 1.0;
dist -= 1.0;
}
else
{
dist = 0.0;
}
characterX += dxf*maxDelta;
characterY += dyf*maxDelta;
}
else
{
// round off the position
characterX = IntToFloat(FloatToInt(characterX)) + 0.5;
characterY = IntToFloat(FloatToInt(characterY)) + 0.5;
// stop moving
dist = 0.0;
}
}
else
{
// pixelMove == 0
// didn't change pixel so just move within the pixel
characterX = characterX + dxf*delta;
characterY = characterY + dyf*delta;
// stop
dist = 0.0;
}
}
function DirectionFromKeyPresses()
{
Direct = DIR_NONE;
if ((IsKeyPressed (371) > 0) || (IsKeyPressed (55) > 0) || ((IsKeyPressed (372) > 0) && (IsKeyPressed (375) > 0))) Direct = DIR_UP_LEFT;
else if ((IsKeyPressed (373) > 0) || (IsKeyPressed (57) > 0) || ((IsKeyPressed (372) > 0) && (IsKeyPressed (377) > 0))) Direct = DIR_UP_RIGHT;
else if ((IsKeyPressed (379) > 0) || (IsKeyPressed (49) > 0) || ((IsKeyPressed (380) > 0) && (IsKeyPressed (375) > 0))) Direct = DIR_DOWN_LEFT;
else if ((IsKeyPressed (381) > 0) || (IsKeyPressed (51) > 0) || ((IsKeyPressed (380) > 0) && (IsKeyPressed (377) > 0))) Direct =DIR_DOWN_RIGHT;
else if ((IsKeyPressed (372) > 0) || (IsKeyPressed (56) > 0)) Direct = DIR_UP;
else if ((IsKeyPressed (375) > 0) || (IsKeyPressed (52) > 0)) Direct = DIR_LEFT;
else if ((IsKeyPressed (376) > 0) || (IsKeyPressed (53) > 0)) Direct = DIR_STOP;
else if ((IsKeyPressed (377) > 0) || (IsKeyPressed (54) > 0)) Direct = DIR_RIGHT;
else if ((IsKeyPressed (380) > 0) || (IsKeyPressed (50) > 0)) Direct = DIR_DOWN;
return Direct;
}
and then in repeatedly_execute:
if (IsGamePaused()==0) {
Direct = DirectionFromKeyPresses(); // as before
if (Direct != oldDirect) {
// changing direction, so reset these
characterX = IntToFloat(player.x) + 0.5;
characterY = IntToFloat(player.y) + 0.5;
}
if (Direct != DIR_STOP) {
float dist = 0.75;
if (IsKeyPressed(keya)) {
// running, so go twice the distance
dist = 1.5;
}
int newDir = Direct;
while (dist > 0.0) {
if (newDir == DIR_DOWN_LEFT) {
newDir = TryDiagonalMove(dist, newDir, -1, 1, DIR_LEFT, DIR_DOWN);
}
else if (newDir == DIR_DOWN_RIGHT) {
newDir = TryDiagonalMove(dist, newDir, 1, 1, DIR_RIGHT, DIR_DOWN);
}
else if (newDir == DIR_UP_LEFT) {
newDir = TryDiagonalMove(dist, newDir, -1, -1, DIR_LEFT, DIR_UP);
}
else if (newDir == DIR_UP_RIGHT) {
newDir = TryDiagonalMove(dist, newDir, 1, -1, DIR_RIGHT, DIR_UP);
}
else if (newDir == DIR_LEFT) {
TryStraightMove(dist, -1, 0);
}
else if (newDir == DIR_RIGHT) {
TryStraightMove(dist, 1, 0);
}
else if (newDir == DIR_UP) {
TryStraightMove(dist, 0, -1);
}
else if (newDir == DIR_DOWN) {
TryStraightMove(dist, 0, 1);
}
} /////////////ENDLESS LOOPING/HANGING HERE
// now animate the character
/*animFrame += 0.1;
int animFrameInt = FloatToInt(animFrame);
if (animFrameInt > 4) animFrameInt = 0;*/
// TODO: set the player loop and frame depending on Direct and animFrameInt
}
else {
// TODO: set the standing frame based on oldDirect
}
player.x = FloatToInt(characterX);
player.y = FloatToInt(characterY);
oldDirect = Direct;
} //end if paused
I'm getting an error when I test the game and hit a direction key that basically tells me the code is looping over and over at the line I've marked above.
[EDIT] THIS IS THE WORKING CODE
Ok, I see the problem I think...
Direct is being set to DIR_NONE which isn't handled by the loop.
What is the difference between DIR_NONE and DIR_STOP?
If you don't know, just remove all references to DIR_NONE and replace them with DIR_STOP.
Or, change the line
if (Direct != DIR_STOP)
to
if (Direct != DIR_STOP || Direct != DIR_NONE)
I'm not near an AGS enabled pc at the moment.
If you'd rather I just got it working later and then got back to you I can do that.
Cheers,
Steve
EDIT - tested and working.
#define DIR_DOWN_LEFT 1
#define DIR_DOWN 2
#define DIR_DOWN_RIGHT 3
#define DIR_LEFT 4
#define DIR_STOP 5
#define DIR_RIGHT 6
#define DIR_UP_LEFT 7
#define DIR_UP 8
#define DIR_UP_RIGHT 9
int oldDirect = DIR_STOP;
int newDirect;
float characterX;
float characterY;
float animFrame = 0.0;
#define MAX_NEARBY_CHARS 8
int gNearbyChars[MAX_NEARBY_CHARS];
int gNumNearbyChars;
// unfortunately I don't see any way to find the character width (help?)
// should probably set up the blocking widths for characters before hand
int GetBlockingWidth(int candidateIndex)
{
Ã, int blockingWidth = 16;
Ã, Character *candidate = character[candidateIndex];
Ã, if (candidate.BlockingWidth != 0)
Ã, {
Ã, Ã, blockingWidth = candidate.BlockingWidth;
Ã, }
Ã, return blockingWidth;
}
int GetBlockingHeight(int candidateIndex)
{
Ã, int blockingHeight = 8;
Ã, Character *candidate = character[candidateIndex];
Ã, if (candidate.BlockingHeight != 0)
Ã, {
Ã, Ã, blockingHeight = candidate.BlockingHeight;
Ã, }
Ã, return blockingHeight;
}
// replace GetWalkableAreaAt with this
bool PlayerCanMoveHere(int x, int y)
{
Ã, bool canMoveHere = false;
Ã, if (GetWalkableAreaAt(x - GetViewportX(), y - GetViewportY()) > 0)
Ã, {
Ã, Ã, canMoveHere = true;
Ã, Ã, int candidateIndexIndex = 0;
Ã, Ã, while (candidateIndexIndex < gNumNearbyChars && canMoveHere)
Ã, Ã, {
Ã, Ã, Ã, int candidateIndex = gNearbyChars[candidateIndexIndex];
Ã, Ã, Ã, Character *candidate = character[candidateIndex];
Ã, Ã, Ã, int dxo = candidate.x - player.x;
Ã, Ã, Ã, int dyo = candidate.y - player.y;
Ã, Ã, Ã, int dxn = candidate.x - x;
Ã, Ã, Ã, int dyn = candidate.y - y;
Ã, Ã, Ã, int cdx = player.BlockingWidth/2 + GetBlockingWidth(candidateIndex)/2;
Ã, Ã, Ã, int cdy = player.BlockingHeight/2 + GetBlockingHeight(candidateIndex)/2;
Ã, Ã, Ã, // overlapping AND getting closer
Ã, Ã, Ã, if ((dxn*dxn < cdx*cdx && dyn*dyn <Ã, cdy*cdy)
Ã, Ã, Ã, Ã, Ã, && ((dxn*dxn + dyn*dyn) < (dxo*dxo + dyo*dyo)))
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, canMoveHere = false;
Ã, Ã, Ã, }
Ã, Ã, Ã, candidateIndexIndex++;
Ã, Ã, }
Ã, }
Ã, return canMoveHere;
}
float TryDiagonalMove(float dist, int dx, int dy, int slideDirX, int slideDirY)
{
Ã, // test that direction
Ã, float delta = 0.7071*dist;
Ã, float dxf = IntToFloat(dx);
Ã, float dyf = IntToFloat(dy);
Ã, float newCharacterX = characterX + dxf*delta;
Ã, float newCharacterY = characterY + dyf*delta;
Ã, int pixelMoveX = FloatToInt(newCharacterX) - FloatToInt(characterX);
Ã, int pixelMoveY = FloatToInt(newCharacterY) - FloatToInt(characterY);
Ã, if (pixelMoveX != 0 || pixelMoveY != 0)
Ã, {
Ã, Ã, // check the diagonal move
Ã, Ã, if (PlayerCanMoveHere(player.x + dx, player.y + dy))
Ã, Ã, {
Ã, Ã, Ã, // can move that way
Ã, Ã, Ã, float maxDelta = delta;
Ã, Ã, Ã, if (maxDelta > 1.0)
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, maxDelta = 1.0;
Ã, Ã, Ã, Ã, dist -= 1.414;
Ã, Ã, Ã, }
Ã, Ã, Ã, else
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, dist = 0.0;
Ã, Ã, Ã, }
Ã, Ã, Ã, characterX += dxf*maxDelta;
Ã, Ã, Ã, characterY += dyf*maxDelta;
Ã, Ã, }
Ã, Ã, else
Ã, Ã, {
Ã, Ã, Ã, if (PlayerCanMoveHere(player.x + dx, player.y))
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, // round off the position
Ã, Ã, Ã, Ã, characterY = IntToFloat(FloatToInt(characterY)) + 0.5;
Ã, Ã, Ã, Ã, newDirect = slideDirX;
Ã, Ã, Ã, }
Ã, Ã, Ã, else
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, // round off the position
Ã, Ã, Ã, Ã, characterX = IntToFloat(FloatToInt(characterX)) + 0.5;
Ã, Ã, Ã, Ã, newDirect = slideDirY;
Ã, Ã, Ã, }
Ã, Ã, }
Ã, }
Ã, else
Ã, {
Ã, Ã, // pixelMove == 0
Ã, Ã, // didn't change pixel so just move within the pixel
Ã, Ã, characterX = newCharacterX;
Ã, Ã, characterY = newCharacterY;
Ã, Ã, // stop
Ã, Ã, dist = 0.0;
Ã, }
Ã, return dist;
}
float TryStraightMove(float dist, int dx, int dy)
{
Ã, float delta = dist;
Ã, float dxf = IntToFloat(dx);
Ã, float dyf = IntToFloat(dy);
Ã, float newCharacterX = characterX + dxf*delta;
Ã, float newCharacterY = characterY + dyf*delta;
Ã, int pixelMoveX = FloatToInt(newCharacterX) - FloatToInt(characterX);
Ã, int pixelMoveY = FloatToInt(newCharacterY) - FloatToInt(characterY);
Ã, if (pixelMoveX != 0 || pixelMoveY != 0)
Ã, {
Ã, Ã, // check the move
Ã, Ã, if (PlayerCanMoveHere(player.x + dx, player.y + dy))
Ã, Ã, {
Ã, Ã, Ã, // can move that way
Ã, Ã, Ã, float maxDelta = delta;
Ã, Ã, Ã, if (maxDelta > 1.0)
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, maxDelta = 1.0;
Ã, Ã, Ã, Ã, dist -= 1.0;
Ã, Ã, Ã, }
Ã, Ã, Ã, else
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, dist = 0.0;
Ã, Ã, Ã, }
Ã, Ã, Ã, characterX += dxf*maxDelta;
Ã, Ã, Ã, characterY += dyf*maxDelta;
Ã, Ã, }
Ã, Ã, else
Ã, Ã, {
Ã, Ã, Ã, // round off the position
Ã, Ã, Ã, characterX = IntToFloat(player.x) + 0.5;
Ã, Ã, Ã, characterY = IntToFloat(player.y) + 0.5;
Ã, Ã, Ã, // stop moving
Ã, Ã, Ã, dist = 0.0;
Ã, Ã, }
Ã, }
Ã, else
Ã, {
Ã, Ã, // pixelMove == 0
Ã, Ã, // didn't change pixel so just move within the pixel
Ã, Ã, characterX = newCharacterX;
Ã, Ã, characterY = newCharacterY;
Ã, Ã, // stop
Ã, Ã, dist = 0.0;
Ã, }
Ã, return dist;
}
function DirectionFromKeyPresses()
{
Ã, int Direct = DIR_STOP;
Ã, if ((IsKeyPressed (371) > 0) || (IsKeyPressed (55) > 0) || ((IsKeyPressed (372) > 0) && (IsKeyPressed (375) > 0))) Direct = DIR_UP_LEFT;
Ã, else if ((IsKeyPressed (373) > 0) || (IsKeyPressed (57) > 0) || ((IsKeyPressed (372) > 0) && (IsKeyPressed (377) > 0))) Direct = DIR_UP_RIGHT;
Ã, else if ((IsKeyPressed (379) > 0) || (IsKeyPressed (49) > 0) || ((IsKeyPressed (380) > 0) && (IsKeyPressed (375) > 0))) Direct = DIR_DOWN_LEFT;
Ã, else if ((IsKeyPressed (381) > 0) || (IsKeyPressed (51) > 0) || ((IsKeyPressed (380) > 0) && (IsKeyPressed (377) > 0))) Direct =DIR_DOWN_RIGHT;
Ã, else if ((IsKeyPressed (372) > 0) || (IsKeyPressed (56) > 0)) Direct = DIR_UP;
Ã, else if ((IsKeyPressed (375) > 0) || (IsKeyPressed (52) > 0)) Direct = DIR_LEFT;
Ã, else if ((IsKeyPressed (376) > 0) || (IsKeyPressed (53) > 0)) Direct = DIR_STOP;
Ã, else if ((IsKeyPressed (377) > 0) || (IsKeyPressed (54) > 0)) Direct = DIR_RIGHT;
Ã, else if ((IsKeyPressed (380) > 0) || (IsKeyPressed (50) > 0)) Direct = DIR_DOWN;
Ã, return Direct;
}
#sectionstart game_startÃ, // DO NOT EDIT OR REMOVE THIS LINE
function game_start() {
Ã, characterX = IntToFloat(player.x) + 0.5;
Ã, characterY = IntToFloat(player.y) + 0.5;
}
#sectionend game_startÃ, // DO NOT EDIT OR REMOVE THIS LINE
#sectionstart repeatedly_executeÃ, // DO NOT EDIT OR REMOVE THIS LINE
function repeatedly_execute() {
Ã, // put anything you want to happen every game cycle here
Ã, if (IsGamePaused()==0) {
Ã, Ã, int Direct = DirectionFromKeyPresses(); // as before
Ã, Ã, if (Direct != oldDirect) {
Ã, Ã, Ã, // changing direction, so reset these
Ã, Ã, Ã, characterX = IntToFloat(player.x) + 0.5;
Ã, Ã, Ã, characterY = IntToFloat(player.y) + 0.5;
Ã, Ã, }
Ã, Ã, if (Direct != DIR_STOP) {
Ã, Ã, Ã, float dist = 0.75;
Ã, Ã, Ã, if (IsKeyPressed(65)) // 'A'
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, dist = 1.5;
Ã, Ã, Ã, }
Ã, Ã, Ã, // before the movement in rep_ex
Ã, Ã, Ã, gNumNearbyChars = 0;
Ã, Ã, Ã, int candidateIndex = 0;
Ã, Ã, Ã, int numCharacters = GetGameParameter(GP_NUMCHARACTERS, 0, 0, 0);
Ã, Ã, Ã, if (player.BlockingWidth == 0) player.BlockingWidth = 16;
Ã, Ã, Ã, if (player.BlockingHeight == 0) player.BlockingHeight = 8;
Ã, Ã, Ã, while (candidateIndex < numCharacters && gNumNearbyChars < MAX_NEARBY_CHARS)
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, Character *candidate = character[candidateIndex];
Ã, Ã, Ã, Ã, if (candidate != player && candidate.Solid && candidate.Room == player.Room)
Ã, Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, Ã, // check proximity to player
Ã, Ã, Ã, Ã, Ã, int dx = player.x - candidate.x;
Ã, Ã, Ã, Ã, Ã, // 10 is a made up number but I doubt the player will move more than 10 pix/frame
Ã, Ã, Ã, Ã, Ã, int cdx = player.BlockingWidth/2 + GetBlockingWidth(candidateIndex)/2 + 10;
Ã, Ã, Ã, Ã, Ã, int dy = player.y - candidate.y;
Ã, Ã, Ã, Ã, Ã, int cdy = player.BlockingHeight/2 + GetBlockingHeight(candidateIndex)/2 + 10;
Ã, Ã, Ã, Ã, Ã, if ((dx*dx < cdx*cdx) && (dy*dy < cdy*cdy))
Ã, Ã, Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, Ã, Ã, gNearbyChars[gNumNearbyChars] = candidateIndex;
Ã, Ã, Ã, Ã, Ã, Ã, gNumNearbyChars++;
Ã, Ã, Ã, Ã, Ã, }
Ã, Ã, Ã, Ã, }
Ã, Ã, Ã, Ã, candidateIndex++;
Ã, Ã, Ã, }
Ã, Ã, Ã, newDirect = Direct;
Ã, Ã, Ã, while (dist > 0.0) {
Ã, Ã, Ã, Ã, if (newDirect == DIR_DOWN_LEFT) {
Ã, Ã, Ã, Ã, Ã, dist = TryDiagonalMove(dist, -1, 1, DIR_LEFT, DIR_DOWN);
Ã, Ã, Ã, Ã, }
Ã, Ã, Ã, Ã, else if (newDirect == DIR_DOWN_RIGHT) {
Ã, Ã, Ã, Ã, Ã, dist = TryDiagonalMove(dist, 1, 1, DIR_RIGHT, DIR_DOWN);
Ã, Ã, Ã, Ã, }
Ã, Ã, Ã, Ã, else if (newDirect == DIR_UP_LEFT) {
Ã, Ã, Ã, Ã, Ã, dist = TryDiagonalMove(dist, -1, -1, DIR_LEFT, DIR_UP);
Ã, Ã, Ã, Ã, }
Ã, Ã, Ã, Ã, else if (newDirect == DIR_UP_RIGHT) {
Ã, Ã, Ã, Ã, Ã, dist = TryDiagonalMove(dist, 1, -1, DIR_RIGHT, DIR_UP);
Ã, Ã, Ã, Ã, }
Ã, Ã, Ã, Ã, else if (newDirect == DIR_LEFT) {
Ã, Ã, Ã, Ã, Ã, dist = TryStraightMove(dist, -1, 0);
Ã, Ã, Ã, Ã, }
Ã, Ã, Ã, Ã, else if (newDirect == DIR_RIGHT) {
Ã, Ã, Ã, Ã, Ã, dist = TryStraightMove(dist, 1, 0);
Ã, Ã, Ã, Ã, }
Ã, Ã, Ã, Ã, else if (newDirect == DIR_UP) {
Ã, Ã, Ã, Ã, Ã, dist = TryStraightMove(dist, 0, -1);
Ã, Ã, Ã, Ã, }
Ã, Ã, Ã, Ã, else if (newDirect == DIR_DOWN) {
Ã, Ã, Ã, Ã, Ã, dist = TryStraightMove(dist, 0, 1);
Ã, Ã, Ã, Ã, }
Ã, Ã, Ã, Ã, player.x = FloatToInt(characterX);
Ã, Ã, Ã, Ã, player.y = FloatToInt(characterY);
Ã, Ã, Ã, }
Ã, Ã, }
Ã, Ã, oldDirect = Direct;
Ã, Ã, // now animate the character
Ã, Ã, if (Direct != DIR_STOP)
Ã, Ã, {
Ã, Ã, Ã, animFrame += 0.1;
Ã, Ã, Ã, // based on Roger who has 10 frames in the walk loop
Ã, Ã, Ã, if (animFrame >= 10.0)
Ã, Ã, Ã, {
Ã, Ã, Ã, Ã, // 9 of which are the walk cycle
Ã, Ã, Ã, Ã, animFrame -= 9.0;
Ã, Ã, Ã, }
Ã, Ã, Ã, // change these if you only have four directions
Ã, Ã, Ã, if (newDirect == DIR_DOWN_LEFT) player.Loop = 6;
Ã, Ã, Ã, else if (newDirect == DIR_DOWN_RIGHT) player.Loop = 4;
Ã, Ã, Ã, else if (newDirect == DIR_UP_LEFT) player.Loop = 7;
Ã, Ã, Ã, else if (newDirect == DIR_UP_RIGHT) player.Loop = 5;
Ã, Ã, Ã, else if (newDirect == DIR_LEFT) player.Loop = 1;
Ã, Ã, Ã, else if (newDirect == DIR_RIGHT) player.Loop = 2;
Ã, Ã, Ã, else if (newDirect == DIR_UP) player.Loop = 3;
Ã, Ã, Ã, else if (newDirect == DIR_DOWN) player.Loop = 0;
Ã, Ã, Ã, player.Frame = FloatToInt(animFrame);
Ã, Ã, }
Ã, Ã, else {
Ã, Ã, Ã, // set the standing frame and reset the walk cycle
Ã, Ã, Ã, player.Frame = 0;
Ã, Ã, Ã, animFrame = 1.0;
Ã, Ã, }
Ã, } //end if paused
Ã,Â
}
#sectionend repeatedly_executeÃ, // DO NOT EDIT OR REMOVE THIS LINE
[EDIT] Changed back from cEgo to player, restored running code.
[EDIT2] Added GetViewPort* adjustments for GetWalkableAreaAt() calls.
[EDIT3] Changed round off in diagonal move to only round the required axis.
[EDIT4] Added animation code.
[EDIT5] Fixed occasional getting stuck in a wall.
[EDIT6] Updated to reset the walk cycle and add comments about the number of walk frames.
[EDIT7] Updated to collide with characters.
[EDIT8] Added room check to characters.
Well, I tried this one out and I get an error with the line: float TryDiagonalMove(float dist, int dx, int dy, int slideDirX, int slideDirY) {
saying it has the wrong number of parameters. I thought you must have meant to write "function" instead of "float" so I changed it and I still get the same message.
It is supposed to be float, but the problem would be with the function being declared (imported into a header) differently than the definition (what you are having problems with).
Edit: I don't see a script header, so this may not be the problem. But that's what it would appear to be with saying the function has the wrong number of parameters when trying to declare it.
Edit: Also, just for the record, "function" is defined as "int". By typing "float" instead of function you state that the return type is "float" (as apposed to "int" if you had written "function"). You can define the return type of all your functions by doing this (using return type in place of the word "function" (and it's safer because if you try to return a "float" from a "function", it's liable to either a) convert the float or b) fail when called...o_0)). Just FYI.
Check you haven't left some old code in there:
If you search for TryDiagonalMove, do you find two definitions of the function?
There should be one definition and four uses.
If there are more, remove the ones that don't correspond to the latest code posted here.
[EDIT] And trying to return a float from a "function" won't compile -- it says the return type is wrong, which by a staggering coincidence, it is.
Yeah, trying to define it twice would have the same effect I suppose. And I figured the thing with not being able to return a float from a "function".
You were right, monkey. I hadn't changed the script header.
Well, the game compiles without any problems now, but when I test the game, my character won't move. The walkable areas are all still there.
Is it a scrolling room?
GetWalkableAreaAt expects screen coordinates, not room coordinates, so you have to adjust the coordinates to take account of that in the GetWalkableAreaAt() calls, like so:
GetWalkableAreaAt(player.x + dx - GetViewportX(), player.y + dy - GetViewportY())
I forgot about that, sorry.
If it's not, I'm not sure what the problem is.
We'll get there!
It's a scrolling room. Given that I just had this exact same problem a couple of days ago, this should have occured to me.
Okay!! It's working for left and right, but not up and down (ie. Not when the character runs into a blockage above or below)
So, what happens up and down?
[EDIT] Did you get all three occurrences of GetWalkableAreaAt()?
If I'm against an edge above or below me and holding up and either left or right, nothing. No movement.
If you let go, does the character pop back a pixel?
After letting go of up or down and keep left or right held, presumably you can immediately move left or right.
[EDIT] I see it just went over a page - did you get my last edit about checking if you'd changed all three occurrences of GetWalkableAreaAt()?
I did check and change all of those.
I checked again and the character doesn't pop back a pixel if I let go (he stays in the exact same position) and if I let go of up or down but keep holding left or right, he does move left or right.
Hmm, I know I tested that.
Let me check again.
[EDIT] I updated the code slightly in the TryDiagonalMove section (changed the round off if a wall was hit) - it might make a difference if you changed the speed of the character.
Phew, this is like a workout.
Okay, I updated the code and it works fine, no problems, on upper edges.
On lower edges, it -sometimes- works fine, and sometimes doesn't.
I tried to figure out exactly where it was working and wasn't, but there seems to be something random about it.
If I hold down walk into a lower edge, THEN press left or right without letting go out down, it will SOMETIMES move, and sometimes stay perfectly still.
If I walk onto a lower edge, let go of all the buttons, then hold a diagonal, it will always work (at least it did so everytime I did it).
EDIT: Oh sorry! I forgot a condition. The only times it WON'T work are while I'm also holding 'run'. When I'm walking, this works 100% of the time. If I hold run, THEN I get the 'sometimes yes, sometimes no'.
EDIT: It almost seems to be happening every second time. Assuming I'm always running, and never let go of 'down' once I hit an edge... If I walk into a lower edge and hit left/right, it won't work. If I go up and then down again, then hit left or right, it will work. Go up and down again, hit left/right, it won't work. Will work, won't work.
Could it be a float putting this out and correcting itself every second time, or something like that?
Hmm, it could be your keyboard.
Did you try with the numeric keypad, going diagonally down? That's one less keypress. Or if you're using the numeric keypad, try the cursor keys.
I added some animation code to the block earlier in the thread.
This can go after oldDirect = Direct in rep_ex.
// now animate the character
if (Direct != DIR_STOP)
{
animFrame += 0.1;
if (animFrame >= 10.0)
{
animFrame -= 9.0;
}
// change these if you only have four directions
if (newDirect == DIR_DOWN_LEFT) player.Loop = 6;
else if (newDirect == DIR_DOWN_RIGHT) player.Loop = 4;
else if (newDirect == DIR_UP_LEFT) player.Loop = 7;
else if (newDirect == DIR_UP_RIGHT) player.Loop = 5;
else if (newDirect == DIR_LEFT) player.Loop = 1;
else if (newDirect == DIR_RIGHT) player.Loop = 2;
else if (newDirect == DIR_UP) player.Loop = 3;
else if (newDirect == DIR_DOWN) player.Loop = 0;
player.Frame = FloatToInt(animFrame);
}
else {
// TODO: set the standing frame based on oldDirect
player.Frame = 0;
}
I just tried it with the num pad and it -always- works with the diagonal keys. However, it works on/off when I use the down key, then left/right.
Forget what I said earlier about contnuously holding down/letting go and holding it again. It's the same either way.
As far as I can see at this stage, it works fine if I approach the edge diagonally.
However, (if running) if I go straight down into it, then try to go diagonally left or right, it only works every second time, no matter if I'm using num pad or directional keys.
I tried changing my 'run' button a couple of times but it was always the same result. I'd try it on my laptop but I don't have any way of transferring files into it yet but if the issue is still unresolved by tonight, I'll give it a go there too, see if it is just this laptop.
The fact that it works every second time though seems suspicious. If it were a keyboard problem, wouldn't it either work or not work 100% of the time?
I'm just too lazy to read all of this thread, but are you going to make the character walks while holding a directrional key, and able to change the direction immediately by pressing another direction key at once?
In that case it's possbly because of limitations to some keyboards, which can't detect some of the simultaneous key combinations (like mine at home), you may try changing the keys to say, the alphabets and test if that is the case.
I don't know about reading it all, but surely reading the last post would help :)
I think you're right though. It's particularly suspicious that it's only down then another direction. Although switching to the cursors and changing the run key would I thought have covered that.
I don't seem to have any problems here though.
What exactly do you mean by every second time? Every second time you run the game? Every second time you run into the wall? Can you describe a series of key presses and releases that will replicate the problem? For example:
press A
press NumPad2
<hit wall>
press NumPad1
<no movement> <holding A, NP2, NP1>
release NumPad1
release NumPad2
press NumPad8
release NumPad8
press NumPad2
<hit wall>
press NumPad1
<slides> <holding A, NP2, NP1>
I have the midfortune to announce that it happens with edges in all 4 directions. I guess when I first started it just randomly worked but when I tested just then, it's not just happening with lower edges.
I also discovered it's not just happening with moving -diagonally- left or right either.
Basically, if I run to an edge (say a left edge) - press up - no movement - press down - no movement - press right (walk away from the edge) - press left (walk back to the edge) - ... etc
That's always running, and I tested all that while letting go of every direction key before hitting another, so at no time was I holding two at once.
Another example [assuming 'run' is always held and all these keys are let go of before the next is pushed]:
DOWN [into an edge]
LEFT
RIGHT
UP
DOWN
LEFT
RIGHT
UP
DOWN
RIGHT
UP
DOWN
LEFT
UP
...etc
It doesn't even happen every second time anymore, just completely randomly. Each time I hit an edge and then try to move along it, it may work or it may not.
Yeah, I get that too now. Oops.
Looks like I need to check this out further.
I'll get back to you.
Did the animation code work out ok?
[EDIT] Found it. Change "round off the position" in TryStraightMove() to
// round off the position
characterX = IntToFloat(player.x) + 0.5;
characterY = IntToFloat(player.y) + 0.5;
and move the player position set code in rep_ex inside the while loop so the end of it looks like:
else if (newDirect == DIR_DOWN) {
dist = TryStraightMove(dist, 0, 1);
}
player.x = FloatToInt(characterX);
player.y = FloatToInt(characterY);
}
}
oldDirect = Direct;
I will update the full code earlier in the thread to reflect this.
Seems pretty solid now.
It sort of works. I had to change it slightly because I don't use diagonal loops, but I got a couple of illegal exceptions when walking around.
Basically I changed it like this:
// now animate the character
if (Direct != DIR_STOP)
{
animFrame += 0.1;
if (animFrame >= 10.0)
{
animFrame -= 9.0;
}
// change these if you only have four directions
if (newDirect == DIR_DOWN_LEFT) player.Loop = 0;
else if (newDirect == DIR_DOWN_RIGHT) player.Loop = 0;
else if (newDirect == DIR_UP_LEFT) player.Loop = 1;
else if (newDirect == DIR_UP_RIGHT) player.Loop = 1;
else if (newDirect == DIR_LEFT) player.Loop = 1;
else if (newDirect == DIR_RIGHT) player.Loop = 2;
else if (newDirect == DIR_UP) player.Loop = 3;
else if (newDirect == DIR_DOWN) player.Loop = 0;
player.Frame = FloatToInt(animFrame);
}
else {
// TODO: set the standing frame based on oldDirect
player.Frame = 0;
}
It'll occasionally give me an error for lines like else if (newDirect == DIR_LEFT) player.Loop = 1; saying the loop specified isn't right, but... I can't figure out what could be wrong with that.
Also, it doesn't walk smoothly. If I walk in a straight line for a bit, it only animates a little, stops, animates a little, stops, animates a little, stops, etc...
Plus, it animates too fast but that's easily changed, really. ^_^
I forgot to mention (guess I thought it was obvious :=) that you should change the 10.0 and 9.0 depend on how many frames of animation the walk animation has (I'm assuming they're all the same).
These numbers are for Roger who has 9 walk frames plus one standing still frame.
Oh, and add "animFrame = 1.0;" after "player.Frame = 0;" in the else clause, just to start the animation off from the same frame every time.
Ah right. It works smoothly now :)
I'm still getting occasional errors with my newdirect == lines and it still animates too fast, but much better.
Just to be sure we're on the same page, to slow down the animation, change "animFrame += 0.1" to say "animFrame += 0.05" to halve the speed.
I'm not sure how you'd get those errors, unless the player's view was changed. You should wait until (newDirect == DIR_STOP) to change the view, and change it back to the walking view (in rep_ex) before this animation code when (oldDirect == DIR_STOP && newDirect != DIR_STOP).
Cheers,
Steve
I'm a little confused, I'm not sure where in the code you're talking about.
I haven't written any code for changing the view between running and walking yet, so yeah, I have no idea why the erros are coming up.
Is there an idle view for the character? With just one loop?
You may have to stop the character from idling every so often since AGS isn't aware the character is moving (we're moving the character behind AGS's back).
Aha, that appears to be it. I did have an idle view with only one loop. I've increased it to all 4 loops now and the game didn't crash but yeah, the character did eventually start it's idle animation.
Perhaps to counter this, we could have some variable that changes to 1 when walking and have the engine check... hmm. Nope. I can't really think of a way to get the idle working properly. I could have a timer start after the character stops perhaps.
I'll check it out and get back to you, unless anyone else knows how to temporarily prevent idles...?
Perhaps just using SetIdle and passing it as -1 when walking starts and re-setting it again when the character stops.
This might involve recoding lots of stuff, but you can also simulate your own idle-state with a timer and some code. Would give you more control, and allow you to decide what triggers it and what doesn't. I can share how I did it, though my coding is infamously messy.
Messy? I'll be the judge of that ^_- If you don't mind, share away!
Ok, let's see. I'll remove the bits that apply to my special "animate before/after the actual idle"...
Rep_Exec:
if (IsTimerExpired(2)) {
Ã, if (player.Moving) SetTimer(2, 10*GetGameSpeed());
Ã, else {
Ã, Ã, if (player.Animating==0 && idling==false && dialog==false) {
Ã, Ã, Ã, idling=true;
Ã, Ã, Ã, player.LockViewOffset(player.View+9,0,-1); //I had to do an offset here. I add 9 because this way I can have up to 10 normal views and respective idles, as long as the idle view animation equals the normal walkcycle view + 9.
Ã, Ã, Ã, if (player.Loop==4) player.Animate(2, player.AnimationSpeed, eOnce, eNoBlock, eForwards); //Diagonals, which I had to adjust in my case. You might not need these four "ifs"
Ã, Ã, Ã, else if (player.Loop==5) player.Animate(3, player.AnimationSpeed, eOnce, eNoBlock, eForwards);
Ã, Ã, Ã, else if (player.Loop==6) player.Animate(1, player.AnimationSpeed, eOnce, eNoBlock, eForwards);
Ã, Ã, Ã, else if (player.Loop==7) player.Animate(3, player.AnimationSpeed, eOnce, eNoBlock, eForwards);
Ã, Ã, Ã, else player.Animate(player.Loop, player.AnimationSpeed, eOnce, eNoBlock, eForwards);
Ã, Ã, }
Ã, }
}
Right, that makes idling active. You'll notice the bool "idling". I needed it for my own purposes, but I think you can scratch it plus the check I used. Now to disable it and generally make sure everything works out allright I made four custom functions. Instead of using player.Walk, I use:
function WalkTo(int dest2x, int dest2y, bool blocking2, bool walkonwalkables) {
Ã, SetTimer(2, 10*40);
Ã, if (idling==true){ //Again, this is for my extra purposes. I think you can ignore this check completely.
Ã, Ã, if (player.Loop>3) player.Animate(player.Loop+4, player.AnimationSpeed, eOnce, eBlock, eForwards);
Ã, Ã, else player.Animate(player.Loop+8, player.AnimationSpeed, eOnce, eBlock, eForwards);
Ã, Ã, idling=false;
Ã, Ã, player.Loop-=8;
Ã, Ã, player.UnlockView(); --> POST EDIT - This is important.
Ã, } //This bit now is not in my code, but my code had many superfluos things for your case, so I changed it accordingly.
Ã, if (blocking2==true && walkonwalkables==true)Ã, player.WalkTo(dest2x,dest2y, eBlock, eWalkableAreas);
Ã, if (blocking2==true && walkonwalkables==false)Ã, player.WalkTo(dest2x,dest2y, eBlock, eAnywahere);
Ã, if (blocking2==false && walkonwalkables==true)Ã, player.WalkTo(dest2x,dest2y, eNoBlock, eWalkableAreas);
Ã, Ã, if (blocking2==false && walkonwalkables==false)Ã, player.WalkTo(dest2x,dest2y, eNoBlock, eAnywhere);
Ã, Ã, }
And instead of calling Display (and I'm using LucasStyle speech and always display as speech, mind) I use:
function Say(string what) {
Ã, SetTimer(2, 10*40);
Ã, if (idling==true){ //That check again... I'm keeping it here so you know that it can be checked whether the player is idling, which is very useful
Ã, Ã, if (player.Loop>3) player.Animate(player.Loop+4, player.AnimationSpeed, eOnce, eBlock, eForwards);
Ã, Ã, else player.Animate(player.Loop+8, player.AnimationSpeed, eOnce, eBlock, eForwards);
Ã, Ã, idling=false;
Ã, Ã, player.Loop-=8;
Ã, Ã, player.UnlockView();--> POST EDIT - This is important.
Ã, }
Ã, else if (player.Moving) {
Ã, Ã, player.StopMoving();
Ã, Ã, stopwalk=false; //This is for my own dark purposes (bwahahaha)
Ã, }
Ã, Display(what);
}
If you're not using "always display as speech", you'd naturally put "character.Say" instead of "Display".
And I made the following very simple functions:
function StartTalking() {
Ã, dialog=true;
Ã, SetTimer(2, 0);
}
function StopTalking() {
Ã, dialog=false;
Ã, SetTimer(2, 10*GetGameSpeed());
}
This is to make sure that in a dialog the idle anim will not kick in, even if the player is not moving for 10 seconds or more. Of course, you may not use it - there IS a certain charm in seeing the player idling during a boring conversation. ;)
K, I think that's it. It's not that messy because I edited it a lot. ;) I hope you find a use for it. Mind you, you'd have to replace ALL your Walk and Say commands, unless you want to check that separately, which is possible, accourse.
EDIT - Mind you, I just noticed something. You might need that check after all. I forgot you have to unlock the view. I edited the code accordingly.
EDIT 2 - Forgot to say this - the advantage is that you now have total control of the idle animations, and you can do what the heck you want.
EDIT 3 - Oh, about that "LockView(player.View+9)" - I did that so I could have at least 10 views. If you only have one, you can just change it to a specific view; if not, then you can do the same adding trick, just make sure that the numerical difference between the idles and walkcycles views remains the same.
EDIT 4 - Duh, I keep forgetting to say stuff... I use StartTalking and StopTalking before and after every conversation.
I'm trying one other thing and if that doesn't work, I'll give your code a try, Rui. Thanks!
EDIT: I solved the idle problem by placing a cEgo.SetIdleView(-1, 30); line after the characterY += dyf*... lines in both the TryDiagonal and TryStraight functions, and then placing:
if ((character[EGO].Animating==0) && (cEgo.IdleView==-1)) {
cEgo.SetIdleView(5, 30);
SetLabelText(27, 0, "IDLE ON");
}
in Repeatedly_execute. Works fine now (as far as I've tested so far).
I've also noticed one more problem. Even though the NPCs in my game are "solid", this walking code doesn't check for them so EGO walks right through them.
EDIT2: Is there any way to check if there's a character at a certain x/y position?
Re EDIT2 - Character.GetAtScreen(x,y), or something? Or am I misunderstanding again?
Well, it's a check to see if -any- character is in said position (gee, why does this sound familiar)...
I'd like my characters to be solid but because this walking code only checks whether there's a walkable area or not, I need it to also check if a character is on said x/y position too.
Character.GetAtScreen(x,y)!=null and Character.GetAtScreen(x,y)==null? Or am I STILL misunderstanding?
I updated the code on page 1 to handle characters.
Rui's check will allow the characters to overlap significantly.
The basic idea is:
- find a list of solid characters near the player in the same room in rep_ex
- replace GetWalkableAreaAt() with PlayerCanMoveHere() which checks the list
Ã, Ã, - if the player is colliding with the character and getting closer don't allow the move
Unfortunately it's difficult to find out the exact width and height required - it might be better to set these directly at the start of the game.
For example:
character.BlockingWidth = 16;
character.BlockingHeight = 8;
Unless someone has a better idea?
That works great, no problems ^_^
Im starting to play around with the game again after a break, so this code has come in question yet again for me.
Actually, I have lots of problems that all seem to stem from it, such as objects being walked through, FaceCharacter not working properly, the Character Collision plugin doesnt seem to work properly with it, EGO randomly appears at different coordinates on the screen when he walks sometimes... Im not sure if they all come from this code, but at the moment I`m wonderinf if maybe there isnt just another way to do what I was originally asking just by modifying my original code to check for edges, etc. Changing the entire system of walking just seems too messy at this stage.
Its probably asking the impossible, but does anyone have an idea of how it could be done?
Oh well, I tried.
Unfortunately I don't really have time to fix those last little issues.
Sorry 'bout dat.
Good luck!
Sorry Steve!!! It doesn't mean I don't really appreciate all your help... I hope you don't think that. I'm honestly just too lazy to anilyse the code and figure out ways to make it work in every way I want it to. I'm really picky and fickle, and not very good at scripting.