Skip to content

Commit

Permalink
Merge pull request #11 from Cygnusfear/alex/facilities
Browse files Browse the repository at this point in the history
feat: valid/invalid build logic, updated models
  • Loading branch information
Cygnusfear authored Oct 8, 2023
2 parents 586efcb + c2db053 commit d118bea
Show file tree
Hide file tree
Showing 12 changed files with 75 additions and 49 deletions.
Binary file removed packages/client/public/models/block00.glb
Binary file not shown.
Binary file removed packages/client/public/models/block01.glb
Binary file not shown.
Binary file added packages/client/public/models/facilities.glb
Binary file not shown.
12 changes: 12 additions & 0 deletions packages/client/src/game/data/entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,17 @@ export type EntityDataType = {
costs: [ResourceType, number][];
produces: [ResourceType, number, number][];
variants: ModelDataType[];
tags: EntityTag[];
};

export const entityTags = [
"groundLevel",
"producesPower",
"producesGravity",
"producesPopulation",
] as const;
export type EntityTag = (typeof entityTags)[number];

const EntityData = {
facilities: {
gravityhill: {
Expand All @@ -21,6 +30,7 @@ const EntityData = {
costs: [["lapu", 500]],
produces: [["gravity", 25, 1]],
variants: [ModelData.well00],
tags: ["groundLevel"],
},
dynamo: {
name: "Whirly Dynamo",
Expand All @@ -31,6 +41,7 @@ const EntityData = {
costs: [["lapu", 200]],
produces: [["power", 25, 1]],
variants: [ModelData.engine00],
tags: [],
},
residence: {
name: "Residence",
Expand All @@ -41,6 +52,7 @@ const EntityData = {
costs: [["lapu", 100]],
produces: [["population", 5, 1]],
variants: [ModelData.block00, ModelData.block01, ModelData.block02],
tags: [],
},
} as { [key: string]: EntityDataType },
} as const;
Expand Down
3 changes: 3 additions & 0 deletions packages/client/src/game/data/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ export type ModelDataType = {
colors: string[];
};

export const importModels = ["/models/plants.glb", "/models/facilities.glb"];
export const importTextures = ["/textures/box01.webp"];

const ModelData: { [key: string]: ModelDataType } = {
block00: {
name: "GenericBlock00",
Expand Down
35 changes: 11 additions & 24 deletions packages/client/src/game/entities/facility.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@ import { useStore } from "../store";
import { AdditiveBlending, DoubleSide, Mesh, Vector3 } from "three";
import { animated } from "@react-spring/three";
import { MouseInputEvent, useInput } from "../input/useInput";
import {
buildFacility,
canBuildAtPosition,
} from "../systems/constructionSystem";
import { buildFacility } from "../systems/constructionSystem";
import { palette } from "../utils/palette";
import { faceDirections } from "@/lib/utils";
import { IFacility } from "../types/entities";

const Renderer = (props: IFacility) => {
const { colorPrimary, colorSecondary, scale, variant, rotation } = props;
const { colorPrimary, colorSecondary, variant, rotation } = props;
const {
assets: { meshes },
} = useStore();
Expand All @@ -29,7 +26,7 @@ const Renderer = (props: IFacility) => {
return (
<group
dispose={null}
scale={scale.multiplyScalar(0.7)}
scale={new Vector3(1, 1, 1)}
position={[0, 0, 0]}
rotation={[0, rotation.y, 0]}
>
Expand Down Expand Up @@ -81,26 +78,16 @@ const Facility = (props: IFacility) => {
const { onMouseMove } = useInput((event: MouseInputEvent) => {
if (faceIndex === undefined) return;
const direction = event.position.clone().add(faceDirections[faceIndex!]);
const canBuild = canBuildAtPosition(direction);
if (canBuild) {
cursor.setCursor({
position: direction,
cursorState: "valid",
direction: faceDirections[faceIndex!].clone().negate(),
});
} else {
cursor.setCursor({ cursorState: "hidden" });
}
cursor.setCursor({
position: direction,
direction: faceDirections[faceIndex!].clone().negate(),
});
}, entityRef);

const { onMouseDown, onMouseClick } = useInput((event: MouseInputEvent) => {
const { onMouseDown, onMouseClick } = useInput(() => {
if (faceIndex === undefined) return;
const direction = event.position.clone().add(faceDirections[faceIndex!]);
const canBuild = canBuildAtPosition(direction);
if (canBuild) {
buildFacility(direction);
setFaceIndex(undefined);
}
buildFacility(cursor.position);
setFaceIndex(undefined);
}, entityRef);

return (
Expand Down Expand Up @@ -141,7 +128,7 @@ const Facility = (props: IFacility) => {
? palette.cursor
: "black"
}
visible={faceIndex !== undefined && faceIndex === index}
visible={false}
transparent={true}
// TODO: Remove the face highlighting completely, or use alternative face highlighting like in Townscraper
opacity={0}
Expand Down
7 changes: 1 addition & 6 deletions packages/client/src/game/entities/ground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ import { Grid, GridProps } from "@react-three/drei";

import { useInput } from "../input/useInput";
import { getState, useStore } from "../store";
import {
buildFacility,
canBuildAtPosition,
} from "../systems/constructionSystem";
import { buildFacility } from "../systems/constructionSystem";
import { Directions } from "@/lib/utils";

const gridSize = 1000;
Expand Down Expand Up @@ -38,10 +35,8 @@ function Ground() {
const {
input: { cursor },
} = getState();
const canBuild = canBuildAtPosition(event.position);
cursor.setCursor({
position: event.position,
cursorState: canBuild ? "valid" : "hidden",
direction: Directions.DOWN(),
});
}, gridRef);
Expand Down
38 changes: 30 additions & 8 deletions packages/client/src/game/input/cursor.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { useEffect, useRef, useState } from "react";
import { Sparkles } from "@react-three/drei";
import { AdditiveBlending, DoubleSide } from "three";
import { AdditiveBlending, DoubleSide, Vector3 } from "three";

import { useStore } from "../store";
import { palette } from "../utils/palette";
import { faceDirections } from "@/lib/utils";
import { canBuildAtPosition } from "../systems/constructionSystem";

function Cursor() {
const cursorRef = useRef<THREE.Mesh>(null);
const {
input: {
cursor: { position, cursorState, direction },
cursor: { position, cursorState, direction, setCursor },
building,
},
assets: { textures },
} = useStore();
Expand All @@ -23,16 +25,34 @@ function Cursor() {
}
}, [direction]);

useEffect(() => {
if (building) {
if (!canBuildAtPosition(position)) {
setCursor({ cursorState: "invalid" });
} else {
setCursor({ cursorState: "valid" });
}
} else {
setCursor({ cursorState: "hidden" });
}
}, [cursorState, building, position, setCursor]);

return (
<group position={position.toArray()} visible={cursorState !== "hidden"}>
<group
position={position.toArray()}
visible={cursorState !== "hidden"}
scale={new Vector3(0.95, 0.95, 0.95)}
>
<mesh userData={{ type: "cursor" }} ref={cursorRef}>
<boxGeometry args={[0.96, 0.96]} />
<boxGeometry args={[1, 1]} />
{/* Face mapping for direction */}
{[...Array(6)].map((_, index) => (
<meshLambertMaterial
attach={`material-${index}`}
key={index}
color={palette.cursor}
color={
cursorState === "valid" ? palette.cursor : palette.cursorInvalid
}
visible={faceIndex !== undefined && faceIndex === index}
transparent={true}
opacity={0.3}
Expand All @@ -48,11 +68,13 @@ function Cursor() {
/>
</mesh>
{/* 🐁 main cursor block */}
<mesh>
<boxGeometry args={[0.99, 0.99, 0.99]} />
<mesh visible={cursorState === "valid"}>
<boxGeometry args={[0.95, 0.95, 0.95]} />
<meshStandardMaterial
map={textures["box01"]}
color={"#76EAE4"}
color={
cursorState === "valid" ? palette.cursor : palette.cursorInvalid
}
transparent
attach="material"
opacity={0.1}
Expand Down
14 changes: 11 additions & 3 deletions packages/client/src/game/systems/constructionSystem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ import { palette } from "../utils/palette";
import { IFacility } from "../types/entities";
import prand from "pure-rand";

// TODO: Extract build conditions, can't build 1 tile below gravity well, only gravity well can build at y==1, etc
const canBuildAtPosition = (position: Vector3) => {
const {
input: { building },
} = getState();
if (position.y < 0) return false;
const { getEntityByPosition } = getState().world;
const entity = getEntityByPosition(position);
return entity ? false : true;
if (entity) return false;
if (building && !building.tags.includes("groundLevel") && position.y < 1) {
return false;
}
return true;
};

const getEntityInDirection = (position: Vector3, direction: Vector3) => {
Expand All @@ -34,6 +42,7 @@ const buildFacility = (position: Vector3) => {

if (!canBuildAtPosition(position)) {
console.error("Cannot build here", position);
cursor.setCursor({ cursorState: "invalid" });
return;
}

Expand All @@ -43,7 +52,7 @@ const buildFacility = (position: Vector3) => {

const newFacility = {
position: position,
scale: new Vector3(Math.random() * 0.1 + 0.9, 1, Math.random() * 0.1 + 0.9),
scale: new Vector3(1, 1, 1),
colorPrimary: getRandom(palette.buildingPrimary),
colorSecondary: getRandom(palette.buildingSecondary),
entityRef: createRef<THREE.Mesh>(),
Expand All @@ -62,7 +71,6 @@ const buildFacility = (position: Vector3) => {

addEntity(newFacility);
// Move Input logic away from here
cursor.setCursor({ cursorState: "hidden" });
setInput({ building: undefined });
console.log(newFacility);
};
Expand Down
12 changes: 5 additions & 7 deletions packages/client/src/game/utils/importer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ import { useGLTF, useTexture } from "@react-three/drei";
import { Material, Mesh, Texture } from "three";
import type { GLTF } from "three-stdlib";
import { useStore } from "../store";

const models = ["/models/plants.glb", "/models/block01.glb"];
const textures = ["/textures/box01.webp"];
import { importModels, importTextures } from "../data/models";

export interface Assets {
meshes: Record<string, Mesh>;
Expand Down Expand Up @@ -51,12 +49,12 @@ function TextureLoader({ path }: { path: string }) {
useTexture.preload(path);
}, [path]);

// Loading and storing the model
// Loading and storing the texture
const texture = useTexture(path) as Texture;

useEffect(() => {
if (texture) {
textures.forEach((node) => {
importTextures.forEach((node) => {
try {
addTexture(node.replace("/textures/", "").split(".")[0], texture);
} catch (error) {
Expand All @@ -72,10 +70,10 @@ function TextureLoader({ path }: { path: string }) {
function Importer() {
return (
<>
{models.map((model) => (
{importModels.map((model) => (
<ModelLoader key={model} path={model} />
))}
{textures.map((texture) => (
{importTextures.map((texture) => (
<TextureLoader key={texture} path={texture} />
))}
</>
Expand Down
1 change: 1 addition & 0 deletions packages/client/src/game/utils/palette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const grassColors = ["#9BD48A", "#8FCD5F", "#69CD1E"];

const palette = {
cursor: "#76EAE4",
cursorInvalid: "#ff0000",
buildingPrimary: buildingPrimary,
buildingSecondary: buildingSecondary,
grassColors: grassColors,
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts/worlds.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"31337": {
"address": "0x5FbDB2315678afecb367f032d93F642f64180aa3"
"address": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e"
}
}

0 comments on commit d118bea

Please sign in to comment.