8 minute read

The Story thus far

For those who haven’t seen the project page for Frogrunner, FrogRunner is the codename of me and my team’s personal project game made in Godot. This is a platforming game, where you run and jump through levels, playing as a frog in a sci-fi mech suit! What makes this different from other platforming games is that the main mechanic revolves around you using your frog’s tongue to grapple and swing around, building momentum that allows you to launch yourself through space!

However, our first foray into 3D games required a lot of research, and getting our pendulum-based physics took far longer than we would have expected. Our first commit for this project dates back to Sep. 26th, 2025, and since then, we’ve evolved the mechanics of our grappling game numerous times.

One misconception I find a lot of people outside of the programming/game-development world tend to have is that these fields don’t share that ‘iterative’ trait you find in creative works. When working on a painting, or writing a novel, or editing a movie, you must iterate over the piece until it’s as close to what you wanted as possible. But some people seem to think that doesn’t apply to fields as involved in logic and math as game development or programming is.

I wanted to make a post that could show otherwise, and show my personal journey with how I’ve gone about programming this! Each ‘snapshot’ will show a video of the movement, as well as comments on how it feels and improvements, and some will even have pseudocode showing the logic. Without further ado, let’s get started with the snapshots.

Current Build

Commit date: Jan. 28th, 2026

As a refresher, this is the current state of our game, and honestly, I’m very happy. The controls feel tight, the movement is fluid, and building up momentum feels very natural. There are even ‘hidden’ techniques like being able to jump out of your swing and launching yourself more vertically. Overall, the different platforming systems of swinging, launching, running, jumping, and reeling in/out all work together really well. Feel free to try it out by downloading here.

Now, let’s go back to one of our very first project commits.

Spring Movement

Commit date: Sep. 29th, 2025

This is one of the earliest project commits I could find with a rope/tongue implemented. As you can see, there is no pendulum movement, and the rope acts more like a simple spring.

There’s also no limit to how far horizontally you can move yourself around. It’s an overall very awkward and unintuitive experience, but it was sufficient enough as an exercise in figuring out how we could apply vectors to our velocity and position!

The spring mechanics were implemented using this tutorial, and the main logic for the spring is shown below:

func handle_grapple(delta: float):
  displacement = distance_to_target - spring_rest_length   # how much spring is being stretched
  
  force = Vector3.ZERO
  if displacement > 0:
    spring_force_magnitude = spring_stiffness * displacement
    spring_force = direction_to_target * spring_force_magnitude
    velocity_dot_product = player.velocity.dot(direction_to_target)
    force = spring_force + (-damping * velocity_dot * target_dir)
  
  player.velocity += force * delta

Hookshot Movement and Auto-Reeling

Commit date: Oct. 18th, 2025

As you can see, by Month 2, we had moved on from the spring-based movement and used our new understanding of vectors in the Godot game engine to make our player move more like Link when using his Hookshot tool in The Legend of Zelda franchise!

What I mean is, the rope would automatically start reeling you towards your destination the moment you shoot it. While the feel was still very awkward, it was a definite improvement over our spring movement and felt much closer to our original vision.

The main code for this became a lot simpler, shown below:

func handle_grapple(target : Vector3) -> void: 
  velocity = global_position.direction_to(target) * grapple_speed

Early Pendulum Movement & Manual Reeling

Commit date: Oct. 20th, 2025

Surprisingly enough, upon digging through the old commits for this project, we started adding in the pendulum movements only two days later! I remember having to teach myself a lot of pendulum physics, and brush up on general vector-math and trigonometry, so seeing that I was able to act on those refreshers so quickly was surprising!

Now, to be completely honest, the initial implementation of pendulum physics was done with ChatGPT, but I made sure to take the time to fully understand and comment every line it gave me. I was even able to later improve on the original responses I got from the AI, both in terms of performance and readability, and am much more confident in my game-dev skills as a result.

Here’s some of the most important code for pendulum movement:

func reel_move(target: Vector3) -> void: 
  velocity = player.position.direction_to(target) * (speed + grapple_speed)

