# Camera rooms

> A level seen room by room, as the action games of the consoles were: the camera stays in the hero’s room and scrolls across to the next when the hero walks out of it.

Example `camera-rooms`, running at https://nacatamalon.com/en/examples/camera-rooms. The whole catalogue: https://nacatamalon.com/llms/examples.md.

`useCameraFollow` with `rooms` cuts the level into rooms the size of the screen (a list of rectangles also works, for rooms of any size). The camera stays in the room the hero is in, and when the hero walks out of it, it scrolls across to the next in half a second (`scroll`).

The hero waits while the screen scrolls, reading `follow.scrolling`, and the counter in the corner changes as each room is entered (`onRoom`).

← → walk, Z jump.

## Code

`index.ts`:

```ts
import { createGame } from 'nacatamalon';
import { Level } from './scenes/level';
import { ACTIONS, VIEW, ZOOM } from './settings';

const game = createGame('#app', {
    width: VIEW.width * ZOOM,
    height: VIEW.height * ZOOM,
    background: '#9fd4ff',
    step: 60,
    actions: ACTIONS
});

// Declare Scenes
game({
    Level
});
```

`components/hero.ts`:

```ts
import { createSprite, useLoadTexture, useTileBody2d } from 'nacatamalon';
import { START } from '../settings';

export const Hero = () => {
    const sprite = createSprite({
        texture: useLoadTexture({
            src: '/example-assets/assets/platformer/hero.png'
        }),
        transform: {
            x: START.x,
            y: START.y
        }
    });

    const body = useTileBody2d({
        width: 12,
        height: 22,
        offset: [0, 1]
    });

    return {
        sprite,
        body
    };
};

export type THero = ReturnType<typeof Hero>;
```

`components/hud.ts`:

```ts
import { createText, useScreenSpace } from 'nacatamalon';
import type { TRect } from 'nacatamalon';
import { VIEW, ZOOM } from '../settings';

export const Hud = () => {
    useScreenSpace();

    createText({
        text: 'ARROWS / WASD WALK  Z / SPACE JUMP',
        transform: {
            x: 8,
            y: 8
        },
        tint: '#40507a'
    });

    const label = createText({
        text: 'ROOM',
        transform: {
            x: VIEW.width * ZOOM - 90,
            y: 22
        },
        tint: '#40507a'
    });

    return {
        showRoom: (room: TRect) => {
            const column = Math.round(room.x / VIEW.width) + 1;
            const row = Math.round(room.y / VIEW.height) + 1;

            label.text = 'ROOM ' + column + '-' + row;
        }
    };
};
```

`hooks/use_hero_controls.ts`:

```ts
import { useActions, useUpdate } from 'nacatamalon';
import type { TCameraFollow } from 'nacatamalon';
import type { THero } from '../components/hero';
import { HERO, START } from '../settings';

export const useHeroControls = ({ sprite, body }: THero, follow: TCameraFollow) => {
    const input = useActions();

    useUpdate(() => {
        // Game rule: wait for the camera to finish crossing into the next room.
        if (follow.scrolling) {
            body.velocity.x = 0;

            return;
        }

        const walk = input.value('right') - input.value('left');

        body.velocity.x = walk * HERO.speed;

        if (walk !== 0) {
            sprite.flipX = walk < 0;
        }

        if ((input.justPressed('jump') || input.justPressed('up')) && body.isOnGround) {
            body.velocity.y = -HERO.jumpSpeed;
        }

        if (sprite.transform.y > HERO.respawnY) {
            body.setPosition(START.x, START.y);
            body.velocity.y = 0;
        }
    });
};
```

`scenes/level.ts`:

```ts
import { createScene, createTilemap, useCamera2d, useCameraFollow, useSpawn } from 'nacatamalon';
import { Hero } from '../components/hero';
import { Hud } from '../components/hud';
import { useHeroControls } from '../hooks/use_hero_controls';
import { SCROLL_SECONDS, VIEW, ZOOM } from '../settings';

export const Level = () => {
    useCamera2d({
        zoom: ZOOM
    });

    const map = createTilemap({
        src: '/example-assets/assets/platformer/wide.tilemap'
    });

    const hero = useSpawn(Hero)();
    const hud = useSpawn(Hud)();

    const follow = useCameraFollow(hero, {
        bounds: map,
        rooms: VIEW,
        scroll: SCROLL_SECONDS,
        onRoom: hud.api.showRoom
    });

    useHeroControls(hero.api, follow);

    return createScene();
};
```

`settings.ts`:

```ts
import { INPUT } from 'nacatamalon';

export const ZOOM = 2;
export const ACTIONS = INPUT.ACTION_PRESETS.platformer;
export const SCROLL_SECONDS = 0.5;

export const VIEW = {
    width: 180,
    height: 160
};

export const START = {
    x: 40,
    y: 250
};

export const HERO = {
    speed: 110,
    jumpSpeed: 330,
    respawnY: 400
};
```
