trouble with walkable areas and things happens before player is at walkToPoint

Started by Blondbraid, Wed 11/11/2015 22:30:13

Previous topic - Next topic

Blondbraid

Ok, this might be tricky to explain, but my game has a big maze-like room with many walk-behinds and two separate walkable areas the character can teleport between, by stepping on one of two regions in each walkable area. The problem is when I want the character to walk to an object and do an animation, but the character and object are in separate walkable areas. Instead of walking to the region, "teleporting" (I used the Player.Move command) and then walk to the object, my character walks to the edge of the walkable area he is in, and then the animation plays out far away from the intended object.

What I want to do is a script where, if the player clicks on the object:
A: If the character is on the same walking area as the object, he goes to straight to it
B: If the character is on a different walking area than the object, so he first goes to the region, "teleports" to the other walking area, then walks to the object the player clicked on

Which script commands can I use to determine which walkable area a character is standing on?


Snarky

Given my complaints about certain other recent questions, I just want to say that this was very well put, explaining both your immediate problem and the bigger context quite clearly.

The answer is very simple:
Code: ags
Room.GetWalkableAreaAt(player.x - Room.GetViewportX(), player.y - Room.GetViewportY());

Blondbraid

Thank you, but I must admit that I'm not sure how to use that line in my script. Where shall I put it and do I need to add any coordinates?


Snarky

Well, do you understand what the line does? If not, look up Room.GetWalkableAreaAt() in the manual.

Quote from: Blondbraid on Wed 11/11/2015 22:30:13
What I want to do is a script where, if the player clicks on the object:
A: If the character is on the same walking area as the object, he goes to straight to it
B: If the character is on a different walking area than the object, so he first goes to the region, "teleports" to the other walking area, then walks to the object the player clicked on

If you only need this for one particular object, you can do:

Code: ags

int someObjectWalkableArea = 5; // Or whatever the right number is

function someObject_Interact()
{
  int playerWalkableArea = Room.GetWalkableAreaAt(player.x - Room.GetViewportX(), player.y - Room.GetViewportY());
  if(playerWalkableArea != someObjectWalkableArea)
  {
    player.Walk(150,100,eBlock); // Or wherever the teleportation region is
  }

  // Do the actual interaction here
}


If you want to make it work for a bunch of different objects, it's a little more work because you don't want to hardcode all the numbers, but it's basically the same idea. Just pull it out into a function that teleports the character if the walkable areas don't match, and always call that function at the top of every interaction script.

Blondbraid

QuoteWell, do you understand what the line does? If not, look up Room.GetWalkableAreaAt() in the manual.
I looked it up, but I didn't understand the text in the manual.
QuoteIf you want to make it work for a bunch of different objects, it's a little more work because you don't want to hardcode all the numbers, but it's basically the same idea. Just pull it out into a function that teleports the character if the walkable areas don't match, and always call that function at the top of every interaction script.
I'm sorry that I didn't bring it up earlier, but it's not one object, but four hotspots I'm using for the puzzle.
Anyway, when I tried using the script for one of the hotspots, I get an error line telling me "GetWalkableAreaAt" isn't a public member of "Room". I checked and the spelling was correct, but I can't see what else I did wrong.


Snarky

Quote from: Blondbraid on Thu 12/11/2015 15:15:18
QuoteWell, do you understand what the line does? If not, look up Room.GetWalkableAreaAt() in the manual.
I looked it up, but I didn't understand the text in the manual.

I'm not sure what to tell you. The manual explains it as simply and clearly as I can imagine:

QuoteGetWalkableAreaAt (int x, int y)

Returns the number of the walkable area at SCREEN co-ordinates (X,Y). If there is no walkable area there, or if invalid co-ordinates are specified, returns 0.

So this method tells you the walkable area that some particular (x,y) coordinates belongs to. It returns it as a number (an int), with 0 if there isn't any walkable area there. Obviously, you can use this to check whether two particular points (like where the player is and where a certain object is) are in the same walkable area.

QuoteNOTE: The co-ordinates are SCREEN co-ordinates, NOT ROOM co-ordinates. This means that with a scrolling room, the co-ordinates you pass are relative to the screen's current position, and NOT absolute room co-ordinates. This means that this function is suitable for use with the mouse cursor position variables.

