I recently downloaded Godot, a game engine and game development environment. I never did much with games, so I figured I might mess about. So far I’ve been playing around with the 2D stuff, something that could be a platformer-style game.
Godot does a decent job of making concepts clear, though as with any new effort, searching is your friend. Most hurdles have been in figuring out the math to use for custom physics, and even there the engine provides a lot of the basics.
One of the hardest challenges in any program is keeping organized and picking up the right way to implement things. There are places I know I should use custom signals, but I don’t quite understand exactly how to wire them up the right way, so I’m relying on direct calls. My tile map places overlapping tiles. Or places where I know I should be processing velocity changes in the frame process function, but I’m modifying the velocity directly, which means I have to make sure it doesn’t get eaten by a collision.
Eaten by a collision? If you run into a wall, that wall eats your velocity in the direction it opposes. Godot provides collision checking which you can use in custom physics, but it’s up to you to decide how to handle collisions because you might want to bounce, or some collisions might break blocks or teleport you or whatever you want them to do. In my case, the collisions should eat the velocity:
func collide_normal(vel, nnorm): var out_vel = Vector2(vel.x, vel.y) var dot_product = vel.x * nnorm.x + vel.y * nnorm.y if sign(vel.x) != sign(nnorm.x): out_vel.x -= dot_product * nnorm.x if sign(vel.y) != sign(nnorm.y): out_vel.y -= dot_product * nnorm.y return out_vel
This function takes a velocity (with an X component and a Y component for how much the object moves frame-to-frame, which together also tells you what direction, like the slope of a line) and a normal vector. A normal vector also has an X and a Y, but if you remember the unit circle from trigonometry, it’s normalized so that it has a length of one, and it points away from the face of an object.
Given those two components, the function negates the velocity that is pointed against the given normal vector. In my case it also has two conditional checks that are used in case either of the components happen to agree in sign (same as direction). Without those, the function would just as happily negate the part of a velocity that points the same way as the normal vector.
But that’s the kind of thing you have to do if you’re poking around and not taking time to do it properly inside the frame process function. Otherwise the bouncy spring you added will sometimes behave like a wall, if the signal of your collision with it happens to come right before the frame process checks if you collided with anything and decides to cancel the bounce.
One of the other things I’m considering is experimenting with a “ghost” player. Godot has its own built-in physics, which is usually applied to inanimate objects, but not to controlled objects and, depending, on animate enemies. But it looks like there are times that it might be handy to ride on the built-in physics, so I believe I can create an invisible player surrogate that will respond to the built-in physics, and for limited uses that might save some code and allow for cool things with limited effort.
I haven’t tried to do any fancy graphics yet (e.g., animations and particles), nor tried anything in 3D, but it’s still fun to mess around with my bouncy springs and gravity fields.