Skip to content

Commit

Permalink
Merge pull request #80 from bananu7/no-fixed-map-size
Browse files Browse the repository at this point in the history
Remove fixed map size constraint
  • Loading branch information
bananu7 authored Jun 23, 2024
2 parents c5482dc + bd441fd commit 5d40d2e
Show file tree
Hide file tree
Showing 13 changed files with 141 additions and 47 deletions.
2 changes: 1 addition & 1 deletion packages/client/src/components/MatchController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ export function MatchController(props: MatchControllerProps) {
resources={lastUpdatePacket.player.resources}
units={lastUpdatePacket.units.filter(u => u.owner === props.ctrl.getPlayerIndex()).length}
/>
<View3D>
<View3D viewX={matchMetadata.board.map.w} viewY={matchMetadata.board.map.h} >
<Board3D
board={matchMetadata.board}
playerIndex={props.ctrl.getPlayerIndex()}
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/components/SpectateController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ export function SpectateController(props: SpectateControllerProps) {
resources={lastUpdatePacket.player.resources}
units={0} // TODO -spectator doesn't receive data about both players
/>
<View3D>
<View3D viewX={matchMetadata.board.map.w} viewY={matchMetadata.board.map.h} >
<Board3D
board={matchMetadata.board}
playerIndex={0} // TODO - spectator has no player index
Expand Down
9 changes: 9 additions & 0 deletions packages/client/src/debug/flags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// TODO make this settable more easily
export const debugFlags = Object.freeze({
showPaths: true,
showHorizons: false,
showCones: false,
showTerrainArrows: true,

showLightConeHelper: false,
});
77 changes: 57 additions & 20 deletions packages/client/src/gfx/Map3D.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,58 @@ type Map3DProps = {
pointerMove: (p: {x: number, y: number}) => void;
}

function tileTypeToColor(tileType: number, vec3Color: THREE.Color) {
const isPassable = tileType === 0;

switch (tileType) {
case 0: {
const color = 0x11aa11;
vec3Color.set(color);
const f = 0.06;
vec3Color.r += (Math.random() - 0.5) * f;
vec3Color.g += (Math.random() - 0.5) * f;
vec3Color.b += (Math.random() - 0.5) * f;
break;
}

case 2: {
const color = 0x3377cc;
vec3Color.set(color);
const f = 0.06;
vec3Color.r += (Math.random() - 0.5) * f;
vec3Color.g += (Math.random() - 0.5) * f;
vec3Color.b += (Math.random() - 0.5) * f;
break;
}

case 1:
default: {
const color = 0x888888;
vec3Color.set(color);
const d = (Math.random() - 0.5) * 0.1;
vec3Color.r += d;
vec3Color.g += d;
vec3Color.b += d;
}
}
}

function tileTypeToHeight(tileType: number): number {
const correction = 0.01;
switch (tileType) {
case 0:
return 0 - correction;

case 2:
return -0.5 - Math.random() * 0.7 - correction

case 1:
default:
return 0.8 + Math.random() * 0.7 - correction;
}
}


export function Map3D(props: Map3DProps) {
// movement
const rawClick = (e: ThreeEvent<MouseEvent>) => {
Expand Down Expand Up @@ -68,31 +120,16 @@ export function Map3D(props: Map3DProps) {
const mat4Pos = new THREE.Matrix4();
const vec3Color = new THREE.Color();

for (let y = 0; y < w; y++){
for (let x = 0; x < h; x++) {
for (let y = 0; y < h; y++){
for (let x = 0; x < w; x++) {
const ix = y*props.map.w+x;

const isPassable = props.map.tiles[ix] === 0;
const tileType = props.map.tiles[ix];
const color = tileTypeToColor(tileType, vec3Color);
const height = tileTypeToHeight(tileType);

const color = isPassable ? 0x11aa11 : 0x888888;
const height = (isPassable ? 0 : 0.8 + Math.random() * 0.7) - 0.01; // TODO quick hack

// TODO - make sure that everything matches with that corrective offset
mat4Pos.makeTranslation(x * xSize + 0.5, height, y * ySize + 0.5); // TODO -1 to move them down because of their height
vec3Color.set(color);

// TODO - this is just a quick and dirty solution
if (isPassable) {
const f = 0.06;
vec3Color.r += (Math.random() - 0.5) * f;
vec3Color.g += (Math.random() - 0.5) * f;
vec3Color.b += (Math.random() - 0.5) * f;
} else {
const d = (Math.random() - 0.5) * 0.1;
vec3Color.r += d;
vec3Color.g += d;
vec3Color.b += d;
}

ref.current.setMatrixAt(ix, mat4Pos);
ref.current.setColorAt(ix, vec3Color);
Expand Down
7 changes: 3 additions & 4 deletions packages/client/src/gfx/MapControls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { OrbitControls } from "./OrbitControls";
import * as THREE from 'three';

export class MapControls extends OrbitControls {
constructor(camera : THREE.Camera, domElement?: HTMLElement) {
constructor(camera : THREE.Camera, minPan: THREE.Vector3, maxPan: THREE.Vector3, domElement?: HTMLElement) {
super(camera, domElement);

this.mouseButtons.RIGHT = undefined;
Expand All @@ -11,8 +11,7 @@ export class MapControls extends OrbitControls {
this.touches.ONE = THREE.TOUCH.PAN;
this.touches.TWO = THREE.TOUCH.DOLLY_ROTATE;

// TODO - real map size
this.minPan.set(15, 0, 15);
this.maxPan.set(85, 10, 85);
this.minPan.copy(minPan);
this.maxPan.copy(maxPan);
}
}
9 changes: 1 addition & 8 deletions packages/client/src/gfx/Unit3D.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,7 @@ import { ThreeCache } from './ThreeCache'
import { FileModel } from './FileModel'
import { UnitDisplayEntry } from './UnitDisplayCatalog'
import { Horizon } from '../debug/Horizon'

// TODO make this settable more easily
const debugFlags = Object.freeze({
showPaths: false,
showHorizons: false,
showCones: false,
showTerrainArrows: true,
});
import { debugFlags } from '../debug/flags'

const cache = new ThreeCache();

Expand Down
24 changes: 20 additions & 4 deletions packages/client/src/gfx/View3D.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import { ReactThreeFiber, Canvas, extend, useThree, useFrame } from '@react-three/fiber'
import { Suspense, useRef, useEffect, useLayoutEffect, useState, CSSProperties } from 'react'
import { debugFlags } from '../debug/flags'

import * as THREE from 'three';

import { MapControls } from './MapControls'
import { Stats } from './Stats'

function CameraControls() {

type CameraControlsProps = {
minPan: THREE.Vector3,
maxPan: THREE.Vector3,
}
function CameraControls(props: CameraControlsProps) {
const { camera, gl: { domElement }, scene } = useThree();

const vert = Math.PI * 0.2;
const horiz = Math.PI * 1.0;

useLayoutEffect (() => {
const c = new MapControls( camera, domElement );
const c = new MapControls( camera, props.minPan, props.maxPan, domElement);

c.minDistance = 30;
c.maxDistance = 300;
Expand Down Expand Up @@ -65,7 +71,8 @@ export default function useShadowHelper(
function MapSpotlight() {
const lightRef = useRef<THREE.SpotLight>(null);
// uncomment to enable
//useShadowHelper(lightRef);
if (debugFlags.showLightConeHelper)
useShadowHelper(lightRef);

const { scene } = useThree();

Expand All @@ -79,6 +86,7 @@ function MapSpotlight() {
lightRef.current.target = target;
}, [lightRef]);

// TODO spotlight setting to allow time of day
return (
<group>
<spotLight
Expand Down Expand Up @@ -107,6 +115,10 @@ export interface Props {
onPointerMissed?: () => void;

enablePan?: boolean;

// map size
viewX: number;
viewY: number;
}

export function View3D(props: Props) {
Expand All @@ -120,6 +132,10 @@ export function View3D(props: Props) {
//zIndex: -1
}

const border = 15.0;
const minPan = new THREE.Vector3(border, 0, border);
const maxPan = new THREE.Vector3(props.viewX - border, 10, props.viewY - border);

return (
<Suspense fallback={null}>
<div style={style} >
Expand All @@ -136,7 +152,7 @@ export function View3D(props: Props) {
dpr={1}
>
<color attach="background" args={[0x11aa11]} />
<CameraControls />
<CameraControls minPan={minPan} maxPan={maxPan} />
<ambientLight args={[0xffffff, 2]} />
<MapSpotlight />
{props.children}
Expand Down
Binary file added packages/server/assets/echo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions packages/server/assets/echo_peninsula.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "Echo Peninsula",
"w": 300,
"h": 150,
"symmetry": "mirror_x",
"imagePath": "echo.png"
}
7 changes: 7 additions & 0 deletions packages/server/assets/map_test_1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "Test Map 1",
"w": 99,
"h": 99,
"symmetry": "none",
"imagePath": "map.png"
}
4 changes: 2 additions & 2 deletions packages/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ rts.post('/create', async (req, res) => {
return
}

// TODO - load or w/e
const map = await getMap('assets/map.png');
const mapPath = "echo_peninsula.json"
const map = await getMap("assets/" + mapPath);
const matchId = String(++lastMatchId); // TODO
const game = newGame(matchId, map);

Expand Down
30 changes: 28 additions & 2 deletions packages/server/src/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,31 @@ import { GameMap } from './types'
import fs from 'fs'
import PNG from 'pngjs'

export function getMap(path: string): Promise<GameMap> {
type Symmetry = "mirror_x" | "mirror_y" | "mirror_xy" | "none";

const mapPathPrefix = "assets/";

export async function getMap(path: string): Promise<GameMap> {
const mapMetadata = JSON.parse(fs.readFileSync(path, 'utf8'));
const gm = await getMapImageData(mapPathPrefix + mapMetadata.imagePath);

if (gm.w !== mapMetadata.w || gm.h !== mapMetadata.h) {
throw new Error("Map image size different than declared");
}

if (!checkSymmetry(gm, mapMetadata.symmetry)) {
throw new Error("Map is not symmetric according to spec");
}

return gm;
}

function checkSymmetry(gm: GameMap, symmetry: Symmetry): boolean {
// TODO
return true;
}

export async function getMapImageData(path: string): Promise<GameMap> {
return new Promise((resolve, reject) => {
fs.createReadStream(path)
.pipe(new PNG.PNG())
Expand All @@ -18,7 +42,9 @@ export function getMap(path: string): Promise<GameMap> {
const b = this.data[idx+2];
const a = this.data[idx+3];

if (b > g)
if (b > (r+g))
tiles.push(2);
else if (b > g)
tiles.push(1);
else
tiles.push(0);
Expand Down
10 changes: 5 additions & 5 deletions packages/server/src/movement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function checkMovePossibility(unit: Unit, gm: GameMap, presence: Presence
return velocity;
}

const allTilesInfluenced = createTilesInfluenced(currentPos, 1);
const allTilesInfluenced = createTilesInfluenced(currentPos, 1, gm);
const otherUnitsNearby =
allTilesInfluenced
.map(t => presence.get(explode(t)))
Expand Down Expand Up @@ -209,14 +209,14 @@ function partition<T> (a: T[], f: (t: T) => boolean): [T[], T[]] {


// TODO duplication with pathfinding
function getSurroundingPos(p: TilePos): TilePos[] {
function getSurroundingPos(p: TilePos, gm: GameMap): TilePos[] {
const SCAN_SIZE = 5;

const tiles = [];
for (let x = p.x - SCAN_SIZE; x < p.x + SCAN_SIZE; x ++) {
for (let y = p.y - SCAN_SIZE; y < p.y + SCAN_SIZE; y ++) {
// TODO map size
if (x < 0 || y < 0 || x > 99 || y > 99)
if (x < 0 || y < 0 || x >= gm.w || y >= gm.h)
continue;

tiles.push({x,y});
Expand All @@ -227,13 +227,13 @@ function getSurroundingPos(p: TilePos): TilePos[] {
}

// TODO use size
function createTilesInfluenced(pos: Position, size: number) {
function createTilesInfluenced(pos: Position, size: number, gm: GameMap) {
const result = [];
const tile = { x: Math.floor(pos.x), y: Math.floor(pos.y) };

// TODO - incorrect, should actually find all affected tiles
// depending on the size
const surrounding = getSurroundingPos(tile);
const surrounding = getSurroundingPos(tile, gm);
surrounding.push(tile);
return surrounding;
}
Expand Down

0 comments on commit 5d40d2e

Please sign in to comment.