In AGS, if you have a room that is bigger than the screen resolution, that gives you a scrolling room. This means that the coordinates of a point on screen are not the same as the coordinates in the room. Some AGS functions work with screen coordinates, other with room coordinates. This one uses screen coordinates, but character positions use room coordinates. To translate a room coordinate to a screen coordinate, you subtract GetViewportX/Y() from the x/y coordinate, respectively.

QuoteExample:

Code: ags
if (GetWalkableAreaAt(mouse.x,mouse.y) == 0)
    Display ("You can't walk there.");

... and that's how you should call it. That also answers your new problem:

QuoteAnyway, when I tried using the script for one of the hotspots, I get an error line telling me "GetWalkableAreaAt" isn't a public member of "Room". I checked and the spelling was correct, but I can't see what else I did wrong.

Because even though this method is part of Room , as you see, it's called without the Room-prefix. (My mistake!) So instead of:

Code: ags
Room.GetWalkableAreaAt(player.x - Room.GetViewportX(), player.y - Room.GetViewportY());


Just use:

Code: ags
GetWalkableAreaAt(player.x - GetViewportX(), player.y - GetViewportY());


QuoteI'm sorry that I didn't bring it up earlier, but it's not one object, but four hotspots I'm using for the puzzle.

I suspected as much. But with the explanation given, don't you think you can solve it on your own? Here's a hint: Like I said, write a function that checks whether the object and the player are in the same walkable area, and if not, does the teleportation. Then for every object interaction, just start by calling that function:

Code: ags
/// Walk/teleport to the walkable area the object is in 
void goToObjectArea(this Character*, Object* obj)
{
  int characterWalkableArea = GetWalkableAreaAt(this.x - GetViewportX(), this.y - GetViewportY());

  // TODO: get objectWalkableArea, the walkable area the object is at (either look up its coordinates or use a custom property)

  if (characterWalkableArea != objectWalkableArea)
  {
    // TODO: Walk to the teleportation region: just hardcode the coordinates (depending on which walkable area the character is in)
    // TODO: Test that the teleportation happens automatically at the right time; if not, just call Character.Move()
  }
}


// Examples of how to use:

function someObject_Interact()
{
  player.goToObjectArea(someObject);
  // Do the object interaction
}

function someOtherObject_Interact()
{
  player.goToObjectArea(someOtherObject);
  // Do the object interaction
}

// Etc.

Blondbraid

I'm terribly sorry, but I think that I've lost the track :-[ (I've already written a lot of code for the room and find it hard to keep track of all the changes).
Also, I get the error message saying Undefined symbol "objectWalkableArea" on the line that says:
Code: ags
if (characterWalkableArea != objectWalkableArea)


Snarky

Just focus on this code for now. Don't put it into your project until you understand it and know how to add the missing steps. If necessary, put it in a new project where you just set up the bare minimum to test it.

The error message is because I didn't give you complete, finished code, but left it to you to implement some of the steps, and you didn't do this bit:

Code: ags
// TODO: get objectWalkableArea, the walkable area the object is at (either look up its coordinates or use a custom property)


In other words, you have to define and set the correct value of this variable.

Blondbraid

Quote from: Snarky on Thu 12/11/2015 19:30:17
Just focus on this code for now. Don't put it into your project until you understand it and know how to add the missing steps. If necessary, put it in a new project where you just set up the bare minimum to test it.
I made a new project, just a single room with two walkable areas, two regions to teleport between the areas and three hotspots, so I could concentrate on this problem. I think I have a better overview now, but I still cannot solve the problem. I've looked at the code and the manual, but I can't tell from the example there how to incorporate any coordinates into that line of code.
Code: ags
  // TODO: get objectWalkableArea, the walkable area the object is at (either look up its coordinates or use a custom property)
if (GetWalkableAreaAt(mouse.x,mouse.y) == 0)
    Display ("You can't walk there.");


Khris

I found this thread and tried to implement a solution. Took me almost 100 lines of room script and a custom Walk function. Still, I'm not even handling non-blocking walking yet.

Plus, the best way to handle this depends on your game's interface and how it handles walking to hotspots. When I click to interact with a hotspot, does the game do a blocking walk there?
Or can I interrupt the walk and do something else, like in Monkey Island?

I just want to make clear that even if you fully understand how GetWalkableAreaAt() works, you're still a long way from a working solution.
Here's my WIP room script to test this: http://pastebin.com/m3ANjnNE

Snarky

Khris, is all of that really necessary?


  • Non-blocking walks? Yeah, that would add significant complexity. But if not actually needed (I assumed not), let's just not support it!
  • If I read repeatedly_execute_always() correctly, it's there to simulate the "player walks onto region" event for any character (and ensure you don't end up in an infinite loop, teleporting back and forth). However:

    • In the blocking case, you can just perform the teleportation in the function script, can't you?
    • To avoid the region-event triggering, just put the teleportation destination outside of the teleportation-triggering region going the other way
  • With blocking walk, you shouldn't need to keep track of what happens after the teleportation; just script it for each interaction.

Khris

Well, I wrote all that with the intention of implementing non-blocking walks; sticking to blocking ones is of course much simpler.
I also wanted to be able to send the player to the exact spot they leave from, hence the deactivating of regions.

Maybe somebody will find it helpful at some point :)

