Parkour? (Adv3Lite)

I’ve been making a parkour system for my upcoming game, where hidden routes between rooms can be discovered by climbing on and jumping between collections stuff.

Right now it’s being designed as a module, because I really love these kinds of mechanics and plan to make it a staple of my future games too.

Would anyone be interested in this as an extension? Just asking because that determines if I write documentation for it or not.

I always make weird games, but idk if anyone else here is interested.

8 Likes

I would be interested in an extension with these features (adv3Lite).

My current game in progress sometimes needs a random hidden direction.

Thanks

5 Likes

Alright, I’ll add documentation to the todo list, then!

5 Likes

Something about this just fired my imagination. Since I am in a 1-2 year stretch of a non-Lite implementation I was reluctant to weigh in, but when I eventually make the jump I already have ideas! Thanks!

3 Likes

I’m looking forward to your development. Thanks.

2 Likes

Code implementation is about 75% done. After that is thorough bughunting and fixing, and then I’m writing the documentation.

2 Likes

Okay, so I’m making a decision.

I’m developing this parkour extension for my Spring Thing game at the moment.

In the interest of completing the game in time, I’m going to work on documentation after the competition, and then release the extension.

This also means the extension can be stress-tested and “sanded down” in an actual project, too.

Win win!

5 Likes

Ugh.

Okay…

So, the first stage of the extension worked perfectly.

The second stage was a little weird, but worked perfectly.

The third stage required a massive refactor/cleanup pass, but worked perfectly.

There was nowhere for elements of the fourth stage to fit, and attempting to fit them proved that the fundamental structure of the extension was incorrect.

So, unfortunately, it’s halfway into January, and Spring Thing fast approaches, but I need parkour to work, before my game makes sense.

I’m redoing the extension from scratch. I literally have to. I’m already making really good progress, and the new project structure makes a lot more sense for the features I need to add. It will also make it way easier to use in other projects.

Here we go, then…

5 Likes

I definitely know that feel, bro. I’m on my third implementation of an ambitious (more) dynamic hint capability that keeps working encouragingly well to a POINT, then needs major refactoring/redesign to get the last few feet. Intellectually, I understand the power of robust paper design before coding, but psychologically I HAVE TO BE CODING, and things will just work out, yeah? It is amazing how often that is proven untrue, yet makes no impact on my NEXT feature…

Which is not to say that is you. Just unburdening myself a bit. :]

3 Likes

THIS.

Like, I do plan stuff out in comments, but if I’m planning code, then I might as well write the actual code.

Sometimes I’ll write out an algorithm in English in the comments and implement it once I have a clearer approach, but oftentimes plans are more robust when you make them “on-site”, if you know what I mean.

There have been many times when I tried planning stuff on paper first, but once it was time to implement it, the paper design simply wasn’t realistic or efficient, and I might as well have skipped it.

I get the value of planning on paper in teams, but if it’s just lil ol’ me, then I might as well just jump in, otherwise it feels like trying to install a door without being on-site to measure the frame.

3 Likes

So, I’m making faster progress than expected, which is good.

This has also given me time to collect more thoughts on the problem of planning.

My usual workflow is I write up a document that lists the goals of the software, and under each goal I’ll usually brainstorm some ideas for how to approach a solution, or connect it to other solutions.

I’ll usually also sketch out some simple algorithms using nested bullet point lists.

From here, I use commented pseudo-code to sketch out my data structures. If I were working with a team, I’d probably draw out these structures with images, to create more intuitive representations. I might also use commented pseudo-code to lay the foundations of interfaces, methods, basic algorithms, etc.

From here, I start coding the actual stuff, using my comments as a sort of guide.

I know some people will go as far as write out every line on paper before typing it in an actual code page, but I feel like that’s an extraneous step, especially in the world of version control.

The moment you start worrying about actual likes of code, it’s best to start writing it for real, because you’ll catch bugs and implementation errors as they would actually appear, and this is going to influence the rest of your code going forward.

I usually make a note to habitually do refactor passes, normally every four or six methods or so.

However, I have a clear separation between actual code and simple outlines, because past a certain level of detail is where outlines stop being outlines.

So, what went wrong with my previous parkour implementation?

