attempt at having stuff produce stuff

This commit is contained in:
circle-gon 2022-12-18 19:14:42 +00:00
parent a48d6595cf
commit e7dd7317d4
5 changed files with 265 additions and 81 deletions

View file

@ -4,7 +4,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Application } from "@pixi/app"; import type { Application } from "@pixi/app";
import { onMounted, shallowRef } from "vue"; import { onMounted, shallowRef } from "vue";
import { blockAmts } from "./factory"; import {size} from "./factory"
import "lib/pixi"; import "lib/pixi";
const element = shallowRef<HTMLElement | null>(null); const element = shallowRef<HTMLElement | null>(null);
@ -24,7 +24,10 @@ onMounted(() => {
</script> </script>
<style scoped> <style scoped>
.factoryDisp { .factoryDisp {
width: 100%; width: v-bind("size.width");
height: 100%; height: v-bind("size.height");
margin: 0;
padding: 0;
box-sizing: border-box;
} }
</style> </style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View file

@ -5,10 +5,10 @@ import { Sprite } from "@pixi/sprite";
import { Graphics } from "@pixi/graphics"; import { Graphics } from "@pixi/graphics";
import { Assets } from "@pixi/assets"; import { Assets } from "@pixi/assets";
import Factory from "./Factory.vue"; import Factory from "./Factory.vue";
import Modal from "components/Modal.vue";
import conveyor from "./factory-components/conveyor.png"; import conveyor from "./factory-components/conveyor.png";
import cursor from "./factory-components/cursor.jpg"; import cursor from "./factory-components/cursor.jpg";
import { computed, reactive, Ref, ref, watchEffect } from "vue"; import square from "./factory-components/square.jpg";
import { computed, ComputedRef, reactive, Ref, ref, watchEffect } from "vue";
import { Direction } from "util/common"; import { Direction } from "util/common";
import { persistent } from "game/persistence"; import { persistent } from "game/persistence";
import player from "game/player"; import player from "game/player";
@ -23,11 +23,17 @@ const day = 20;
// 20x20 block size // 20x20 block size
// TODO: unhardcode stuff // TODO: unhardcode stuff
const size = {
enum FactoryDirections {
Any,
None
}
type FactoryDirection = FactoryDirections | Direction;
export const size = {
width: 1000, width: 1000,
height: 340 height: 345
}; };
export const blockAmts = { const blockAmts = {
w: 50, w: 50,
h: 17 h: 17
}; };
@ -42,45 +48,110 @@ function getRelativeCoords(e: MouseEvent) {
y: e.clientY - rect.top y: e.clientY - rect.top
}; };
} }
async function createSprite(name: string) {
interface FactoryComponent { const sheet = await Assets.load(name);
directionIn: Direction | undefined; return new Sprite(sheet);
directionOut: Direction | undefined; }
imageSrc: string;
name: string; async function positionSprite(name: string, y: number, x: number, width: number, height: number) {
description: string; const sprite = await createSprite(name);
type: string; sprite.width = width;
sprite: Sprite; sprite.height = height;
sprite.y = y;
sprite.x = x;
return sprite;
} }
const FACTORY_COMPONENTS = {
cursor: {
directionIn: undefined,
directionOut: undefined,
imageSrc: cursor,
name: "Cursor",
description: "Use this to move."
},
conveyor: {
directionIn: Direction,
directionOut: Direction,
imageSrc: conveyor,
name: "Conveyor",
description: "Moves 1 item per tick."
},
someOtherComponent: {
directionIn: Direction.Down,
directionOut: undefined,
imageSrc: conveyor,
description: "Accepts anything and produces nothing."
}
};
type FactoryCompNames = keyof typeof FACTORY_COMPONENTS;
const factory = createLayer(id, () => { const factory = createLayer(id, () => {
// layer display // layer display
const name = "The Factory"; const name = "The Factory";
const color = "grey"; const color = "grey";
const FACTORY_COMPONENTS = {
cursor: {
imageSrc: cursor,
name: "Cursor",
description: "Use this to move.",
tick: 0,
directionIn: FactoryDirections.None,
directionOut: FactoryDirections.None,
consumption: {},
consumptionStock: {},
production: {},
productionStock: {}
},
conveyor: {
directionIn: FactoryDirections.Any,
directionOut: FactoryDirections.Any,
imageSrc: conveyor,
name: "Conveyor",
description: "Moves 1 item per tick.",
tick: 1,
consumption: {},
consumptionStock: {},
production: {},
productionStock: {}
},
square: {
directionIn: FactoryDirections.Any,
directionOut: FactoryDirections.None,
imageSrc: square,
name: "???",
description: "Produces 1 square every 1 tick.",
tick: 1,
production: {
square: 1
},
productionStock: {
square: Infinity
},
consumption: {},
consumptionStock: {},
onProduce(times) {
}
}
} as Record<string, FactoryComponentDeclaration>;
type FactoryCompNames = keyof typeof FACTORY_COMPONENTS;
type BuildableCompName = Exclude<FactoryCompNames, "cursor">;
interface FactoryComponent {
type: BuildableCompName;
ticksDone: number;
// current consumption stock
consumptionStock: Record<string, number>;
// current production stock
productionStock: Record<string, number>;
}
interface FactoryComponentDeclaration {
tick: number;
directionIn: FactoryDirection;
directionOut: FactoryDirection;
imageSrc: string;
name: string;
description: string;
// amount it consumes
consumption: Record<string, number>;
// maximum stock of consumption
consumptionStock: Record<string, number>;
// amount it produces
production: Record<string, number>;
// maximum stock of production
productionStock: Record<string, number>;
// on produce, do something
onProduce?: (times: number) => void;
// can it produce? (in addtion to the stock check)
canProduce?: ComputedRef<boolean>;
}
interface FactoryInternal {
sprite: Sprite;
canProduce: ComputedRef<boolean>;
}
// mouse positions // mouse positions
const mouseCoords = reactive({ const mouseCoords = reactive({
x: 0, x: 0,
@ -88,36 +159,124 @@ const factory = createLayer(id, () => {
}); });
const isMouseHoverShown = ref(false); const isMouseHoverShown = ref(false);
const whatIsHovered = ref<FactoryCompNames | "">(""); const whatIsHovered = ref<FactoryCompNames | "">("");
const compSelected = ref<FactoryCompNames | "">(""); const compSelected = ref<FactoryCompNames>("cursor");
const components: Ref<unknown[][]> = persistent(
const componentData: Ref<(FactoryComponent | null)[][]> = persistent(
Array(blockAmts.h) Array(blockAmts.h)
.fill(undefined) .fill(undefined)
.map(() => Array(blockAmts.w).fill(undefined)) .map(() => Array(blockAmts.w).fill(null))
); );
const components: (FactoryInternal | null)[][] = Array(blockAmts.h)
.fill(undefined)
.map(() => Array(blockAmts.w).fill(null));
window.components = components;
// pixi // pixi
const app = new Application(size); const app = new Application(size);
const graphicContainer = new Graphics(); const graphicContainer = new Graphics();
const spriteContainer = new Container(); const spriteContainer = new Container();
let blockWidth = 0; const movingBlocks = new Container();
let blockHeight = 0; const blockWidth = ref(app.screen.width / blockAmts.w);
app.stage.addChild(graphicContainer, spriteContainer); const blockHeight = ref(app.screen.height / blockAmts.h);
globalBus.on("update", () => { graphicContainer.zIndex = 1;
blockWidth = app.screen.width / blockAmts.w; app.stage.addChild(graphicContainer, spriteContainer, movingBlocks);
blockHeight = app.screen.height / blockAmts.h; app.stage.sortableChildren = true;
globalBus.on("update", diff => {
blockWidth.value = app.screen.width / blockAmts.w;
blockHeight.value = app.screen.height / blockAmts.h;
// will change soon:tm:
const tick = diff;
for (const y of components.keys()) {
for (const x of components[y].keys()) {
const data = componentData.value[y][x];
const compData = components[y][x];
//console.log(compData, data)
if (data === null || compData === null) continue;
const factoryData = FACTORY_COMPONENTS[data.type];
if (data.ticksDone >= factoryData.tick) {
console.log(compData.canProduce);
if (!compData.canProduce.value) continue;
const cyclesDone = Math.floor(data.ticksDone / factoryData.tick);
console.log("produce", data.ticksDone, factoryData.tick);
factoryData.onProduce?.(cyclesDone);
for (const [key, val] of Object.entries(factoryData.consumption)) {
data.consumptionStock[key] -= val;
}
for (const [key, val] of Object.entries(factoryData.production)) {
data.productionStock[key] -= val;
}
data.ticksDone -= cyclesDone * factoryData.tick;
} else {
data.ticksDone += tick;
}
}
}
}); });
globalBus.on("onLoad", async () => {
for (const y of componentData.value.keys()) {
for (const x of componentData.value[y].keys()) {
changeFactoryComponent(y, x);
}
}
});
async function changeFactoryComponent(y: number, x: number) {
const comp = componentData.value[y][x];
if (comp === null) return;
const data = FACTORY_COMPONENTS[comp.type];
const sprite = await positionSprite(
FACTORY_COMPONENTS[comp.type].imageSrc,
y * blockHeight.value,
x * blockWidth.value,
blockWidth.value,
blockHeight.value
);
components[y][x] = {
sprite,
canProduce: computed(() => {
if (!(data.canProduce?.value ?? true)) return false;
for (const [key, res] of Object.entries(comp.productionStock)) {
// if the current stock + production is more than you can handle
if (res + data.production[key] > data.productionStock[key]) return false;
}
for (const [key, res] of Object.entries(comp.consumptionStock)) {
// make sure you have enough to produce
if (res < data.consumptionStock[key]) return false;
}
return true;
})
};
spriteContainer.addChild(sprite);
}
function removeFactoryComponent(y: number, x: number) {
const comp = components[y][x];
if (comp === null) return;
comp.sprite.destroy();
componentData.value[y][x] = null;
components[y][x] = null;
spriteContainer.removeChild(comp.sprite);
}
// draw graphics // draw graphics
function updateGraphics() { function updateGraphics() {
graphicContainer.clear(); graphicContainer.clear();
if (isMouseHoverShown.value) { if (isMouseHoverShown.value && compSelected.value !== "cursor") {
graphicContainer.beginFill(0x808080); const { x, y } = {
x: roundDownTo(mouseCoords.x, blockWidth.value) / blockWidth.value,
y: roundDownTo(mouseCoords.y, blockHeight.value) / blockHeight.value
};
console.log(isMouseHoverShown.value, x, y);
graphicContainer.beginFill(components[y][x] !== null ? 0xff0000 : 0xffff00);
graphicContainer.drawRect( graphicContainer.drawRect(
roundDownTo(mouseCoords.x, blockWidth), roundDownTo(mouseCoords.x, blockWidth.value),
roundDownTo(mouseCoords.y, blockHeight), roundDownTo(mouseCoords.y, blockHeight.value),
blockWidth, blockWidth.value,
blockHeight blockHeight.value
); );
} }
} }
@ -131,24 +290,31 @@ const factory = createLayer(id, () => {
mouseCoords.y = y; mouseCoords.y = y;
} }
async function onClick(e: MouseEvent) { async function onClick(e: MouseEvent) {
if (compSelected.value === "") { const coords = getRelativeCoords(e);
console.warn("You haven't hovered over anything, trickster!"); const x = roundDownTo(coords.x, blockWidth.value) / blockWidth.value;
return; const y = roundDownTo(coords.y, blockHeight.value) / blockHeight.value;
if (e.button === 0) {
// you shouldn't be putting down a mouse
if (compSelected.value === "cursor") return;
// should not already be placed
if (components[y][x] !== null) return;
const basicData = FACTORY_COMPONENTS[compSelected.value];
componentData.value[y][x] = {
type: compSelected.value,
ticksDone: 0,
consumptionStock: Object.fromEntries(
Object.entries(basicData.consumptionStock).map(i => [i[0], 0])
),
productionStock: Object.fromEntries(
Object.entries(basicData.productionStock).map(i => [i[0], 0])
)
};
await changeFactoryComponent(y, x);
} else if (e.button === 2) {
// right click
removeFactoryComponent(y, x);
} }
let { x, y } = getRelativeCoords(e);
x = roundDownTo(x, blockWidth) / blockWidth;
y = roundDownTo(y, blockHeight) / blockHeight;
const basicData = structuredClone(
FACTORY_COMPONENTS[compSelected.value]
) as FactoryComponent;
basicData.type = compSelected.value;
const sheet = await Assets.load(basicData.imageSrc);
basicData.sprite = new Sprite(sheet);
basicData.sprite.x = x;
basicData.sprite.y = y;
basicData.sprite.width = blockWidth;
basicData.sprite.height = blockHeight;
spriteContainer.addChild(basicData.sprite);
} }
function onMouseEnter() { function onMouseEnter() {
isMouseHoverShown.value = true; isMouseHoverShown.value = true;
@ -160,6 +326,7 @@ const factory = createLayer(id, () => {
player.tabs.splice(0, Infinity, "main"); player.tabs.splice(0, Infinity, "main");
} }
function onComponentHover(name: FactoryCompNames | "") { function onComponentHover(name: FactoryCompNames | "") {
if (compSelected.value !== "cursor") return;
whatIsHovered.value = name; whatIsHovered.value = name;
} }
function onCompClick(name: FactoryCompNames) { function onCompClick(name: FactoryCompNames) {
@ -171,6 +338,7 @@ const factory = createLayer(id, () => {
color, color,
minWidth: 700, minWidth: 700,
minimizable: false, minimizable: false,
componentData,
display: jsx(() => ( display: jsx(() => (
<div class="layer-container"> <div class="layer-container">
<button class="goBack" onClick={goBack}> <button class="goBack" onClick={goBack}>
@ -180,9 +348,13 @@ const factory = createLayer(id, () => {
<tr> <tr>
<td class="info" colspan="2"> <td class="info" colspan="2">
<div style="min-height: 3em"> <div style="min-height: 3em">
{whatIsHovered.value === "" {whatIsHovered.value !== "" ? (
? undefined <>
: FACTORY_COMPONENTS[whatIsHovered.value].description} <b>{FACTORY_COMPONENTS[whatIsHovered.value].name}</b>
<br />
{FACTORY_COMPONENTS[whatIsHovered.value].description}
</>
) : undefined}
</div> </div>
</td> </td>
</tr> </tr>
@ -201,7 +373,7 @@ const factory = createLayer(id, () => {
"aspect-ratio": "1", "aspect-ratio": "1",
border: border:
compSelected.value === key compSelected.value === key
? "1px solid white" ? "1px solid green"
: "" : ""
}} }}
onMouseenter={() => onComponentHover(key)} onMouseenter={() => onComponentHover(key)}
@ -212,20 +384,27 @@ const factory = createLayer(id, () => {
})} })}
</div> </div>
</td> </td>
<td> <td
style={{
width: size.width,
height: size.height,
margin: 0,
padding: 0
}}
>
<Factory <Factory
application={app} application={app}
onMousemove={onMouseMove} onMousemove={onMouseMove}
onClick={onClick} onMouseup={onClick}
onMouseenter={onMouseEnter} onMouseenter={onMouseEnter}
onMouseleave={onMouseLeave} onMouseleave={onMouseLeave}
onContextmenu={(e: MouseEvent) => e.preventDefault()}
/> />
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
)), ))
components
}; };
}); });
export default factory; export default factory;

View file

@ -7,6 +7,7 @@
.factoryDisp { .factoryDisp {
border-left: 1px solid white; border-left: 1px solid white;
border-bottom: 1px solid white; border-bottom: 1px solid white;
border-right: 1px solid white;
} }
.info { .info {
border-bottom: 1px solid white; border-bottom: 1px solid white;

View file

@ -137,7 +137,8 @@ setInterval(() => {
window.onbeforeunload = () => { window.onbeforeunload = () => {
if ( if (
player.autosave && player.autosave &&
(layers as any).main.days[(layers as any).main.day.value - 1].opened.value ((layers as any).main.days[(layers as any).main.day.value - 1].opened.value ||
import.meta.env.DEV)
) { ) {
save(); save();
} }