Hey guys!
It was recently brought up by Bilbis too from a editor dev. angle though..
I am trying to effectively use the pushing of objects and blocks around in a game for use in puzzles, sorta like Zelda.
I am pulling my hair out trying to isolate why the object does not travel in a straight path. Ex.
object[objPush].Move(WhatX + 60, WhatY, 4, eBlock, eWalkableAreas);
Played with the walkable areas, baselines, blocking heights, location of my character.. I cannot make sense of it at all.
Found some clues on the forum which make me think perhaps it's because I have to figure out where, on the 3x3 grid AGS uses for pathfinding, I have to align my objects... or maybe it is trying to avoid walkbehinds???
1) Any insight into the behavior of the pathfinding that will help me to cooperate *with* it?
2) Should I create my own a loop using "object.SetPosition" in one pixel increments, and checking for walkable space each loop? (will that work any better?)
If that command doesn't move the object in a straight path, the only reason I can think of is that WhatX and WhatY don't have the proper values (apart of course from a weird walkable area, as opposed to an area at least three pixels tall covering the distance).
Also, why aren't you using:
object[objPush].Move(object[objPush].X + 60, object[objPush].Y, 4, eBlock, eWalkableAreas);
Its because of the way I am caling the function, probably convoluted..
PushAnimate(1, object[objPush].X, object[objPush].Y);
...
function PushAnimate(int Way, int WhatX, int WhatY)
The object 75% of the time will move straight, the other times it likes to move in large U shapes, some times move several pixels away from the destination (if the walkable area is tight and usually to the left or right). I am moving these things around rooms with corners etc, the walkables are not all perpendicular lines, often curved.
I've found that making my own movement function is actually easier than deciphering the pathfinding voodoo. But the coding is more complex, trying to do it right with pointers this time.
Maybe you can have a look at what I've done, if it can be cleaned up the next person with this issue might find it useful.
function PushAnimate(int Way)
{
roller = 0;
Object *objSlide = object[objPush];
Object *objStrike;
int pushX = objSlide.X;
int pushY = objSlide.Y;
while (roller != 21)
{
if (Way == 1) { //Left
pushX -= 3;
spriteEdgeX = pushX - GetViewportX(); // Left edge
spriteEdgeY = pushY - GetViewportY(); // Bottom edge
}
else if (Way == 2) { //up
pushY -= 3;
spriteEdgeX = pushX - GetViewportX(); // Left edge
spriteEdgeY = (pushY - GetViewportY()) - (Game.SpriteHeight[objSlide.Graphic]/2); //Isometric Top edge
}
else if (Way == 3) { //Right
pushX += 3;
spriteEdgeX = (pushX - GetViewportX()) + Game.SpriteWidth[objSlide.Graphic]; //Right edge
spriteEdgeY = pushY - GetViewportY(); // Bottom edge
}
else if (Way == 4) { //Down
pushY += 3;
spriteEdgeX = pushX - GetViewportX(); // Left edge
spriteEdgeY = pushY - GetViewportY(); // Bottom edge
}
if (GetWalkableAreaAt(spriteEdgeX, spriteEdgeY))
// create something to scan across entire side for an object and use are-objects-colliding...
{
if (Object.GetAtScreenXY(spriteEdgeX, spriteEdgeY) != null) {
objStrike = Object.GetAtScreenXY(spriteEdgeX, spriteEdgeY);
if (objStrike.Solid) boink();
}
else {
objSlide.SetPosition(pushX, pushY);
roller ++;
}
}
else
boink();
Wait(1);
}
cEgo.UnlockView();
hunger -= 3;
}
I want to next make a little loop to scan across the entire leading side of the sprite for a solid object etc... just worried it might be too many loops per game-cycle or something... any help appreciated :)
Edit:
here's the other thread I referenced earlier,
http://www.adventuregamestudio.co.uk/forums/index.php?topic=48529.msg636462401#msg636462401
* So I've built a function that I am pretty happy with, it scans along the leading edge of the object for anything solid or un-walkable then moves the object, and repeat... I doesn't get messed up in tight spaces like the built in pathfinding, it just goes strait until it can't anymore (nor does it suffer slow-down, I underestimate computers). I would post it but there doesn't seem to be alot of interest in this topic :( , I searched like crazy for some answers when my objects moved like drunk sailors when they have no apparent reason to do so!
Quote from: MiteWiseacreLives!I searched like crazy for some answers when my objects moved like drunk sailors when they have no apparent reason to do so!
Well, like you said : it's probably a bug in the "old pathfinder" algorithm which is called (instead of Dijkstra) on straight line movements.
You can post your solution here for future readers. :smiley:
One non-solution that can do the job in certain situations is to NOT trigger straight line movement by adding a +/-3 in your walk/move movements.
object[objPush].Move(WhatX + 60, WhatY+3, 4, eBlock, eWalkableAreas); //note the "WhatY+3"
If it's not called repeatidly and on high res game, you won't see any differences.
That's kinda crazy, if you move on an angle it goes straight to target ??? maybe there is some reason for this (more interesting character paths?.. naw that's not it). Here's what I came up with to slide some blocks around a room that will move 60 pixels in a straight line unless something stops them, if then a little sparkle animation at point of impact. I removed the GUI part and the 'pushing' animations, so hopefully I didn't delete any crucial variables, but at least it can give some others ideas for a work-around.
(feel free to clean it up or let me know if I am going way beyond what is necessary... :) )
int spriteEdgeX;
int spriteEdgeY;
int roller;
int limit;
int start;
bool obstruction;
Object *objStrike;
Object *objSlide;
void boink() // Call this if object strikes something, will bring a 16x16 character named cBoink to the point of impact and animate
{
if (spriteEdgeX < 0) spriteEdgeX = 1; // and keep it on the screen
if (spriteEdgeY < 0) spriteEdgeY = 1;
if (spriteEdgeX > 640) spriteEdgeX = 640;
if (spriteEdgeY > 480) spriteEdgeY = 480;
cBoink.ChangeRoom(player.Room, (spriteEdgeX + GetViewportX()), (spriteEdgeY + GetViewportY()) + 8);
cBoink.Transparency = 20;
cBoink.Animate(0, 3, eOnce, eBlock);
cBoink.Transparency = 100;
obstruction = true;
}
bool checkStrikeY() // runs along the Y-Axis of the sprite checking for obstructions
{
while (spriteEdgeY != limit)
{
if (GetWalkableAreaAt(spriteEdgeX, spriteEdgeY)) // is it walkable?
{
if (Object.GetAtScreenXY(spriteEdgeX, spriteEdgeY) != null) // is there an object?
{
objStrike = Object.GetAtScreenXY(spriteEdgeX, spriteEdgeY);
if (objStrike.Solid) // it the object solid?
{
boink(); // call the Boink function and set obstruction to true.
spriteEdgeY = limit;
}
else {
obstruction = false; // nothing in the way!
spriteEdgeY --;
}
}
else
{
obstruction = false; // nothing in the way!
spriteEdgeY --;
}
}
else {
// the pixel is not walkable, so call boink
boink();
spriteEdgeY = limit;
}
}
spriteEdgeY = start;
}
bool checkStrikeX() // runs along the X-Axis of the sprite checking for obstructions
{
while (spriteEdgeX != limit)
{
if (GetWalkableAreaAt(spriteEdgeX, spriteEdgeY))
{
if (Object.GetAtScreenXY(spriteEdgeX, spriteEdgeY) != null)
{
objStrike = Object.GetAtScreenXY(spriteEdgeX, spriteEdgeY);
if (objStrike.Solid && objStrike != objSlide)
{
boink(); // there is an object there and it is solid!
spriteEdgeX = limit;
}
else {
obstruction = false;
spriteEdgeX ++; // nothing in the way!
}
}
else {
obstruction = false;
spriteEdgeX ++; // nothing in the way!
}
}
else {
boink();
spriteEdgeX = limit;
}
}
spriteEdgeX = start;
}
function PushAnimate(int Way, int ObjPush)
{
roller = 0;
objSlide = object[objPush];
int pushX = objSlide.X;
int pushY = objSlide.Y;
if (Way == 1) { // Left
spriteEdgeY = (pushY - 1) - GetViewportY(); // Bottom edge
start = spriteEdgeY;
limit = (pushY - GetViewportY()) - (Game.SpriteHeight[objSlide.Graphic]/2) + 1; //Isometric Top edge
}
else if (Way == 2) { // Up
spriteEdgeX = (pushX - GetViewportX()) + 1; // Left edge
start = spriteEdgeX;
limit = ((pushX - GetViewportX()) + Game.SpriteWidth[objSlide.Graphic]) - 2; //Right edge
}
else if (Way == 3) { //Right
spriteEdgeY = (pushY - 1) - GetViewportY(); // Bottom edge
start = spriteEdgeY;
limit = (pushY - GetViewportY()) - (Game.SpriteHeight[objSlide.Graphic]/2) + 1; //Isometric Top edge
}
else if (Way == 4) { //Down
spriteEdgeX = (pushX - GetViewportX()) + 1; // Left edge
start = spriteEdgeX;
limit = ((pushX - GetViewportX()) + Game.SpriteWidth[objSlide.Graphic]) - 2; //Right edge
}
while (roller != 21)
{
if (Way == 1) { //Left
pushX -= 3;
spriteEdgeX = pushX - GetViewportX(); // Left edge
checkStrikeY();
}
else if (Way == 2) { //up
pushY -= 3;
spriteEdgeY = (pushY - GetViewportY()) - (Game.SpriteHeight[objSlide.Graphic]/2); //Isometric Top edge
checkStrikeX();
}
else if (Way == 3) { //Right
pushX += 3;
spriteEdgeX = (pushX - GetViewportX()) + Game.SpriteWidth[objSlide.Graphic]; //Right edge
checkStrikeY();
}
else if (Way == 4) { //Down
pushY += 3;
spriteEdgeY = pushY - GetViewportY(); // Bottom edge
checkStrikeX();
}
if (!obstruction)
{
objSlide.SetPosition(pushX, pushY);
roller ++; // If nothing in the way, advance the object.
}
else
roller = 21;
Wait(1);
}
}