About halfway through implementing the whole outline document, it occurred to me that there were some weird functionality quirks (sometimes bugs) which I would have never been able to predict at the outline stage. Again, this is why it’s important for me to write actual code as soon as I get more detailed than a simple outline.

The bugfixing process for this created a really weird branch of the codebase, but it was essentially an edge case at the time, so I didn’t think about it much.

I then did a major refactor pass. My instincts told me that this edge case should be refactored, but my brain quickly realized that this rabbit hole went wayyyy deeper than expected, so I made a little TODO note to outline a proper large-scale refactor after I implemented one more thing.

Now, some of you will read that and say “Oh no. Refactoring is not something to kick down the road.” and you’re right; it’s not. However, that one more thing was an idea I had literally come up with the day before writing that TODO note, and added to the list of goals because it was an extremely important idea that would really take the parkour system to the next level.

This one more thing also seemed super easy to implement in very little time, so it didn’t feel like I was kicking refactoring down the road at all. In fact, I thought it would be better to see how this last feature would fit in, and maybe influence the upcoming refactoring pass. After that, I had a lot of bughunting scheduled.

I got maybe two-thirds of the way through, and that last feature immediately ripped open every possible issue with the aforementioned “edge case”. It was like pulling on a thread and undoing an entire garment.

This showed me that a major refactor pass was not enough to solve the issue. I sat down for a few hours, and wrote some outlines on a possible solution, but the result kept getting further and further from the original project structure. Once I finally had something that was going to work, it required to redo everything from scratch.

All because of this one last feature.

Again, the delayed refactoring was not the cause of the problem, it was a symptom of a problem I was to discover later. This last feature actually required a full restructuring of the entire program. I would have made this same realization during or after refactoring, because a refactor would not have saved the project.

If this feature had occured to me from the beginning, I could have avoided this. Also, if a few of those early implementation bugs had been more obvious, that would have helped as well.

However, using my brand-new outline, I can proudly say that there are no edge cases, and all features will work smoothly.

If I was any more pressed for time, I might have been tempted to cut that last feature, but it was something small that would have double the possibilities of the system.

Additionally, the new structure for the parkour system makes its use a lot more flexible and intuitive, which means less documentation and an easier learning curve.

So…onward!

3 Likes

Woah!! That went by fast!

Had to take a break to get my blood sugar back up to normal, but I think I’m nearing the 65% complete mark already!!

1 Like

Me: “I gotta change the logic of the stagingLocation PreCondition to account for the new parkour challenges, and not make the player throw themselves off of ledges to get to something that’s really near.”

Me: (starts to behold the scale of the problem)

Me: (Implements a simple parkour pathfinding algorithm that finds safe connections with the lowest possible loss in climb height, but will only offer one auto-climb upward, if necessary.)

Me: “Wow that was way harder than it was supposed to be. Okay, what percentage are we at now?”

Project Outline: 67%; up from 65%

Me: “Hmmmmmm…”

2 Likes

Are you working on hints in adv3? I made some modifications that I’ve been pretty happy with to the hint system… you just have to have a lot of .reveals (or other tags) in your code for the adaptivity to check with…

2 Likes

I’d be interested to hear what you’ve done there. (I actually devour ALL the code discussions, relevant to my work or not. I inevitably pick up more capabilities I never knew existed. Soft vocabulary, for example.) Tangentially this does confound me a bit. On the one hand, I’d like to become a full partner in sharing code. On the other, I am reluctant to air what I hope to be game play surprises to the very small crowd most likely to encounter them.

To the hint topic, .reveals definitely have a role to play in what I’m doing, but two bigger changes I’m playing with are a) location-specific menu functionality and b) dynamic generation. I don’t envision these being generally useful (in some ways they are more limiting). I am doing it to try and serve a very specific narrative purpose. It has been an interesting enough diversion though, that I’ll probably write it up once the game is released. Y’know in a year or so :]

3 Likes

I don’t know, maybe it’s not all that much compared to what you’re going for… I’ll send some code when I get back to my computer some time…

2 Likes

Okay, so after refining the pathfinding system for parkour I have unfortunately realized that allowing for automatic pathfinding creates problems for the player.

So, as proud as I am for the pathfinding thing, I’m just gonna stow that code in the vault for the moment. Parkour will need to have a bit more intent now. The most pathfinding this thing will do is if you have an adjacent platform with something you wanted to enter or board. Pathfinding will search as far as the adjacent connections, and no further.

