# Minimap

> The same level drawn again, whole and small, in the corner: a view of the world with a camera of its own. Click it and the hero goes there.

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

`createSpriteTexture({ sees: 'world' })` draws the world of its scene once more, through the camera its component asks for, without running it twice: a minimap of the whole level in the corner. The red marker is drawn by the minimap itself and is seen only there, and `hide` leaves out the far layers by their tag.

Click the minimap and the hero goes there: `viewToWorld` turns a point on the sprite showing a view into the world it sees.

Click the preview first so it hears the keyboard. ← → walk, Z or ↑ jump.

## Code

`index.ts`:

```ts
import { createGame, INPUT } from 'nacatamalon';
import { Level } from './scenes/level';
import { WIDTH, HEIGHT } from './settings';

// Arrows or A/D walk; Z, Space or Up jump. The same actions also read the gamepad.
const game = createGame('#app', {
    width: WIDTH,
    height: HEIGHT,
    background: '#9fd4ff',
    step: 60,
    actions: INPUT.ACTION_PRESETS.platformer
});

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

`components/backdrops.ts`:

```ts
import { createBackdrop, useLoadTexture } from 'nacatamalon';

// The far layers, tagged so the minimap can leave them out.
export const Backdrops = () => {
    createBackdrop({
        texture: useLoadTexture({
            src: '/example-assets/assets/platformer/clouds.png'
        }),
        parallax: {
            x: 0.1,
            y: 0.1
        },
        y: 30
    });
    createBackdrop({
        texture: useLoadTexture({
            src: '/example-assets/assets/platformer/hills.png'
        }),
        parallax: {
            x: 0.4,
            y: 0.4
        },
        y: 150
    });
};
```

`components/hero.ts`:

```ts
import { createSprite, useActions, useLoadTexture, useTileBody2d, useUpdate } from 'nacatamalon';
import type { TSprite, TCharacterBody2d } from 'nacatamalon';
import { START } from '../settings';

export type THero = {
    sprite: TSprite;
    body: TCharacterBody2d
};

export const Hero = (): THero => {
    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]
    });

    const input = useActions();

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

        body.velocity.x = walk * 110;

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

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

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

    return {
        sprite,
        body
    };
};
```

`components/hud.ts`:

```ts
import { createSprite, createText, createView, usePointer, useScreenSpace, viewToWorld } from 'nacatamalon';
import type { TGameObject } from 'nacatamalon';
import type { THero } from './hero';
import { Minimap } from './minimap';
import { MINI, WIDTH } from '../settings';

export const Hud = (hero: TGameObject<THero>) => {
    useScreenSpace();
    createSprite({
        width: MINI.width * 2 + 4,
        height: MINI.height * 2 + 4,
        tint: '#0b0f18',
        anchor: {
            x: 1,
            y: 0
        },
        transform: {
            x: WIDTH - 6,
            y: 6
        }
    });

    const shown = createView({
        x: WIDTH - 8 - MINI.width * 2,
        y: 8,
        width: MINI.width,
        height: MINI.height,
        hide: {
            tags: ['far']
        },
        background: '#9fd4ff'
    }, Minimap, hero);

    // Keep the original pixel grid, displayed twice as large.
    shown.width = MINI.width * 2;
    shown.height = MINI.height * 2;

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

    usePointer().onDown((info) => {
        const at = viewToWorld(shown, info);

        if (at.inside) {
            hero.api.body.setPosition(at.x, Math.min(at.y, 250));
            hero.api.body.velocity.y = 0;
        }
    });
};
```

`components/minimap.ts`:

```ts
import { createSprite, useCamera2d, useUpdate } from 'nacatamalon';
import type { TGameObject } from 'nacatamalon';
import type { THero } from './hero';
import { MINI, LEVEL } from '../settings';

// What the minimap draws itself: its camera over the whole level, and a marker on the hero that
// only the minimap shows.
export const Minimap = (hero: TGameObject<THero>) => {
    useCamera2d({
        zoom: MINI.width / LEVEL.width
    });

    const you = createSprite({
        width: 40,
        height: 40,
        tint: '#ff3b5c'
    });

    useUpdate(() => {
        you.transform.x = hero.api.sprite.transform.x;
        you.transform.y = hero.api.sprite.transform.y;
    });
};
```

`scenes/level.ts`:

```ts
import { createScene, createTilemap, useCamera2d, useCameraFollow, useSpawn } from 'nacatamalon';
import { Backdrops } from '../components/backdrops';
import { Hero } from '../components/hero';
import { Hud } from '../components/hud';
import { ZOOM } from '../settings';

export const Level = () => {
    useCamera2d({
        zoom: ZOOM
    });
    useSpawn(Backdrops, {
        tags: ['far']
    })();

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

    const hero = useSpawn(Hero)();

    useCameraFollow(hero, {
        bounds: map
    });

    useSpawn(Hud)(hero);

    return createScene();
};
```

`settings.ts`:

```ts
export const ZOOM = 2;
export const WIDTH = 216 * ZOOM;
export const HEIGHT = 160 * ZOOM;
export const START = {
    x: 40,
    y: 250
};
export const LEVEL = {
    width: 1440,
    height: 320
};
// The whole level at a tenth, drawn twice as big to be seen.
export const MINI = {
    width: 144,
    height: 32
};
```