Blondbraid

QuotePlus, the best way to handle this depends on your game's interface and how it handles walking to hotspots. When I click to interact with a hotspot, does the game do a blocking walk there?
Or can I interrupt the walk and do something else, like in Monkey Island?
I use eBlock in the walking commands for my script since I felt that it would be easier to handle at my current level of (in)experience.
QuoteIf I read repeatedly_execute_always() correctly, it's there to simulate the "player walks onto region" event for any character (and ensure you don't end up in an infinite loop, teleporting back and forth). However:
In the blocking case, you can just perform the teleportation in the function script, can't you?
To avoid the region-event triggering, just put the teleportation destination outside of the teleportation-triggering region going the other way
As for the teleporting, I just use a player.move command to move the player from one teleporting region to standing just next to the other region, and that works decently so far.
My problem is that when the player character is in one walking area, and interacts with a hotspot in another area, instead of walking to the teleport region and then walking to the hotspot, they just walk to the edge of their current walking area and do the interaction there.


Snarky

If you look at Khris's code, you can use it to fill in the gaps in what I gave you (or you can just use his directly, just changing some of the coordinate values), and so within the constraints you mention (blocking walks, teleportations to outside of the teleportation regions), that ought to... work.

Blondbraid

Quote from: Snarky on Fri 20/11/2015 19:22:14
If you look at Khris's code, you can use it to fill in the gaps in what I gave you (or you can just use his directly, just changing some of the coordinate values), and so within the constraints you mention (blocking walks, teleportations to outside of the teleportation regions), that ought to... work.
I've looked at Khris's code, and I must say I greatly appreciate your effort, Khris ;-D, but when I tried using it on a new project the problem was still there.
Quote from: Khris on Thu 19/11/2015 20:00:11
I just want to make clear that even if you fully understand how GetWalkableAreaAt() works, you're still a long way from a working solution.
I'm just barely beginning to understand what it means, and I'm starting to feel that this is currently to complicated for me as I'm just a beginner, so I have been thinking of coming up with an easier solution altogether and perhaps save these functions for a later project when I have more experience.

I considered just disabling the hotspots when the player steps onto the region, and enable them when they step onto the other region, so that the player can't interact with a hotspot in the wrong area,
but I would want the player to have some clue that the hotspot could be interacted with.
What I'm thinking is that when the player is in the first walkable area, they can interact with the hotspot, but when they step onto the teleporting region, they will trigger a change in the hotspot script so that the player character instead just says something along the line of "That's too far away, I must get closer" when you click on the hotspot, and vice versa when the player steps onto the other teleporting region. Is there a command for changing the script of a hotspot like this?


Snarky

Quote from: Blondbraid on Fri 20/11/2015 20:14:37
I'm just barely beginning to understand what it means, and I'm starting to feel that this is currently to complicated for me as I'm just a beginner, so I have been thinking of coming up with an easier solution altogether and perhaps save these functions for a later project when I have more experience.

I mean, the code is there, so if it's not working there's probably just some small error somewhere. I'm guessing you're not actually calling it: it's not enough to add this script to your project, you have to actually use it when you interact with those objects, you know.

QuoteIs there a command for changing the script of a hotspot like this?

Just add an if/else condition to the interaction handler. So instead of something like "when the player clicks on the object, go to this position, say this line, and add this inventory item", you put "when the player clicks on the object, if they are in the right walkable area then go to this position, say this line and add this inventory item, else just say this other line". But that's the same thing you can do to make the character actually do the walking/teleportation, so if you can get it working you could just do that.

Blondbraid

It took a while, but I just figured it out and was able to solve it! Now the character moves to the right position before doing the interaction, and I think that all the big bugs have been solved.
Thank you both for your time and patience! ;-D


Snarky


SMF spam blocked by CleanTalk