Walk Boxes!
Apr 27, 2015
Here's a quick video I did narrating walk boxes, how they work, and how they are used with doors and other blocking objects... enjoy.
As the video shows (You did watch the video? I spent hours making it, the least you can do is actually watch it!) walk boxes can be turned on and off via script control and that was one of my basic requirements for the system.
That introduces some complexity into the path finding, but that complexity is worth it in how easy it makes blocking players with closed doors, gates, etc.
Right now, walk boxes must be convex polygons, but I plan on making it so actors can navigate around the interior of concave polygons.
That's a slightly more complex problem because with convex polygons, you can draw a straight line/path between any two points inside the polygon, so if the actor is walking within it, there's no pathfinding. With concave polygons, the actor will need to path find around the edges of the polygon.
Not a huge problem, but I wanted to get walk boxes working and then move on to other tasks in the engine and game. I'll revisit path finding in a few months. As I mentioned on last week's podcast, path finding is a task you can get lost in very easily. It's a rabbit hole of refinements. My goal is to get everything working in the engine, then go back and refine what needs refining.
Here is the code for the jail seen in the video above (You did watch it? Right?).
{
background = "SheriffsOffice"
enter = function()
{
if (sheriffsOfficeJailDoor.jail_door_state == OPEN) {
walkboxHidden("jail_door", NO)
} else {
walkboxHidden("jail_door", YES)
}
}
exit = function()
{
}
jail_close_duration = 1.5
function openJailDoor() {
objectOffsetTo(sheriffsOfficeJailDoor, -60, 0, SheriffsOffice.jail_close_duration)
objectTouchable(sheriffsOfficeJailDoor, NO)
breaktime(jail_close_duration)
objectTouchable(sheriffsOfficeJailDoor, YES)
sheriffsOfficeJailDoor.jail_door_state = OPEN
walkboxHidden("jail_door", NO)
}
function closeJailDoor() {
walkboxHidden("jail_door", YES)
objectOffsetTo(sheriffsOfficeJailDoor, 0, 0, SheriffsOffice.jail_close_duration)
objectTouchable(sheriffsOfficeJailDoor, NO)
breaktime(jail_close_duration)
objectTouchable(sheriffsOfficeJailDoor, YES)
sheriffsOfficeJailDoor.jail_door_state = CLOSED
}
...
sheriffsOfficeJailDoor =
{
name = "Jail Door"
useDist = 20
jail_door_state = CLOSED
verbLookAt = function()
{
if (jail_door_state == CLOSED) {
sayLine("The door is closed.")
} else {
sayLine("The door is wide open.")
}
}
verbOpen = function()
{
if (actorInWalkbox(currentActor, "jail")) {
sayLine("I can't open it from in here.")
return
}
if (jail_door_state == OPEN) {
sayLine("The door already open.")
} else {
startthread(openJailDoor)
}
}
verbClose = function()
{
if (jail_door_state == CLOSED) {
sayLine("The door is already closed.")
} else {
startthread(closeJailDoor)
}
}
}
...
}
- Ron
One's inclined to think there should be an efficient pathfinding algorithm already? Why I keep seeing devs trying to make their own? Is this some "dev coming-of-age" thing? ("You're not considered a true dev until you develop your own efficient pathfinding algorithm, little grasshopper!")
:P
How do you apply pathfinding BETWEEN boxes? Do you have some kind of precompiled adjacency matrix, or do you apply some pathfinding algorithm like A* or similar, treating every box as a node of the search graph?
Please Ron, enlighten me!
The file polygons.png must be amongst Gary's finest work! :P
Are the verbs hardcoded in the engine?
/Kim
First thing where rectangles, but it was giving quite "ugly" walking box though working. As it was easy to get from a point to another as inside a rectangle you can go directly to any point in the rectangle, so just needed links between rectangles and there you go. But well it was not that nice, so I added triangles and mixed triangles and rectangles as you can also go anywhere frome inside a triangle to any other point inside the same triangle, which give me a rough basic working pathfinding and with some depth illusion playing on the character size following movement.
I should get back to that at some point, I still have the cource code and a demo I made might share it if some want a look as well as source code. But it is "very old" I did that almost 10 years ago, using SDL for graphics and audiere for sound though. The rest was my own work no editor but easy to make text file to configure everything :p
Really great blog and lot of memories on my own like having sound playing on specific frame of an animation for the walk to make sure the sound would play when the foot would it the ground :) Looking forward next devsblog :)
1) Can a player stand on the little walkbox that's in-between the inside and outside of the jail cell? If yes, then what happens if Reyes is standing on it and Rey goes to shut the cell door? Does the walkbox disappear causing Reyes to get pushed into the jail cell walkbox, outside the jail cell walkbox, or does a message appear saying "i can't do that right now" when trying to "close" the door.
2) When a player does activate a jail door to close or open, or activates some other type of mechanism with a very brief half a second animation, does the animation have to finish before the player can move an actor or use a verb or can the player do stuff in that half a second while those animations are happening?
#2: In the case of the door, it doesn't really matter if the actor walks around while the door is opening or closing (the walk box is changed when the action starts). In other cases if there is a small window of "danger", the input is silently turned off and then back on. 99.9% of the time, players won't notice. We did this all the time in MI.
In some kind of weird pseudo-code this should do the trick:
function turn_concave_polygon_into_a_series_of_convex_polygons(Polygon concave) /* TODO: Find better name... */
{
Polygon convex_array[];
while(concave.number_of_vertexes > 3)
{
/* Create a new polygon from the first 3 vertexes of "concave". A triangle is, by definition, convex */
Polygon convex = new Polygon(concave.vertex[0] , concave.vertex[1] , concave.vertex[2]);
/* Add it to the series of convex polygons */
convex_array.push(convex);
/* Remove vertex 1 from the list of vertexes in the concave polygon, thereby connecting the old vertex[0] directly with vertex[2] */
concave.remove_vertex(1);
}
/* At this point concave will only have 3 vertexes left and since triangles are convex, we might as well add it to the convex_array and forget it even existed... */
convex_array.push(concave);
return(convex_array);
}
Actually, you could probably use that function on polygons that are already convex without any problems, so you don't even have to check if the polygon is already a convex hull or not.
walkboxHidden() would need to know that it might need to change the state of more than one polygon, but that's just small details.
BTW: In verbOpen, wouldn't it be a good idea to check if the door is already open BEFORE you check if the currentActor is in the jail or not?
Something like:
verbOpen = function()
{
if (jail_door_state == OPEN) {
sayLine("The door already open.")
return
}
if (actorInWalkbox(currentActor, "jail")) {
sayLine("I can't open it from in here.")
return
}
startthread(openJailDoor)
}
"It's a walk box."
OPEN walk box.
Are you planning to also have the objects handle the earlier mentioned give/receive logic in a similar manner? It seems this would make sense contextually, but perhaps at the risk of making the objects somewhat bloated(?)
I just couln't hold myself on how relevant the following tool and especialy the video showing it, is to this post and the man posting it :P
https://www.youtube.com/watch?v=k8RH1jFYHEA
The cell door animation is a linear object movement. I wondered if you could add an easing function (so that the cell door slams shut instead of gliding gently) and of course you CAN... now. But could you then, and if not will you now?
I'm wondering if simple things like easing functions (especially elastic bounce, or any computationally intensive one) were avoided on the games back in the day because of CPU power. You're limiting things like color palettes for vintage aesthetics so I wondered: would excluding "fancy animations" fall under the same goal of 'maintaining authenticity'? Thanks!
That's very interesting. Can you elaborate how these "motors" work, from a technical perspective? Is it just a method that is called on every tick for each actively moving object which applies a function to the some attribute (e.g., position, scale, rotation, color, etc.)?
-dZ.
Thanks for sharing! :)
-dZ.
I wonder if it would be possible to put styles into MOTOR that would look and feel like that. Of course back in the day, there were technical limitations stopping you from doing it the way you do it now. It's just a thought.
Imagine the game had one mode where it would go to great lengths to act like the old games on a technical level, too. No smooth animations of big objects. Doors that open and close in 1-frame. Things like that.
Why go through the trouble of building the limitations into your game when running an emulated ancient computer will enforce it for you?
-dZ.
Really interesting, so that's how someone could get stuck... they erase the walkable area under their feet!
I have a question, however. I use the feet of the character as the position reference, and if I have to scroll right, left or down it's easy: if the character is near the screen and there's still some background left in that direction, scroll. But when going up? It should be dependent on the height of the character, or the distance between the top of the background and the highest walking point... nothing impossible, but still, nothing as trivial as the horizontal scrolling.
How do you handle vertical scrolling in the rooms?