Again, this forces the player to be a bit more step-by-step and have more intent, but moving in parkour can sometimes have punishments or environmental issues, so it’s better for the player to approach it one step at a time, just in case pathfinding would have done something unexpected.

I didn’t lose a lot of progress, compared to the rest of the project, so that’s good. Pathfinding was actually a relatively small thing. I’ve been working on a lot more facets of the larger system, and fixing one bug made pathfinding “show its true colors”, but as I start tweaking pathfinding, I was like “Hmmm… Maybe I shouldn’t fix this. This seems like more of a problem than a tool…”

1 Like

I don’t know exactly what the implementation nuts and bolts look like here, but it sounds like it might make sense to implement automatic pathfinding only for sequences that the player has explicitly traversed themselves “manually” first.

So if you theoretically have five different paths from point A and point B and the player has only taken path #1, then pathfinding between A and B will always select path #1. If the player has taken path #2 and #5 but none of the other paths, pathfinding will { take the most recent path | take an arbitrary previously-traversed path | take the shortest previously-traversed path | prompt the player about which previously-traversed path they want to take }.

If the paths are extremely dynamic (traversing the path is basically playing Frogger instead of solving a touring knights problem) or something like that then this won’t work, but it’s something worth considering.

Underlying principle being that the first time it’s a puzzle and the second time it’s a pain in the ass, so whenever possible prevent situations where the player has to keep re-solving the same puzzle over and over unless it’s part of your core gameplay loop (like combat in a JRPG or jumping mechanics in a platformer).

3 Likes

Yeah, that’s how the pathfinding was originally implemented. There’s actually an option in the extension settings that lets you choose whether or not implicit actions can use unexplored paths or not.

The problem is more that this extension could be used in an environment with a lot more dangers, like stepping on certain things could cause penalties and stuff, as implemented by whoever is making the game. I could add in a thing where pathfinding avoids danger zones, but then the game designer might want some dangers to be hidden, or to be inspected by the player and have the player decide if they’re dangerous or not, etc.

Additionally, the pathfinding would need to be deeply-entwined with the “can reach” checks, because attempting parkour on something far away results in a reach fail.

So I would need to do a pathfinding eval for every reach check, in case the player was trying to get a distant item, etc.

Again, it was implemented pretty close to this (was maybe two tweaks away), but it had a lot of uncomfortable implications for how reach checks might start working. If someone was just testing for if something was in reach, and didn’t mean to go somewhere, then would the player be able to teleport distant items into inventory? Do I want to bog down the system with a pathfinding eval for every reach check? Do I need to create a caching system to save on computation? Etc etc

The idea I was leaning towards was creating a custom precondition specifically for handling implicit parkour pathfinding, which would save the result for any future reach checks, but trying to figure out how to get these two systems to work together based on context started to explode in scope quite a lot. Like, what I try to auto-parkour to something in another room? Do I need to edit the preconditions of other actions to account for this? Etc etc.

I might recycle the pathfinding code for NPCs, though.

Again, I’m not deleting the whole thing; it’s useful code, but how to prevent exploits, slow-downs, reference loops, etc was starting to get a lil sweaty.

EDIT: Full pathfinding for both players and NPCs will eventually get added, but I might keep it minimal until after SpringThing. For now, version 1.0 is gonna have to require intent until I figure out a system that doesn’t completely explode, and works better in dynamic and dangerous environments. It’s just that figuring out how to handle this is gonna take a lot more time, and I gotta wrap this up and work on the rest of my SpringThing project.

1 Like

Not trying to talk you into anything, but if you only pathfind through “problem” areas via recorded player pathing then you’ll never reveal information about traps (or whatever), and you won’t have to worry about reachability checks unless reachability is non-positional (that is reachability is a function of something other than the endpoints and the actor traversing them).

Basically if your “main” pathfinding is Dijkstra or something, then you’re collapsing all of the “problem” parts into a single node, and then you have a lookup table of checks for the single node, if that makes sense.

Like I said, not trying to talk you into anything. But this sort of thing is a pretty common pathfinding problem in e.g. roguelikes and metroidvanias.

2 Likes