Welcome to the April 2023 update for openage
This month we had progress in several subsystems of the engine, most of which we built in the previous months: the event system, the renderer, and the gamestate. These systems already worked together, but previously consisted more of hardcoded "duct tape" code to make it all work. In the past weeks, we replaced many of these code paths with something that is closer to the final architecture targeted by the engine.
Spawning Entities Reloaded
We already showed off a spawn event last month which created a Gaben entity on mouse click.
Previously, this just placed Gaben at a hardcoded position at the origin point of the 3D scene
With the new changes from this month, Gaben is able to spawn where the player clicks on the screen.
To achive this mouse spawning feature, we rewrote parts of the engine's old coordinate system and added a raycasting algorithm that can point at objects in the 3D scene.
The coordinate system is necessary to convert between the different coordinate types used by the engine's subsystems. For example, the input system mainly receives 2D pixel coordinates from the window management that represent the position of the mouse inside the window. The game world on the other hand uses 3D coordinates for positions of objects in the game world. A different kind of 3D coordinates are also used in the renderer to draw animations and terrain.
To place Gaben at the correct position inside the 3D game world, we have to convert the 2D pixel coordinates from the input system to a 3D coordinate in the scene. We achieve this with a very straightforward technique called "raycasting". Basically, we cast a ray from the position of the camera using its direction vector as the direction of the ray. Then, we check for a point where this ray intersects with an object in the 3D scene, e.g. the terrain mesh. The resulting intersection point is placement position we are looking for (as 3D scene coordinates). Since the 3D scene coordinates use a different axis orientation than 3D game world coordinates, we have to make one final conversion to get the correct values for the gamestate.
Spawning entities at the mouse position is pretty cool by itself, but we are not done yet. With the power of the coordinate system, we can also make objects move!
To effectively explain how objects in the gamestate move, you have to understand curves - the
data containers that openage uses to store its runtime data. They are described in more detail in
an older blogpost, but here's the gist of it: Instead of calculating the current position of
an object every frame (like many other engines do), curves store only changes to the position
as keyframes, containing the new position and a timestamp. Basically, the keyframes represent
waypoints of the objects where each waypoint also is assigned a timestamp that signifies when
the object reached the waypoint. To get the position at a specific point in time
t, the curve
interpolate between the two keyframes before and after
t. In case of positions, this means
that it calculates the position between the two waypoints defined by keyframes.
Curves may sound complicated and internally they definitely are. However, they also make internal gamestate calculations and testing much easier because we can just insert a bunch of keyframes and let the curve figure out what the position at the current simulation time is (curves also allow us to easily go backwards in time, but that is a story for another month). In the current implementation, we add 4 additional waypoints to every spawned entity so that they follow a "square" path after creation.
Spawning and moving entities is nice, but there is obviously more to do to make this feel more like an actual game. There are actually several options for what to do next. Adding more input events that do other stuff than spawning would be nice, e.g. movement or selection. On the other hand, we can also improve the internal gamestate by adding more event types that affect the simulation itself. Or maybe we do both, depending on how well each of them goes.
Any more questions? Let us know and discuss those ideas by visiting our subreddit /r/openage!
As always, if you want to reach us directly in the dev chatroom: