Scene switching powered by Redux!

This commit is contained in:
Hamcha 2020-09-29 11:31:55 +02:00
parent efb127dedd
commit 0b30af51c8
Signed by: hamcha
GPG key ID: 41467804B19A3315
11 changed files with 58 additions and 46 deletions

View file

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

View file

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

View file

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

View file

@ -1,6 +1,7 @@
import { combineReducers } from "@reduxjs/toolkit"; import { combineReducers } from "@reduxjs/toolkit";
import uiReducer from "./ui/reducer"; 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; export default reducer;

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;

View file

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

View file

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

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 { export default interface UIStore {
layers: LayerList; layers: LayerList;

View file

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

View file

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

View file

@ -1,12 +1,12 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useDispatch } from "react-redux"; import { useDispatch } from "react-redux";
import { UILayer } from "~ui/UI";
import { addLayer, removeLayer, showLayer, hideLayer } from "~store/ui/reducer"; import { addLayer, removeLayer, showLayer, hideLayer } from "~store/ui/reducer";
import { UILayer } from "~store/ui/state";
export default function useUILayer(data: UILayer, show: boolean) { export default function useUILayer(data: UILayer, show: boolean) {
const dispatch = useDispatch(); 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); const [visible, setVisible] = useState(show);
useEffect(() => { useEffect(() => {