diff --git a/src/signal.ts b/src/signal.ts new file mode 100644 index 0000000..d626669 --- /dev/null +++ b/src/signal.ts @@ -0,0 +1,13 @@ +export type SignalSubscriber = (props?: any) => void; + +export default class SignalBus { + subscribers: SignalSubscriber[] = []; + + emit(props?: any) { + this.subscribers.forEach((item) => item(props)); + } + + subscribe(callback: SignalSubscriber) { + this.subscribers.push(callback); + } +} diff --git a/src/stage/index.tsx b/src/stage/index.tsx index dedd652..d60db4c 100644 --- a/src/stage/index.tsx +++ b/src/stage/index.tsx @@ -1,10 +1,10 @@ import { styled } from "solid-styled-components"; import { Show, createSignal, onMount } from "solid-js"; import { vector2d } from "./vector"; +import SignalBus from "../signal"; import Player from "./objects/player"; import Crystal from "./objects/crystal"; -import Attacker from "./objects/enemies/attacker"; import TimerProvider from "./providers/timer"; import CooldownProvider from "./providers/cooldown"; import CooldownUI from "./ui/cooldown"; @@ -12,6 +12,7 @@ import CooldownUI from "./ui/cooldown"; import "./objects/common.css"; import OverviewProvider from "./providers/overview"; import OverviewUI from "./ui/overview"; +import SpawnFarm, { EnemiesTemplates } from "./objects/spawn-farm"; const StageContainer = styled("div")` width: 100vw; @@ -25,32 +26,20 @@ const StageContainer = styled("div")` export default function Stage() { let container: HTMLDivElement = document.createElement("div"); + let stageSize = new vector2d(0, 0); let centerPosition = new vector2d(0, 0); let playerPosition = new vector2d(0, 0); - let randomPosition = new vector2d(0, 0); - let [ready, setReady] = createSignal(false); - function calcRandomPosition(maxX: number, maxY: number) { - return new vector2d( - Math.floor(Math.random() * maxX), - Math.floor(Math.random() * maxY) - ); - } + const enemiesSpawnSignal = new SignalBus(); function initializeStage(element: HTMLDivElement) { - centerPosition = new vector2d( - element.clientWidth / 2, - element.clientHeight / 2 - ); + stageSize = new vector2d(element.clientWidth, element.clientHeight); + centerPosition = new vector2d(stageSize.x / 2, stageSize.y / 2); playerPosition = centerPosition.clone(); - randomPosition = calcRandomPosition( - element.clientWidth, - element.clientHeight - ); - console.log("example pos:", randomPosition); + setInterval(() => enemiesSpawnSignal.emit(), 1000) setReady(true); } @@ -67,7 +56,13 @@ export default function Stage() { - + {/* Object Sets */} + {/* UI Elements */} diff --git a/src/stage/objects/enemies/attacker.tsx b/src/stage/objects/enemies/attacker.tsx index d758260..f95a070 100644 --- a/src/stage/objects/enemies/attacker.tsx +++ b/src/stage/objects/enemies/attacker.tsx @@ -10,8 +10,8 @@ export default function Attacker(props: { damage?: number; position?: vector2d; }) { - const width = props.size ? props.size / 6 : 2; - const height = props.size ?? 20; + const width = props.size ? props.size / 6 : 5; + const height = props.size ?? 32; // Just some random comment // https://youtube.com/ishowspeed diff --git a/src/stage/objects/spawn-farm.tsx b/src/stage/objects/spawn-farm.tsx new file mode 100644 index 0000000..cb0f0b7 --- /dev/null +++ b/src/stage/objects/spawn-farm.tsx @@ -0,0 +1,67 @@ +import { createSignal, type Component, JSX, For, createMemo } from "solid-js"; +import { vector2d } from "../vector"; +import SignalBus from "../../signal"; + +import Attacker from "./enemies/attacker"; +import { TimerContext, useTimer } from "../providers/timer"; + +export const EnemiesTemplates = [ + { element: Attacker, weight: 10 }, + { element: Attacker, weight: 10 }, +]; + +export default function SpawnFarm({ + templates, + signal, + borderX, + borderY, +}: { + templates: { element: Component; weight: number }[]; + signal: SignalBus; + borderX: number; + borderY: number; +}) { + const [objects, setObjects] = createSignal([]); + + const timer = useTimer(); + + function createObject(template: Component, props?: any) { + return ( + + {template(props)} + + ); + } + + function pickTemplate() { + const totalWeight = templates.reduce((sum, { weight }) => sum + weight, 0); + const randomNumber = Math.random() * totalWeight; + + let cumulativeWeight = 0; + for (let i = 0; i < templates.length; i++) { + cumulativeWeight += templates[i].weight; + if (randomNumber < cumulativeWeight) { + return templates[i].element; + } + } + } + + function pickPosition() { + return new vector2d( + Math.floor(Math.random() * borderX), + Math.floor(Math.random() * borderY) + ); + } + + function generate() { + const template = pickTemplate(); + if (template) { + const object = createObject(template, { position: pickPosition() }); + setObjects(objects().concat([object])); + } + } + + signal.subscribe(() => generate()); + + return {(item) => item}; +} diff --git a/src/stage/providers/timer.tsx b/src/stage/providers/timer.tsx index bb4695d..5ddca44 100644 --- a/src/stage/providers/timer.tsx +++ b/src/stage/providers/timer.tsx @@ -6,7 +6,7 @@ import { useContext, } from "solid-js"; -const TimerContext = createContext(); +export const TimerContext = createContext(); export const TickDuration = 100; diff --git a/src/stage/ui/overview.tsx b/src/stage/ui/overview.tsx index e90fa15..aa009b0 100644 --- a/src/stage/ui/overview.tsx +++ b/src/stage/ui/overview.tsx @@ -26,7 +26,7 @@ export default function OverviewUI() { return ( <> - Crystal {crystalHealth()}/{crystalMaxHealth()} + Crystal {crystalHealth()}/{crystalMaxHealth()} >