✨ 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 { styled } from "solid-styled-components";
|
||||||
import { Show, createSignal, onMount } from "solid-js";
|
import { Show, createSignal, onMount } from "solid-js";
|
||||||
import { vector2d } from "./vector";
|
import { vector2d } from "./vector";
|
||||||
|
import SignalBus from "../signal";
|
||||||
|
|
||||||
import Player from "./objects/player";
|
import Player from "./objects/player";
|
||||||
import Crystal from "./objects/crystal";
|
import Crystal from "./objects/crystal";
|
||||||
import Attacker from "./objects/enemies/attacker";
|
|
||||||
import TimerProvider from "./providers/timer";
|
import TimerProvider from "./providers/timer";
|
||||||
import CooldownProvider from "./providers/cooldown";
|
import CooldownProvider from "./providers/cooldown";
|
||||||
import CooldownUI from "./ui/cooldown";
|
import CooldownUI from "./ui/cooldown";
|
||||||
@ -12,6 +12,7 @@ import CooldownUI from "./ui/cooldown";
|
|||||||
import "./objects/common.css";
|
import "./objects/common.css";
|
||||||
import OverviewProvider from "./providers/overview";
|
import OverviewProvider from "./providers/overview";
|
||||||
import OverviewUI from "./ui/overview";
|
import OverviewUI from "./ui/overview";
|
||||||
|
import SpawnFarm, { EnemiesTemplates } from "./objects/spawn-farm";
|
||||||
|
|
||||||
const StageContainer = styled("div")`
|
const StageContainer = styled("div")`
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
@ -25,32 +26,20 @@ const StageContainer = styled("div")`
|
|||||||
export default function Stage() {
|
export default function Stage() {
|
||||||
let container: HTMLDivElement = document.createElement("div");
|
let container: HTMLDivElement = document.createElement("div");
|
||||||
|
|
||||||
|
let stageSize = new vector2d(0, 0);
|
||||||
let centerPosition = new vector2d(0, 0);
|
let centerPosition = new vector2d(0, 0);
|
||||||
let playerPosition = new vector2d(0, 0);
|
let playerPosition = new vector2d(0, 0);
|
||||||
|
|
||||||
let randomPosition = new vector2d(0, 0);
|
|
||||||
|
|
||||||
let [ready, setReady] = createSignal(false);
|
let [ready, setReady] = createSignal(false);
|
||||||
|
|
||||||
function calcRandomPosition(maxX: number, maxY: number) {
|
const enemiesSpawnSignal = new SignalBus();
|
||||||
return new vector2d(
|
|
||||||
Math.floor(Math.random() * maxX),
|
|
||||||
Math.floor(Math.random() * maxY)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function initializeStage(element: HTMLDivElement) {
|
function initializeStage(element: HTMLDivElement) {
|
||||||
centerPosition = new vector2d(
|
stageSize = new vector2d(element.clientWidth, element.clientHeight);
|
||||||
element.clientWidth / 2,
|
centerPosition = new vector2d(stageSize.x / 2, stageSize.y / 2);
|
||||||
element.clientHeight / 2
|
|
||||||
);
|
|
||||||
playerPosition = centerPosition.clone();
|
playerPosition = centerPosition.clone();
|
||||||
|
|
||||||
randomPosition = calcRandomPosition(
|
setInterval(() => enemiesSpawnSignal.emit(), 1000)
|
||||||
element.clientWidth,
|
|
||||||
element.clientHeight
|
|
||||||
);
|
|
||||||
console.log("example pos:", randomPosition);
|
|
||||||
|
|
||||||
setReady(true);
|
setReady(true);
|
||||||
}
|
}
|
||||||
@ -67,7 +56,13 @@ export default function Stage() {
|
|||||||
<Crystal size={128} position={centerPosition} />
|
<Crystal size={128} position={centerPosition} />
|
||||||
<Player size={64} position={playerPosition} />
|
<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 */}
|
{/* UI Elements */}
|
||||||
<CooldownUI />
|
<CooldownUI />
|
||||||
|
@ -10,8 +10,8 @@ export default function Attacker(props: {
|
|||||||
damage?: number;
|
damage?: number;
|
||||||
position?: vector2d;
|
position?: vector2d;
|
||||||
}) {
|
}) {
|
||||||
const width = props.size ? props.size / 6 : 2;
|
const width = props.size ? props.size / 6 : 5;
|
||||||
const height = props.size ?? 20;
|
const height = props.size ?? 32;
|
||||||
|
|
||||||
// Just some random comment
|
// Just some random comment
|
||||||
// https://youtube.com/ishowspeed
|
// 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,
|
useContext,
|
||||||
} from "solid-js";
|
} from "solid-js";
|
||||||
|
|
||||||
const TimerContext = createContext();
|
export const TimerContext = createContext();
|
||||||
|
|
||||||
export const TickDuration = 100;
|
export const TickDuration = 100;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ export default function OverviewUI() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<BottomSideContainer class="healthy-overview">
|
<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} />
|
<progress class="h-[4px] progress progress-error w-screen" value={regenerationProgress()} max={100} />
|
||||||
</BottomSideContainer>
|
</BottomSideContainer>
|
||||||
</>
|
</>
|
||||||
|
Loading…
Reference in New Issue
Block a user