Overview


A number of people have been asking about how I made the orbiting mechanics in Homeworld. I think it is an interesting programming problem, with many possible solutions, so I wanted to share with everyone the thought process I went through and how my ideas changed while implementing the mechanic which helped define my game. To help fully understand the mechanic, feel free to check out my game here!

Step 1 – Squares

Initially, my idea for the game was to have a square pixel planet, which grows slowly outwards in four directions, creating squares of a constant size for the player to traverse. The idea was that this should be simpler to implement, given that the player should only need to face 4 directions. As well as this, I thought it would give me more control over the shape that the planet grows, as I could restrict which pixels could grow out from the planet by how many surrounding pixels were full. For example, I could prevent a pixel from being allowed to grow unless it had 3 adjacent pixels (including diagonally adjacent pixels). This prevents long skinny tendrils forming out from the planet.

My initial movement system was extremely simple. Assuming the player is moving left, if they collide with something, rotate 90 degrees right (and redo the movement from the original position). This ensures the player will go around rather than through the planet. If there is nothing below the player, rotate 90 degrees left.  This ensures the player won’t go more than a set distance from the planet. While simple, this approach simply didn’t work, and was inelegant. Back to the drawing board!

Step 2 – Hooks

My next idea was to implement a system using “hooks”, points on the surface that could act as anchors for the player. These anchors could follow the shape of the surface, and the player’s position and direction could be found by extrapolating between the two hooks. The idea was to have something working as in the above gif, but again, I couldn’t get it working quickly, and because of the time constraints of the competition, I decided to move on to a simpler system.

I did come back to this idea after the competition (to make the above gif). This time, I managed to get it working. As you can see above, it does do the job well, and it can handle both curved edges and corners really smoothly. In order to achieve this, I used a simple script (click here) to allow each hook to follow the surface by changing their direction up until they will no longer be in a wall, then back down until they are. This ensures the will always be on the edge, but it does require them to start on an edge (or go into an infinite loop looking for one), a problem which my simpler final algorithm did not have.

Step 3 – Cheating

Okay, so by this point, I’d already sunk a couple of hours into prototyping a few ways of doing the orbiting: it was really cutting into the time for the rest of the work that needed to be done. Because of this, I went for a really simple way of implementing it, using the new restriction that only circles were to be used. Contrary to my initial thoughts, circles were significantly easier to work around, given their consistent geometry. (with squares you have to worry about corners). My idea was to give the player a circle to rotate around, with a defined centre point and radius. If they collided with a new circle, simply set the player’s circle to that circle plus a small offset to the radius, placing the player above the surface. In the diagram above, the player is moving left, hits the circle, and the centre point and radius changes. As my flatmate always says, if it’s stupid, but it works, it’s not stupid. Here’s the script I used (the relevant parts).

Step 4 – Cleanup


With the player now orbiting the planet somewhat nicely, there was still a bit of cleanup to do. Some was simple stuff like rotating the player to always face away from the planet. It was also necessary to give the player a slightly wider hitbox than the visual bounds to allow for the player to change which circle to orbit before actually colliding with it, maintaining the visual effect of the player hovering slightly over the planet’s surface. This also reduced the jumpiness when the player changed circles.

Finally, the movement of the player had to be cleaned up. Previously, the player was moving directly to the side and then correcting it’s position (due to the constant radius) at each step. The solution to this was to convert the horizontal distance I wanted the player to cover into an angular distance relative to the player’s current radius. The angle (in degrees) is equal to (360*d)/(2*pi*r), where d is the distance we want to travel, and r is the radius of the player’s current circle. We can then set the player’s position using vectors. To do this, we get a vector pointing at the right angle, with the radius of the player’s circle and add this to the centre point of the player’s circle. This really helped smooth out the motion of the player.

Wrapup


Hopefully you have found this exploration of my thought process interesting. I think it really shows how an idea can change and evolve over time, and how sometimes a simple, hacky way of doing things can be the right thing to do. This jam was both extremely stressful and a lot of fun, and I learnt a great deal from it. I would really be interested in feedback of what people thought of this.
Did you enjoy this kind of post?
What did you think of my thought process?
How would you have approached this differently?
And what interesting problems/challenges have you come across when implementing features in your games?

 


One Response to “Real Planets Have Curves – Making Homeworld’s Orbiting”

  1. Drury says:

    For my game, the very first thing I had to figure out was how to have a train following a track. Found all kinds of splines and nodes and god knows what on the internet, but in the end settled with familiar things, colliders.

    It went fairly smoothly. I had edge colliders for straight pieces of track and circle colliders for curves. The train’s bogies had two raycasts checking the space underneath the bogie and moving the whole bogie to the point of impact with a possible collider every physics update. Stacking straight rails to curves was fairly accurate with the right numbers and there was absolutely no glitching even when cornering at ridiculous speeds..

    The circle collider method was fairly accurate but proved unusable with my drifting mechanics, as raycasts didn’t work reliably inside other colliders (need two overlapping circles for every curve since there are two interactable rails next to each other). Thus I opted for edge colliders which I tediously shaped into perfect circles following existing circle collider outlines. The end result is much neater than circle colliders, albeit a bit less reliable and derailing is a fairly easily reproducible glitch.

    If I were to use this method on rectangular colliders, I reckon I could just aim the raycasts at a slight angle to check for walls past corners. It probably wouldn’t be that neat for extremely convex shapes, but rectangles definitely so.

    I think neither solution gets close to the optimal approach, but I still find it interesting how you never thought of using raycasts. It was the first and most intuitive choice for me. That’s just the way I do it, all else fails, fire lasers at the problem.

Leave a Reply

You must be logged in to post a comment.

[cache: storing page]