func pendulum_move(delta: float) -> void:
  n = (bob_position - pivot_point).normalized() # 3d vector, direction from pivot to bob
  g = Vector3(0, gravity, 0) # 3d gravity vector

  a_tan = g - n * g.dot(n) # tangential acceleration, removes parallel forces that move us closer/further to the rope

  bob_velocity += a_tan * delta # calculate velocity
  bob_velocity *= damping # apply damping
  bob_velocity -= n * bob_velocity.dot(n) # again remove any forces that move us closer/further to the rope

  # apply corrected bob_velocity to character's velocity
  bob_position += bob_velocity * delta
  n = (bob_position - pivot_point).normalized()
  bob_position = pivot_point + n * rope_arm_length
  velocity = (bob_position - player.position) / delta

As you can see, there are still two distinct physics being applied based on whether you’re reeling towards the target or not. Yes, by this point, reeling towards your target was done manually by left-clicking.

By this point, the game was feeling much better, but the fact that our reeling in was instantly negating the pendulum physics felt off, and there were clearly still bugs. You can see at the end of the video that the rope was changing size based on how fast we were moving, not ideal.

Evolved Pendulum Movement

Commit date: Nov. 19th, 2025

About a month later, we had finally merged the reeling and pendulum physics and had fixed bugs correlated to rope size. The movement was finally feeling buttery smooth, fluid, dynamic. Everything was flowing and working together! We adapted our reeling as follows:

func reel_move(target: Vector3, reeling_in_or_out: bool) -> void: 
  direction = reeling_in_or_out * player.position.direction_to(target)
  velocity = lerp(velocity, direction * speed, reeling_acc)
  arm_length = get_distance_to_target()

You can see in the video an early ‘echo-trail’ effect. There were also still some bugs with reeling in and out while in pendulum-motion. Still, however, the movement had drastically improved, and the whole game felt much better.

Current Movement and Future Plans

Commit Date: Jan. 28th, 2026

Now, all the earlier bugs have been fixed, the controls are even comfier, and we’ve added mechanics like jumping out of your pendulum mid-swing, and more! While I’m very happy with current progress, there’s still a lot to work on, and many questions and game-design paradigms to answer, such as:

  • Handling rope collisions
    • What do we do when we’re swinging, and an object comes into collision with our rope? Should we destroy/retract the rope?
    • If we’re too strict, then the movement could suffer greatly, and being able to do full circles around objects could be impossible
    • If we’re not strict enough, then game-breaking glitches could occur, and you’ll be able to grapple through walls
  • ‘Stilts movement’
    • Because of how we’ve coded the physics, the rope has a fixed-length that is only changed when reeling in or out. However, if we launch our rope out at an odd angle (especially when we’re right above our target), that fixed-length suddenly turns our rope into a stilt, and movement halts! You can see this in the video a few times.
  • ‘Hard’ rope vs ‘soft’ rope
    • Should we switch from a rope with a fixed length to a more ‘fluid’ and flexible rope? What’s the right approach?

Our current plan is to actually go back and borrow concepts from our very first rope! We think adding in some of the original springiness could fix lots of the above issues, acting both as a solution to the stilt-like movement and as a good balance between a hard and soft rope.

Final Thoughts

Our first commit for this project dates back to Sep. 26th, 2025, and we’ve been working on this on-and-off ever since then. This is by far the most time I’ve ever spent on a personal project, and for our first time trying to make a 3D game, I’m very satisfied so far!

Every other project, whether for school or work, has always had strict deadlines or requirements. There was never as much time to make the game or code that I wanted, or I lacked the experience. After graduating from college, I felt a lot of doubt and insecurity about my ability to code or direct a project. It was terrifying, I was basically facing the reality that maybe the last few years of school, the months of sacrificing sleep and mental-wellbeing, and the several thousand dollars worth of my own hard-earned money, were all spent on a major I wasn’t good at, or maybe didn’t want to be good at anymore.

This project was the exact eye-opener I needed after graduating. I found myself voluntarily staying up late working on it, researching game mechanics and physics, even relearning Blender! I wasn’t just building a game; I found myself building systems and procedures for creating levels, modifying physics, changing and viewing debugging variables, and more! The fact that I’ve been able to do it with friends has undoubtedly been the best part.

I’m very proud of what’s been accomplished so far, and I still hold true to eventually releasing this as a demo on Steam at some point! Until the next Antholog…

“Work hard, study well, and eat and sleep plenty! That’s the Turtle Hermit way to learn!”
Master Roshi