mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-02 03:15:43 +08:00
Collision detection between children (#943)
* Enable children of different components to collide * Re-add import
This commit is contained in:
@ -129,8 +129,8 @@ This could be used for example if you have components outside of the screen that
|
||||
about at the moment but that might later come back in to view so they are not completely removed
|
||||
from the game.
|
||||
|
||||
These are just examples of how you could use these types, there will be a lot more usecases for them
|
||||
so don't doubt to use them even if your use-case isn't listed here.
|
||||
These are just examples of how you could use these types, there will be a lot more use cases for
|
||||
them so don't doubt to use them even if your use case isn't listed here.
|
||||
|
||||
### HasCollidables
|
||||
If you want to use this collision detection in your game you have to add the `HasCollidables` mixin
|
||||
|
||||
@ -213,6 +213,35 @@ class CollidableSnowman extends MyCollidable {
|
||||
addHitbox(top);
|
||||
addHitbox(middle);
|
||||
addHitbox(bottom);
|
||||
add(randomCollidable(
|
||||
Vector2(size.x / 2, size.y * 0.75),
|
||||
size / 4,
|
||||
Vector2.zero(),
|
||||
screenCollidable,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
MyCollidable randomCollidable(
|
||||
Vector2 position,
|
||||
Vector2 size,
|
||||
Vector2 velocity,
|
||||
ScreenCollidable screenCollidable, {
|
||||
Random? rng,
|
||||
}) {
|
||||
final _rng = rng ?? Random();
|
||||
final rotationSpeed = 0.5 - _rng.nextDouble();
|
||||
final shapeType = Shapes.values[_rng.nextInt(Shapes.values.length)];
|
||||
switch (shapeType) {
|
||||
case Shapes.circle:
|
||||
return CollidableCircle(position, size, velocity, screenCollidable)
|
||||
..rotationSpeed = rotationSpeed;
|
||||
case Shapes.rectangle:
|
||||
return CollidableRectangle(position, size, velocity, screenCollidable)
|
||||
..rotationSpeed = rotationSpeed;
|
||||
case Shapes.polygon:
|
||||
return CollidablePolygon(position, size, velocity, screenCollidable)
|
||||
..rotationSpeed = rotationSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,7 +268,7 @@ class MultipleShapes extends FlameGame
|
||||
add(snowman);
|
||||
var totalAdded = 1;
|
||||
while (totalAdded < 20) {
|
||||
lastToAdd = createRandomCollidable(lastToAdd, screenCollidable);
|
||||
lastToAdd = nextRandomCollidable(lastToAdd, screenCollidable);
|
||||
final lastBottomRight =
|
||||
lastToAdd.toAbsoluteRect().bottomRight.toVector2();
|
||||
if (lastBottomRight.x < size.x && lastBottomRight.y < size.y) {
|
||||
@ -254,9 +283,9 @@ class MultipleShapes extends FlameGame
|
||||
final _rng = Random();
|
||||
final _distance = Vector2(100, 0);
|
||||
|
||||
MyCollidable createRandomCollidable(
|
||||
MyCollidable nextRandomCollidable(
|
||||
MyCollidable lastCollidable,
|
||||
ScreenCollidable screen,
|
||||
ScreenCollidable screenCollidable,
|
||||
) {
|
||||
final collidableSize = Vector2.all(50) + Vector2.random(_rng) * 100;
|
||||
final isXOverflow = lastCollidable.position.x +
|
||||
@ -270,19 +299,13 @@ class MultipleShapes extends FlameGame
|
||||
..x += collidableSize.x / 2;
|
||||
}
|
||||
final velocity = (Vector2.random(_rng) - Vector2.random(_rng)) * 400;
|
||||
final rotationSpeed = 0.5 - _rng.nextDouble();
|
||||
final shapeType = Shapes.values[_rng.nextInt(Shapes.values.length)];
|
||||
switch (shapeType) {
|
||||
case Shapes.circle:
|
||||
return CollidableCircle(position, collidableSize, velocity, screen)
|
||||
..rotationSpeed = rotationSpeed;
|
||||
case Shapes.rectangle:
|
||||
return CollidableRectangle(position, collidableSize, velocity, screen)
|
||||
..rotationSpeed = rotationSpeed;
|
||||
case Shapes.polygon:
|
||||
return CollidablePolygon(position, collidableSize, velocity, screen)
|
||||
..rotationSpeed = rotationSpeed;
|
||||
}
|
||||
return randomCollidable(
|
||||
position,
|
||||
collidableSize,
|
||||
velocity,
|
||||
screenCollidable,
|
||||
rng: _rng,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@ -56,6 +56,7 @@
|
||||
- `HasGameRef` can now operate independently from `Game`
|
||||
- `initialDelay` and `peakDelay` for effects to handle time before and after an effect
|
||||
- `component.onMount` now runs every time a component gets a new parent
|
||||
- Add collision detection between child components
|
||||
|
||||
## [1.0.0-releasecandidate.13]
|
||||
- Fix camera not ending up in the correct position on long jumps
|
||||
|
||||
@ -325,6 +325,12 @@ class Component with Loadable {
|
||||
}
|
||||
}
|
||||
|
||||
/// This method sets up the `OrderedSet` instance used by this component to
|
||||
/// handle its children,
|
||||
/// This is set up before any lifecycle methods happen.
|
||||
///
|
||||
/// You can return a specific sub-class of OrderedSet, like
|
||||
/// `QueryableOrderedSet` for example.
|
||||
@mustCallSuper
|
||||
ComponentSet createComponentSet() {
|
||||
return ComponentSet.createDefault(this);
|
||||
|
||||
@ -19,6 +19,12 @@ mixin Collidable on Hitbox {
|
||||
|
||||
void onCollision(Set<Vector2> intersectionPoints, Collidable other) {}
|
||||
void onCollisionEnd(Collidable other) {}
|
||||
|
||||
@override
|
||||
void onRemove() {
|
||||
super.onRemove();
|
||||
findParent<HasCollidables>()?.collidables.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ScreenCollidable<T extends FlameGame> extends PositionComponent
|
||||
|
||||
@ -1,8 +1,21 @@
|
||||
import '../../../components.dart';
|
||||
import '../../../game.dart';
|
||||
import '../../components/mixins/collidable.dart';
|
||||
import '../../geometry/collision_detection.dart';
|
||||
|
||||
/// Keeps track of all the [Collidable]s in the component tree and initiates
|
||||
/// collision detection every tick.
|
||||
mixin HasCollidables on FlameGame {
|
||||
final List<Collidable> collidables = [];
|
||||
|
||||
@override
|
||||
void prepareComponent(Component component) {
|
||||
super.prepareComponent(component);
|
||||
if (component is Collidable) {
|
||||
collidables.add(component);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void>? onLoad() {
|
||||
children.register<Collidable>();
|
||||
@ -16,6 +29,6 @@ mixin HasCollidables on FlameGame {
|
||||
}
|
||||
|
||||
void handleCollidables() {
|
||||
collisionDetection(children.query<Collidable>());
|
||||
collisionDetection(collidables);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,14 +2,13 @@ import 'dart:ui';
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../../components.dart';
|
||||
import '../../extensions.dart';
|
||||
import '../components/component.dart';
|
||||
import '../components/mixins/collidable.dart';
|
||||
import '../components/mixins/draggable.dart';
|
||||
import '../components/mixins/has_collidables.dart';
|
||||
import '../components/mixins/hoverable.dart';
|
||||
import '../components/mixins/tappable.dart';
|
||||
import '../extensions/vector2.dart';
|
||||
import 'camera/camera.dart';
|
||||
import 'camera/camera_wrapper.dart';
|
||||
import 'mixins/game.dart';
|
||||
|
||||
@ -294,6 +294,38 @@ void main() {
|
||||
game.update(0);
|
||||
expect(blockA.containsPoint(Vector2.all(11)), true);
|
||||
});
|
||||
|
||||
test('Detects collision on child components', () async {
|
||||
final blockA = TestBlock(
|
||||
Vector2.zero(),
|
||||
Vector2.all(10),
|
||||
CollidableType.active,
|
||||
);
|
||||
final innerBlockA = TestBlock(
|
||||
blockA.size / 4,
|
||||
blockA.size / 2,
|
||||
CollidableType.active,
|
||||
);
|
||||
blockA.add(innerBlockA);
|
||||
|
||||
final blockB = TestBlock(
|
||||
Vector2.all(5),
|
||||
Vector2.all(10),
|
||||
CollidableType.active,
|
||||
);
|
||||
final innerBlockB = TestBlock(
|
||||
blockA.size / 4,
|
||||
blockA.size / 2,
|
||||
CollidableType.active,
|
||||
);
|
||||
blockB.add(innerBlockB);
|
||||
|
||||
await gameWithCollidables([blockA, blockB]);
|
||||
expect(blockA.collisions, <Collidable>[blockB, innerBlockB]);
|
||||
expect(blockB.collisions, <Collidable>[blockA, innerBlockA]);
|
||||
expect(innerBlockA.collisions, <Collidable>[blockB, innerBlockB]);
|
||||
expect(innerBlockB.collisions, <Collidable>[blockA, innerBlockA]);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user