How to get to a pixel-perfect destination using Character.Walk()?

Started by LostTrainDude, Wed 07/12/2016 17:25:49

Previous topic - Next topic

LostTrainDude

As per subject, I'm trying to make a character reach a very specific destination, before performing an animation.
This is the line I've been using:
Code: ags
player.WalkStraight(object[0].X+(Game.SpriteWidth[object[0].Graphic]/2), player.y, eNoBlock);


The result is that most of the time the character gets a few pixels off the target. For instance: while that specific x is 733, the Character reaches 732 or 731.

I tried using both Character.Walk() and Character.WalkStraight(), also I originally had just object[0].X for the x parameter of the function. The results are the same.
Is this something strictly related to the way those function work? Is it because of the walking animation, perhaps?

It is probably worth mentioning that the object[0] is placed everytime right outside the players' Viewport (whether the player moves to the right or to the left) with the following code:
Code: ags
function RandomItem()
{
    // Choose which item to place
    int r = Random(2);
	
    // Check if any item is already in the viewport
    // if NOT, put one
    if (!isItemInViewport())
    {
        // Make all the items different than r invisible
        for (int i = 0; i <= 2; i++)
        {
            if (i != r)
	    {
                object[i].Transparency = 100;
	    }
        }

	// Check which direction is the player taking
	if (player.DestinationX < player.x) // LEFT
	{
	    object[r].SetPosition(playerViewportEdgeLeft-Game.SpriteWidth[object[r].Graphic], 278); // Then move it right outside the viewport
	    object[r].Transparency = 0;
	}
	else if (player.DestinationX > player.x) // RIGHT
	{
	    object[r].SetPosition(playerViewportEdgeRight+Game.SpriteWidth[object[r].Graphic], 278);
	    object[r].Transparency = 0;
	}
    }
}


Thanks in advance, everybody :)
"We do not stop playing because we grow old, we grow old because we stop playing."

Khris

My guess is that the object is solid and thus cuts a rectangle out of the walkable area. So while AGS tries to get to the coordinates exactly (and usually succeeds) it can't. Try pressing Ctrl+A during the game to take a look.

LostTrainDude



I know that the walkable area is unnecessarily tall, but still... I'm not sure. The object appears below the player's walkable area (as it should be).

And, yes... I'm reverse-engineering Rags To Riches from the C64 (roll)
"We do not stop playing because we grow old, we grow old because we stop playing."

morganw

