Browse Source

Scene switching powered by Redux!

master
Hamcha 6 months ago
parent
commit
0b30af51c8
Signed by: Hamcha GPG Key ID: 41467804B19A3315
11 changed files with 58 additions and 46 deletions
  1. +11
    -27
      src/game/scenes/Game.tsx
  2. +5
    -0
      src/game/scenes/MapEditor.tsx
  3. +2
    -2
      src/index.tsx
  4. +2
    -1
      src/store/reducer.ts
  5. +17
    -0
      src/store/scene/reducer.ts
  6. +2
    -0
      src/store/state.ts
  7. +4
    -4
      src/store/ui/reducer.ts
  8. +5
    -1
      src/store/ui/state.ts
  9. +1
    -1
      src/ui/MapEditor.tsx
  10. +7
    -8
      src/ui/UI.tsx
  11. +2
    -2
      src/ui/utils/useLayer.ts

+ 11
- 27
src/game/scenes/Game.tsx View File

@ -1,32 +1,16 @@
import React, { Fragment } from "react";
import useLoader from "~game/lib/Loader";
import InGameSpaceBG from "./backgrounds/InGameSpaceBG";
// Resources, this will make TS go crazy!
//@ts-expect-error Image resource
import NoiseSpaceFine from "~/../assets/images/noise/space_fine.png";
//@ts-expect-error Image resource
import NoiseSpaceSparse from "~/../assets/images/noise/space_sparse.png";
import { useSelector } from "react-redux";
import { SceneStore } from "~store/scene/reducer";
import { GameStore } from "~store/state";
import MapEditor from "~game/scenes/MapEditor";
export default function Game() {
const { loaded, resources } = useLoader({
bg_fine: NoiseSpaceFine,
bg_sparse: NoiseSpaceSparse,
});
if (!loaded) {
return <Fragment></Fragment>;
const scene = useSelector<GameStore, SceneStore>((state) => state.scene);
switch (scene.type) {
case "MapEditor":
return <MapEditor />;
default:
// Bad case, should have something to show just in case!
return <Fragment></Fragment>;
}
return (
<Fragment>
<InGameSpaceBG
textures={{
noise_fine: resources.bg_fine,
noise_sparse: resources.bg_sparse,
}}
/>
</Fragment>
);
}

+ 5
- 0
src/game/scenes/MapEditor.tsx View File

@ -11,6 +11,11 @@ import NoiseSpaceSparse from "~/../assets/images/noise/space_sparse.png";
import LoadingScreen from "./LoadingScreen";
import useUILayer from "~ui/utils/useLayer";
// Scene switcher entry
export interface MapEditorScene {
type: "MapEditor";
}
export default function MapEditor() {
const { loaded, resources } = useLoader({
bg_fine: NoiseSpaceFine,


+ 2
- 2
src/index.tsx View File

@ -6,7 +6,7 @@ import { Stage } from "@inlet/react-pixi";
import { configureStore } from "@reduxjs/toolkit";
import UI from "~ui/UI";
import reducer from "~store/reducer";
import MapEditor from "~game/scenes/MapEditor";
import Game from "~game/scenes/Game";
PIXI.settings.SCALE_MODE = PIXI.SCALE_MODES.NEAREST;
@ -23,7 +23,7 @@ ReactDOM.render(
<React.Fragment>
<Stage options={{ resolution: 1, resizeTo: window }} onMount={mounted}>
<Provider store={store}>
<MapEditor />
<Game />
</Provider>
</Stage>
<Provider store={store}>


+ 2
- 1
src/store/reducer.ts View File

@ -1,6 +1,7 @@
import { combineReducers } from "@reduxjs/toolkit";
import uiReducer from "./ui/reducer";
import sceneReducer from "./scene/reducer";
const reducer = combineReducers({ ui: uiReducer });
const reducer = combineReducers({ ui: uiReducer, scene: sceneReducer });
export default reducer;

+ 17
- 0
src/store/scene/reducer.ts View File

@ -0,0 +1,17 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { MapEditorScene } from "~game/scenes/MapEditor";
export type SceneStore = MapEditorScene;
const initialState: SceneStore = {
type: "MapEditor",
};
const sceneSlice = createSlice({
name: "scene",
initialState,
reducers: {},
});
export const {} = sceneSlice.actions;
export default sceneSlice.reducer;

+ 2
- 0
src/store/state.ts View File

@ -1,5 +1,7 @@
import { SceneStore } from "./scene/reducer";
import UIStore from "./ui/state";
export interface GameStore {
ui: UIStore;
scene: SceneStore;
}

+ 4
- 4
src/store/ui/reducer.ts View File

@ -1,6 +1,5 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { UILayer } from "~ui/UI";
import UIStore from "./state";
import UIStore, { UILayer } from "./state";
const initialState: UIStore = {
layers: [],
@ -38,7 +37,8 @@ const uiSlice = createSlice({
if (index < 0) {
return;
}
state.layers[index].visible = true;
state.layers[index] = { ...state.layers[index], visible: true };
},
hideLayer(state, action: PayloadAction<LayerActionPayload>) {
const index = state.layers.findIndex(
@ -47,7 +47,7 @@ const uiSlice = createSlice({
if (index < 0) {
return;
}
state.layers[index].visible = false;
state.layers[index] = { ...state.layers[index], visible: false };
},
},
});


+ 5
- 1
src/store/ui/state.ts View File

@ -1,4 +1,8 @@
import { LayerList } from "~ui/UI";
import { MapEditorLayer } from "~ui/MapEditor";
export type UILayer = MapEditorLayer;
export type LayerList = { id: string; data: UILayer; visible: boolean }[];
export default interface UIStore {
layers: LayerList;


+ 1
- 1
src/ui/MapEditor.tsx View File

@ -4,7 +4,7 @@ export interface MapEditorLayer {
type: "MapEditor";
}
export default function MapEditor() {
export default function MapEditorUI() {
return (
<div>
<p>HEY HEY</p>


+ 7
- 8
src/ui/UI.tsx View File

@ -1,16 +1,13 @@
import React from "react";
import { useSelector } from "react-redux";
import { GameStore } from "~store/state";
import MapEditor, { MapEditorLayer } from "./MapEditor";
export type UILayer = MapEditorLayer;
export type LayerList = { id: string; data: UILayer; visible: boolean }[];
import { UILayer, LayerList } from "~store/ui/state";
import MapEditorUI from "./MapEditor";
function renderLayer(data: UILayer) {
switch (data.type) {
case "MapEditor":
return <MapEditor />;
return <MapEditorUI />;
default:
throw new Error("unknown or invalid ui layer");
}
@ -20,8 +17,10 @@ export default function UI() {
const layers = useSelector<GameStore, LayerList>((state) => state.ui.layers);
return (
<div id="ui">
{layers.map(({ id, data }) => (
<div key={id}>{renderLayer(data)}</div>
{layers.map(({ id, data, visible }) => (
<div key={id} style={{ display: visible ? "" : "none" }}>
{renderLayer(data)}
</div>
))}
</div>
);


+ 2
- 2
src/ui/utils/useLayer.ts View File

@ -1,12 +1,12 @@
import { useEffect, useState } from "react";
import { useDispatch } from "react-redux";
import { UILayer } from "~ui/UI";
import { addLayer, removeLayer, showLayer, hideLayer } from "~store/ui/reducer";
import { UILayer } from "~store/ui/state";
export default function useUILayer(data: UILayer, show: boolean) {
const dispatch = useDispatch();
const id = data.type + "-" + Math.random().toString(32).slice(2);
const [id] = useState(data.type + "-" + Math.random().toString(32).slice(2));
const [visible, setVisible] = useState(show);
useEffect(() => {