Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix rendering of maps and add chunk config per map #49

Merged
merged 6 commits into from
Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions packages/phaserx/src/createChunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,25 @@ import { map, Observable, Subject } from "rxjs";
import { Area, ChunkCoord } from "./types";
import { CoordMap, getChunksInArea, subtract } from "./utils";

export function createChunks(worldView$: Observable<Area>, chunkSize: number) {
export function createChunks(worldView$: Observable<Area>, chunkSize: number, padding = 100) {
const visibleChunks = { current: new CoordMap<boolean>() };

const addedChunks$ = new Subject<ChunkCoord>();
const removedChunks$ = new Subject<ChunkCoord>();

const visibleChunkStream = worldView$.pipe(
map((area) => getChunksInArea(area, chunkSize)) // Calculate current chunks from the world view
map(({ x, y, width, height }) =>
// Calculate current chunks from the world view
getChunksInArea(
{
x: x - padding,
y: y - padding,
width: width + 2 * padding,
height: height + 2 * padding,
},
chunkSize
)
)
Comment on lines +12 to +23
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We extend the viewport for chunking by 100px on each side to "prerender" beyond the actual viewport and avoid panning into unrendered areas

);

visibleChunkStream.subscribe((newVisibleChunks) => {
Expand Down
17 changes: 11 additions & 6 deletions packages/phaserx/src/createPhaserEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { generateFrames } from "./utils";
import { createInput } from "./createInput";

export async function createPhaserEngine<S extends ScenesConfig>(options: PhaserEngineConfig<S>) {
const { scale, sceneConfig, cameraConfig, chunkSize } = options;
const { scale, sceneConfig, cameraConfig, cullingChunkSize } = options;

// Set up Phaser scenes
const sceneConstructors = Object.keys(sceneConfig).map((key) => {
Expand Down Expand Up @@ -60,11 +60,11 @@ export async function createPhaserEngine<S extends ScenesConfig>(options: Phaser
// Setup camera
const camera = createCamera(phaserScene.cameras.main, cameraConfig);

// Setup chunks
const chunks = createChunks(camera.worldView$, chunkSize);
// Setup chunks for viewport culling
const cullingChunks = createChunks(camera.worldView$, cullingChunkSize);

// Setup viewport culling
const culling = createCulling(objectPool, camera, chunks);
const culling = createCulling(objectPool, camera, cullingChunks);

// Setup sprite animations
for (const anim of config.animations) {
Expand All @@ -87,7 +87,12 @@ export async function createPhaserEngine<S extends ScenesConfig>(options: Phaser
// Setup maps
const partialMaps: Partial<Maps<keyof S[typeof key]["maps"]>> = {};
for (const mapKey of Object.keys(config.maps)) {
const { layers, backgroundTile, tileWidth, tileHeight, animationInterval, tileAnimations } = config.maps[mapKey];
const { layers, backgroundTile, tileWidth, tileHeight, animationInterval, tileAnimations, chunkSize } =
config.maps[mapKey];

// Setup chunks
const chunks = createChunks(camera.worldView$, chunkSize);
Comment on lines +90 to +94
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chunk sizes can now be configured per map instead of global (before chunk sizes for the lowest LOD map was 2x2 tiles, way too small and way to high chunking overhead)


const map = createAnimatedTilemap({
scene: phaserScene,
tilesets,
Expand All @@ -112,7 +117,7 @@ export async function createPhaserEngine<S extends ScenesConfig>(options: Phaser

const input = createInput(phaserScene.input);

partialScenes[key] = { phaserScene, objectPool, camera, chunks, culling, maps, input };
partialScenes[key] = { phaserScene, objectPool, camera, culling, maps, input };
}
const scenes = partialScenes as Scenes<S>;

Expand Down
9 changes: 8 additions & 1 deletion packages/phaserx/src/tilemap/createChunkedTilemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export function createChunkedTilemap<TileKeys extends number, LayerKeys extends
params: ChunkedTilemapConfig<TileKeys, LayerKeys>
): ChunkedTilemap<TileKeys, LayerKeys> {
const { scene, tilesets, layerConfig, chunks, backgroundTile, tiles, tileWidth, tileHeight } = params;
const relevantTilesets = Object.keys(layerConfig.layers)
.map((key) => layerConfig.layers[key as LayerKeys].tilesets)
.flat();

// Chunk pixel size must be a multiple of tile witdth and height.
if (mod(chunks.chunkSize, tileWidth) !== 0 || mod(chunks.chunkSize, tileHeight) !== 0) {
Expand Down Expand Up @@ -98,7 +101,9 @@ export function createChunkedTilemap<TileKeys extends number, LayerKeys extends
tileWidth,
width: chunkTileSize.x,
height: chunkTileSize.y,
tilesets: Object.values(tilesets),
tilesets: Object.entries(tilesets)
.filter(([key]) => relevantTilesets.includes(key))
.map(([, tileset]) => tileset),
Comment on lines +104 to +106
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were including all tilesets on every map, now we only include the ones relevant for this map (currently we only have one tileset, but we might have different ones for different LOD maps in the future)

});

const map = new Phaser.Tilemaps.Tilemap(scene, data);
Expand Down Expand Up @@ -128,6 +133,8 @@ export function createChunkedTilemap<TileKeys extends number, LayerKeys extends
if (!visible.current) return;
const map = getMapAtTileCoord(coord);
const putTile = map.putTileAt(tile, mod(coord.x, chunkTileSize.x), mod(coord.y, chunkTileSize.y), undefined, layer);
putTile.width = map.tileWidth;
putTile.height = map.tileHeight;
Comment on lines +136 to +137
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Phaser is automatically setting the tile width/hight to the tileset tileWith/tileHeight when setting a single tile: https://github.com/photonstorm/phaser/blob/1591ebdb777a9be5c706fc18f86a6107fb66717f/src/tilemaps/components/PutTileAt.js#L78-L79

Out tileset has a tile size of 16x16px, but we explicitly want to render it at a larger size for our Tactic/Strategic map with lower level of detail / larger tile sizes. So we have to manually reset the tile size to the map tile size here.


if (tint) {
putTile.tint = tint;
Expand Down
4 changes: 2 additions & 2 deletions packages/phaserx/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export type LayerConfig<A extends Assets, T extends TilesetConfig<A>> = {
};

export type MapConfig<A extends Assets, T extends TilesetConfig<A>, L extends LayerConfig<A, T>> = {
chunkSize: number;
tileWidth: number;
tileHeight: number;
layers: { layers: L; defaultLayer: keyof L & string };
Expand Down Expand Up @@ -137,7 +138,6 @@ type Scene<C extends AnySceneConfig> = {
phaserScene: Phaser.Scene;
objectPool: ObjectPool;
camera: Camera;
chunks: Chunks;
culling: Culling;
maps: Maps<keyof C["maps"]>;
input: Input;
Expand Down Expand Up @@ -191,5 +191,5 @@ export type PhaserEngineConfig<S extends ScenesConfig> = {
sceneConfig: S;
scale: Phaser.Types.Core.ScaleConfig;
cameraConfig: CameraConfig;
chunkSize: number;
cullingChunkSize: number;
};
8 changes: 4 additions & 4 deletions packages/ri/client/src/boot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ async function bootLayers() {
const privateKey = params.get("burnerWalletPrivateKey");
const chainIdString = params.get("chainId");
const personaIdString = params.get("personaId");
const jsonRpc = params.get("rpc") ?? undefined;
const wsRpc = jsonRpc && jsonRpc.replace("http", "ws");
const checkpointUrl = params.get("checkpoint") ?? undefined;
const devMode = params.get("dev") === "true" ?? false;
const jsonRpc = params.get("rpc") || undefined;
const wsRpc = params.get("wsRpc") || (jsonRpc && jsonRpc.replace("http", "ws"));
const checkpointUrl = params.get("checkpoint") || undefined;
const devMode = params.get("dev") === "true" || false;
Comment on lines +43 to +46
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible to configure rpc/wsRpc now via get params as well


let networkLayerConfig;
if (contractAddress && privateKey && chainIdString && personaIdString) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export async function createNetworkLayer(config?: NetworkLayerConfig) {
Stamina: defineComponent(
world,
{ current: Type.Number, max: Type.Number, regeneration: Type.Number },
{ id: "Stamina", metadata: { contractId: keccak256("ember.component.staminaComponent") } }
{ id: "Stamina", metadata: { contractId: keccak256("ember.component.personaComponent") } }
),
LastActionTurn: defineComponent(
world,
Expand Down
5 changes: 4 additions & 1 deletion packages/ri/client/src/layers/Renderer/Phaser/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const config = {
},
maps: {
[Maps.Main]: defineMapConfig({
chunkSize: TILE_WIDTH * 64, // tile size * tile amount
tileWidth: TILE_WIDTH,
tileHeight: TILE_HEIGHT,
backgroundTile: [Tileset.Wall1],
Expand All @@ -51,6 +52,7 @@ export const config = {
},
}),
[Maps.Tactic]: defineMapConfig({
chunkSize: TILE_WIDTH * 64, // tile size * tile amount
tileWidth: TILE_WIDTH * 4,
tileHeight: TILE_HEIGHT * 4,
backgroundTile: [Tileset.Wall1],
Expand All @@ -63,6 +65,7 @@ export const config = {
},
}),
[Maps.Strategic]: defineMapConfig({
chunkSize: TILE_WIDTH * 64 * 8, // tile size * tile amount
tileWidth: TILE_WIDTH * 16,
tileHeight: TILE_HEIGHT * 16,
backgroundTile: [Tileset.Wall1],
Expand Down Expand Up @@ -114,5 +117,5 @@ export const config = {
maxZoom: 2,
minZoom: 1 / 32,
}),
chunkSize: TILE_WIDTH * 16 * 4, // tile size * tile amount
cullingChunkSize: TILE_HEIGHT * 16,
};
12 changes: 9 additions & 3 deletions packages/ri/launcher/src/Store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { JsonRpcProvider } from "@ethersproject/providers";

const burnerWalletStorageKey = "burnerWallet";
const personaStorageKey = "personaId";
const defaultChainSpec = "https://launcher-config.pages.dev/chainSpec.json";
const defaultGameSpec = "https://launcher-config.pages.dev/gameSpec.json";
const defaultChainSpec = "https://config.maps.lattice.xyz/chainSpec.json";
const defaultGameSpec = "https://config.maps.lattice.xyz/gameSpec.json";

interface ChainSpec {
chainId: number;
Expand Down Expand Up @@ -60,6 +60,8 @@ export class Store {
// Override via get params
chainSpec.chainId = Number(params.get("chainId")) || chainSpec.chainId;
chainSpec.personaAddress = params.get("personaAddress") || chainSpec.personaAddress;
chainSpec.rpc = params.get("rpc") || chainSpec.rpc;
chainSpec.wsRpc = params.get("wsRpc") || chainSpec.wsRpc;
chainSpec.personaMirrorAddress = params.get("personaMirrorAddress") || chainSpec.personaMirrorAddress;
chainSpec.personaAllMinterAddress = params.get("personaAllMinterAddress") || chainSpec.personaAllMinterAddress;
gameSpec.address = params.get("address") || gameSpec.address;
Expand Down Expand Up @@ -113,7 +115,11 @@ export class Store {

public get instanceUrl(): string | undefined {
if (this.burnerWallet && this.gameSpec && this.chainSpec && this.persona != null) {
return `${this.gameSpec.client}?burnerWalletPrivateKey=${this.burnerWallet.privateKey}&personaId=${this.personaId}&chainId=${this.chainSpec.chainId}&contractAddress=${this.gameSpec.address}&rpc=${this.chainSpec.rpc}&checkpoint=${this.gameSpec.checkpoint}`;
return `${this.gameSpec.client ?? ""}?burnerWalletPrivateKey=${this.burnerWallet.privateKey ?? ""}&personaId=${
this.personaId ?? ""
}&chainId=${this.chainSpec.chainId ?? ""}&contractAddress=${this.gameSpec.address ?? ""}&rpc=${
this.chainSpec.rpc ?? ""
}&wsRpc=${this.chainSpec.wsRpc ?? ""}&checkpoint=${this.gameSpec.checkpoint ?? ""}`;
}
}
}
Expand Down