some changes
This commit is contained in:
parent
dd9c35d3bd
commit
51a2396d9a
@ -96,7 +96,7 @@ export class Game {
|
|||||||
8,
|
8,
|
||||||
0.5,
|
0.5,
|
||||||
8,
|
8,
|
||||||
this.world.getInterpolatedHeight.bind(this.world),
|
this.world.getHeight.bind(this.world),
|
||||||
);
|
);
|
||||||
|
|
||||||
const flowerfield = Grass.getInstance().createGrassPatch(
|
const flowerfield = Grass.getInstance().createGrassPatch(
|
||||||
@ -104,7 +104,7 @@ export class Game {
|
|||||||
8,
|
8,
|
||||||
4,
|
4,
|
||||||
3,
|
3,
|
||||||
this.world.getInterpolatedHeight.bind(this.world),
|
this.world.getHeight.bind(this.world),
|
||||||
);
|
);
|
||||||
|
|
||||||
const flowerfield2 = Grass.getInstance().createGrassPatch(
|
const flowerfield2 = Grass.getInstance().createGrassPatch(
|
||||||
@ -112,7 +112,7 @@ export class Game {
|
|||||||
4,
|
4,
|
||||||
4,
|
4,
|
||||||
3,
|
3,
|
||||||
this.world.getInterpolatedHeight.bind(this.world),
|
this.world.getHeight.bind(this.world),
|
||||||
);
|
);
|
||||||
|
|
||||||
const grass = Grass.getInstance().createInstance(
|
const grass = Grass.getInstance().createInstance(
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { CanvasTexture, LinearFilter, ClampToEdgeWrapping } from 'three';
|
import { CanvasTexture, LinearFilter, ClampToEdgeWrapping } from 'three';
|
||||||
|
import { rgbToHex, to1D } from '../../common/convert';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws a rounded rectangle using the current state of the canvas.
|
* Draws a rounded rectangle using the current state of the canvas.
|
||||||
@ -172,4 +173,49 @@ export class CanvasUtils {
|
|||||||
|
|
||||||
return { texture, width, height };
|
return { texture, width, height };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readPixelDataRGB(image: HTMLImageElement): number[] {
|
||||||
|
const array = new Array(image.width * image.height);
|
||||||
|
const ctx = document.createElement('canvas').getContext('2d');
|
||||||
|
ctx.canvas.width = image.width;
|
||||||
|
ctx.canvas.height = image.height;
|
||||||
|
ctx.drawImage(image, 0, 0, image.width, image.height);
|
||||||
|
|
||||||
|
// pixel data
|
||||||
|
const data = ctx.getImageData(0, 0, image.width, image.height);
|
||||||
|
for (let x = 0; x < image.width; x++) {
|
||||||
|
for (let y = 0; y < image.height; y++) {
|
||||||
|
const index = to1D(x, y, image.width);
|
||||||
|
array[index] = rgbToHex(
|
||||||
|
data.data[index * 4],
|
||||||
|
data.data[index * 4 + 1],
|
||||||
|
data.data[index * 4 + 2],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readPixelDataRScaled(
|
||||||
|
image: HTMLImageElement,
|
||||||
|
scale: number,
|
||||||
|
): number[] {
|
||||||
|
const array = new Array(image.width * image.height);
|
||||||
|
const ctx = document.createElement('canvas').getContext('2d');
|
||||||
|
ctx.canvas.width = image.width;
|
||||||
|
ctx.canvas.height = image.height;
|
||||||
|
ctx.drawImage(image, 0, 0, image.width, image.height);
|
||||||
|
|
||||||
|
// pixel data
|
||||||
|
const data = ctx.getImageData(0, 0, image.width, image.height);
|
||||||
|
for (let x = 0; x < image.width; x++) {
|
||||||
|
for (let y = 0; y < image.height; y++) {
|
||||||
|
const index = to1D(x, y, image.width);
|
||||||
|
array[index] = (data.data[index * 4] * scale) / 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,10 @@ const nameTagBuilder = new CanvasUtils({
|
|||||||
export class PonyEntity {
|
export class PonyEntity {
|
||||||
public velocity = new Vector3(0, 0, 0);
|
public velocity = new Vector3(0, 0, 0);
|
||||||
public angularVelocity = new Vector3(0, 0, 0);
|
public angularVelocity = new Vector3(0, 0, 0);
|
||||||
|
public onFloor = true;
|
||||||
|
public remote = false;
|
||||||
|
public gravity = -50;
|
||||||
|
public jumpPower = 16;
|
||||||
public mixer!: AnimationMixer;
|
public mixer!: AnimationMixer;
|
||||||
public container!: Object3D;
|
public container!: Object3D;
|
||||||
public model!: Object3D;
|
public model!: Object3D;
|
||||||
@ -58,6 +62,14 @@ export class PonyEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(dt: number) {
|
update(dt: number) {
|
||||||
|
this.mixer.update(dt);
|
||||||
|
|
||||||
|
if (this.remote) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.velocity.y += this.gravity * dt;
|
||||||
|
|
||||||
this.container.position.add(this.velocity.clone().multiplyScalar(dt));
|
this.container.position.add(this.velocity.clone().multiplyScalar(dt));
|
||||||
this.container.rotation.setFromVector3(
|
this.container.rotation.setFromVector3(
|
||||||
new Vector3(
|
new Vector3(
|
||||||
@ -69,13 +81,18 @@ export class PonyEntity {
|
|||||||
|
|
||||||
// Put pony on the terrain
|
// Put pony on the terrain
|
||||||
const terrainFloorHeight =
|
const terrainFloorHeight =
|
||||||
this.heightSource?.getInterpolatedHeight(
|
this.heightSource?.getHeight(
|
||||||
this.container.position.x,
|
this.container.position.x,
|
||||||
this.container.position.z,
|
this.container.position.z,
|
||||||
) || 0;
|
) || 0;
|
||||||
this.container.position.y = terrainFloorHeight;
|
|
||||||
|
|
||||||
this.mixer.update(dt);
|
if (this.container.position.y <= terrainFloorHeight) {
|
||||||
|
this.onFloor = true;
|
||||||
|
this.velocity.y = 0;
|
||||||
|
this.container.position.y = terrainFloorHeight;
|
||||||
|
} else {
|
||||||
|
this.onFloor = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
@ -106,6 +123,10 @@ export class PonyEntity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public jump() {
|
||||||
|
this.velocity.y = 16;
|
||||||
|
}
|
||||||
|
|
||||||
public setColor(color: number | string) {
|
public setColor(color: number | string) {
|
||||||
this.material.color = new Color(color);
|
this.material.color = new Color(color);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ export class PlayerEntity extends PonyEntity {
|
|||||||
private _targetFrame: any = null;
|
private _targetFrame: any = null;
|
||||||
private _lastFrame: any = null;
|
private _lastFrame: any = null;
|
||||||
private _chats: ChatBubble[] = [];
|
private _chats: ChatBubble[] = [];
|
||||||
|
public remote = true;
|
||||||
|
|
||||||
private _p1 = new Vector3();
|
private _p1 = new Vector3();
|
||||||
private _p2 = new Vector3();
|
private _p2 = new Vector3();
|
||||||
|
@ -97,14 +97,17 @@ export class Player extends PonyEntity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vector.y !== 0) {
|
if (vector.y !== 0) {
|
||||||
this.velocity.copy(this._lookVector.clone().multiplyScalar(vector.y * 5));
|
const directional = this._lookVector
|
||||||
|
.clone()
|
||||||
|
.multiplyScalar(vector.y * 2.5);
|
||||||
|
this.velocity.set(directional.x, this.velocity.y, directional.z);
|
||||||
this.changes.velocity = this.velocity.toArray();
|
this.changes.velocity = this.velocity.toArray();
|
||||||
|
|
||||||
this._wasMoving = true;
|
this._wasMoving = true;
|
||||||
this.setWalkAnimationState(1);
|
this.setWalkAnimationState(1);
|
||||||
} else if (this._wasMoving && !wasExternalForce) {
|
} else if (this._wasMoving && !wasExternalForce) {
|
||||||
this._wasMoving = false;
|
this._wasMoving = false;
|
||||||
this.velocity.set(0, 0, 0);
|
this.velocity.set(0, this.velocity.y, 0);
|
||||||
this.changes.velocity = this.velocity.toArray();
|
this.changes.velocity = this.velocity.toArray();
|
||||||
this.changes.position = this.container.position.toArray();
|
this.changes.position = this.container.position.toArray();
|
||||||
this.setWalkAnimationState(0);
|
this.setWalkAnimationState(0);
|
||||||
@ -133,6 +136,10 @@ export class Player extends PonyEntity {
|
|||||||
this._direction.x = 0;
|
this._direction.x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.keydownMap[' '] && !this._prevKeydownMap[' '] && this.onFloor) {
|
||||||
|
this.jump();
|
||||||
|
}
|
||||||
|
|
||||||
this.moveCharacter(dt);
|
this.moveCharacter(dt);
|
||||||
super.update(dt);
|
super.update(dt);
|
||||||
|
|
||||||
|
@ -17,10 +17,10 @@ export class ClientWorld extends WorldManager {
|
|||||||
private _shader = new ClientWorldChunkShader(this._worldTextures);
|
private _shader = new ClientWorldChunkShader(this._worldTextures);
|
||||||
|
|
||||||
getNormalVector(x: number, y: number): Vector3 {
|
getNormalVector(x: number, y: number): Vector3 {
|
||||||
const heightL = this.getHeight(x - 1, y);
|
const heightL = this.getPointHeight(x - 1, y);
|
||||||
const heightR = this.getHeight(x + 1, y);
|
const heightR = this.getPointHeight(x + 1, y);
|
||||||
const heightD = this.getHeight(x, y - 1);
|
const heightD = this.getPointHeight(x, y - 1);
|
||||||
const heightU = this.getHeight(x, y + 1);
|
const heightU = this.getPointHeight(x, y + 1);
|
||||||
const normalized = new Vector3(heightL - heightR, 2, heightD - heightU);
|
const normalized = new Vector3(heightL - heightR, 2, heightD - heightU);
|
||||||
normalized.normalize();
|
normalized.normalize();
|
||||||
return normalized;
|
return normalized;
|
||||||
@ -75,7 +75,7 @@ export class ClientWorld extends WorldManager {
|
|||||||
material,
|
material,
|
||||||
);
|
);
|
||||||
|
|
||||||
root.getHeight = this.getInterpolatedHeight.bind(this);
|
root.getHeight = this.getHeight.bind(this);
|
||||||
root.getNormal = this.getNormalVector.bind(this);
|
root.getNormal = this.getNormalVector.bind(this);
|
||||||
root.initialize();
|
root.initialize();
|
||||||
|
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { ImageLoader } from 'three';
|
import { ImageLoader } from 'three';
|
||||||
import { to1D } from '../../../common/convert';
|
|
||||||
import { WorldLoader } from '../../../common/world/WorldLoader';
|
import { WorldLoader } from '../../../common/world/WorldLoader';
|
||||||
|
import { CanvasUtils } from '../canvas-utils';
|
||||||
|
|
||||||
const loader = new ImageLoader();
|
const loader = new ImageLoader();
|
||||||
const worldPath = '/assets/terrain/region/';
|
const canvasUtil = new CanvasUtils();
|
||||||
|
const worldPath = '/assets/terrain/region';
|
||||||
|
|
||||||
export class ClientWorldLoader implements WorldLoader {
|
export class ClientWorldLoader implements WorldLoader {
|
||||||
async loadHeightMap(
|
async loadHeightMap(
|
||||||
@ -14,7 +15,7 @@ export class ClientWorldLoader implements WorldLoader {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
loader.load(
|
loader.load(
|
||||||
`${worldPath}/height-${chunkX}-${chunkY}.png`,
|
`${worldPath}/height-${chunkX}-${chunkY}.png`,
|
||||||
(data) => resolve(ClientWorldLoader.heightFromImage(data, scale)),
|
(data) => resolve(canvasUtil.readPixelDataRScaled(data, scale)),
|
||||||
undefined,
|
undefined,
|
||||||
(err) => {
|
(err) => {
|
||||||
reject(err);
|
reject(err);
|
||||||
@ -22,26 +23,4 @@ export class ClientWorldLoader implements WorldLoader {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static heightFromImage(
|
|
||||||
image: HTMLImageElement,
|
|
||||||
scale: number,
|
|
||||||
): number[] {
|
|
||||||
const array = new Array(image.width * image.height);
|
|
||||||
const ctx = document.createElement('canvas').getContext('2d');
|
|
||||||
ctx.canvas.width = image.width;
|
|
||||||
ctx.canvas.height = image.height;
|
|
||||||
ctx.drawImage(image, 0, 0, image.width, image.height);
|
|
||||||
|
|
||||||
// pixel data
|
|
||||||
const data = ctx.getImageData(0, 0, image.width, image.height);
|
|
||||||
for (let x = 0; x < image.width; x++) {
|
|
||||||
for (let y = 0; y < image.height; y++) {
|
|
||||||
const index = to1D(x, y, image.width);
|
|
||||||
array[index] = (data.data[index * 4] * scale) / 255;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ export class QuadtreeNode {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (this._leaf) {
|
if (this._leaf) {
|
||||||
if (abs.distanceTo(camera) < size && this._canSubdivide()) {
|
if (this._canSubdivide() && abs.distanceTo(camera) < size) {
|
||||||
this._subdivide();
|
this._subdivide();
|
||||||
this.root.actionsLeft -= 1;
|
this.root.actionsLeft -= 1;
|
||||||
return;
|
return;
|
||||||
|
@ -6,6 +6,10 @@ export function convertHex(hex: number): { r: number; g: number; b: number } {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function rgbToHex(r: number, g: number, b: number): number {
|
||||||
|
return (1 << 24) + (r << 16) + (g << 8) + b;
|
||||||
|
}
|
||||||
|
|
||||||
export function hexToString(hex: number): string {
|
export function hexToString(hex: number): string {
|
||||||
const { r, g, b } = convertHex(hex);
|
const { r, g, b } = convertHex(hex);
|
||||||
return `#${r.toString(16).padStart(2, '0')}${g
|
return `#${r.toString(16).padStart(2, '0')}${g
|
||||||
|
@ -46,7 +46,7 @@ export class WorldManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getHeight(x: number, y: number): number {
|
getPointHeight(x: number, y: number): number {
|
||||||
const chunkX = Math.floor(x / this.worldChunkSize);
|
const chunkX = Math.floor(x / this.worldChunkSize);
|
||||||
const chunkY = Math.floor(y / this.worldChunkSize);
|
const chunkY = Math.floor(y / this.worldChunkSize);
|
||||||
if (
|
if (
|
||||||
@ -64,7 +64,7 @@ export class WorldManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
getInterpolatedHeight(x: number, y: number): number {
|
getHeight(x: number, y: number): number {
|
||||||
const chunkX = Math.floor(x / this.worldChunkSize);
|
const chunkX = Math.floor(x / this.worldChunkSize);
|
||||||
const chunkY = Math.floor(y / this.worldChunkSize);
|
const chunkY = Math.floor(y / this.worldChunkSize);
|
||||||
if (
|
if (
|
||||||
|
Loading…
Reference in New Issue
Block a user