Difference between revisions of "W4 Collision System"

From Ciliz|W4
Line 94: Line 94:
  
 
== The Collider class ==
 
== The Collider class ==
This class implements control of collider interactions
+
This class implements the control of collider interactions.
 
=== Bounding Volume ===
 
=== Bounding Volume ===
 +
The collider cannot be created without a given volume, but you can change the collider's volume using the method:
 +
<syntaxhighlight lang="c++">
 +
void setVolume(cref<BoundingVolume>);
 +
</syntaxhighlight>
 +
=== Local Transform ===
 +
Method signature:
 +
<syntaxhighlight lang="c++">
 +
void setLocalTransform(math::Transform::cref);
 +
math::Transform::cref  getLocalTransform() const;
  
=== Local Transform ===
+
void setLocalTranslation(math::vec3::cref);
 +
math::vec3::cref getLocalTranslation() const;
 +
 
 +
void setLocalRotation(math::Rotator::cref);
 +
math::Rotator::cref getLocalRotation() const;
  
 +
void setLocalScale(math::vec3::cref);
 +
math::vec3::cref getLocalScale() const;
 +
</syntaxhighlight>
 +
Features:
 +
* BoundingVolume has its own local transform relative to the parent node (its interface is identical to the Node transform management interface).
 +
* The Collider class proxies the interface to the BoundingVolume.
 +
* Changes to the node and/or collider transform are calculated at the moment of interaction.
 
=== Intersect ===
 
=== Intersect ===
 +
Below is the part of the Collider class interface that is responsible for intersections:
 +
<syntaxhighlight lang="c++">
 +
using IntersectCallback = std::function<void(const CollisionInfo&)>;
 +
 +
void setIntersecting(bool flag = true);
 +
bool isIntersecting() const;
 +
 +
void setIntersectCallback(const IntersectCallback&);
 +
void resetIntersectCallback();
 +
</syntaxhighlight>
 +
Note. By default, the collider does not take part in intersections.
  
 +
How it works:
 +
* The intersection is calculated in onUpdate() (see [[IGame class]] description) every frame.
 +
* For all crossed colliders, the corresponding IntersectCallback will be called (if set).
 +
* There can be only one IntersectCallback per collider.
 +
* When setting IntersectCallback, setIntersecting() is automatically called on the collider.
 
=== Screencast ===
 
=== Screencast ===
 
Reaction to TouchEvent
 
Reaction to TouchEvent
 
=== Raycast ===
 
=== Raycast ===

Revision as of 14:50, 29 July 2020

Scope

The collision system provides the handling of intersections between objects. For one object, you can set several different volumes (bounding boxes, spheres) at once and subscribe to intersections.

The W4 Engine implements the following types of interactions with colliders:

  • Intersect - intersection of two colliders.
  • Raycast - collider and ray intersection.
  • Screencast - intersection of the collider and the ray emitted from the given screen coordinates.

The following examples of the working code of the collision system can be found in the W4 Engine:

  • apps/internal/gist-colliding
  • apps/internal/test-screencast-blocking
  • apps/samples/gist-raycast

Let's take a closer look at the Collision system. Consider the main elements of the Collision system:

  • BoundingVolume - interface. This is a visitor whose descendants implement methods for calculating intersections. Also BoundingVolume contains a data about local transformation.
  • CollisionInfo - structure containing an intersection data. The data depends on the type of interaction and the types of interacting volumes.
  • Collider - class containing BoundingVolume and callback management mechanisms.
  • ColliderEventDispatcher - utility static class containing arrays of colliders, distributed by type of interaction. This class also contains general onUpdate event handling methods for calculating Intersect and onTouch (Screencast calculation).
  • Node (see W4_Coordinate_system_and_Node_structure) contains the collider management interface.

Collider management

Any node has access to the collider management interface, which allows it to add, remove, and find colliders by name.

The number of colliders is not limited.

Note. Colliders must have unique names. When adding a collider with the same name as an existing one, a warning will be displayed in the console, and the existing collider will be destroyed.

Adding a collider

1) Adding a collider by passing arguments to the Collider class constructor:

template<typename... Args>
cref<Collider> addCollider(Args&&... args);
template<typename String, typename... Args>
cref<Collider> addCollider(const String& name, Args&&... args);

Code example:

// automatic generation of collider name
cube->addCollider(make::sptr<core::AABB>(1.f));
// collider name set manually 
cube->addCollider("Intersect", make::sptr<core::AABB>(1.f));

2) Adding a collider by specifying the BoundingVolume type and passing arguments to the constructor of the given type T:

template<typename T, typename... Args>
cref<Collider> addCollider(Args&&... args);
template<typename T, typename String, typename... Args>
cref<Collider> addCollider(const String& name, Args&&... args);

Code example:

// automatic generation of collider name
cube->addCollider<core::AABB>(1.f);
// collider name set manually 
cube->addCollider<core::AABB>("Intersect", 1.f);

All options give identical results:

  • collider is an Axis-aligned Bounding Box with a side size of 1;
  • collider with an automatically generated name added in the first case, or "Intersect" in the second.

Getting a collider

Signature:

cref<Collider> getCollider(const std::string& name);

The addCollider method returns a pointer to the created collider:

auto collider = cube->addCollider<core::BoundingBox>("Intersect", 1.f);

If you know the name of the collider, you can get a pointer to it:

auto collider = cube->getCollider("Intersect");

Note. If the collider's name is specified incorrectly, an error is displayed in the console, and the program terminates.

Removing a collider

Signature:

void removeCollider(cref<Collider>);
void removeCollider(const std::string& name);

Delete the collider by pointer:

cube->removeCollider(collider);

Delete the collider by name:

cube->removeCollider(collider);

cube->removeCollider("Intersect");

The Collider class

This class implements the control of collider interactions.

Bounding Volume

The collider cannot be created without a given volume, but you can change the collider's volume using the method:

void setVolume(cref<BoundingVolume>);

Local Transform

Method signature:

void setLocalTransform(math::Transform::cref);
math::Transform::cref   getLocalTransform() const;

void setLocalTranslation(math::vec3::cref);
math::vec3::cref getLocalTranslation() const;

void setLocalRotation(math::Rotator::cref);
math::Rotator::cref getLocalRotation() const;

void setLocalScale(math::vec3::cref);
math::vec3::cref getLocalScale() const;

Features:

  • BoundingVolume has its own local transform relative to the parent node (its interface is identical to the Node transform management interface).
  • The Collider class proxies the interface to the BoundingVolume.
  • Changes to the node and/or collider transform are calculated at the moment of interaction.

Intersect

Below is the part of the Collider class interface that is responsible for intersections:

using IntersectCallback = std::function<void(const CollisionInfo&)>;

void setIntersecting(bool flag = true);
bool isIntersecting() const;

void setIntersectCallback(const IntersectCallback&);
void resetIntersectCallback();

Note. By default, the collider does not take part in intersections.

How it works:

  • The intersection is calculated in onUpdate() (see IGame class description) every frame.
  • For all crossed colliders, the corresponding IntersectCallback will be called (if set).
  • There can be only one IntersectCallback per collider.
  • When setting IntersectCallback, setIntersecting() is automatically called on the collider.

Screencast

Reaction to TouchEvent

Raycast