Compare commits
No commits in common. "b3c7979f87027e457c31304543eea8b6929a61d9" and "8bc56a433db6915727247c3b7a44c4968eee1e04" have entirely different histories.
b3c7979f87
...
8bc56a433d
|
|
@ -3,12 +3,7 @@ import type { Character } from "../types";
|
||||||
|
|
||||||
export const CharacterView = observer(function ({ character }: { character: Character }) {
|
export const CharacterView = observer(function ({ character }: { character: Character }) {
|
||||||
|
|
||||||
const pos = character.position;
|
return <mesh position={character.position} rotation={character.look}>
|
||||||
|
|
||||||
return <mesh
|
|
||||||
position={[pos[0] + 0.5, pos[1] + 0.5, pos[2] + 0.5]}
|
|
||||||
rotation={character.look}
|
|
||||||
>
|
|
||||||
<boxGeometry args={[0.8, 0.8, 0.8]} />
|
<boxGeometry args={[0.8, 0.8, 0.8]} />
|
||||||
<meshStandardMaterial color="yellow" />
|
<meshStandardMaterial color="yellow" />
|
||||||
</mesh>
|
</mesh>
|
||||||
|
|
|
||||||
|
|
@ -1,37 +1,14 @@
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import type { ObjectInstance, ObjectType } from "../types";
|
import type { ObjectInstance } from "../types";
|
||||||
import { useRef, type RefObject } from "react";
|
import { useRef, type RefObject } from "react";
|
||||||
import type { Group } from "three";
|
import type { Group } from "three";
|
||||||
import { Instance, Instances, TransformControls, useHelper } from "@react-three/drei";
|
import { TransformControls, useHelper } from "@react-three/drei";
|
||||||
import { BoxHelper } from "three";
|
import { BoxHelper } from "three";
|
||||||
import type { ThreeEvent } from "@react-three/fiber";
|
import type { ThreeEvent } from "@react-three/fiber";
|
||||||
import { state } from "../state";
|
import { state } from "../state";
|
||||||
import { nextSelectionEditMode } from "../state/worldEditorState";
|
import { nextSelectionEditMode } from "../state/worldEditorState";
|
||||||
import type { R3 } from "../types/3d";
|
import type { R3 } from "../types/3d";
|
||||||
|
|
||||||
type VoxelGroup = {
|
|
||||||
id: string;
|
|
||||||
color: string;
|
|
||||||
opacity: number;
|
|
||||||
positions: [number, number, number][];
|
|
||||||
};
|
|
||||||
|
|
||||||
function voxelGroups(objectType: ObjectType): VoxelGroup[] {
|
|
||||||
const map = new Map<string, VoxelGroup>();
|
|
||||||
for (const idx in objectType.voxels) {
|
|
||||||
const v = objectType.voxels[idx];
|
|
||||||
const vt = state.world.getVoxelTypeById(v.typeId);
|
|
||||||
const color = (v.color ?? vt?.color) ?? 'white';
|
|
||||||
const opacity = (v.opacity ?? vt?.opacity) ?? 1;
|
|
||||||
const key = `${color}-${opacity}`;
|
|
||||||
if (!map.has(key))
|
|
||||||
map.set(key, { id: key, color, opacity, positions: [] });
|
|
||||||
const p = v.position;
|
|
||||||
map.get(key)!.positions.push([p[0] + 0.5, p[1] + 0.5, p[2] + 0.5]);
|
|
||||||
}
|
|
||||||
return [...map.values()];
|
|
||||||
}
|
|
||||||
|
|
||||||
type ObjectViewProps = {
|
type ObjectViewProps = {
|
||||||
object: ObjectInstance;
|
object: ObjectInstance;
|
||||||
}
|
}
|
||||||
|
|
@ -89,16 +66,25 @@ export const ObjectView = observer(function ({ object }: ObjectViewProps) {
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
voxelGroups(objectType).map((vg) => (
|
objectType.voxels.map((v, idx) => {
|
||||||
<Instances key={vg.id}>
|
const vt = state.world.getVoxelTypeById(v.typeId);
|
||||||
|
const color = (v.color ?? vt?.color) ?? 'white';
|
||||||
|
const opacity = (v.opacity ?? vt?.opacity) ?? 1;
|
||||||
|
return (
|
||||||
|
<mesh
|
||||||
|
key={idx}
|
||||||
|
name={`voxel ${idx} [${v.position}]`}
|
||||||
|
position={v.position}
|
||||||
|
>
|
||||||
<boxGeometry args={[1, 1, 1]} />
|
<boxGeometry args={[1, 1, 1]} />
|
||||||
<meshStandardMaterial color={vg.color} opacity={vg.opacity} transparent={vg.opacity < 1} />
|
<meshStandardMaterial
|
||||||
{
|
color={color}
|
||||||
vg.positions
|
opacity={opacity}
|
||||||
.map((pos, i) => <Instance key={i} position={pos} />)
|
transparent={opacity < 1}
|
||||||
}
|
/>
|
||||||
</Instances>
|
</mesh>
|
||||||
))
|
);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</group>
|
</group>
|
||||||
</>);
|
</>);
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { useLayoutEffect, useRef } from 'react';
|
import { useLayoutEffect, useRef } from 'react';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { useThree } from '@react-three/fiber';
|
import { useThree } from '@react-three/fiber';
|
||||||
import { Grid, OrbitControls } from '@react-three/drei';
|
import { OrbitControls } from '@react-three/drei';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import { state } from '../state';
|
import { state } from '../state';
|
||||||
import { SceneView } from './SceneView';
|
import { SceneView } from './SceneView';
|
||||||
import type { Pos3 } from '../types/3d';
|
import type { Pos3 } from '../types/3d';
|
||||||
import { type OrthographicCamera, type PerspectiveCamera } from 'three';
|
import type { OrthographicCamera, PerspectiveCamera } from 'three';
|
||||||
|
|
||||||
const CameraSync = observer(function ({ camera }: { camera: Pos3 }) {
|
const CameraSync = observer(function ({ camera }: { camera: Pos3 }) {
|
||||||
const { camera: threeCamera } = useThree();
|
const { camera: threeCamera } = useThree();
|
||||||
|
|
@ -62,12 +62,6 @@ export const SceneEditorView = observer(function () {
|
||||||
enableDamping={false}
|
enableDamping={false}
|
||||||
/>
|
/>
|
||||||
<CameraSync camera={state.worldEditor.camera} />
|
<CameraSync camera={state.worldEditor.camera} />
|
||||||
<Grid
|
|
||||||
sectionThickness={0.5}
|
|
||||||
cellThickness={0}
|
|
||||||
sectionColor="white"
|
|
||||||
infiniteGrid
|
|
||||||
/>
|
|
||||||
<SceneView scene={state.worldEditor.scene} />
|
<SceneView scene={state.worldEditor.scene} />
|
||||||
</>);
|
</>);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,5 @@
|
||||||
import { Canvas, useFrame, useThree } from '@react-three/fiber';
|
import { Canvas } from '@react-three/fiber';
|
||||||
import { Stats } from '@react-three/drei';
|
import { Stats } from '@react-three/drei';
|
||||||
import { useRef } from 'react';
|
|
||||||
|
|
||||||
function RenderInfoUpdater({ domRef }: { domRef: React.RefObject<HTMLDivElement | null> }) {
|
|
||||||
const { gl } = useThree();
|
|
||||||
useFrame(() => {
|
|
||||||
if (!domRef.current)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const { calls, triangles } = gl.info.render;
|
|
||||||
const shaders = gl.info.programs?.length ?? 0;
|
|
||||||
const { geometries, textures } = gl.info.memory;
|
|
||||||
|
|
||||||
domRef.current.textContent = `draw: ${calls} | tri: ${triangles} | shaders: ${shaders} | geometries: ${geometries} | textures: ${textures}`;
|
|
||||||
});
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import { state } from '../state';
|
import { state } from '../state';
|
||||||
import { GameView } from './GameView';
|
import { GameView } from './GameView';
|
||||||
|
|
@ -28,7 +11,6 @@ const IconPlay = () => <svg viewBox="0 0 14 14"><polygon points="3,1 13,7 3,13"
|
||||||
|
|
||||||
export const ThreeView = observer(function () {
|
export const ThreeView = observer(function () {
|
||||||
const isGame = state.isGamePlaying;
|
const isGame = state.isGamePlaying;
|
||||||
const infoRef = useRef<HTMLDivElement>(null);
|
|
||||||
return (
|
return (
|
||||||
<div style={{ position: 'relative', width: '800px', height: '600px', border: '1px solid #333', borderRadius: '8px', overflow: 'hidden' }}>
|
<div style={{ position: 'relative', width: '800px', height: '600px', border: '1px solid #333', borderRadius: '8px', overflow: 'hidden' }}>
|
||||||
<Canvas
|
<Canvas
|
||||||
|
|
@ -36,15 +18,8 @@ export const ThreeView = observer(function () {
|
||||||
onPointerMissed={() => state.worldEditor.resetSelectedObject()}
|
onPointerMissed={() => state.worldEditor.resetSelectedObject()}
|
||||||
>
|
>
|
||||||
<Stats />
|
<Stats />
|
||||||
<RenderInfoUpdater domRef={infoRef} />
|
|
||||||
{isGame ? <GameView /> : <SceneEditorView />}
|
{isGame ? <GameView /> : <SceneEditorView />}
|
||||||
</Canvas>
|
</Canvas>
|
||||||
<div ref={infoRef} style={{
|
|
||||||
position: 'absolute', bottom: 8, left: 8,
|
|
||||||
color: 'white', fontSize: 11, fontFamily: 'monospace',
|
|
||||||
background: 'rgba(0,0,0,0.5)', padding: '2px 6px', borderRadius: 3,
|
|
||||||
pointerEvents: 'none',
|
|
||||||
}} />
|
|
||||||
<div style={{ position: 'absolute', top: 8, right: 8, display: 'flex', gap: 4 }}>
|
<div style={{ position: 'absolute', top: 8, right: 8, display: 'flex', gap: 4 }}>
|
||||||
{
|
{
|
||||||
state.game
|
state.game
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { makeAutoObservable, reaction, toJS } from "mobx";
|
import { makeAutoObservable, reaction, toJS } from "mobx";
|
||||||
import { WorldFactory } from "../model/worldFactory";
|
import { WorldFactory } from "../model/worldFactory";
|
||||||
import type { ObjectInstance, ObjectType, World } from "../types";
|
import type { ObjectType, World } from "../types";
|
||||||
import type { VoxelType } from "../types/voxel";
|
import type { VoxelType } from "../types/voxel";
|
||||||
import { state } from "./rootState";
|
import { state } from "./rootState";
|
||||||
import { DEFAULT_VOXEL_TYPES } from "../model/defaultVoxelTypes";
|
import { DEFAULT_VOXEL_TYPES } from "../model/defaultVoxelTypes";
|
||||||
|
|
@ -39,17 +39,7 @@ export class WorldState {
|
||||||
public loadMock() {
|
public loadMock() {
|
||||||
console.log('Mocking world...');
|
console.log('Mocking world...');
|
||||||
|
|
||||||
const objects = Array(3).fill(0)
|
const objectId1 = 'object1';
|
||||||
.map((_, idx) => ({
|
|
||||||
id: `obj${idx}`,
|
|
||||||
typeId: 'wolf',
|
|
||||||
position: [idx * 10 - 10, 0, 0],
|
|
||||||
rotation: [0, 0, 0],
|
|
||||||
scale: [1, 1, 1],
|
|
||||||
}));
|
|
||||||
const objectMap = Object.fromEntries(
|
|
||||||
objects.map((obj) => [obj.id, obj]),
|
|
||||||
) as Record<string, ObjectInstance>
|
|
||||||
|
|
||||||
this.data = {
|
this.data = {
|
||||||
objectTypes: {
|
objectTypes: {
|
||||||
|
|
@ -69,7 +59,16 @@ export class WorldState {
|
||||||
position: [0, 0, 0],
|
position: [0, 0, 0],
|
||||||
look: [0, 0, 0],
|
look: [0, 0, 0],
|
||||||
},
|
},
|
||||||
objects: objectMap,
|
objects: {
|
||||||
|
[objectId1]: {
|
||||||
|
id: objectId1,
|
||||||
|
typeId: 'wolf',
|
||||||
|
position: [0, 0, 0],
|
||||||
|
rotation: [0, 0, 0],
|
||||||
|
scale: [1, 1, 1],
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
},
|
},
|
||||||
gameRules: {
|
gameRules: {
|
||||||
gravity: true,
|
gravity: true,
|
||||||
|
|
@ -78,7 +77,6 @@ export class WorldState {
|
||||||
playing: false,
|
playing: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
console.log(objects);
|
|
||||||
state.worldEditor.resetSelectedObject();
|
state.worldEditor.resetSelectedObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue