Skip to content

Commit

Permalink
Merge pull request #89 from bananu7/player-spawn-locations
Browse files Browse the repository at this point in the history
Player spawn locations
  • Loading branch information
bananu7 committed Jun 25, 2024
2 parents 5d40d2e + d0c3155 commit e65b451
Show file tree
Hide file tree
Showing 14 changed files with 294 additions and 179 deletions.
22 changes: 22 additions & 0 deletions packages/client/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,30 @@ function App() {
if (!username)
return;

let abort = false;

const setupMultiplayer = async () => {
console.log("[App] Setup multiplayer start");
const multiplayer = await Multiplayer.new(username);

if (abort) {
console.log("[App] Setup multiplayer aborted");
return;
}

setMultiplayer(multiplayer);
const rejoinedCtrl = await multiplayer.setup({});

if (abort) {
console.log("[App] Setup multiplayer aborted");
return;
}

if (rejoinedCtrl) {
rejoinedCtrl.setOnLeaveMatch(cleanupOnLeave);
setController(rejoinedCtrl);
}
console.log("[App] Setup multiplayer end");
}

setupMultiplayer()
Expand All @@ -57,6 +72,13 @@ function App() {
fetch(HTTP_API_URL + '/version')
.then(res => res.text())
.then(res => console.log("[App] Server version: " + res));

return () => {
if (multiplayer)
multiplayer.disconnect();
abort = true;
setController(null);
}
}, []);

const joinMatch = async (matchId: string) => {
Expand Down
5 changes: 5 additions & 0 deletions packages/client/src/Multiplayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ export class Multiplayer {
});
}

public disconnect() {
console.log(`[Multiplayer] disconnecting channel`)
this.channel.close();
}

async createMatch(): Promise<MatchCreateResponse> {
const response = await fetch(HTTP_API_URL+'/create', {
method: 'POST',
Expand Down
6 changes: 5 additions & 1 deletion packages/client/src/components/MatchController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,11 @@ export function MatchController(props: MatchControllerProps) {
resources={lastUpdatePacket.player.resources}
units={lastUpdatePacket.units.filter(u => u.owner === props.ctrl.getPlayerIndex()).length}
/>
<View3D viewX={matchMetadata.board.map.w} viewY={matchMetadata.board.map.h} >
<View3D
startPosition={matchMetadata.board.playerStartLocations[props.ctrl.getPlayerIndex()-1]}
viewX={matchMetadata.board.map.w}
viewY={matchMetadata.board.map.h}
>
<Board3D
board={matchMetadata.board}
playerIndex={props.ctrl.getPlayerIndex()}
Expand Down
6 changes: 5 additions & 1 deletion packages/client/src/components/SpectateController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,11 @@ export function SpectateController(props: SpectateControllerProps) {
resources={lastUpdatePacket.player.resources}
units={0} // TODO -spectator doesn't receive data about both players
/>
<View3D viewX={matchMetadata.board.map.w} viewY={matchMetadata.board.map.h} >
<View3D
startPosition={matchMetadata.board.playerStartLocations[0]}
viewX={matchMetadata.board.map.w}
viewY={matchMetadata.board.map.h}
>
<Board3D
board={matchMetadata.board}
playerIndex={0} // TODO - spectator has no player index
Expand Down
78 changes: 78 additions & 0 deletions packages/client/src/gfx/MapSpotlight.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { extend, useThree, useFrame } from '@react-three/fiber'
import { useRef, useEffect } from 'react'
import * as THREE from 'three';

import { debugFlags } from '../debug/flags'

export type MapSpotlightProps = {
target: THREE.Vector3,
}

export function MapSpotlight(props: MapSpotlightProps) {
const lightRef = useRef<THREE.SpotLight>(null);
if (debugFlags.showLightConeHelper)
useShadowHelper(lightRef);

const { scene } = useThree();

useEffect(() => {
if (!lightRef.current) return;

const target = new THREE.Object3D();
target.position.copy(props.target);
scene.add(target);

lightRef.current.target = target;
}, [lightRef]);

// TODO spotlight setting to allow time of day
return (
<group>
<spotLight
ref={lightRef}
position={[400, 180, 90]}
angle={0.16}
distance={0}
decay={0}
intensity={4}
color={0xffffff}

castShadow
shadow-camera-near={300}
shadow-camera-far={500}
shadow-mapSize-height={1024}
shadow-mapSize-width={1024}
shadow-bias={-0.002}
/>
</group>
)
}


export default function useShadowHelper(
ref: React.RefObject<THREE.Light | undefined>
) {
const helper = useRef<THREE.CameraHelper>();
const scene = useThree((state) => state.scene);

useEffect(() => {
if (!ref.current) return;

helper.current = new THREE.CameraHelper(ref.current?.shadow.camera);
if (helper.current) {
scene.add(helper.current);
}

return () => {
if (helper.current) {
scene.remove(helper.current);
}
};
}, [helper.current?.uuid, ref.current]);

useFrame(() => {
if (helper.current?.update) {
helper.current.update();
}
});
}
109 changes: 28 additions & 81 deletions packages/client/src/gfx/View3D.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { ReactThreeFiber, Canvas, extend, useThree, useFrame } from '@react-three/fiber'
import { Suspense, useRef, useEffect, useLayoutEffect, useState, CSSProperties } from 'react'
import { debugFlags } from '../debug/flags'

import * as THREE from 'three';

import { MapSpotlight } from './MapSpotlight'
import { MapControls } from './MapControls'
import { Stats } from './Stats'

import { Position} from '@bananu7-rts/server/src/types'

type CameraControlsProps = {
minPan: THREE.Vector3,
maxPan: THREE.Vector3,
startTarget: THREE.Vector3,
}
function CameraControls(props: CameraControlsProps) {
const { camera, gl: { domElement }, scene } = useThree();
Expand All @@ -29,7 +30,7 @@ function CameraControls(props: CameraControlsProps) {

c.enableRotate = false;

c.target = new THREE.Vector3(50, 0, 50);
c.target = props.startTarget;
c.update();

return () => {
Expand All @@ -40,85 +41,17 @@ function CameraControls(props: CameraControlsProps) {
return null;
};

export default function useShadowHelper(
ref: React.RefObject<THREE.Light | undefined>
) {
const helper = useRef<THREE.CameraHelper>();
const scene = useThree((state) => state.scene);

useEffect(() => {
if (!ref.current) return;

helper.current = new THREE.CameraHelper(ref.current?.shadow.camera);
if (helper.current) {
scene.add(helper.current);
}

return () => {
if (helper.current) {
scene.remove(helper.current);
}
};
}, [helper.current?.uuid, ref.current]);

useFrame(() => {
if (helper.current?.update) {
helper.current.update();
}
});
}

function MapSpotlight() {
const lightRef = useRef<THREE.SpotLight>(null);
// uncomment to enable
if (debugFlags.showLightConeHelper)
useShadowHelper(lightRef);

const { scene } = useThree();

useEffect(() => {
if (!lightRef.current) return;
export type Props = {
children: JSX.Element | JSX.Element[],
onPointerMissed?: () => void,

const target = new THREE.Object3D();
target.position.set(50, 0, 50);
scene.add(target);lightRef

lightRef.current.target = target;
}, [lightRef]);

// TODO spotlight setting to allow time of day
return (
<group>
<spotLight
ref={lightRef}
position={[400, 180, 90]}
angle={0.16}
distance={0}
decay={0}
intensity={4}
color={0xffffff}

castShadow
shadow-camera-near={300}
shadow-camera-far={500}
shadow-mapSize-height={1024}
shadow-mapSize-width={1024}
shadow-bias={-0.002}
/>
</group>
)
}


export interface Props {
children: JSX.Element | JSX.Element[];
onPointerMissed?: () => void;

enablePan?: boolean;
enablePan?: boolean,

startPosition: Position,
// map size
viewX: number;
viewY: number;
viewX: number,
viewY: number,
}

export function View3D(props: Props) {
Expand All @@ -135,12 +68,26 @@ export function View3D(props: Props) {
const border = 15.0;
const minPan = new THREE.Vector3(border, 0, border);
const maxPan = new THREE.Vector3(props.viewX - border, 10, props.viewY - border);
const startTarget = new THREE.Vector3(props.startPosition.x, 0, props.startPosition.y);
// TODO specify that as angles
const startCameraPosition = new THREE.Vector3();
startCameraPosition.copy(startTarget);
startCameraPosition.y += 60;
startCameraPosition.z += 40;
const middleOfTheMap = new THREE.Vector3(props.viewX/2, 0, props.viewY/2);

return (
<Suspense fallback={null}>
<div style={style} >
<Canvas
camera={{ fov: 27.8, near: 10, far: 500, up:[0,1,0], position: [50, 60, 90] }}
camera={{
fov: 27.8,
near: 10,
far: 500,
up:[0,1,0],

position: startCameraPosition,
}}
gl={{
physicallyCorrectLights: true,
pixelRatio: window.devicePixelRatio,
Expand All @@ -152,9 +99,9 @@ export function View3D(props: Props) {
dpr={1}
>
<color attach="background" args={[0x11aa11]} />
<CameraControls minPan={minPan} maxPan={maxPan} />
<CameraControls minPan={minPan} maxPan={maxPan} startTarget={startTarget} />
<ambientLight args={[0xffffff, 2]} />
<MapSpotlight />
<MapSpotlight target={middleOfTheMap}/>
{props.children}
<Stats />
</Canvas>
Expand Down
29 changes: 28 additions & 1 deletion packages/server/assets/echo_peninsula.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,32 @@
"w": 300,
"h": 150,
"symmetry": "mirror_x",
"imagePath": "echo.png"
"imagePath": "echo.png",
"playerStartLocations": [
{
"x": 20,
"y": 10
},
{
"x": 280,
"y": 10
}
],
"neutralSpawns": [
{"kind":"ResourceNode", "position": {"x": 6, "y": 6}},
{"kind":"ResourceNode", "position": {"x": 6, "y": 10}},
{"kind":"ResourceNode", "position": {"x": 6, "y": 14}},

{"kind":"ResourceNode", "position": {"x": 294, "y": 6}},
{"kind":"ResourceNode", "position": {"x": 294, "y": 10}},
{"kind":"ResourceNode", "position": {"x": 294, "y": 14}},

{"kind":"ResourceNode", "position": {"x": 84, "y": 140}},
{"kind":"ResourceNode", "position": {"x": 88, "y": 140}},
{"kind":"ResourceNode", "position": {"x": 92, "y": 140}},

{"kind":"ResourceNode", "position": {"x": 208, "y": 140}},
{"kind":"ResourceNode", "position": {"x": 212, "y": 140}},
{"kind":"ResourceNode", "position": {"x": 216, "y": 140}}
]
}
29 changes: 28 additions & 1 deletion packages/server/assets/map_test_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,32 @@
"w": 99,
"h": 99,
"symmetry": "none",
"imagePath": "map.png"
"imagePath": "map.png",
"playerStartLocations": [
{
"x": 30,
"y": 10
},
{
"x": 80,
"y": 85
}
],
"neutralSpawns": [
{"kind":"ResourceNode", "position": {"x": 6, "y": 6}},
{"kind":"ResourceNode", "position": {"x": 6, "y": 10}},
{"kind":"ResourceNode", "position": {"x": 6, "y": 14}},

{"kind":"ResourceNode", "position": {"x": 90, "y": 88}},
{"kind":"ResourceNode", "position": {"x": 90, "y": 84}},
{"kind":"ResourceNode", "position": {"x": 90, "y": 80}},

{"kind":"ResourceNode", "position": {"x": 6, "y": 50}},
{"kind":"ResourceNode", "position": {"x": 6, "y": 54}},
{"kind":"ResourceNode", "position": {"x": 6, "y": 58}},

{"kind":"ResourceNode", "position": {"x": 86, "y": 40}},
{"kind":"ResourceNode", "position": {"x": 86, "y": 44}},
{"kind":"ResourceNode", "position": {"x": 86, "y": 48}}
]
}
Loading

0 comments on commit e65b451

Please sign in to comment.