Nov 20, 2020

Code Concepts: "Gyrusscopic Motion" (I trademarked that, yo!)

I'm sure I'm not the first person to come up with this concept, but so many people don't think about game worlds in this way, so I wanted to write about it.

Circular motion is of course easily defined by trig functions, like cos(), sin(), acos(), and asin(). For those using Game Maker, you also have the derivative functions lengthdir_x() and lengthdir_y(). However, there is no reason circular motion needs to be expressly circular. It can be entirely one-dimensional, or 1.5D if you will. The circular motion should be a projection of linear motion.

Consider a person standing on a planetoid. The farther you pull back from the planet, the more the angle of the person appears to conform to the planet's surface. If that person on the planetoid were to walk straight forward the entire circumference of the planetoid, an outsider in space would perceive that motion as circular, even though to the person actually walking it is completely linear.

When you program your game with "circular motion", you might perceive the player as an external observer and your instinct will be to code the game as such. The player is not an observer, though. That little icon of a person walking around a planet is the player. To that person, the world is flat and your code should reflect that. That building protruding from the planet isn't 8 degrees away from the player, it is straight ahead.

If the player is going to move along x and y, then you would need to draw at artificial coordinates. Alternatively, move the player along artificial coordinates and update x and y to supplement the on-screen coordinates. In either case, the player's position needs to be defined relative to the surface of the planetoid. You will need to define the circumference of each planet and its radius. Don't force the computer to do the math for you, just use a calculator or Google and then save the values in variables; but just in case you don't know the formulae:

circumference = 2 * pi * radius
radius = circumference / pi / 2

If your planetoids will be barren, flat wastelands, then you could define them by just their radius. If you want any sort of obstacles, interactive elements, or terrain, then you should define your planetoids by their circumference (and then find the radius using a calculator)

 The circumference is what defines an instance's position along the surface of the planet. To an outside observer, the player's position is

xAngled = 180 - x / circumference * 360

Subtracting the observed coordinate from 180 is entirely optional, but doing so allows moving right, which traditionally increases x, to decrease the angle without breaking tradition. Notice we are only concerned with the x-coordinate relative to the circumference.

The player's y-coordinate relative to the planetoid is the distance from the surface, thus the y-coordinate relative to the planetoid's center is 

yAngled = y + radius

 The angle of the sprite is just its observed x-coordinate. If using Game Maker and your sprites by default are standing upright, subtract 90 from image_angle, otherwise make all your sprites rotated 90 degrees. 

image_angle = xAngled - 90 ;if using Game Maker

 To render the sprite properly relative to the planet as observed by the outsider, we now need basic trig to find the screen coordinates.

xScreen = xPlanet + cos(xAngled) * yAngled
yScreen = yPlanet + sin(xAngled) * yAngled

Or if you want to use Game Maker's in-house functions:

xScreen = xPlanet + lengthdir_x(yAngled, xAngled)
yScreen = yPlanet + lengthdir_y(yAngled, xAngled)

 If trying to land on the planet, you would want to use trig to find xAngled and then find x from that.

xAngled = point_direction(xPlanet, yPlanet, xScreen, yScreen)
x = xAngled * circumference / 360

And don't forget to multiply yAngled in those calculations by your zoom factor if allowing the player to zoom in and out.


If we negate xAngled in our calculations for xScreen and yScreen, we can move the starting point from the top of the circle down to the bottom of the circle. Then by subtracting xAngled from 180 in image_angle, we can flip the sprite upright.

image_angle = 180 - xAngled - 90
xScreen = xPlanet + cos(-xAngled) * yAngled
yscreen = yPlanet + cos(-xAngled) * yAngled

What we end up with is rudimentary Gyruss movement!

 

That's all there is to it. It was a pretty simple concept that came to mind and took only a couple minutes to implement with very few quirks to speak of. Trig is still involved, but not to the extent many young programmers expect. I strongly feel programming these kind of gimmicky games is a lot simpler with this approach in mind. There is some pixel discrepancy between the north and south poles that rears its ugly head when moving around the outside of the planetoid, but that could probably be worked out with a little rounding or math magic, but for a cheap Gyruss knockoff, the pixel discrepancy could be safely ignored.

No comments:

Post a Comment

©TheouAegis Productions™. Powered by Blogger.