## 003 Can Touch This

March 16, 2024 8:41 am | by zBuLe | Posted in Chronicle Destiny, DevLog

It’s been a few months, but I have finally uploaded the third alpha build of Chronicles Destiny. This devlog summarizes the second and third alpha builds, both dealing with implementing a 3D collision system. Previously, the focus was on drawing objects in 3D space to maintain an isometric look. While objects can be positioned and rotated freely, collision detection remained confined to 2D. GameMaker offers a robust built-in 2D collision system. The plan was to extend the built in system for 3d use. An initial XY plane check is done with GameMaker’s collision functions. A follow up check comparing Z related variable is done afterwards. This will determine if the initial XY check is valid or not. This approach would allow movement similar to classic 3D Zelda games like Ocarina of Time and Majora’s Mask.

Well, that was the plan. After viewing DragoniteSpam’s series on native GML 3D Collision, I decided to implement at least some of that solution. Since it is implemented in GML, it works in all supported platform, specifically HTML5. This system leverages GameMaker’s relatively new struct syntax to organize related data and functions.

– This is the core struct that enables anything 3D. It consists of the`Vector3(x, y, z)`

`x`

,`y`

, and`z`

variables to store a position or a direction (normal) in 3D space. It also has many functions that are crucial, ranging from simple arithmetic like`add(val)`

or`multiply(val)`

to more complex ones like`dot(val)`

and`cross(val)`

.– This struct stores the collision`Collider(shape)`

`shape`

to be used. It acts as an interface between the object and the collision system, passing the relevant information to the relevant shapes.– This struct simply stores a`Point(position)`

`Vector3(x,y,z)`

for its`position`

.– This is like a thick point, very simple and fast to calculate. If the distance between its`Sphere(position, radius)`

`position`

and the other shape is less than the`radius`

, then a collision occurs.– Axis Aligned Bounding Box. This defines a rectangular volume that is always parallel to the axes. It stores its center and half the length of each side. However, an AABB can also be defined as the volume between two points. This struct uses`AABB(point_min, point_max, [min_max])`

`min_max`

as an optional argument. If not provided, it defaults to`true`

and calculates the`position`

and`half-extents`

from two points. If`false`

is provided as the third argument, it just assigns the first two arguments for the`position`

and`half-extents`

.– This simply represents a line segment between the`Line(start, finish)`

`start`

and`finish`

points.– This is similar to a line, but it has no endpoint. It starts at the`Ray(origin, direction)`

`origin`

, following a`direction`

, and extends to infinity. It uses a helper struct to store information about the collision.– This is a helper struct used by rays to store information about the collision between the ray and another shape. This information includes the distance between the ray’s`Ray_Hit_Info()`

`origin`

and where it collided on the shape, and the point where the collision occurred.– Oriented Bounding Box. This is similar to an AABB but can be rotated. In addition to the`OBB(position, size, orientation)`

`position`

and half the`size`

of the sides, it also stores the`orientation`

in a 3×3 matrix.– A thick line, commonly used for player characters, so I implemented it.`Capsule(start, finish, radius)`

This is everything so far. There are just a few shapes I haven’t implemented yet: triangles, meshes, and planes. Additionally, there’s no hierarchy system in place, like octree or spatial hash. However, even with this partial implementation, basic movement is possible. All collisions now use the 3D system, replacing the built-in 2D system. Since there’s no hierarchy yet, a jimmy rigged solution is in place. The `Wall`

object creates an AABB collider. It calculates its position and size based on its built-in variables, including `z`

and `image_z_scale`

. Then, it adds itself to a global array. The `Player`

object iterates against the global array to see if there’s a collision. For the various test objects, each generates a wireframe based on its properties and checks if it’s colliding with the `Player`

object. If they collide, they turn red; otherwise, they stay blue. The ray test object also generates a point wireframe based on where it collided with the `Player`

And that is all for now. Next, I’ll focus on implementing a collision hierarchy. I also plan to add an input manager. A struct that the `Player`

or other objects can poll instead of directly polling the hardware. Additionally, I’ll be working on animations and player actions. I hope to start on the dialogue system afterward. I aim to share the next update within a month, give or take a month or so.

Thanks for your time.