Replies: 1 comment
-
|
Example of possible implementation that I use in my project: import { CollisionGroup } from "excalibur";
function createGroupsFromMap<T extends string>(collisionMap: Partial<Record<T, T[]>>, options: {symmetric?: boolean} = {}): Record<T, CollisionGroup> {
const { symmetric = true } = options; // Автоматически делать коллизии симметричными
// Собираем все уникальные имена групп
const allGroupNames = new Set<T>([
...Object.keys(collisionMap) as T[],
...Object.values<T[]>(collisionMap).flat(),
]);
// Проверяем, что не превышен лимит групп (32 бита)
if (allGroupNames.size > 32) {
throw new Error(`Слишком много групп коллизий: ${allGroupNames.size}. Максимум 32.`);
}
// Создаем категории
const categories = {} as Record<T, number>;
let currentBit = 1;
allGroupNames.forEach(groupName => {
categories[groupName] = currentBit;
currentBit <<= 1;
});
// Создаем расширенную карту коллизий (с симметрией если нужно)
const expandedCollisionMap = { ...collisionMap };
if (symmetric) {
// Добавляем симметричные коллизии
(Object.keys(collisionMap) as T[]).forEach(sourceGroup => {
collisionMap[sourceGroup]!.forEach(targetGroup => {
if (!expandedCollisionMap[targetGroup]) {
expandedCollisionMap[targetGroup] = [];
}
if (!expandedCollisionMap[targetGroup].includes(sourceGroup)) {
expandedCollisionMap[targetGroup].push(sourceGroup);
}
});
});
}
// Создаем группы
const groups = {} as Record<T, CollisionGroup>;
allGroupNames.forEach(groupName => {
let mask = 0;
if (expandedCollisionMap[groupName]) {
expandedCollisionMap[groupName].forEach(targetGroup => {
if (categories[targetGroup]) {
mask |= categories[targetGroup];
} else {
console.warn(`Collision group "${targetGroup}" not found for "${groupName}"`);
}
});
}
groups[groupName] = new CollisionGroup(groupName, categories[groupName], mask);
});
return groups;
}
export const CollisionGroups = createGroupsFromMap({
World: ['Player'],
Player: ['World', 'Enemy', 'EnemyBullet'],
Enemy: ['Player', 'PlayerBullet']
}); |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
For now there is 3 ways to declare collision groups and masks, and I think both of it is inconvenient.
First, we can only create groups, so members of one groups will not collide with each other, but will with other groups.
Second, we can manyally provide bit-masks, and it's flexible way, but you need manually compute masks.
And third, we can use collidesWith helper, it is as flexible as manually providing bit-masks, but helper computing it automatically. It's best way for me, but code seems not convenient enough and a little excess:
I think that more convenient way of declaring groups may look like:
And under the hood it can use third way from below, or even compute bit-masks without creating "default" groups, since it have full list of the collision groups at one time. Also, I think it can extract types from provided map and return typed list of collision groups, this will be amazing!
Beta Was this translation helpful? Give feedback.
All reactions