Hitboxes
Volver a la referencia

Hitboxes

The parts of an object that can be touched, and what to do when two of them meet: hits, pickups and triggers without a physics engine.

12 símbolos

collisionBetweenfunctionnacatamalon

collisionBetween(a: TCollisionTarget, b: TCollisionTarget) => boolean

Whether two things touch right now: a bullet and a brick, the player and a door, a sword and whatever is in front of it. With no physics: just whether their rectangles share any area.

Each side can be an object, a sprite, a text, a panel, or a rectangle of the world ({ x, y, width, height }, from its top-left corner). An object is measured by its hitboxes (useHitbox) when it has any, and by what it draws when it has none. Everything is measured where it is drawn: turned, grown and moved with everything above it. Edges that only meet do not count, so two tiles side by side are not touching.

For many things against many, every frame, useCollisionBetween with components or tags says it once.

Parámetros

aTCollisionTarget

One thing.

bTCollisionTarget

The other.

Ejemplo

declare const bullet: TSprite;
declare const brick: TSprite;

useUpdate(() => {
    if (collisionBetween(bullet, brick)) {
        bullet.visible = false;
    }
});
Ver el código · hitbox/collision_between.ts:80

useCollisionBetweenfunctionhooknacatamalon

useCollisionBetween(a: A, b: B, callback: (a: TCollisionMatched<A>, b: TCollisionMatched<B>) => void) => () => void

Calls callback for every thing of kind a touching one of kind b, every frame they touch: a rule of the scene, shots against enemies, the player against coins. A piece says itself what it collides with with useCollisionWith; this is for the scene that knows both. Each kind is a component, whose pieces come with their api typed, or a tag, as in useCollisionWith, and physics bodies meet as they do there.

Run once every useUpdate of the scene is over, before useLateUpdate, measured as collisionBetween measures. The two come in the order the tags were named. Once one is destroyed it is not called with again, so a bullet hits one enemy and not the three behind it. A tag can be named twice, useCollisionBetween('enemy', 'enemy', ...), and each pair comes once. Stops when what registered it goes away; not while its scene is paused.

Parámetros

aA

One kind: a component, or a tag.

bB

The other.

callback(a: TCollisionMatched<A>, b: TCollisionMatched<B>) => void

What to do with each pair, in that order.

Ejemplo

declare const Bat: (props: { x: number }) => { hurt(damage: number): void };

export const Cave: TSceneFn = () => {
    useSpawn(Bat)({ x: 200 });
    useCollisionBetween('shot', Bat, (shot, bat) => {
        destroy(shot);
        bat.api.hurt(1);
    });
    return createScene();
};
Ver el código · hooks/hitbox/use_collision_between.ts:42

useCollisionWithfunctionhooknacatamalon

useCollisionWith(match: M, callback: (other: TCollisionMatched<M>) => void, options: TCollisionWithOptions) => () => void

Calls callback with each thing the object being built touches, of one kind: a bullet and the enemies, the player and the coins. The piece says itself what it collides with, so a bullet and an enemy written apart need no rule in the scene that knows them both.

The kind is a component or a tag. A component (useCollisionWith(Enemy, ...)) meets the pieces useSpawn made from it, and gives each with its api typed. A tag ('damageable', or what useTag gives) meets everything carrying it, pieces of any kind and sprites, texts or panels tagged on their own, so what comes is either: 'api' in thing tells. A tag is also what a saved scene and the editor can name.

Measured as collisionBetween measures: a piece by its hitboxes that are on, or by what it draws when it has none; a sprite, text or panel by itself. Two pieces with physics bodies also touch when the simulation says so, in 2D and in 3D, so the same line works whether a hitbox or a body tells it. Run with the scene's other collisions, once its updates are over; not while it is paused. Stops when the object goes away.

Parámetros

matchM

What it collides with: a component, or a tag.

callback(other: TCollisionMatched<M>) => void

What to do with each one.

Ejemplo

declare const Bat: () => { hurt(damage: number): void };

const Bullet = ({ x }: { x: number }) => {
    const self = useSelf();
    createSprite({ width: 4, height: 4, transform: { x, y: 200 } });
    useHitbox();
    useCollisionWith(Bat, (bat) => {
        destroy(self);
        bat.api.hurt(1);
    });
};
Ver el código · hooks/hitbox/use_collision_with.ts:61

useHitboxfunctionhooknacatamalon

useHitbox(options: THitboxOptions) => THitbox

Gives this object a part that can be touched: what useCollisionWith, useCollisionBetween and collisionBetween measure it by instead of its picture. What it is ('enemy') is its tag (useTag), not the hitbox's.

Apart from the picture, because that is how these games were made. The hero's hitbox is smaller than his sprite, so a bullet that grazes his hair misses; a sword only hurts on the frames of the swing. Left without a size it is the size of the picture, frame after frame, and it is changed whenever the game likes: written to, it takes effect on the next comparison.

It is measured like the picture, in the object's own pixels, from the picture's centre: it turns, grows and moves with the object. A sword that hurts beside a body that is hurt is a piece of its own, with its own tag.

Parámetros

optionsTHitboxOptions

Where it is and how big, and whether it is on.

Ejemplo

const Hero = () => {
    const keys = useKeyboard();
    createSprite({ key: 'hero', transform: { x: 40, y: 160 } });
    useTag('player').add(useSelf());
    const body = useHitbox({ width: 10 });

    useUpdate(() => {
        // A hero 24 pixels tall, crouching: 12 tall, and 6 lower so the feet stay where they were.
        const crouching = keys.isDown('ArrowDown');
        body.height = crouching ? 12 : undefined;
        body.y = crouching ? 6 : 0;
    });
};
Ver el código · hooks/hitbox/use_hitbox.ts:59

TCollisionMatchtypenacatamalon

TCollisionMatch: string | TTag | (args: never[]) => unknown

What a collision is asked by: a tag (what useTag gives, or its name), which meets everything carrying it, or a component, which meets the pieces useSpawn made from it.

Ver el código · hitbox/types/t_hitbox.ts:53

TCollisionMatchedtypenacatamalon

TCollisionMatched: conditional

What a collision asked by M is called with: a piece of that component, its api typed, for a component; a piece, or a sprite, text or panel tagged on its own, for a tag.

Ver el código · hitbox/types/t_hitbox.ts:63

TCollisionWhentypenacatamalon

TCollisionWhen: 'start' | 'touching' | 'end'

When useCollisionWith calls: on the first frame two things touch, every frame they do, or on the first they no longer do.

Ver el código · hitbox/types/t_hitbox.ts:43

THitboxtypenacatamalon

The part of an object that can be touched. Made by useHitbox, and changed whenever the game likes: smaller while crouching, off while blinking after a hit. What the object is ('enemy') is its tag, not the hitbox's: see useTag.

Measured like the object's picture, in its own pixels: it turns, grows and moves with it.

Propiedades

xnumber

How far its centre is moved from the centre of the picture, in the object's own pixels. 0, 0 by default.

ynumber
widthnumber | undefined

Its size, in the object's own pixels. undefined takes the picture's, frame after frame, so it follows an animation whose frames change size; a number fixes it.

heightnumber | undefined
enabledboolean

Off, nothing touches it: a character blinking after a hit, a sword between swings. true by default.

Ver el código · hitbox/types/t_hitbox.ts:15

THitboxOptionstypenacatamalon

How a hitbox starts. All of it is optional: it begins as the picture.

Propiedades

xopcionalnumber
yopcionalnumber
widthopcionalnumber
heightopcionalnumber
enabledopcionalboolean
Ver el código · hooks/hitbox/use_hitbox.ts:12