Skip to content

Commit

Permalink
performance improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
RafaelBarbosatec committed Dec 1, 2023
1 parent c21638a commit e1b2f99
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 87 deletions.
4 changes: 2 additions & 2 deletions example/assets/images/tiled/mapa2.json
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,8 @@
"x":0,
"y":0
}],
"nextlayerid":13,
"nextobjectid":106,
"nextlayerid":14,
"nextobjectid":107,
"orientation":"orthogonal",
"renderorder":"right-down",
"tiledversion":"1.9.0",
Expand Down
86 changes: 50 additions & 36 deletions lib/collision/block_movement_collision.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ export 'collision_data.dart';

/// Mixin responsible for adding stop the movement when happen collision
mixin BlockMovementCollision on Movement {
bool _reflectionEnabled = false;
bool _isRigid = true;
bool _blockMovementCollisionEnabled = true;
bool get blockMovementCollisionEnabled => _blockMovementCollisionEnabled;
bool get blockMovementCollisionReflectionEnabled => _reflectionEnabled;
bool get blockMovementCollisionReflectionEnabled => _isRigid;
final Map<BlockMovementCollision, CollisionData> _collisionsResolution = {};

void setupBlockMovementCollision({bool? enabled, bool? reflectionEnabled}) {
_reflectionEnabled = reflectionEnabled ?? _reflectionEnabled;
void setCollisionResolution(
BlockMovementCollision other,
CollisionData data,
) {
_collisionsResolution[other] = data;
}

void setupBlockMovementCollision({bool? enabled, bool? isRigid}) {
_isRigid = isRigid ?? _isRigid;
_blockMovementCollisionEnabled = enabled ?? _blockMovementCollisionEnabled;
}

Expand Down Expand Up @@ -44,13 +52,13 @@ mixin BlockMovementCollision on Movement {
PositionComponent other,
CollisionData collisionData,
) {
if (_reflectionEnabled) {
velocity -= getCollisionVelocityReflection(other, collisionData);
} else {
if (_isRigid) {
velocity -= Vector2(
velocity.x * collisionData.normal.x.abs(),
velocity.y * collisionData.normal.y.abs(),
);
} else {
velocity -= getCollisionVelocityReflection(other, collisionData);
}
}

Expand All @@ -72,18 +80,23 @@ mixin BlockMovementCollision on Movement {
: true;
if (other is BlockMovementCollision) {
stopOtherMovement = other.onBlockMovement(intersectionPoints, this);
isStatic =
_reflectionEnabled ? false : other.velocity.length > velocity.length;
isStatic = _isRigid ? other.velocity.length > velocity.length : false;
}

if (!stopMovement || !stopOtherMovement) {
return;
}

if (_collisionsResolution.containsKey(other)) {
onBlockedMovement(other, _collisionsResolution[other]!);
_collisionsResolution.remove(other);
return;
}

ShapeHitbox shape1 = shapeHitboxes.first;
ShapeHitbox shape2 = other.children.query<ShapeHitbox>().first;

(Vector2 normal, double depth)? colisionResult;
({Vector2 normal, double depth})? colisionResult;

if (_isPolygon(shape1)) {
if (_isPolygon(shape2)) {
Expand All @@ -105,23 +118,24 @@ mixin BlockMovementCollision on Movement {
}

if (colisionResult != null) {
onBlockedMovement(
other,
CollisionData(
normal: colisionResult.$1,
depth: isStatic ? 0 : colisionResult.$2,
intersectionPoints: intersectionPoints.toList(),
direction: colisionResult.$1.toDirection(),
),
final data = CollisionData(
normal: colisionResult.normal,
depth: isStatic ? 0 : colisionResult.depth,
intersectionPoints: intersectionPoints.toList(),
direction: colisionResult.normal.toDirection(),
);
onBlockedMovement(other, data);
if (other is BlockMovementCollision) {
other.setCollisionResolution(this, data.inverted());
}
}
}

bool _isPolygon(ShapeHitbox shape) {
return shape is RectangleHitbox || shape is PolygonHitbox;
}

(Vector2 normal, double depth) _intersectPolygons(
({Vector2 normal, double depth}) _intersectPolygons(
ShapeHitbox shapeA,
ShapeHitbox shapeB,
PositionComponent other,
Expand All @@ -137,19 +151,19 @@ mixin BlockMovementCollision on Movement {
verticesB,
);

if (normalAndDepthA.second < depth) {
depth = normalAndDepthA.second;
normal = normalAndDepthA.first;
if (normalAndDepthA.depth < depth) {
depth = normalAndDepthA.depth;
normal = normalAndDepthA.normal;
}
var normalAndDepthB = CollisionUtil.getNormalAndDepth(
verticesB,
verticesA,
insverted: true,
);

if (normalAndDepthB.second < depth) {
depth = normalAndDepthB.second;
normal = normalAndDepthB.first;
if (normalAndDepthB.depth < depth) {
depth = normalAndDepthB.depth;
normal = normalAndDepthB.normal;
}

Vector2 direction = shapeB.absoluteCenter - shapeA.absoluteCenter;
Expand All @@ -158,10 +172,10 @@ mixin BlockMovementCollision on Movement {
normal = -normal;
}

return (normal, depth);
return (normal: normal, depth: depth);
}

(Vector2 normal, double depth) _intersectCirclePolygon(
({Vector2 normal, double depth}) _intersectCirclePolygon(
ShapeHitbox shapeA,
CircleHitbox shapeB,
PositionComponent other, {
Expand All @@ -182,14 +196,14 @@ mixin BlockMovementCollision on Movement {
axis = Vector2(-edge.y, edge.x);
axis = axis.normalized();

Vector2 pA = CollisionUtil.projectVertices(vertices, axis);
Vector2 pB = CollisionUtil.projectCircle(
final pA = CollisionUtil.projectVertices(vertices, axis);
final pB = CollisionUtil.projectCircle(
shapeB.absoluteCenter,
shapeB.radius,
axis,
);

axisDepth = min(pB.y - pA.x, pA.y - pB.x);
axisDepth = min(pB.max - pA.min, pA.max - pB.min);

if (axisDepth < depth) {
depth = axisDepth;
Expand All @@ -206,14 +220,14 @@ mixin BlockMovementCollision on Movement {
axis = cp - shapeB.absoluteCenter;
axis = axis.normalized();

Vector2 pA = CollisionUtil.projectVertices(vertices, axis);
Vector2 pB = CollisionUtil.projectCircle(
final pA = CollisionUtil.projectVertices(vertices, axis);
final pB = CollisionUtil.projectCircle(
shapeB.absoluteCenter,
shapeB.radius,
axis,
);

axisDepth = min(pB.y - pA.x, pA.y - pB.x);
axisDepth = min(pB.max - pA.min, pA.max - pB.min);

if (axisDepth < depth) {
depth = axisDepth;
Expand All @@ -228,10 +242,10 @@ mixin BlockMovementCollision on Movement {
normal = -normal;
}

return (normal, depth);
return (normal: normal, depth: depth);
}

(Vector2 normal, double depth) _intersectCircles(
({Vector2 normal, double depth}) _intersectCircles(
CircleHitbox shapeA, CircleHitbox shapeB) {
Vector2 normal = Vector2.zero();
double depth = double.maxFinite;
Expand All @@ -242,6 +256,6 @@ mixin BlockMovementCollision on Movement {
normal = (shapeB.absoluteCenter - shapeA.absoluteCenter).normalized();
depth = radii - distance;

return (normal, depth);
return (normal: normal, depth: depth);
}
}
9 changes: 9 additions & 0 deletions lib/collision/collision_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,13 @@ class CollisionData {
intersectionPoints: intersectionPoints ?? this.intersectionPoints,
);
}

CollisionData inverted() {
return CollisionData(
normal: -normal,
depth: depth,
direction: (-normal).toDirection(),
intersectionPoints: intersectionPoints,
);
}
}
31 changes: 18 additions & 13 deletions lib/collision/collision_util.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import 'dart:math';

import 'package:bonfire/bonfire.dart';
import 'package:bonfire/util/pair.dart';

class CollisionUtil {

static List<Vector2> getPolygonVertices(ShapeHitbox shape) {
if (shape is PolygonComponent) {
return (shape as PolygonComponent).absoluteVertices;
}
return [];
}

static Pair<Vector2, double> getNormalAndDepth(
static ({Vector2 normal, double depth}) getNormalAndDepth(
List<Vector2> verticesA,
List<Vector2> verticesB, {
bool insverted = false,
Expand All @@ -27,21 +25,24 @@ class CollisionUtil {
Vector2 axis = Vector2(-edge.y, edge.x);
axis = axis.normalized();

Vector2 pA = projectVertices(insverted ? verticesB : verticesA, axis);
Vector2 pB = projectVertices(insverted ? verticesA : verticesB, axis);
final pA = projectVertices(insverted ? verticesB : verticesA, axis);
final pB = projectVertices(insverted ? verticesA : verticesB, axis);

double axisDepth = min(pB.y - pA.x, pA.y - pB.x);
double axisDepth = min(pB.max - pA.min, pA.max - pB.min);
if (axisDepth < depth) {
depth = axisDepth;
normal = axis;
}
}
return Pair(normal, depth);
return (normal: normal, depth: depth);
}

static Vector2 projectVertices(List<Vector2> vertices, Vector2 axis) {
static ({double min, double max}) projectVertices(
List<Vector2> vertices,
Vector2 axis,
) {
double min = double.maxFinite;
double max = double.minPositive;
double max = -double.maxFinite;
for (var v in vertices) {
double proj = v.dot(axis);

Expand All @@ -52,10 +53,11 @@ class CollisionUtil {
max = proj;
}
}
return Vector2(min, max);
return (min: min, max: max);
}

static Vector2 projectCircle(Vector2 center, double radius, Vector2 axis) {
static ({double min, double max}) projectCircle(
Vector2 center, double radius, Vector2 axis) {
Vector2 direction = axis.normalized();
Vector2 directionAndRadius = direction * radius;

Expand All @@ -71,10 +73,13 @@ class CollisionUtil {
min = max;
max = t;
}
return Vector2(min, max);
return (min: min, max: max);
}

static int findClosesPointOnPolygon(Vector2 circleCenter, List<Vector2> vertices) {
static int findClosesPointOnPolygon(
Vector2 circleCenter,
List<Vector2> vertices,
) {
int result = -1;
double minDistance = double.maxFinite;

Expand Down
61 changes: 32 additions & 29 deletions lib/forces/handle_forces.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ export 'package:bonfire/forces/forces_2d.dart';
/// Mixin that makes the component suffer influences from global or local forces.
/// To adds local forces just call `addForce` method. To adds global foreces use the param `globalForces` in `BonfireWidget`.
mixin HandleForces on Movement {
Vector2 _accelerationOfForces = Vector2.zero();

/// Mass of the Component
double _mass = 1.0;

Expand All @@ -29,46 +27,51 @@ mixin HandleForces on Movement {
}

@override
Vector2 onVelocityTransform(double dt) {
Vector2 onVelocityUpdate(double dt, Vector2 velocity) {
final oldVelocity = velocity.clone();
List<Force2D> mergeForces = [..._forces, ...gameRef.globalForces];
_accelerationOfForces = _getAccelerationForces(mergeForces, dt);

var currentVelocity = velocity + _accelerationOfForces;

Vector2 newVel = _applyResistenceForces(mergeForces, currentVelocity, dt);
final acceleration = mergeForces.whereType<AccelerationForce2D>();
final resistence = mergeForces.whereType<ResistanceForce2D>();
final linear = mergeForces.whereType<LinearForce2D>();

newVel = _applyLinearForces(mergeForces, newVel, dt);
Vector2 newVel = onApplyAccelerationForces(acceleration, velocity, dt);
newVel = onApplyLinearForces(linear, newVel, dt);
newVel = onApplyResistenceForces(resistence, newVel, dt);

return velocity = (oldVelocity + newVel) * 0.5;
return (oldVelocity + newVel) * 0.5;
}

Vector2 _getAccelerationForces(List<Force2D> mergeForces, double dt) {
return mergeForces.whereType<AccelerationForce2D>().fold<Vector2>(
Vector2.zero(),
(p, e) => p + e.transform(p, mass, dt),
);
Vector2 onApplyAccelerationForces(
Iterable<Force2D> forces,
Vector2 velocity,
double dt,
) {
final accelerations = forces.fold<Vector2>(
Vector2.zero(),
(p, e) => p + e.transform(p, mass, dt),
);
return velocity + accelerations;
}

Vector2 _applyResistenceForces(
List<Force2D> mergeForces,
Vector2 currentVelocity,
Vector2 onApplyResistenceForces(
Iterable<Force2D> forces,
Vector2 velocity,
double dt,
) {
return mergeForces.whereType<ResistanceForce2D>().fold<Vector2>(
currentVelocity,
(p, e) => e.transform(p, mass, dt),
);
return forces.fold<Vector2>(
velocity,
(p, e) => e.transform(p, mass, dt),
);
}

Vector2 _applyLinearForces(
List<Force2D> mergeForces,
Vector2 newVel,
Vector2 onApplyLinearForces(
Iterable<Force2D> forces,
Vector2 velocity,
double dt,
) {
return mergeForces.whereType<LinearForce2D>().fold<Vector2>(
newVel,
(p, e) => e.transform(p, mass, dt),
);
return forces.fold<Vector2>(
velocity,
(p, e) => e.transform(p, mass, dt),
);
}
}
Loading

0 comments on commit e1b2f99

Please sign in to comment.