✨ Spawn farm
This commit is contained in:
parent
f0af12f4bb
commit
f64f3bd544
13
src/signal.ts
Normal file
13
src/signal.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
@ -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() {
|
||||
<Crystal size={128} position={centerPosition} />
|
||||
<Player size={64} position={playerPosition} />
|
||||
|
||||
<Attacker size={32} position={randomPosition} />
|
||||
{/* Object Sets */}
|
||||
<SpawnFarm
|
||||
templates={EnemiesTemplates}
|
||||
signal={enemiesSpawnSignal}
|
||||
borderX={stageSize.x}
|
||||
borderY={stageSize.y}
|
||||
/>
|
||||
|
||||
{/* UI Elements */}
|
||||
<CooldownUI />
|
||||
|
@ -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
|
||||
|
67
src/stage/objects/spawn-farm.tsx
Normal file
67
src/stage/objects/spawn-farm.tsx
Normal file
@ -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<JSX.Element[]>([]);
|
||||
|
||||
const timer = useTimer();
|
||||
|
||||
function createObject(template: Component, props?: any) {
|
||||
return (
|
||||
<TimerContext.Provider value={timer}>
|
||||
{template(props)}
|
||||
</TimerContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
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 <For each={objects()}>{(item) => item}</For>;
|
||||
}
|
@ -6,7 +6,7 @@ import {
|
||||
useContext,
|
||||
} from "solid-js";
|
||||
|
||||
const TimerContext = createContext();
|
||||
export const TimerContext = createContext();
|
||||
|
||||
export const TickDuration = 100;
|
||||
|
||||
|
@ -26,7 +26,7 @@ export default function OverviewUI() {
|
||||
return (
|
||||
<>
|
||||
<BottomSideContainer class="healthy-overview">
|
||||
<div class="text-xl">Crystal {crystalHealth()}/{crystalMaxHealth()}</div>
|
||||
<div class="text-lg">Crystal {crystalHealth()}/{crystalMaxHealth()}</div>
|
||||
<progress class="h-[4px] progress progress-error w-screen" value={regenerationProgress()} max={100} />
|
||||
</BottomSideContainer>
|
||||
</>
|
||||
|
Loading…
Reference in New Issue
Block a user