I'm pretty sure it uses the character's speed to predetermine the distance it needs to move per frame, for the x and y directions. I think the offset you are seeing is probably because the speed is enforced so animation frames always look correct (rather than it snap the character to the destination at the end of the walk, at a speed that doesn't match the animation frames).

If you change the character speed to 1 pixel per frame, does it still miss the destination?

Khris

I don't think this is a speed issue; afaik the character does indeed get moved to the exact destination at the end of the walk, provided the remaining distance is below the movement speed.

@LostTrainDude:
Try to use .Walk instead of .WalkStraight, and also try the eAnywhere option.

LostTrainDude

Quote from: morganw on Wed 07/12/2016 21:06:14
If you change the character speed to 1 pixel per frame, does it still miss the destination?

I'm tracking the Character.X on screen and apparently it always walks 2 pixels at a time. Things I tried:

  • I tried coding the WalkSpeed to (1, 1) in the game_start() function
  • I tried setting the speed manually in the Character's Properties
  • I tried setting the AnimationDelay property to 1
  • I tried setting the MovementLinkedToAnimation property to false

...Or is there another way to set it properly?

Quote from: Khris on Wed 07/12/2016 21:20:01
Try to use .Walk instead of .WalkStraight, and also try the eAnywhere option.

I tried that before but tried it again now. The same result, unfortunately.
I also tried making it an eBlock, instead. But no.
"We do not stop playing because we grow old, we grow old because we stop playing."

Cassiebsg

Try checking General Settings->Use low-resolution co-ordinates in script-> false
There are those who believe that life here began out there...

LostTrainDude

Quote from: Cassiebsg on Wed 07/12/2016 22:06:42
Try checking General Settings->Use low-resolution co-ordinates in script-> false

It was set to false already. I tried switching it to true but, as the disclaimer would say, it made all other coordinates go crazy (roll)
"We do not stop playing because we grow old, we grow old because we stop playing."

Crimson Wizard

I do not have real ideas about what causes this at the moment, but I was thinking about workaround, what if you just force-move the character to the target destination when it is close to it? You could remember target coordinates yourself, or, if you are using AGS 3.4.0, there is Character.DestinationX and Character.DestinationY properties.

EDIT: btw, do you take image alignment into consideration? IIRC character's frames are centered at its position, which may make character look a bit "offset" if sprites are not fully symmetric.
Did you try displaying character's position on screen?

LostTrainDude



Thankfully I did display them! It's the reason I found out what the problem was in the first place :)
Player X is a single pixel away from the Obiect[0] Mid position.
I also tried using the Object[0] X instead, but the results are the same.

This time, though, I also added the DestinationX and found out that when I click on the object it doesn't really send the character to the position I set up in the Character.Walk() function.
No matter where I click on the object, it always send it to a pixel away from the destination I'd like to send it.

It almost feels like it doesn't like odd numbers (laugh)

Quote from: Crimson Wizard on Thu 08/12/2016 09:43:35
EDIT: btw, do you take image alignment into consideration? IIRC character's frames are centered at its position, which may make character look a bit "offset" if sprites are not fully symmetric.

I had the feeling that characters' frames and sprites did not have the same "origin" point. If I understood correctly, characters have it in the center while objects at their left (that's why I'm calculating the character's destination to be the object.X + half of its sprite's length). Still, I'm not sure I have the logic needed to deal with the problem :(
"We do not stop playing because we grow old, we grow old because we stop playing."

Khris

Wait, what is the basis for the Player Destination X value in the screenshot?
And what happens if you place the object at an even X coordinate?

Crimson Wizard

Maybe this is a rounding mistake? either in script or pathfinder.

Snarky

Isn't there a thing where the pathfinder only checks every third pixel to identify walkable areas? Could have something to do with that, maybe?

But if I understand correctly it's not working even if you're placing the character directly by setting the x/y coordinates? That really should always work: if positioning things with pixel accuracy doesn't work reliably then AGS has a serious problem.

Crimson Wizard

Quote from: Snarky on Thu 08/12/2016 13:43:51
Isn't there a thing where the pathfinder only checks every third pixel to identify walkable areas? Could have something to do with that, maybe?
Yes it is something like that, but since LostTrainDude said that he tried eAnywhere flag before, I thought that should be something else.

BTW, what is game resolution?

LostTrainDude

Quote from: Khris on Thu 08/12/2016 12:47:35
Wait, what is the basis for the Player Destination X value in the screenshot?

The displayed value is the one that the game sends when I click on the Object. It should get it from the player.Walk() function within the oBottle_Interact() one (which is the one I showed in the first post), but it always get it a pixel off.

But still, it works whenever I click somewhere on the screen. I noticed that wherever I click, the result is alwas an even number.

Quote from: Khris on Thu 08/12/2016 12:47:35
And what happens if you place the object at an even X coordinate?

I tried something simple (which may be wrong, of course):
Code: ags
function oBottle_Interact()
{
    int p = object[0].X+(Game.SpriteWidth[object[0].Graphic]/2);
    
    if (p % 2 != 0)
    {
        p++;
    }
    
    player.Walk(p, player.y, eBlock, eAnywhere);
}


And, instead of adding 1, it adds 2 pixels :\

Quote from: Crimson Wizard on Thu 08/12/2016 13:47:59
BTW, what is game resolution?

As I'm currently just doing tests, it's a custom and temporary 608x304. Is it a problem?
"We do not stop playing because we grow old, we grow old because we stop playing."

LostTrainDude

Of course the easiest workaround for me is to simply check whether the player walks in a position that is between the object origin and its center.
This puts a patch on the problem and basically solves it, but I don't know... Is this an AGS bug to report, anyway?

Thanks everybody for your help, up to now :)
"We do not stop playing because we grow old, we grow old because we stop playing."

Gurok

Quote from: LostTrainDude on Thu 08/12/2016 09:26:58
Quote from: Cassiebsg on Wed 07/12/2016 22:06:42
Try checking General Settings->Use low-resolution co-ordinates in script-> false

It was set to false already. I tried switching it to true but, as the disclaimer would say, it made all other coordinates go crazy (roll)

You say it made all other coordinates go crazy. Aside from that, did it fix the problem? Were you able to achieve precise positioning with high-resolution coordinates?
[img]http://7d4iqnx.gif;rWRLUuw.gi

LostTrainDude

Quote from: Gurok on Wed 14/12/2016 00:32:04
You say it made all other coordinates go crazy. Aside from that, did it fix the problem? Were you able to achieve precise positioning with high-resolution coordinates?

You're right. I didn't really try.

I disabled all the scripts that involved object placement and manually placed an object on the screen. Displaying the Object.X, its "center" (object[a].X+(Game.SpriteWidth[object[a].Graphic]/2) and player.DestinationX I can tell it seems to work as I originally intended.

Now I wonder more about this setting, though. Is it best to enable it before doing anything else in the game, maybe?
I'm not sure if there is any specific "conversion" I should make in terms of XY coordinates in my scripts in order to make them work properly. Most rely on variables such as player.X+arbitrary_value_I_choose.

Is there anything that I can read about it?

Thanks for the heads up, Gurok!
"We do not stop playing because we grow old, we grow old because we stop playing."

Crimson Wizard

IIRC enabling "Use low-resolution co-ordinates in script" makes your game use 320x200 coordinate grid regardless of your resolution. That means that precision of script commands will lower down. You won't be able to order any random coordinate anymore by script command, only coordinates inside 320x200 rectangle, which will be remapped to your WxH game by rough multiplication.

For example, if you have 640x400 game, "Use low-resolution co-ordinates in script" is enabled, and you do "player.Walk(100,100)" - that will result in character walking to (200,200) in reality instead.
On other hand, you won't make it walk to real (201,201) coordinates. (100,100) => (200,200), but (101,101) => (202,202). So the number of possible points you can set object position on screen is reduced.

Frankly I see no point in enabling this option. It was provided for backwards compatibility only, that is when you are loading very old project in newer version of AGS.


That said, it could maybe explain what is happening with your game if that option was enabled. But above you said it was false...

I think we need a proper test case, like a small game project with matching settings that lets you reproduce the problem. Ideally we would test your actual project, if you think it is okay to share it.

Gurok

Sorry, I must have misread the text initially. Yeah, I don't recommend enabling "Use low-resolution co-ordinates in script" either. I somehow read that as you had set it to True and wanted you to try turning it off. That's what everything you describe is pointing to.

Anyway, it is very strange if you're experiencing things otherwise and I agree with CW about the test case.
[img]http://7d4iqnx.gif;rWRLUuw.gi

LostTrainDude

Please do :) Here is the whole thing in a comfy zip format (laugh)

I called it rAGS because it made sense :P Of course nothing is final, as the background is one huge placeholder pasted from the original game.
It may be easy to get confused by which are actual objects and which are just part of the background, but if you look at them closely you find out that actual objects are uncompressed and better defined.

Also, I apologize in advance for the messy, spaghetti, useless or incomprehensible code you may find! Let me know if I you need anything!
"We do not stop playing because we grow old, we grow old because we stop playing."

SMF spam blocked by CleanTalk