game state separated from world state
This commit is contained in:
parent
b3c7979f87
commit
c52458391d
|
|
@ -1,24 +1,12 @@
|
|||
import { useLayoutEffect, useRef } from 'react';
|
||||
import { useRef } from 'react';
|
||||
import type React from 'react';
|
||||
import { useThree } from '@react-three/fiber';
|
||||
import { Grid, OrbitControls } from '@react-three/drei';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { state } from '../state';
|
||||
import { SceneView } from './SceneView';
|
||||
import type { Pos3 } from '../types/3d';
|
||||
import { type OrthographicCamera, type PerspectiveCamera } from 'three';
|
||||
import { CameraSync } from './tools/CameraSync';
|
||||
|
||||
const CameraSync = observer(function ({ camera }: { camera: Pos3 }) {
|
||||
const { camera: threeCamera } = useThree();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
threeCamera.position.set(camera.position[0], camera.position[1], camera.position[2]);
|
||||
threeCamera.rotation.set(camera.look[0], camera.look[1], camera.look[2]);
|
||||
threeCamera.updateProjectionMatrix();
|
||||
});
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
export const SceneEditorView = observer(function () {
|
||||
const controlsRef = useRef<React.ComponentRef<typeof OrbitControls>>(null);
|
||||
|
|
|
|||
|
|
@ -49,14 +49,14 @@ export const ThreeView = observer(function () {
|
|||
{
|
||||
state.game
|
||||
? <>
|
||||
<button onClick={() => state.game!.stop()}><IconStop /></button>
|
||||
<button onClick={() => state.stopGame()}><IconStop /></button>
|
||||
{
|
||||
state.game!.isPaused
|
||||
? <button onClick={() => state.game!.resume()}><IconPlay /></button>
|
||||
: <button onClick={() => state.game!.pause()}><IconPause /></button>
|
||||
}
|
||||
</>
|
||||
: <button onClick={() => state.world.play()}><IconPlay /></button>
|
||||
: <button onClick={() => state.startGame()}><IconPlay /></button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
import { useThree } from "@react-three/fiber";
|
||||
import type { Pos3 } from "../../types/3d";
|
||||
import { useLayoutEffect } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
export const CameraSync = observer(function ({ camera }: { camera: Pos3 }) {
|
||||
const { camera: threeCamera } = useThree();
|
||||
|
||||
useLayoutEffect(() => {
|
||||
threeCamera.position.set(camera.position[0], camera.position[1], camera.position[2]);
|
||||
threeCamera.rotation.set(camera.look[0], camera.look[1], camera.look[2]);
|
||||
threeCamera.updateProjectionMatrix();
|
||||
});
|
||||
|
||||
return null;
|
||||
});
|
||||
|
|
@ -14,9 +14,6 @@ export class WorldFactory {
|
|||
},
|
||||
objects: {},
|
||||
},
|
||||
state: {
|
||||
playing: false,
|
||||
},
|
||||
gameRules: {
|
||||
gravity: true,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,27 +1,33 @@
|
|||
import { makeAutoObservable } from "mobx";
|
||||
import { makeAutoObservable, toJS } from "mobx";
|
||||
import type { WorldState } from "./worldState";
|
||||
import type { RunningGameState, Scene } from "../types";
|
||||
import type { Game, Scene } from "../types";
|
||||
import type { Pos3 } from "../types/3d";
|
||||
import type { CameraProps } from "@react-three/fiber";
|
||||
import { clone } from "../utils";
|
||||
import { state } from "./rootState";
|
||||
|
||||
export class GameState {
|
||||
private readonly world: WorldState;
|
||||
|
||||
public readonly data: Game;
|
||||
|
||||
constructor(world: WorldState) {
|
||||
this.world = world;
|
||||
this.data = {
|
||||
paused: false,
|
||||
time: 0,
|
||||
scene: clone(toJS(this.world.data.initialScene)),
|
||||
};
|
||||
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
public get state(): RunningGameState {
|
||||
return this.world.data.state as RunningGameState;
|
||||
}
|
||||
|
||||
public get isPaused(): boolean {
|
||||
return this.state.paused;
|
||||
return this.data.paused;
|
||||
}
|
||||
|
||||
public get scene(): Scene {
|
||||
return this.state.scene;
|
||||
return this.data.scene;
|
||||
}
|
||||
|
||||
public get camera(): Pos3 {
|
||||
|
|
@ -38,18 +44,17 @@ export class GameState {
|
|||
}
|
||||
|
||||
public resume(): void {
|
||||
this.state.paused = false;
|
||||
this.data.paused = false;
|
||||
}
|
||||
|
||||
public pause(): void {
|
||||
this.state.paused = true;
|
||||
this.data.paused = true;
|
||||
}
|
||||
|
||||
public stop(): void {
|
||||
this.world.data.state = { playing: false };
|
||||
}
|
||||
public tick(deltaTime: number): void {
|
||||
if (this.isPaused)
|
||||
return;
|
||||
|
||||
public tick(_deltaTime: number): void {
|
||||
//TODO
|
||||
this.data.time += deltaTime;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import { GameState } from "./gameState";
|
|||
export class RootState {
|
||||
public readonly world = new WorldState();
|
||||
public readonly worldEditor: WorldEditorState;
|
||||
public game: GameState | undefined;
|
||||
|
||||
constructor() {
|
||||
this.worldEditor = new WorldEditorState(this.world);
|
||||
|
|
@ -19,12 +20,22 @@ export class RootState {
|
|||
}
|
||||
|
||||
public get isGamePlaying(): boolean {
|
||||
return this.world.data.state.playing;
|
||||
return this.game !== undefined;
|
||||
}
|
||||
|
||||
public get game(): GameState | undefined {
|
||||
if (this.isGamePlaying)
|
||||
return new GameState(this.world);
|
||||
public startGame(): void {
|
||||
if (this.game)
|
||||
this.stopGame();
|
||||
this.game = new GameState(this.world),
|
||||
state.worldEditor.resetSelectedObject();
|
||||
}
|
||||
|
||||
public stopGame(): void {
|
||||
if (!this.game)
|
||||
return;
|
||||
|
||||
this.game.pause();
|
||||
this.game = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,9 +74,6 @@ export class WorldState {
|
|||
gameRules: {
|
||||
gravity: true,
|
||||
},
|
||||
state: {
|
||||
playing: false,
|
||||
},
|
||||
};
|
||||
console.log(objects);
|
||||
state.worldEditor.resetSelectedObject();
|
||||
|
|
@ -109,18 +106,4 @@ export class WorldState {
|
|||
public getVoxelTypeById(id: string): VoxelType | undefined {
|
||||
return this.data.voxelTypes[id];
|
||||
}
|
||||
|
||||
public play(): void {
|
||||
if (state.game)
|
||||
state.game.resume();
|
||||
else {
|
||||
this.data.state = {
|
||||
playing: true,
|
||||
paused: false,
|
||||
time: 0,
|
||||
scene: clone(this.data.initialScene),
|
||||
}
|
||||
state.worldEditor.resetSelectedObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
import type { Scene } from "./scene";
|
||||
|
||||
export type Game = {
|
||||
paused: boolean;
|
||||
time: number;
|
||||
scene: Scene;
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
import type { Scene } from "./scene";
|
||||
|
||||
export type StoppedGameState = {
|
||||
playing: false;
|
||||
}
|
||||
|
||||
export type RunningGameState = {
|
||||
playing: true;
|
||||
paused: boolean;
|
||||
time: number;
|
||||
scene: Scene;
|
||||
}
|
||||
|
||||
export type GameState = StoppedGameState | RunningGameState;
|
||||
|
|
@ -2,7 +2,7 @@ export * from './object';
|
|||
export * from './scene';
|
||||
export * from './world';
|
||||
export * from './gameRules';
|
||||
export * from './gameState';
|
||||
export * from './game';
|
||||
export * from './character';
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import type { GameRules } from "./gameRules";
|
||||
import type { GameState } from "./gameState";
|
||||
import type { ObjectType } from "./object";
|
||||
import type { Scene } from "./scene";
|
||||
import type { Pos3 } from "./3d";
|
||||
|
|
@ -11,5 +10,4 @@ export type World = {
|
|||
editorCamera: Pos3;
|
||||
initialScene: Scene;
|
||||
gameRules: GameRules;
|
||||
state: GameState;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue