FaceLocation & WalkToPoint problem

Started by Marcel86, Sun 01/03/2020 19:00:36

Previous topic - Next topic

Marcel86

I am heavyly struggeling with FaceLocation in AGS 3.5. Maybe I'm doing something wrong?

This is my setup (using the Timbleweed config):

1. I have a hotspot in a room (basically a plant in the background). The user is able to interact with it via following code

Code: ags

function plant_AnyClick()
{
  player.FaceLocation(mouse.x, mouse.y, eBlock);
  if (Verbs.UsedAction(eGA_LookAt)) {
    player.Say("A little plant I bought at the gas station.");
  }
  else Verbs.Unhandled();


2. I also defined a WalkToPoint right of the plant hotspot

3. In the General Settings I set all options under "CHARACTER MOVEMENT" to true.

4. Walking-Animations for left, right etc. are all set correctly for the player. Same for the talking animations.

This is what I would expect:

1. I trigger "Look at" while clicking on the plant. 
2. The player moves to the WalkToPoint that is defined on the plant (hotspot)
3. Since the WalkToPoint is located right from the hotspot, I would expect the player
    to always look to the left once he arrives at the WalkToPoint.

This is what happens:

Sometimes it works correctly, but sometimes the player looks in the wrong direction when
he arrives at the WalkToPoint and starts talking. It seems like something randomly affects the calculation
what is left and what is right of the player. It also seems that the closer the WalkToPoint is located near the hotspot itself
the more often the wrong direction is chosed.


My theories:

1. mouse.x, mouse.y might change to something else while walking to the walktopoint is still in progress and causing the facelocation method to use the wrong coordinates
    (the mouse is NOT locked while walking, so I guess the coordinates can be overwritten here?

2. maybe something wrong with the timing? Since I can't define a eBlock for WalkToPoint, the facelocation might be triggered to early?


What puzzles me most is, that according to the API, there is no way to get a hotspots x, y coordinates. I guess player.FaceLocation(myhotspot.x, myhotspot.y, eBlock); would solve my problems within seconds.

Anyone else got an idea?

Cassiebsg

When you use mouse.x and mouse.y is not very good solution, cause if you move the mouse they'll change.
So either you save them, by using int MouseY=mouse.y; and int MouseX=mouse.x; right at the start of the function and then use MouseY and MouseX, or the better solution is to just tell it to FaceDirection=Left since you know which direction he will have to use .  ;)
There are those who believe that life here began out there...

Marcel86

Quote from: Cassiebsg on Sun 01/03/2020 19:28:15
When you use mouse.x and mouse.y is not very good solution, cause if you move the mouse they'll change.
So either you save them, by using int MouseY=mouse.y; and int MouseX=mouse.x; right at the start of the function and then use MouseY and MouseX, or the better solution is to just tell it to FaceDirection=Left since you know which direction he will have to use .  ;)

That's a possible workaround I also had in my mind. However as a programmer, I struggle to believe that there is no possibility to get the hotspots location and use that information for FaceLocation.
Without that, the whole FaceLocation functions looks kinda useless to me. At least in combination with hotspots (objects do provide x, y coordinates).

Slasher

#3
Examples in Rooms Rep Execute

Code: ags

if (Hotspot.GetAtScreenXY(mouse.x, mouse.y) == hotspot[1]) {
 cEgo.Say("Captain. We are bordering on an unauthorised area.");
}
else if (Hotspot.GetAtScreenXY(mouse.x, mouse.y) == hotspot[2]) {
  //Change cursor graphic for Hotspot 2
}

//Etc for other hotspots

//the same applies for Object.GetAtScreenXY(mouse.x, mouse.y) and Character.getAtScreenXY(mouse.x, mouse.y).



Hope this helps...

Marcel86

Quote from: Slasher on Sun 01/03/2020 19:45:44
Examples in Rooms Rep Execute

Code: ags

