# Split screen

> One level, two players, each with half of the screen: two views of the world, each following its player with its own parallax.

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

One level and two players, each with half of the screen. Each half is a view of the world in a rectangle of the screen (`createView`) with a camera that follows its own player: the level runs once, and each half draws it again with its own parallax. `useWorldOffScreen` has the screen draw only the two halves, so the world is not drawn a third time underneath.

Click the preview first so it hears the keyboard. Player 1: A and D walk, W jumps. Player 2: ← → walk, ↑ jumps.

## Code

`index.ts`:

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

const game = createGame('#app', {
    width: WIDTH,
    height: HEIGHT,
    background: '#0b0f18',
    step: 60
});

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

`components/half.ts`:

```ts
import { useCamera2d, useCameraFollow, useSpawn } from 'nacatamalon';
import type { TGameObject, TSprite, TTilemap } from 'nacatamalon';

import { Label } from './label';

export const Half = (who: TGameObject<TSprite>, map: TTilemap, name: string, tint: string) => {
    useCamera2d();
    useCameraFollow(who, {
        bounds: map
    });
    useSpawn(Label)(name, tint);
};
```

`components/hero.ts`:

```ts
import { createSprite, getColor, useKeyboard, useLoadTexture, useTileBody2d, useUpdate } from 'nacatamalon';
import type { TSprite } from 'nacatamalon';

import type { TControls } from '../settings';

export const Hero = (start: number, tint: string, controls: TControls): TSprite => {
    const sprite = createSprite({
        texture: useLoadTexture({
            src: '/example-assets/assets/platformer/hero.png'
        }),
        tint: getColor(tint),
        transform: {
            x: start,
            y: 250
        }
    });

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

    const keys = useKeyboard();

    useUpdate(() => {
        const walk = (keys.isDown(controls.right) ? 1 : 0) - (keys.isDown(controls.left) ? 1 : 0);

        body.velocity.x = walk * 110;

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

        if (keys.justPressed(controls.jump) && body.isOnGround) {
            body.velocity.y = -330;
        }

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

    return sprite;
};
```

`components/label.ts`:

```ts
import { createText, getColor, useScreenSpace } from 'nacatamalon';

export const Label = (text: string, tint: string) => {
    useScreenSpace();
    createText({
        text,
        tint: getColor(tint),
        transform: {
            x: 8,
            y: 8
        }
    });
};
```

`scenes/demo.ts`:

```ts
import { createBackdrop, createScene, createTilemap, createView, getColor, useLoadTexture, useSpawn, useWorldOffScreen } from 'nacatamalon';

import * as Settings from '../settings';
import { Hero } from '../components/hero';
import { Half } from '../components/half';

export const Level = () => {
    useWorldOffScreen();
    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
    });

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

    const p1 = useSpawn(Hero)(40, '#ffb0b0', {
        left: 'a',
        right: 'd',
        jump: 'w'
    });

    const p2 = useSpawn(Hero)(120, '#b0d0ff', {
        left: 'ArrowLeft',
        right: 'ArrowRight',
        jump: 'ArrowUp'
    });

    const sky = getColor('#9fd4ff');

    createView({
        x: 0,
        y: 0,
        ...Settings.HALF,
        background: sky
    }, Half, p1, map, 'P1  A D W', '#a03030');
    createView({
        x: Settings.WIDTH / 2 + 1,
        y: 0,
        ...Settings.HALF,
        background: sky
    }, Half, p2, map, 'P2  ← → ↑', '#30509f');

    return createScene();
};
```

`settings.ts`:

```ts
export const WIDTH = 480;
export const HEIGHT = 270;
export const HALF = {
    width: WIDTH / 2 - 1,
    height: HEIGHT
};

export type TControls = { left: string; right: string; jump: string };
```
