Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!: enhance ContactCallback process (#1547)
Migration notes The entire contact callback process has been redefined to mimic Flame's CollisionCallbacks. In order to simplify the migration to this new code, the following steps should facilitate doing so: Remove lines of code that used addContactCallback, removeContactCallback, clearContactCallback. Remove subclasses of ContactCallbacks<Type1, Type2>. 2.1. Include with ContactCallback in your BodyComponent class signature. 2.2. Override the contact method that you are interested in, and check that other is Type2, then perform the logic. The above is just a suggested migration approach. There are other code alternatives or patterns you might want to follow. In addition, you can define your own custom contact logic by providing a ContactListener to your Forge2DGame. For more information check the examples, Flame documentation, or the class documentation of ContactCallbacks and WorldContactListener.
- Loading branch information
Showing
11 changed files
with
610 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,51 @@ | ||
import 'package:forge2d/forge2d.dart'; | ||
|
||
import 'body_component.dart'; | ||
|
||
class ContactTypes<T1, T2> { | ||
// If o1 is, or inherits from, T1 or T2 | ||
bool has(Object o1) => o1 is T1 || o1 is T2; | ||
bool hasOne(Object o1, Object o2) => has(o1) || has(o2); | ||
|
||
// Only makes sense to call with objects that you know is in [T1, T2] | ||
bool inOrder(Object o1, Object o2) => o1 is T1 && o2 is T2; | ||
|
||
// Remember that this is not symmetric, it checks if the types in `o1` and | ||
// `o2` are the same or inherits from the types in `other` | ||
bool match(Object o1, Object o2) => | ||
(o1 is T1 && o2 is T2) || (o2 is T1 && o1 is T2); | ||
} | ||
|
||
typedef ContactCallbackFun = void Function(Object a, Object b, Contact contact); | ||
|
||
abstract class ContactCallback<Type1, Type2> { | ||
ContactTypes<Type1, Type2> types = ContactTypes<Type1, Type2>(); | ||
|
||
void begin(Type1 a, Type2 b, Contact contact) {} | ||
void end(Type1 a, Type2 b, Contact contact) {} | ||
void preSolve(Type1 a, Type2 b, Contact contact, Manifold oldManifold) {} | ||
void postSolve(Type1 a, Type2 b, Contact contact, ContactImpulse impulse) {} | ||
} | ||
|
||
class ContactCallbacks extends ContactListener { | ||
final List<ContactCallback> _callbacks = []; | ||
|
||
void register(ContactCallback callback) { | ||
_callbacks.add(callback); | ||
import 'flame_forge2d.dart'; | ||
|
||
/// Used to listen to a [BodyComponent]'s contact events. | ||
/// | ||
/// Contact events occur whenever two [Fixture] meet each other. | ||
/// | ||
/// To react to contacts you should assign [ContactCallbacks] to a [Body]'s | ||
/// userData or/and to a [Fixture]'s userData. | ||
/// {@macro flame_forge2d.world_contact_listener.algorithm} | ||
class ContactCallbacks { | ||
/// Called when two [Fixture]s start being in contact. | ||
/// | ||
/// It is called for sensors and non-sensors. | ||
void beginContact(Object other, Contact contact) { | ||
onBeginContact?.call(other, contact); | ||
} | ||
|
||
void deregister(ContactCallback callback) { | ||
_callbacks.remove(callback); | ||
/// Called when two [Fixture]s cease being in contact. | ||
/// | ||
/// It is called for sensors and non-sensors. | ||
void endContact(Object other, Contact contact) { | ||
onEndContact?.call(other, contact); | ||
} | ||
|
||
void clear() { | ||
_callbacks.clear(); | ||
/// Called after collision detection, but before collision resolution. | ||
/// | ||
/// This gives you a chance to disable the [Contact] based on the current | ||
/// configuration. | ||
/// Sensors do not create [Manifold]s. | ||
void preSolve(Object other, Contact contact, Manifold oldManifold) { | ||
onPreSolve?.call(other, contact, oldManifold); | ||
} | ||
|
||
void _maybeCallback( | ||
Contact contact, | ||
ContactCallback callback, | ||
ContactCallbackFun f, | ||
) { | ||
final a = contact.fixtureA.body.userData; | ||
final b = contact.fixtureB.body.userData; | ||
final wanted = callback.types; | ||
|
||
if (a == null || b == null) { | ||
return; | ||
} | ||
|
||
if (wanted.match(a, b) || | ||
(wanted.has(BodyComponent) && wanted.hasOne(a, b))) { | ||
wanted.inOrder(a, b) ? f(a, b, contact) : f(b, a, contact); | ||
} | ||
/// Called after collision resolution. | ||
/// | ||
/// Usually defined to gather collision impulse results. | ||
/// If one of the colliding objects is a sensor, this will not be called. | ||
void postSolve(Object other, Contact contact, ContactImpulse impulse) { | ||
onPostSolve?.call(other, contact, impulse); | ||
} | ||
|
||
@override | ||
void beginContact(Contact contact) => | ||
_callbacks.forEach((c) => _maybeCallback(contact, c, c.begin)); | ||
void Function(Object other, Contact contact)? onBeginContact; | ||
|
||
@override | ||
void endContact(Contact contact) => | ||
_callbacks.forEach((c) => _maybeCallback(contact, c, c.end)); | ||
void Function(Object other, Contact contact)? onEndContact; | ||
|
||
@override | ||
void preSolve(Contact contact, Manifold oldManifold) { | ||
_callbacks.forEach((c) { | ||
void preSolveAux(Object a, Object b, Contact contact) { | ||
c.preSolve(a, b, contact, oldManifold); | ||
} | ||
void Function(Object other, Contact contact, Manifold oldManifold)? | ||
onPreSolve; | ||
|
||
_maybeCallback(contact, c, preSolveAux); | ||
}); | ||
} | ||
|
||
@override | ||
void postSolve(Contact contact, ContactImpulse impulse) { | ||
_callbacks.forEach((c) { | ||
void postSolveAux(Object a, Object b, Contact contact) { | ||
c.postSolve(a, b, contact, impulse); | ||
} | ||
|
||
_maybeCallback(contact, c, postSolveAux); | ||
}); | ||
} | ||
void Function(Object other, Contact contact, ContactImpulse impulse)? | ||
onPostSolve; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.