if (Hotspot.GetAtScreenXY(mouse.x, mouse.y) == hotspot[1]) {
 cEgo.Say("Captain. We are bordering on an unauthorised area.");
}
else if (Hotspot.GetAtScreenXY(mouse.x, mouse.y) == hotspot[2]) {
  //Change cursor graphic for Hotspot 2
}

//Etc for other hotspots

//the same applies for Object.GetAtScreenXY(mouse.x, mouse.y) and Character.getAtScreenXY(mouse.x, mouse.y).



Hope this helps...


Not really, this is a routine to check if a certain hotspot is located at given coordinates of the courser. It returns a bolean.

I actually need a method that is returning x & y coordinates of a given hotspot to hand them over to FaceLocation to make the player facing the hotspod, and not facing the cursor position.

Khris

#5
First the simple fix: you have your walkto point to the right of the plant, so you simply want
Code: ags
  player.FaceDirection(eDirectionLeft);


(Note: Since you have a walkto point set and turned on the option, the player walks to that point blocking before the AnyClick function is called. This is unlike Lucasfilm games, where the player can cancel an action by clicking elsewhere while the player character approaches the hotspot; there's Verbs.MovePlayer(x, y) instead which doesn't block the game. If you want to keep using walkto points, note that imo this diminishes the experience for the player because if you accidentally give a command you have to wait it out.)

Regarding the actual problem again, the reason for the unexpected behavior is that the mouse might move anywhere else while the player walks to the walkto point, and only the position when they arrive is used because that's when the AnyClick function runs, and it will use the mouse coordinates at that time. To save them at the time of the click means you need to do it before the click is processed, which requires editing the main Thumbleweed script. Again, this is a moot point because you can simply use .FaceDirection.

Getting hotspot coordinates isn't possible because a hotspot doesn't have coordinates. It's a bunch of pixels. What you can do though is use Hotspot.GetAtRoomXY() to probe a sufficient amount of room pixels, then calculate a center based on the coordinates found. If you want to use this you should to this once when a room is loaded for the first time and store the coordinates in a suitable array.

Laura Hunt

Quote from: Marcel86 on Sun 01/03/2020 19:35:54
Quote from: Cassiebsg on Sun 01/03/2020 19:28:15
When you use mouse.x and mouse.y is not very good solution, cause if you move the mouse they'll change.
So either you save them, by using int MouseY=mouse.y; and int MouseX=mouse.x; right at the start of the function and then use MouseY and MouseX, or the better solution is to just tell it to FaceDirection=Left since you know which direction he will have to use .  ;)

That's a possible workaround I also had in my mind. However as a programmer, I struggle to believe that there is no possibility to get the hotspots location and use that information for FaceLocation.
Without that, the whole FaceLocation functions looks kinda useless to me. At least in combination with hotspots (objects do provide x, y coordinates).

A quick and dirty fix that I use quite often and gets the job done is to look up in the room editor the X coordinate roughly corresponding to the middle of my hotspot, and then simply check if the player is to the right or to the left of it, and turn accordingly. It's obviously not the most elegant solution, especially if you have lots of hotspots you want to do this for, but for the odd case here and there, it works:

Code: ags
if (player.x > yourhotspotcenterx) player.FaceDirection(eDirectionLeft);
else player.FaceDirection(eDirectionRight);



TheManInBoots

Hi Marcel,

I think you might be looking for this function:

For every hotspot you can set a walkto-x coordinate and walkto-y coordinate (You can set and change the exact coordinates in the hotspot's property panel in the room editor).
Once you set those, you can simply script:

Code: ags
 player.FaceLocation(hHotspot1.WalkToX, hHotspot1.WalkToY);



Hope that helps ;)

Khris

That won't help I'm afraid because the player character will be standing on that exact point when the command is being run, so AGS wouldn't know which direction to use.
A better choice of coordinates for .FaceLocation would be a spot on the ground directly beneath the hotspot.

One could actually set that ground spot as walkto point and indeed use that command, but only after using Verbs.MovePlayer() to make the character walk to a suitable spot nearby.

TheManInBoots

