Skip to content

Commit

Permalink
perf: pure type check 2x faster with bloom filter
Browse files Browse the repository at this point in the history
  • Loading branch information
ASGAlex committed Nov 3, 2023
1 parent bc92a90 commit 7c8948a
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 12 deletions.
8 changes: 8 additions & 0 deletions example/lib/game.dart
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ all collisions are disabled.

@override
Future<void> onLoad() async {
pureTypeCheckWarmUpComponents = [
Player(position: Vector2.zero(), size: Vector2.zero(), priority: 0),
Npc(position: Vector2.zero(), size: Vector2.zero(), priority: 0),
Brick(position: Vector2.zero(), sprite: null),
Water(position: Vector2.zero(), animation: null),
Bullet(position: Vector2.zero(), displacement: Vector2.zero()),
BoundingBoxGridGame(),
];
super.onLoad();
player = world.player;
camera.viewfinder.zoom = 5;
Expand Down
106 changes: 94 additions & 12 deletions lib/src/collisions/broadphase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'dart:collection';
import 'dart:math';
import 'dart:ui';

import 'package:dart_bloom_filter/dart_bloom_filter.dart';
import 'package:flame/collisions.dart';
import 'package:flame/components.dart';
import 'package:flame_spatial_grid/flame_spatial_grid.dart';
Expand Down Expand Up @@ -76,6 +77,8 @@ class SpatialGridBroadphase extends Broadphase<ShapeHitbox> {
PureTypeCheck? globalPureTypeCheck;

final _checkByTypeCache = <int, bool>{};
BloomFilter<int>? _checkByTypeCacheBloomTrue;
BloomFilter<int>? _checkByTypeCacheBloomFalse;

@internal
static final broadphaseCheckCache =
Expand Down Expand Up @@ -358,6 +361,11 @@ class SpatialGridBroadphase extends Broadphase<ShapeHitbox> {
}
}

var _key1 = 0;
var _canToCollide1 = true;
var _key2 = 0;
var _canToCollide2 = true;

bool _canPairToCollide(
ShapeHitbox activeItem,
PositionComponent activeParent,
Expand All @@ -375,13 +383,24 @@ class SpatialGridBroadphase extends Broadphase<ShapeHitbox> {
potentialParent.primaryHitboxCollisionType ?? potentialType;
}
var key = activeItem.runtimeType.hashCode & potentialType.hashCode;
final cache = _checkByTypeCache[key];
if (cache == null) {
canToCollide =
_pureTypeCheckHitbox(activeItem, potentialItem, potentialType);
_checkByTypeCache[key] = canToCollide;
if (key == _key1) {
canToCollide = _canToCollide1;
} else {
canToCollide = cache;
_key1 = key;
final bloomCheck = _bloomCacheCheck(key);
if (bloomCheck == null) {
final cache = _checkByTypeCache[key];
if (cache == null) {
canToCollide =
_pureTypeCheckHitbox(activeItem, potentialItem, potentialType);
_checkByTypeCache[key] = canToCollide;
} else {
canToCollide = cache;
}
_canToCollide1 = canToCollide;
} else {
_canToCollide1 = canToCollide = bloomCheck;
}
}

/// 2. Checking types of components itself.
Expand All @@ -391,13 +410,26 @@ class SpatialGridBroadphase extends Broadphase<ShapeHitbox> {
}
final activeItemParentType = activeParent.runtimeType;
key = activeItemParentType.hashCode & potentialType.hashCode;
final cache = _checkByTypeCache[key];

if (cache == null) {
canToCollide = _pureTypeCheckComponent(activeParent, potentialParent);
_checkByTypeCache[key] = canToCollide;
if (key == _key2) {
canToCollide = _canToCollide2;
} else {
canToCollide = cache;
_key2 = key;
final bloomCheck = _bloomCacheCheck(key);
if (bloomCheck == null) {
final cache = _checkByTypeCache[key];

if (cache == null) {
canToCollide =
_pureTypeCheckComponent(activeParent, potentialParent);
_checkByTypeCache[key] = canToCollide;
} else {
canToCollide = cache;
}
_canToCollide2 = canToCollide;
} else {
canToCollide = bloomCheck;
_canToCollide2 = canToCollide;
}
}
}

Expand Down Expand Up @@ -472,6 +504,56 @@ class SpatialGridBroadphase extends Broadphase<ShapeHitbox> {
return canToCollide;
}

void pureTypeCheckWarmUp(List<PositionComponent> components) {
final result = <int, bool>{};
for (var i = 0; i < components.length; i++) {
final active = components[i];
for (var j = 0; j < components.length; j++) {
final potential = components[j];
var canToCollide = true;
if (active is BoundingHitbox && potential is ShapeHitbox) {
canToCollide =
_pureTypeCheckHitbox(active, potential, potential.runtimeType);
}
if (canToCollide) {
canToCollide = _pureTypeCheckComponent(active, potential);
}
//store result here
final key =
active.runtimeType.hashCode & potential.runtimeType.hashCode;
result[key] = canToCollide;
}
}

_checkByTypeCacheBloomTrue = BloomFilter<int>(result.length, 0.01);
_checkByTypeCacheBloomFalse = BloomFilter<int>(result.length, 0.01);
for (final item in result.entries) {
if (item.value) {
_checkByTypeCacheBloomTrue!.add(item: item.key);
} else {
_checkByTypeCacheBloomFalse!.add(item: item.key);
}
}
}

bool? _bloomCacheCheck(int key) {
if (_checkByTypeCacheBloomTrue == null) {
return null;
}

final collide = _checkByTypeCacheBloomTrue!.contains(item: key);
if (collide) {
final noCollide = _checkByTypeCacheBloomFalse!.contains(item: key);
if (!noCollide) {
return true;
} else {
return false;
}
} else {
return false;
}
}

bool _minimumDistanceCheck(
ShapeHitbox activeItem,
ShapeHitbox potential,
Expand Down
7 changes: 7 additions & 0 deletions lib/src/core/has_spatial_grid_framework.dart
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ mixin HasSpatialGridFramework<W extends World> on FlameGame<W>

bool doOnGameResizeForAllComponents = false;

var pureTypeCheckWarmUpComponents = <PositionComponent>[];

/// Initializes the framework. This function *MUST* be called with [await]
/// keyword to ensure that framework had been initialized correctly and all
/// resources were loaded before game loop start.
Expand Down Expand Up @@ -291,6 +293,11 @@ mixin HasSpatialGridFramework<W extends World> on FlameGame<W>
throw 'Lazy load initialization error!';
}
}

if (pureTypeCheckWarmUpComponents.isNotEmpty) {
collisionDetection.broadphase
.pureTypeCheckWarmUp(pureTypeCheckWarmUpComponents);
}
}

void onTrackedComponentPositionUpdate() {
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies:
flame_tiled: ^1.12.0
meta: ^1.8.0
isolate_manager: ^4.1.3
dart_bloom_filter: ^1.0.0
flat_buffers:
git:
url: https://github.com/google/flatbuffers.git
Expand Down

0 comments on commit 7c8948a

Please sign in to comment.