Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make colliders fully transformable #500

Merged
merged 208 commits into from
Jan 30, 2025
Merged

Conversation

freezy
Copy link
Owner

@freezy freezy commented Jan 6, 2025

This PR introduces fully transformable colliders to the physics engine.

The key to transforming objects lies in how their transformations are stored. In VPX, due to its restrictions, transformations are generally stored as separate values. In Unity (and game engines in general), transformations are stored as matrices. Instead of converting between the transformations that the physics engine understands and the transformation matrix — and thereby restricting the editor's transformation tools to those limitations — we decided to rely exclusively on the transformation matrix. This approach allows complete freedom in transforming objects.

It also enables VPE to support parenting objects to others, allowing transformations of parent objects without disrupting the physics simulation.

So, how can the VPX physics code handle arbitrary transformations? The solution is a simple trick: rather than transforming the colliders, we transform the balls: To resolve a collision between a ball and a collider that is transformed in a non-supported way, we temporarily move the ball into the collider's local space, resolve the collision, and then return the ball to the playfield space.

Collider Data

Our colliders don't and won't know about our transformation matrices, i.e. the data used to calculate the simulation is still the same as in VPX. So, we need to get this data from the transformation matrices into the colliders. The chosen approach is the following:

  • Each collider gets a Transform(float4x4) method that transforms the collider in the playfield space. Transforming means updating the collider's position, rotation, and scale, whatever is supported. That's the data the VPX physics code uses.
  • This comes with restrictions as mentioned above. For example, a Line collider, by definition, is aligned parallel and orthogonally to the playfield. In this case we'd transform its two points and retrieve their new xy position. This works for translate and scale, but rotating around anything else than the z-axis would still result in a rectangle parallel and orthogonal to the playfield, which wouldn't be desired.
  • But more on that problem later. What's important is that for transformations supported by the VPX physics code, we have a method that allows to transform each collider, based on a matrix.
  • Additionally, colliders are always instantiated without any transformation. That means by default, they are placed at the origin and have no rotation or scale.
  • Finally, each collider gets a TransformAABBs(float4x4) method that only transforms
    the collider's axis-aligned bounding boxes, and that works for all transformations.

So, with all of the above, we do the following when the game starts:

  1. We retrieve the overall world-to-local matrix of an item.
  2. Using the playfield's world-to-local matrix, we calculate the local-to-playfield matrix
    of the item. We call it LocalToPlayfieldMatrixInVpx.
  3. When adding new colliders, we check which kind of transformation the VPX physics code supports for the type of collider and compare it to the transformation of LocalToPlayfieldMatrixInVpx matrix.
    • If all transformations are supported, we simply transform the collider with the item's transformation matrix.
    • If not, we check whether this collider might be replaceable by another type of collider that supports the transformation. For example, a line collider can be replaced by two triangle colliders, which then are 100% transformable.
    • If neither of the above is possible, we fall back to ball transformation trick, which is to transform the ball during collision resolution. Note that the AABBs of the object still need to be transformed, so the broad phase can correctly sort out the items that are out of range (using TransformAABBs(float4x4)). Also note for kinematic colliders that aren't fully transformable, we'll fall back to this approach as well, because we don't know how the item will be transformed during runtime.

This relatively simple approach gives us an incredible amount of flexibility. We now have a true 3D physics engine that can handle any kind of transformation, including parenting, while still being able to rely on the heuristics of the VPX physics code that has been tuned over the years.

Code Changes

Let's dive into the code. We'll need three more methods for each collider:

  1. IsTransformable(float4x4): This method checks whether the collider can be transformed with the given matrix, i.e. if the physics code supports the transformation natively.
  2. Transform(float4x4): This method transforms the collider in VPX space.
  3. TransformAABBs(float4x4): This method transforms the collider's axis-aligned bounding boxes.

In our ColliderReference class, we'll add a float4x4 to each Add() method. This method goes through the three use cases described above.

  • Using IsTransformable(float4x4), it'll determine whether the collider can be transformed natively and uses Transform(float4x4) if that's the case.
  • Otherwise, it'll check whether the collider can be replaced by another collider, converts it and transforms the converted collider(s) instead.
  • Otherwise, it only transforms its AABBs and marks the collider as non-transformable by setting the IsTransformed of the collider to false. It also stores the transformation matrix so it can be used during runtime for the ball transformation trick.

Note

For already fully transformable items like primitives, the above checks are not necessary, and we transform the collider with its AABBs directly without checking the actual transformation.

To summarize:

  • We remove transformation data from the components and retrieve it from the transformation matrices.
  • Colliders are instantiated without transformation and only adding it to the collection at runtime will transform or save them as-is, depending on their transformability.
  • The transformation overrides in the Unity editor are completely removed

Other Changes

  • All the mesh generators now generate meshes that correspond to meters at scale 1.
  • Fixed a regression in the bumper mesh generation
  • Meshes, materials and prefabs for the following items have been moved to the asset library: Bumper, drop targets, gates, hit targets, kickers, spinner.
  • Added documentation for how to texture assets in the library.
  • Upgraded docfx from v2.71.0 to v2.77.0.
  • Fixed a few bugs in the asset library
  • Removed mesh variation dropdown from drop targets, hit targets, kickers
  • Removed table height parameter
  • Made kinematic "is movable" toggle global for all collider items.
  • Fixed ray projection of ball roller when playfield is transformed
  • Moved physics movement code into a separate class.
  • Added a new component SpinnerLeverAnimation for new spinner prefab.

TODO

  • Add illustrations for 3D space doc page.
  • Make collider gizmos behave like before.
  • Revisit kickers (check if type is still necessary, fix gizmo, ..)
  • Check all public override void UpdateTransforms(), there should only be minimal stuff in there.
  • Remove ITargetData? It's pretty empty now...
  • Ditch isLocked, also go through isEnabled and isVisible.
  • Provide more collision info on hit events.
  • Remove center float2.zero from data components.
  • Don't trigger updated kinematics when flipper rotates.

@freezy freezy self-assigned this Jan 6, 2025
freezy added 29 commits January 6, 2025 13:48
@freezy freezy force-pushed the feature/transformable-colliders branch from 7e67bf4 to f1d17a2 Compare January 6, 2025 12:54
@freezy freezy merged commit a8c0fcd into master Jan 30, 2025
12 of 16 checks passed
@freezy freezy deleted the feature/transformable-colliders branch January 30, 2025 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants