Skip to content

Commit

Permalink
progress: state + test rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
Grzegorz Tańczyk committed Feb 10, 2024
1 parent 5322e31 commit 05a1c99
Show file tree
Hide file tree
Showing 8 changed files with 322 additions and 13 deletions.
2 changes: 2 additions & 0 deletions games/nukes/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { GameState } from './game-states/types';
import { GameStateIntro } from './game-states/state-intro';
import { GameStateTechMap } from './game-states/state-tech-map';
import { GameStateTechNuke } from './game-states/state-tech-nuke';
import { GameStateTechWorld } from './game-states/state-tech-world';

function App() {
return (
Expand All @@ -14,6 +15,7 @@ function App() {
<Route path={GameStateIntro.path} element={<GameStateRoute state={GameStateIntro} />} />
<Route path={GameStateTechMap.path} element={<GameStateRoute state={GameStateTechMap} />} />
<Route path={GameStateTechNuke.path} element={<GameStateRoute state={GameStateTechNuke} />} />
<Route path={GameStateTechWorld.path} element={<GameStateRoute state={GameStateTechWorld} />} />
</Routes>
</BrowserRouter>
</>
Expand Down
6 changes: 5 additions & 1 deletion games/nukes/src/game-states/state-intro.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { GameState, GameStateComponent } from './types';
import { GameStateTechMap } from './state-tech-map';
import { GameStateTechNuke } from './state-tech-nuke';
import { GameStateTechWorld } from './state-tech-world';

const Intro: GameStateComponent = ({ setGameState }) => {
return (
<>
intro
<h3>intro</h3>
<button onClick={() => setGameState(GameStateTechMap)}>Map tech demo</button>
<br />
<button onClick={() => setGameState(GameStateTechNuke)}>Nuke tech demo</button>
<br />
<button onClick={() => setGameState(GameStateTechWorld)}>Nuke world demo</button>
</>
);
};
Expand Down
193 changes: 193 additions & 0 deletions games/nukes/src/game-states/state-tech-world.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import { useCallback, useState } from 'react';
import { createWorldState } from '../world/world-state-create';
import { updateWorldState } from '../world/world-state-updates';
import { GameState, GameStateComponent } from './types';
import { City, Explosion, Missile, Sector, State, WorldState } from '../world/world-state-types';
import styled from 'styled-components';

const WorldComponent: GameStateComponent = ({ setGameState }) => {
const [worldState, setWorldState] = useState(() => createWorldState());
const updateWorld = useCallback(
(worldState: WorldState, deltaTime: number) => setWorldState(updateWorldState(worldState, deltaTime)),
[],
);

return (
<StateContainer>
<div className="meta-controls">
<div>Timestamp: {worldState.timestamp}</div>
<div>
<button onClick={() => updateWorld(worldState, 1)}>+1 Second</button>
<button onClick={() => updateWorld(worldState, 10)}>+10 Seconds</button>
<button onClick={() => updateWorld(worldState, 60)}>+60 seconds</button>
</div>
</div>
<WorldStateRender state={worldState} />
</StateContainer>
);
};

function WorldStateRender({ state }: { state: WorldState }) {
return (
<div className="world-render">
{state.sectors.map((sector) => (
<SectorRender key={sector.id} sector={sector} />
))}
{state.states.map((state) => (
<StateRender key={state.id} state={state} />
))}
{state.cities.map((city) => (
<CityRender key={city.id} city={city} />
))}
{state.missiles.map((missile) => (
<MissileRender key={missile.id} missile={missile} worldTimestamp={state.timestamp} />
))}
{state.explosions.map((explosion) => (
<ExplosionRender key={explosion.id} explosion={explosion} worldTimestamp={state.timestamp} />
))}
</div>
);
}

function StateRender({ state }: { state: State }) {
return <div className="state-render"></div>;
}

function CityRender({ city }: { city: City }) {
return <div className="city-render" style={{} as React.CSSProperties}></div>;
}

function MissileRender({ missile, worldTimestamp }: { missile: Missile; worldTimestamp: number }) {
const progress = Math.min(
Math.max(0, (worldTimestamp - missile.launchTimestamp) / (missile.targetTimestamp - missile.launchTimestamp)),
1,
);

const x = missile.launch.x + (missile.target.x - missile.launch.x) * progress;
const y = missile.launch.y + (missile.target.y - missile.launch.y) * progress;

return (
<div
className="missile-render"
style={
{
'--x': x,
'--y': y,
} as React.CSSProperties
}
></div>
);
}

function ExplosionRender({ explosion, worldTimestamp }: { explosion: Explosion; worldTimestamp: number }) {
if (explosion.startTimestamp > worldTimestamp || explosion.endTimestamp < worldTimestamp) {
return null;
}

const progress = Math.min(
Math.max(0, (worldTimestamp - explosion.startTimestamp) / (explosion.endTimestamp - explosion.startTimestamp)),
1,
);

return (
<div
className="explosion-render"
style={
{
'--x': explosion.position.x,
'--y': explosion.position.y,
'--radius': explosion.radius * progress,
} as React.CSSProperties
}
></div>
);
}

function SectorRender({ sector }: { sector: Sector }) {
return (
<div
className="sector-render"
data-sector-type={sector.type}
style={
{
'--x': sector.rect.left,
'--y': sector.rect.top,
'--width': sector.rect.right - sector.rect.left,
'--height': sector.rect.bottom - sector.rect.top,
} as React.CSSProperties
}
></div>
);
}

const StateContainer = styled.div`
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: black;
.meta-controls {
display: flex;
flex-grow: 0;
border: 1px solid rgb(0, 255, 0);
padding: 5px 10px;
text-align: left;
color: white;
z-index: 1;
}
.world-render {
display: flex;
flex-grow: 1;
background: black;
.state-render {
}
.sector-render {
transform: translate(calc(var(--x) * 1px), calc(var(--y) * 1px));
position: absolute;
width: calc(var(--width) * 1px);
height: calc(var(--height) * 1px);
&[data-sector-type='GROUND'] {
background: rgb(93, 42, 0);
}
&[data-sector-type='WATER'] {
background: rgb(0, 34, 93);
}
}
.missile-render {
transform: translate(calc(var(--x) * 1px), calc(var(--y) * 1px));
position: absolute;
width: 1px;
height: 1px;
background: rgb(0, 255, 0);
}
.explosion-render {
transform: translate(calc(var(--x) * 1px), calc(var(--y) * 1px)) translate(-50%, -50%);
position: absolute;
width: calc(var(--radius) * 1px);
height: calc(var(--radius) * 1px);
border-radius: 50%;
background: rgb(255, 255, 255);
}
}
`;

export const GameStateTechWorld: GameState = {
Component: WorldComponent,
path: '/tech-world',
};
3 changes: 3 additions & 0 deletions games/nukes/src/math/position-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function distance(ax: number, ay: number, bx: number, by: number) {
return Math.sqrt(Math.pow(bx - ax, 2) + Math.pow(by - ay, 2));
}
Empty file.
61 changes: 61 additions & 0 deletions games/nukes/src/world/world-state-create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { distance } from '../math/position-utils';
import { SectorType, WorldState } from './world-state-types';

export function createWorldState(): WorldState {
const result: WorldState = {
timestamp: 0,
states: [
{
id: 'test-state',
name: 'Test',
},
],
cities: [],
launchSites: [],
missiles: [
{
id: 'test-missile',
launch: { x: 100, y: 100 },
launchTimestamp: 0,
target: { x: 200, y: 200 },
targetTimestamp: 10,
},
],
explosions: [
{
id: 'test-explosion',
startTimestamp: 10,
endTimestamp: 15,
position: { x: 200, y: 200 },
radius: 30,
},
],
sectors: generateSectors(128, 50),
};

return result;
}

function generateSectors(sectorCount: number, sectorSize: number) {
const cols = Math.floor(Math.sqrt(sectorCount));
const rows = Math.floor(sectorCount / cols);

const centerColX = cols / 2;
const centerRowY = rows / 2;

return Array.from({ length: sectorCount }).map((v, i) => {
const x = i % cols;
const y = Math.floor(i / rows);

return {
id: 'test-sector-' + i,
type: distance(x, y, centerColX, centerRowY) <= centerColX ? SectorType.GROUND : SectorType.WATER,
rect: {
left: x * sectorSize,
top: y * sectorSize,
right: x * sectorSize + sectorSize,
bottom: y * sectorSize + sectorSize,
},
};
});
}
53 changes: 41 additions & 12 deletions games/nukes/src/world/world-state-types.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,70 @@
export type Position = { x: Number; y: Number; z: Number };
export type Position = { x: number; y: number };

export type Rect = { left: number; top: number; right: number; bottom: number };

export type StateId = string;

export type CityId = string;

export type MissileId = string;

export type SectorId = string;

export type ExplosionId = string;

export type State = {
id: string;
id: StateId;
name: string;
border: Position[];
};

export type City = {
id: string;
id: CityId;
stateId: StateId;
name: string;
position: Position;
size: Number;
};

export enum SectorType {
WATER = 'WATER',
GROUND = 'GROUND',
}

export type Sector = {
id: SectorId;
rect: Rect;
type: SectorType;
};

export type LaunchSite = {
position: Position;
stateId?: StateId;
};

export type Missile = {
startTimestamp: Number;
start: Position;
position: Position;
id: MissileId;
launch: Position;
launchTimestamp: number;

target: Position;
targetTimestamp: number;
};

export type Explosion = {
startTimestamp: Number;
id: ExplosionId;
startTimestamp: number;
endTimestamp: number;
position: Position;
radius: number;
};

export type WorldState = {
timestamp: Number;
timestamp: number;

states: State[];
cities: City[];
launchSites: LaunchSite[];

sectors: Sector[];

missiles: Missile[];
explosion: Explosion[];
explosions: Explosion[];
};
17 changes: 17 additions & 0 deletions games/nukes/src/world/world-state-updates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { WorldState, Missile } from './world-state-types';

export function updateWorldState(state: WorldState, deltaTime: number): WorldState {
const worldTimestamp = state.timestamp + deltaTime;

const result: WorldState = {
timestamp: worldTimestamp,
states: state.states,
cities: state.cities,
launchSites: state.launchSites,
missiles: state.missiles,
explosions: state.explosions,
sectors: state.sectors,
};

return result;
}

0 comments on commit 05a1c99

Please sign in to comment.