#9
Oh yeah right.
The character automatically walks to those points.
Sorry.

TheManInBoots

#10
Edited the previous post.
I'm only half thinking while writing this, working on something else at the moment sorry :P

Cassiebsg

I guess, if one would want to use the WalkToPoints them, it's probably possible to do this:

Code: ags

player.FaceLocation(hHotspot1.WalkToX-10, hHotspot1.WalkToY); // removing 10 pixels (or whatever value) would make the look at point 10 pixels to the left, so it should work


I often use that "trick" to place my character in place when relating to other characters or objects, and it's handy. But for the above? I would just face left, and I think setting those points in the editor are a pain (and cause other problems), so I never use them anymore.
There are those who believe that life here began out there...

TheManInBoots

He could place a transparent dummy character at the Hotspot center, and name him hotspotcenter.
Then he can code
Code: ags
player. FaceLocation(hotspotcenter. x, hotspotcenter. y) ;


But again, none of this would be truly necessary, because he can simply write
Code: ags
player.FaceLocation(125,768,eBlock);

With 125,768 being the Hotspot center.
Simple solutions are still the best, why beat your brains out when you don't have to. And it still makes totally valid use of the FaceLocation function.

Khris

#13
The only actually useful information was in the very first reply.

Quote from: Cassiebsg on Sun 01/03/2020 19:28:15the [better] solution is to just tell it to FaceDirection=Left since you know which direction he will have to use .  ;)

Everything else is needless distraction, including the previous post which suddenly introduces a pointless dummy character but doesn't suggest to use .FaceCharacter for some reason.

ManicMatt

Indeed, I for one will stick to the tried and tested FaceDirection code as I will 100% know the character will face the direction I want. There's no need to complicate this.

TheManInBoots

#15
Yeah, it's all over-complicating.

But Marcel wanted a means to have hotspot points.

I like the idea though of scanning the room for hotspots and calculating the center points, Khris.
Quote from: Khris on Sun 01/03/2020 20:05:46
Getting hotspot coordinates isn't possible because a hotspot doesn't have coordinates. It's a bunch of pixels. What you can do though is use Hotspot.GetAtRoomXY() to probe a sufficient amount of room pixels, then calculate a center based on the coordinates found. If you want to use this you should to this once when a room is loaded for the first time and store the coordinates in a suitable array.

If for example you have a room full of hotspots it might be useful.
This way you just create a custom function that uses the calculated and saved hotspot center points and all you need to write is:

Code: ags
player.Facehotspot(Hotspot[1]);


or probably rather
Code: ags
player.Facehotspot(1);


with 1 being the hotspot ID

Crimson Wizard

#16
Quote from: Khris on Sun 01/03/2020 20:05:46
Getting hotspot coordinates isn't possible because a hotspot doesn't have coordinates. It's a bunch of pixels. What you can do though is use Hotspot.GetAtRoomXY() to probe a sufficient amount of room pixels, then calculate a center based on the coordinates found. If you want to use this you should to this once when a room is loaded for the first time and store the coordinates in a suitable array.

I think there was already a module that does similar thing, for displaying visual hints for player (as in - where player is allowed to click on screen). I am not sure it's calculating exactly center though.

Although, I am not sure if having automatic solution would be suitable here, because this may be rather situational: for some cases you'd want to face hotspot's center, in others you'll find facing hotspot's bottom gives best result.

Frankly, if this is a game-wide problem (and not just one place), I'd either make an array of preset coordinates in script, or add custom properties and set them by hand for every hotspot I need. Then I'll be able to just get these properties' values and face character at them. This is slower than having them calculated automatically, but would allow to adjust character behavior anytime.

Snarky

A couple of modules that work out the coordinates of hotspots (in order to highlight them):

Hint Highlighting: https://www.adventuregamestudio.co.uk/forums/index.php?topic=56463
ShowInteractiveAreas: https://www.adventuregamestudio.co.uk/forums/index.php?topic=47195

(ALARCOST apparently has something similar.)

SMF spam blocked by CleanTalk