# Photo capture

> useCapture photographs a part of the screen without the HUD, and says what came out in it and how much.

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

`useCapture()` gives the game a camera of its own. `capture({ region, hide, width, height })` resolves on the next frame with the photo: its pixels, as the player sees them, and `boxes`, what came out in it, each with how much of it is in (`seen`, from 0 to 1) and where.

`region` is a rectangle of the screen or a box: here the viewfinder, measured even though the viewfinder itself is left out with `hide`, along with the HUD. The print in the corner is a picture painted in code (`createPixels`, `createPixelTexture`) that each photo is copied into before `updatePixelTexture`.

Click the preview first so it hears the keyboard. The arrows move the viewfinder and space takes the photo: the score says how much of the bird you caught.

## Code

`index.ts`:

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

import * as Settings from './settings';
import { Sky } from './scenes/demo';

const game = createGame('#app', {
    width: Settings.WIDTH,
    height: Settings.HEIGHT,
    background: '#9fd3f0',
    scaling: 'integer'
});

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

`components/bird.ts`:

```ts
import { createSprite, useTransform, useUpdate } from 'nacatamalon';

import * as Settings from '../settings';

export function Bird() {
    const place = useTransform({
        x: -20,
        y: 70
    });

    createSprite({
        width: 14,
        height: 8,
        tint: '#2a2238'
    });
    createSprite({
        width: 6,
        height: 6,
        tint: '#2a2238',
        transform: {
            x: 8,
            y: -3
        }
    });
    useUpdate((delta, time) => {
        place.x += 70 * delta;
        place.y = 70 + Math.sin(time * 2) * 30;

        if (place.x > Settings.WIDTH + 20) {
            place.x = -20;
        }
    });
}
```

`components/hud.ts`:

```ts
import { createSprite, createText } from 'nacatamalon';

import { createPixelTexture, createPixels } from 'nacatamalon/pixels';
import * as Settings from '../settings';

export function Hud() {
    const film = createPixels(Settings.SHOT_W, Settings.SHOT_H);
    const print = createPixelTexture(film);

    createSprite({
        width: Settings.SHOT_W + 4,
        height: Settings.SHOT_H + 4,
        tint: '#f4efe0',
        anchor: {
            x: 1,
            y: 0
        },
        transform: {
            x: Settings.WIDTH - 6,
            y: 6
        }
    });
    createSprite({
        texture: print,
        anchor: {
            x: 1,
            y: 0
        },
        transform: {
            x: Settings.WIDTH - 8,
            y: 8
        }
    });

    const score = createText({
        text: 'SPACE: PHOTO',
        tint: '#2a2238',
        transform: {
            x: 8,
            y: Settings.HEIGHT - 14
        }
    });

    return {
        film,
        print,
        score
    };
}
```

`components/viewfinder.ts`:

```ts
import { createSprite, getColor, useTransform } from 'nacatamalon';

import * as Settings from '../settings';

export function Viewfinder() {
    const place = useTransform({
        x: Settings.WIDTH / 2,
        y: Settings.HEIGHT / 2
    });

    const edge = getColor('#ffffff');

    createSprite({
        width: Settings.SHOT_W,
        height: Settings.SHOT_H,
        tint: '#ffffff',
        visible: false
    });
    createSprite({
        width: Settings.SHOT_W,
        height: 1,
        tint: edge,
        transform: {
            y: -Settings.SHOT_H / 2
        }
    });
    createSprite({
        width: Settings.SHOT_W,
        height: 1,
        tint: edge,
        transform: {
            y: Settings.SHOT_H / 2
        }
    });
    createSprite({
        width: 1,
        height: Settings.SHOT_H,
        tint: edge,
        transform: {
            x: -Settings.SHOT_W / 2
        }
    });
    createSprite({
        width: 1,
        height: Settings.SHOT_H,
        tint: edge,
        transform: {
            x: Settings.SHOT_W / 2
        }
    });

    return {
        place
    };
}
```

`scenes/demo.ts`:

```ts
import { createScene, createSprite, useCapture, useKeyboard, useSpawn, useUpdate } from 'nacatamalon';
import { clamp } from 'nacatamalon/math';
import { updatePixelTexture } from 'nacatamalon/pixels';
import * as Settings from '../settings';
import { Bird } from '../components/bird';
import { Viewfinder } from '../components/viewfinder';
import { Hud } from '../components/hud';

export const Sky = () => {
    createSprite({
        width: Settings.WIDTH,
        height: Settings.HEIGHT,
        tint: '#9fd3f0',
        anchor: {
            x: 0,
            y: 0
        }
    });
    createSprite({
        width: Settings.WIDTH,
        height: 30,
        tint: '#6fae5c',
        anchor: {
            x: 0,
            y: 1
        },
        transform: {
            y: Settings.HEIGHT
        }
    });
    useSpawn(Bird, 'Bird')();

    const viewfinder = useSpawn(Viewfinder, 'Viewfinder')().api;
    const hud = useSpawn(Hud, 'Hud')().api;

    const capture = useCapture();
    const keys = useKeyboard();

    useUpdate((delta) => {
        const dx = (keys.isDown('ArrowRight') ? 1 : 0) - (keys.isDown('ArrowLeft') ? 1 : 0);
        const dy = (keys.isDown('ArrowDown') ? 1 : 0) - (keys.isDown('ArrowUp') ? 1 : 0);

        viewfinder.place.x = clamp(viewfinder.place.x + dx * 140 * delta, Settings.SHOT_W / 2, Settings.WIDTH - Settings.SHOT_W / 2);
        viewfinder.place.y = clamp(viewfinder.place.y + dy * 140 * delta, Settings.SHOT_H / 2, Settings.HEIGHT - Settings.SHOT_H / 2);

        if (keys.justPressed(' ')) {
            void capture({
                region: 'Viewfinder',
                hide: ['Hud', 'Viewfinder'],
                width: Settings.SHOT_W,
                height: Settings.SHOT_H
            }).then((photo) => {
                hud.film.data.set(photo.data);
                updatePixelTexture(hud.print);

                const bird = photo.boxes.find((box) => box.name === 'Bird');

                hud.score.text = bird ? `BIRD ${Math.round(bird.seen * 100)}%` : 'NO BIRD';
            });
        }
    });

    return createScene();
};
```

`settings.ts`:

```ts
export const WIDTH = 320;
export const HEIGHT = 180;
export const SHOT_W = 64;
export const SHOT_H = 48;
```
