implement block placing and destroying
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
window.GameWindow = class {
|
window.GameWindow = class {
|
||||||
|
|
||||||
constructor(renderer, canvasWrapperId) {
|
constructor(minecraft, renderer, canvasWrapperId) {
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
this.canvasWrapperId = canvasWrapperId;
|
this.canvasWrapperId = canvasWrapperId;
|
||||||
|
|
||||||
@@ -30,6 +30,9 @@ window.GameWindow = class {
|
|||||||
// Mouse motion
|
// Mouse motion
|
||||||
document.addEventListener('mousemove', event => this.onMouseMove(event), false);
|
document.addEventListener('mousemove', event => this.onMouseMove(event), false);
|
||||||
|
|
||||||
|
// Mouse buttons
|
||||||
|
document.addEventListener('click', event => minecraft.onMouseClicked(event.button), false);
|
||||||
|
|
||||||
// Create keyboard
|
// Create keyboard
|
||||||
Keyboard.create();
|
Keyboard.create();
|
||||||
}
|
}
|
||||||
@@ -51,7 +54,7 @@ window.GameWindow = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove(event) {
|
onMouseMove(event) {
|
||||||
this.mouseMotionX = -event.movementX;
|
this.mouseMotionX = event.movementX;
|
||||||
this.mouseMotionY = event.movementY;
|
this.mouseMotionY = -event.movementY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,7 +5,7 @@ window.Minecraft = class {
|
|||||||
*/
|
*/
|
||||||
constructor(canvasWrapperId) {
|
constructor(canvasWrapperId) {
|
||||||
this.worldRenderer = new WorldRenderer(this);
|
this.worldRenderer = new WorldRenderer(this);
|
||||||
this.window = new GameWindow(this.worldRenderer, canvasWrapperId);
|
this.window = new GameWindow(this, this.worldRenderer, canvasWrapperId);
|
||||||
this.timer = new Timer(20);
|
this.timer = new Timer(20);
|
||||||
|
|
||||||
this.frames = 0;
|
this.frames = 0;
|
||||||
@@ -66,6 +66,7 @@ window.Minecraft = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onRender(partialTicks) {
|
onRender(partialTicks) {
|
||||||
|
// Player rotation
|
||||||
if (this.window.mouseLocked) {
|
if (this.window.mouseLocked) {
|
||||||
this.player.turn(this.window.mouseMotionX, this.window.mouseMotionY);
|
this.player.turn(this.window.mouseMotionX, this.window.mouseMotionY);
|
||||||
|
|
||||||
@@ -78,7 +79,35 @@ window.Minecraft = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onTick() {
|
onTick() {
|
||||||
|
// Tick the player
|
||||||
this.player.onTick();
|
this.player.onTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMouseClicked(button) {
|
||||||
|
let hitResult = this.player.rayTrace(5, this.timer.partialTicks);
|
||||||
|
|
||||||
|
// Destroy block
|
||||||
|
if (button === 0) {
|
||||||
|
if (hitResult != null) {
|
||||||
|
this.world.setBlockAt(hitResult.x, hitResult.y, hitResult.z, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place block
|
||||||
|
if (button === 2) {
|
||||||
|
if (hitResult != null) {
|
||||||
|
let x = hitResult.x + hitResult.face.x;
|
||||||
|
let y = hitResult.y + hitResult.face.y;
|
||||||
|
let z = hitResult.z + hitResult.face.z;
|
||||||
|
|
||||||
|
let placedBoundingBox = new BoundingBox(x, y, z, x + 1, y + 1, z + 1);
|
||||||
|
|
||||||
|
// Don't place blocks if the player is standing there
|
||||||
|
if (!placedBoundingBox.intersects(this.player.boundingBox)) {
|
||||||
|
this.world.setBlockAt(x, y, z, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ window.Player = class {
|
|||||||
this.motionY = 0.42;
|
this.motionY = 0.42;
|
||||||
|
|
||||||
if (this.sprinting) {
|
if (this.sprinting) {
|
||||||
let radiansYaw = -this.yaw * (Math.PI / 180);
|
let radiansYaw = this.yaw * (Math.PI / 180) + Math.PI;
|
||||||
this.motionX -= Math.sin(radiansYaw) * 0.2;
|
this.motionX -= Math.sin(radiansYaw) * 0.2;
|
||||||
this.motionZ += Math.cos(radiansYaw) * 0.2;
|
this.motionZ += Math.cos(radiansYaw) * 0.2;
|
||||||
}
|
}
|
||||||
@@ -281,7 +281,7 @@ window.Player = class {
|
|||||||
up = up * distance;
|
up = up * distance;
|
||||||
forward = forward * distance;
|
forward = forward * distance;
|
||||||
|
|
||||||
let yawRadians = -this.yaw * (Math.PI / 180);
|
let yawRadians = this.yaw * (Math.PI / 180) + Math.PI;
|
||||||
let sin = Math.sin(yawRadians);
|
let sin = Math.sin(yawRadians);
|
||||||
let cos = Math.cos(yawRadians);
|
let cos = Math.cos(yawRadians);
|
||||||
|
|
||||||
@@ -473,4 +473,41 @@ window.Player = class {
|
|||||||
return this.z - (this.z < 0 ? 1 : 0);
|
return this.z - (this.z < 0 ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPositionEyes(partialTicks) {
|
||||||
|
if (partialTicks === 1.0) {
|
||||||
|
return new Vector3(this.x, this.y + this.getEyeHeight(), this.z);
|
||||||
|
} else {
|
||||||
|
let x = this.prevX + (this.x - this.prevX) * partialTicks;
|
||||||
|
let y = this.prevY + (this.y - this.prevY) * partialTicks + this.getEyeHeight();
|
||||||
|
let z = this.prevZ + (this.z - this.prevZ) * partialTicks;
|
||||||
|
return new Vector3(x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interpolated look vector
|
||||||
|
*/
|
||||||
|
getLook(partialTicks) {
|
||||||
|
// TODO interpolation
|
||||||
|
return this.getVectorForRotation(this.pitch, this.yaw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Vec3 using the pitch and yaw of the entities rotation.
|
||||||
|
*/
|
||||||
|
getVectorForRotation(pitch, yaw) {
|
||||||
|
let z = Math.cos(-yaw * 0.017453292 - Math.PI);
|
||||||
|
let x = Math.sin(-yaw * 0.017453292 - Math.PI);
|
||||||
|
let xz = -Math.cos(-pitch * 0.017453292);
|
||||||
|
let y = Math.sin(-pitch * 0.017453292);
|
||||||
|
return new Vector3(x * xz, y, z * xz);
|
||||||
|
}
|
||||||
|
|
||||||
|
rayTrace(blockReachDistance, partialTicks) {
|
||||||
|
let from = this.getPositionEyes(partialTicks);
|
||||||
|
let direction = this.getLook(partialTicks);
|
||||||
|
let to = from.addVector(direction.x * blockReachDistance, direction.y * blockReachDistance, direction.z * blockReachDistance);
|
||||||
|
return this.world.rayTraceBlocks(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ window.BlockRenderer = class {
|
|||||||
let textureIndex = block.getTextureForFace(face);
|
let textureIndex = block.getTextureForFace(face);
|
||||||
let minU = (textureIndex % 16) / 16.0;
|
let minU = (textureIndex % 16) / 16.0;
|
||||||
let maxU = minU + (16 / 256);
|
let maxU = minU + (16 / 256);
|
||||||
let minV = Math.round(textureIndex / 16);
|
let minV = Math.floor(textureIndex / 16);
|
||||||
let maxV = minV + (16 / 256);
|
let maxV = minV + (16 / 256);
|
||||||
|
|
||||||
// Flip V
|
// Flip V
|
||||||
@@ -65,25 +65,25 @@ window.BlockRenderer = class {
|
|||||||
this.addBlockCorner(world, face, minX, maxY, minZ, minU, minV);
|
this.addBlockCorner(world, face, minX, maxY, minZ, minU, minV);
|
||||||
this.addBlockCorner(world, face, minX, maxY, maxZ, minU, maxV);
|
this.addBlockCorner(world, face, minX, maxY, maxZ, minU, maxV);
|
||||||
}
|
}
|
||||||
if (face === EnumBlockFace.EAST) {
|
if (face === EnumBlockFace.NORTH) {
|
||||||
this.addBlockCorner(world, face, minX, maxY, minZ, maxU, minV);
|
this.addBlockCorner(world, face, minX, maxY, minZ, maxU, minV);
|
||||||
this.addBlockCorner(world, face, maxX, maxY, minZ, minU, minV);
|
this.addBlockCorner(world, face, maxX, maxY, minZ, minU, minV);
|
||||||
this.addBlockCorner(world, face, maxX, minY, minZ, minU, maxV);
|
this.addBlockCorner(world, face, maxX, minY, minZ, minU, maxV);
|
||||||
this.addBlockCorner(world, face, minX, minY, minZ, maxU, maxV);
|
this.addBlockCorner(world, face, minX, minY, minZ, maxU, maxV);
|
||||||
}
|
}
|
||||||
if (face === EnumBlockFace.WEST) {
|
if (face === EnumBlockFace.SOUTH) {
|
||||||
this.addBlockCorner(world, face, minX, maxY, maxZ, minU, minV);
|
this.addBlockCorner(world, face, minX, maxY, maxZ, minU, minV);
|
||||||
this.addBlockCorner(world, face, minX, minY, maxZ, minU, maxV);
|
this.addBlockCorner(world, face, minX, minY, maxZ, minU, maxV);
|
||||||
this.addBlockCorner(world, face, maxX, minY, maxZ, maxU, maxV);
|
this.addBlockCorner(world, face, maxX, minY, maxZ, maxU, maxV);
|
||||||
this.addBlockCorner(world, face, maxX, maxY, maxZ, maxU, minV);
|
this.addBlockCorner(world, face, maxX, maxY, maxZ, maxU, minV);
|
||||||
}
|
}
|
||||||
if (face === EnumBlockFace.NORTH) {
|
if (face === EnumBlockFace.WEST) {
|
||||||
this.addBlockCorner(world, face, minX, maxY, maxZ, maxU, minV);
|
this.addBlockCorner(world, face, minX, maxY, maxZ, maxU, minV);
|
||||||
this.addBlockCorner(world, face, minX, maxY, minZ, minU, minV);
|
this.addBlockCorner(world, face, minX, maxY, minZ, minU, minV);
|
||||||
this.addBlockCorner(world, face, minX, minY, minZ, minU, maxV);
|
this.addBlockCorner(world, face, minX, minY, minZ, minU, maxV);
|
||||||
this.addBlockCorner(world, face, minX, minY, maxZ, maxU, maxV);
|
this.addBlockCorner(world, face, minX, minY, maxZ, maxU, maxV);
|
||||||
}
|
}
|
||||||
if (face === EnumBlockFace.SOUTH) {
|
if (face === EnumBlockFace.EAST) {
|
||||||
this.addBlockCorner(world, face, maxX, minY, maxZ, minU, maxV);
|
this.addBlockCorner(world, face, maxX, minY, maxZ, minU, maxV);
|
||||||
this.addBlockCorner(world, face, maxX, minY, minZ, maxU, maxV);
|
this.addBlockCorner(world, face, maxX, minY, minZ, maxU, maxV);
|
||||||
this.addBlockCorner(world, face, maxX, maxY, minZ, maxU, minV);
|
this.addBlockCorner(world, face, maxX, maxY, minZ, maxU, minV);
|
||||||
|
|||||||
@@ -58,8 +58,8 @@ window.WorldRenderer = class {
|
|||||||
let player = this.minecraft.player;
|
let player = this.minecraft.player;
|
||||||
|
|
||||||
// Rotation
|
// Rotation
|
||||||
this.camera.rotation.y = player.yaw * (Math.PI / 180);
|
this.camera.rotation.y = -player.yaw * (Math.PI / 180) + Math.PI;
|
||||||
this.camera.rotation.x = player.pitch * (Math.PI / 180);
|
this.camera.rotation.x = -player.pitch * (Math.PI / 180);
|
||||||
|
|
||||||
// Position
|
// Position
|
||||||
let x = player.prevX + (player.x - player.prevX) * partialTicks;
|
let x = player.prevX + (player.x - player.prevX) * partialTicks;
|
||||||
@@ -90,21 +90,14 @@ window.WorldRenderer = class {
|
|||||||
renderChunks(renderer, partialTicks) {
|
renderChunks(renderer, partialTicks) {
|
||||||
let world = this.minecraft.world;
|
let world = this.minecraft.world;
|
||||||
|
|
||||||
const xKeys = Object.keys(world.chunks)
|
for(let i in world.chunks) {
|
||||||
for (let x = 0; x < xKeys.length; x++) {
|
let chunk = world.chunks[i];
|
||||||
|
|
||||||
let zArray = world.chunks[xKeys[x]];
|
for (let y = 0; y < chunk.sections.length; y++) {
|
||||||
const zKeys = Object.keys(zArray)
|
let section = chunk.sections[y];
|
||||||
|
|
||||||
for (let z = 0; z < zKeys.length; z++) {
|
if (section.dirty) {
|
||||||
let chunk = zArray[zKeys[z]];
|
section.rebuild(renderer);
|
||||||
|
|
||||||
for (let y = 0; y < chunk.sections.length; y++) {
|
|
||||||
let section = chunk.sections[y];
|
|
||||||
|
|
||||||
if (section.dirty) {
|
|
||||||
section.rebuild(renderer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,15 +22,15 @@ window.World = class {
|
|||||||
return y < 0 || y > World.TOTAL_HEIGHT ? null : chunk.getSection(y >> 4);
|
return y < 0 || y > World.TOTAL_HEIGHT ? null : chunk.getSection(y >> 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCollisionBoxes(aabb) {
|
getCollisionBoxes(region) {
|
||||||
let boundingBoxList = [];
|
let boundingBoxList = [];
|
||||||
|
|
||||||
let minX = MathHelper.floor_double(aabb.minX);
|
let minX = MathHelper.floor_double(region.minX);
|
||||||
let maxX = MathHelper.floor_double(aabb.maxX + 1.0);
|
let maxX = MathHelper.floor_double(region.maxX + 1.0);
|
||||||
let minY = MathHelper.floor_double(aabb.minY);
|
let minY = MathHelper.floor_double(region.minY);
|
||||||
let maxY = MathHelper.floor_double(aabb.maxY + 1.0);
|
let maxY = MathHelper.floor_double(region.maxY + 1.0);
|
||||||
let minZ = MathHelper.floor_double(aabb.minZ);
|
let minZ = MathHelper.floor_double(region.minZ);
|
||||||
let maxZ = MathHelper.floor_double(aabb.maxZ + 1.0);
|
let maxZ = MathHelper.floor_double(region.maxZ + 1.0);
|
||||||
|
|
||||||
for (let x = minX; x < maxX; x++) {
|
for (let x = minX; x < maxX; x++) {
|
||||||
for (let y = minY; y < maxY; y++) {
|
for (let y = minY; y < maxY; y++) {
|
||||||
@@ -64,16 +64,15 @@ window.World = class {
|
|||||||
return chunkSection == null ? 0 : chunkSection.getBlockAt(x & 15, y & 15, z & 15);
|
return chunkSection == null ? 0 : chunkSection.getBlockAt(x & 15, y & 15, z & 15);
|
||||||
}
|
}
|
||||||
|
|
||||||
getChunkAt(x, z) {
|
getChunkSectionAt(chunkX, layerY, chunkZ) {
|
||||||
let zArray = this.chunks[x];
|
return this.getChunkAt(chunkX, chunkZ).getSection(layerY);
|
||||||
if (typeof zArray === 'undefined') {
|
}
|
||||||
zArray = this.chunks[x] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
let chunk = zArray[z];
|
getChunkAt(x, z) {
|
||||||
|
let index = x + (z << 16);
|
||||||
|
let chunk = this.chunks[index];
|
||||||
if (typeof chunk === 'undefined') {
|
if (typeof chunk === 'undefined') {
|
||||||
chunk = new Chunk(this, x, z);
|
this.chunks[index] = chunk = new Chunk(this, x, z);
|
||||||
this.chunks[x][z] = chunk;
|
|
||||||
this.group.add(chunk.group);
|
this.group.add(chunk.group);
|
||||||
}
|
}
|
||||||
return chunk;
|
return chunk;
|
||||||
@@ -99,10 +98,123 @@ window.World = class {
|
|||||||
for (let x = minX; x <= maxX; x++) {
|
for (let x = minX; x <= maxX; x++) {
|
||||||
for (let y = minY; y <= maxY; y++) {
|
for (let y = minY; y <= maxY; y++) {
|
||||||
for (let z = minZ; z <= maxZ; z++) {
|
for (let z = minZ; z <= maxZ; z++) {
|
||||||
this.getChunkAt(x, y, z).queueForRebuild();
|
this.getChunkSectionAt(x, y, z).queueForRebuild();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rayTraceBlocks(from, to) {
|
||||||
|
let toX = MathHelper.floor_double(to.x);
|
||||||
|
let toY = MathHelper.floor_double(to.y);
|
||||||
|
let toZ = MathHelper.floor_double(to.z);
|
||||||
|
|
||||||
|
let x = MathHelper.floor_double(from.x);
|
||||||
|
let y = MathHelper.floor_double(from.y);
|
||||||
|
let z = MathHelper.floor_double(from.z);
|
||||||
|
|
||||||
|
let blockId = this.getBlockAt(x, y, z);
|
||||||
|
let block = Block.getById(blockId);
|
||||||
|
let hit = block == null ? null : block.collisionRayTrace(x, y, z, from, to);
|
||||||
|
|
||||||
|
if (hit != null) {
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastHit = null;
|
||||||
|
|
||||||
|
let counter = 200;
|
||||||
|
while (counter-- >= 0) {
|
||||||
|
if (x === toX && y === toY && z === toZ) {
|
||||||
|
return lastHit;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hitX = true;
|
||||||
|
let hitY = true;
|
||||||
|
let hitZ = true;
|
||||||
|
|
||||||
|
let nearestX1 = 999.0;
|
||||||
|
let nearestY1 = 999.0;
|
||||||
|
let nearestZ1 = 999.0;
|
||||||
|
|
||||||
|
if (toX > x) {
|
||||||
|
nearestX1 = x + 1.0;
|
||||||
|
} else if (toX < x) {
|
||||||
|
nearestX1 = x;
|
||||||
|
} else {
|
||||||
|
hitX = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toY > y) {
|
||||||
|
nearestY1 = y + 1.0;
|
||||||
|
} else if (toY < y) {
|
||||||
|
nearestY1 = y;
|
||||||
|
} else {
|
||||||
|
hitY = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toZ > z) {
|
||||||
|
nearestZ1 = z + 1.0;
|
||||||
|
} else if (toZ < z) {
|
||||||
|
nearestZ1 = z;
|
||||||
|
} else {
|
||||||
|
hitZ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let nearestX = 999.0;
|
||||||
|
let nearestY = 999.0;
|
||||||
|
let nearestZ = 999.0;
|
||||||
|
|
||||||
|
let diffX = to.x - from.x;
|
||||||
|
let diffY = to.y - from.y;
|
||||||
|
let diffZ = to.z - from.z;
|
||||||
|
|
||||||
|
if (hitX) {
|
||||||
|
nearestX = (nearestX1 - from.x) / diffX;
|
||||||
|
}
|
||||||
|
if (hitY) {
|
||||||
|
nearestY = (nearestY1 - from.y) / diffY;
|
||||||
|
}
|
||||||
|
if (hitZ) {
|
||||||
|
nearestZ = (nearestZ1 - from.z) / diffZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nearestX === -0.0) {
|
||||||
|
nearestX = -1.0E-4;
|
||||||
|
}
|
||||||
|
if (nearestY === -0.0) {
|
||||||
|
nearestY = -1.0E-4;
|
||||||
|
}
|
||||||
|
if (nearestZ === -0.0) {
|
||||||
|
nearestZ = -1.0E-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
let face;
|
||||||
|
if (nearestX < nearestY && nearestX < nearestZ) {
|
||||||
|
face = toX > x ? EnumBlockFace.WEST : EnumBlockFace.EAST;
|
||||||
|
from = new Vector3(nearestX1, from.y + diffY * nearestX, from.z + diffZ * nearestX);
|
||||||
|
} else if (nearestY < nearestZ) {
|
||||||
|
face = toY > y ? EnumBlockFace.BOTTOM : EnumBlockFace.TOP;
|
||||||
|
from = new Vector3(from.x + diffX * nearestY, nearestY1, from.z + diffZ * nearestY);
|
||||||
|
} else {
|
||||||
|
face = toZ > z ? EnumBlockFace.NORTH : EnumBlockFace.SOUTH;
|
||||||
|
from = new Vector3(from.x + diffX * nearestZ, from.y + diffY * nearestZ, nearestZ1);
|
||||||
|
}
|
||||||
|
|
||||||
|
x = MathHelper.floor_double(from.x) - (face === EnumBlockFace.EAST ? 1 : 0);
|
||||||
|
y = MathHelper.floor_double(from.y) - (face === EnumBlockFace.TOP ? 1 : 0);
|
||||||
|
z = MathHelper.floor_double(from.z) - (face === EnumBlockFace.SOUTH ? 1 : 0);
|
||||||
|
|
||||||
|
let blockId = this.getBlockAt(x, y, z);
|
||||||
|
let block = Block.getById(blockId);
|
||||||
|
let hit = block == null ? null : block.collisionRayTrace(x, y, z, from, to);
|
||||||
|
if (hit != null) {
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastHit;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -51,6 +51,117 @@ window.Block = class {
|
|||||||
return this.boundingBox;
|
return this.boundingBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
collisionRayTrace(x, y, z, start, end) {
|
||||||
|
start = start.addVector(-x, -y, -z);
|
||||||
|
end = end.addVector(-x, -y, -z);
|
||||||
|
|
||||||
|
let vec3 = start.getIntermediateWithXValue(end, this.boundingBox.minX);
|
||||||
|
let vec31 = start.getIntermediateWithXValue(end, this.boundingBox.maxX);
|
||||||
|
let vec32 = start.getIntermediateWithYValue(end, this.boundingBox.minY);
|
||||||
|
let vec33 = start.getIntermediateWithYValue(end, this.boundingBox.maxY);
|
||||||
|
let vec34 = start.getIntermediateWithZValue(end, this.boundingBox.minZ);
|
||||||
|
let vec35 = start.getIntermediateWithZValue(end, this.boundingBox.maxZ);
|
||||||
|
|
||||||
|
if (!this.isVecInsideYZBounds(vec3)) {
|
||||||
|
vec3 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isVecInsideYZBounds(vec31)) {
|
||||||
|
vec31 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isVecInsideXZBounds(vec32)) {
|
||||||
|
vec32 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isVecInsideXZBounds(vec33)) {
|
||||||
|
vec33 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isVecInsideXYBounds(vec34)) {
|
||||||
|
vec34 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isVecInsideXYBounds(vec35)) {
|
||||||
|
vec35 = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let vec36 = null;
|
||||||
|
if (vec3 != null && (vec36 == null || start.squareDistanceTo(vec3) < start.squareDistanceTo(vec36))) {
|
||||||
|
vec36 = vec3;
|
||||||
|
}
|
||||||
|
if (vec31 != null && (vec36 == null || start.squareDistanceTo(vec31) < start.squareDistanceTo(vec36))) {
|
||||||
|
vec36 = vec31;
|
||||||
|
}
|
||||||
|
if (vec32 != null && (vec36 == null || start.squareDistanceTo(vec32) < start.squareDistanceTo(vec36))) {
|
||||||
|
vec36 = vec32;
|
||||||
|
}
|
||||||
|
if (vec33 != null && (vec36 == null || start.squareDistanceTo(vec33) < start.squareDistanceTo(vec36))) {
|
||||||
|
vec36 = vec33;
|
||||||
|
}
|
||||||
|
if (vec34 != null && (vec36 == null || start.squareDistanceTo(vec34) < start.squareDistanceTo(vec36))) {
|
||||||
|
vec36 = vec34;
|
||||||
|
}
|
||||||
|
if (vec35 != null && (vec36 == null || start.squareDistanceTo(vec35) < start.squareDistanceTo(vec36))) {
|
||||||
|
vec36 = vec35;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vec36 == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let face = null;
|
||||||
|
if (vec36 === vec3) {
|
||||||
|
face = EnumBlockFace.WEST;
|
||||||
|
}
|
||||||
|
if (vec36 === vec31) {
|
||||||
|
face = EnumBlockFace.EAST;
|
||||||
|
}
|
||||||
|
if (vec36 === vec32) {
|
||||||
|
face = EnumBlockFace.BOTTOM;
|
||||||
|
}
|
||||||
|
if (vec36 === vec33) {
|
||||||
|
face = EnumBlockFace.TOP;
|
||||||
|
}
|
||||||
|
if (vec36 === vec34) {
|
||||||
|
face = EnumBlockFace.NORTH;
|
||||||
|
}
|
||||||
|
if (vec36 === vec35) {
|
||||||
|
face = EnumBlockFace.SOUTH;
|
||||||
|
}
|
||||||
|
return new MovingObjectPosition(vec36.addVector(x, y, z), face, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a vector is within the Y and Z bounds of the block.
|
||||||
|
*/
|
||||||
|
isVecInsideYZBounds(point) {
|
||||||
|
return point == null ? false : point.y >= this.boundingBox.minY
|
||||||
|
&& point.y <= this.boundingBox.maxY
|
||||||
|
&& point.z >= this.boundingBox.minZ
|
||||||
|
&& point.z <= this.boundingBox.maxZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a vector is within the X and Z bounds of the block.
|
||||||
|
*/
|
||||||
|
isVecInsideXZBounds(point) {
|
||||||
|
return point == null ? false : point.x >= this.boundingBox.minX
|
||||||
|
&& point.x <= this.boundingBox.maxX
|
||||||
|
&& point.z >= this.boundingBox.minZ
|
||||||
|
&& point.z <= this.boundingBox.maxZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a vector is within the X and Y bounds of the block.
|
||||||
|
*/
|
||||||
|
isVecInsideXYBounds(point) {
|
||||||
|
return point == null ? false : point.x >= this.boundingBox.minX
|
||||||
|
&& point.x <= this.boundingBox.maxX
|
||||||
|
&& point.y >= this.boundingBox.minY
|
||||||
|
&& point.y <= this.boundingBox.maxY;
|
||||||
|
}
|
||||||
|
|
||||||
static getById(typeId) {
|
static getById(typeId) {
|
||||||
return Block.blocks[typeId];
|
return Block.blocks[typeId];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,7 +243,6 @@ window.BoundingBox = class {
|
|||||||
this.maxZ += z;
|
this.maxZ += z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new bounding box with the given offset
|
* Create a new bounding box with the given offset
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ window.EnumBlockFace = class {
|
|||||||
let c = window.EnumBlockFace;
|
let c = window.EnumBlockFace;
|
||||||
c.TOP = new EnumBlockFace(0, 1, 0);
|
c.TOP = new EnumBlockFace(0, 1, 0);
|
||||||
c.BOTTOM = new EnumBlockFace(0, -1, 0);
|
c.BOTTOM = new EnumBlockFace(0, -1, 0);
|
||||||
c.NORTH = new EnumBlockFace(-1, 0, 0);
|
c.NORTH = new EnumBlockFace(0, 0, -1);
|
||||||
c.EAST = new EnumBlockFace(0, 0, -1);
|
c.EAST = new EnumBlockFace(1, 0, 0);
|
||||||
c.SOUTH = new EnumBlockFace(1, 0, 0);
|
c.SOUTH = new EnumBlockFace(0, 0, 1);
|
||||||
c.WEST = new EnumBlockFace(0, 0, 1);
|
c.WEST = new EnumBlockFace(-1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
window.MovingObjectPosition = class {
|
||||||
|
|
||||||
|
constructor(vector, face, x, y, z) {
|
||||||
|
this.vector = vector;
|
||||||
|
this.face = face;
|
||||||
|
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,49 +1,35 @@
|
|||||||
window.Timer = class {
|
window.Timer = class {
|
||||||
|
|
||||||
|
static MS_PER_SECOND = 1000;
|
||||||
|
static MAX_MS_PER_UPDATE = 1000;
|
||||||
|
static MAX_TICKS_PER_UPDATE = 100;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Timer to control the tick speed independently of the framerate
|
* Timer to control the tick speed independently of the framerate
|
||||||
*
|
*
|
||||||
* @param ticksPerSecond Amount of ticks per second
|
* @param ticksPerSecond Amount of ticks per second
|
||||||
*/
|
*/
|
||||||
constructor(ticksPerSecond) {
|
constructor(ticksPerSecond) {
|
||||||
this.MS_PER_SECOND = 1000;
|
// Amount of ticks per second
|
||||||
this.MAX_MS_PER_UPDATE = 1000;
|
|
||||||
this.MAX_TICKS_PER_UPDATE = 100;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Amount of ticks per second
|
|
||||||
*/
|
|
||||||
this.ticksPerSecond = ticksPerSecond;
|
this.ticksPerSecond = ticksPerSecond;
|
||||||
|
|
||||||
/**
|
// Last time updated in milliseconds
|
||||||
* Last time updated in nano seconds
|
this.lastTime = Date.now();
|
||||||
*/
|
|
||||||
this.lastTime = this._nanoTime();
|
|
||||||
|
|
||||||
/**
|
// Scale the tick speed
|
||||||
* Scale the tick speed
|
|
||||||
*/
|
|
||||||
this.timeScale = 1.0;
|
this.timeScale = 1.0;
|
||||||
|
|
||||||
/**
|
// Framerate of the advanceTime update
|
||||||
* Framerate of the advanceTime update
|
|
||||||
*/
|
|
||||||
this.fps = 0.0;
|
this.fps = 0.0;
|
||||||
|
|
||||||
/**
|
// Passed time since last game update
|
||||||
* Passed time since last game update
|
|
||||||
*/
|
|
||||||
this.passedTime = 0.0;
|
this.passedTime = 0.0;
|
||||||
|
|
||||||
/**
|
// The amount of ticks for the current game update.
|
||||||
* The amount of ticks for the current game update.
|
// It's the passed time as an integer
|
||||||
* It's the passed time as an integer
|
|
||||||
*/
|
|
||||||
this.ticks = 0;
|
this.ticks = 0;
|
||||||
|
|
||||||
/**
|
// The overflow of the current tick, caused by casting the passed time to an integer
|
||||||
* The overflow of the current tick, caused by casting the passed time to an integer
|
|
||||||
*/
|
|
||||||
this.partialTicks = 0;
|
this.partialTicks = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +39,7 @@ window.Timer = class {
|
|||||||
* Call this function in the main render loop of the game
|
* Call this function in the main render loop of the game
|
||||||
*/
|
*/
|
||||||
advanceTime() {
|
advanceTime() {
|
||||||
let now = this._nanoTime();
|
let now = Date.now();
|
||||||
let passedMs = now - this.lastTime;
|
let passedMs = now - this.lastTime;
|
||||||
|
|
||||||
// Store nano time of this update
|
// Store nano time of this update
|
||||||
@@ -61,24 +47,20 @@ window.Timer = class {
|
|||||||
|
|
||||||
// Maximum and minimum
|
// Maximum and minimum
|
||||||
passedMs = Math.max(0, passedMs);
|
passedMs = Math.max(0, passedMs);
|
||||||
passedMs = Math.min(this.MAX_MS_PER_UPDATE, passedMs);
|
passedMs = Math.min(Timer.MAX_MS_PER_UPDATE, passedMs);
|
||||||
|
|
||||||
// Calculate fps
|
// Calculate fps
|
||||||
this.fps = this.MS_PER_SECOND / passedMs;
|
this.fps = Timer.MS_PER_SECOND / passedMs;
|
||||||
|
|
||||||
// Calculate passed time and ticks
|
// Calculate passed time and ticks
|
||||||
this.passedTime += passedMs * this.timeScale * this.ticksPerSecond / this.MS_PER_SECOND;
|
this.passedTime += passedMs * this.timeScale * this.ticksPerSecond / Timer.MS_PER_SECOND;
|
||||||
this.ticks = parseInt(this.passedTime);
|
this.ticks = parseInt(this.passedTime);
|
||||||
|
|
||||||
// Maximum ticks per update
|
// Maximum ticks per update
|
||||||
this.ticks = Math.min(this.MAX_TICKS_PER_UPDATE, this.ticks);
|
this.ticks = Math.min(Timer.MAX_TICKS_PER_UPDATE, this.ticks);
|
||||||
|
|
||||||
// Calculate the overflow of the current tick
|
// Calculate the overflow of the current tick
|
||||||
this.passedTime -= this.ticks;
|
this.passedTime -= this.ticks;
|
||||||
this.partialTicks = this.passedTime;
|
this.partialTicks = this.passedTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
_nanoTime() {
|
|
||||||
return Date.now();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
window.Vector3 = class {
|
||||||
|
|
||||||
|
constructor(x = 0, y = 0, z = 0) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
addVector(x, y, z) {
|
||||||
|
return new Vector3(this.x + x, this.y + y, this.z + z);
|
||||||
|
}
|
||||||
|
|
||||||
|
squareDistanceTo(vec) {
|
||||||
|
let d0 = vec.x - this.x;
|
||||||
|
let d1 = vec.y - this.y;
|
||||||
|
let d2 = vec.z - this.z;
|
||||||
|
return d0 * d0 + d1 * d1 + d2 * d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new vector with x value equal to the second parameter, along the line between this vector and the
|
||||||
|
* passed in vector, or null if not possible.
|
||||||
|
*/
|
||||||
|
getIntermediateWithXValue(vec, x) {
|
||||||
|
let d0 = vec.x - this.x;
|
||||||
|
let d1 = vec.y - this.y;
|
||||||
|
let d2 = vec.z - this.z;
|
||||||
|
|
||||||
|
if (d0 * d0 < 1.0000000116860974E-7) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
let d3 = (x - this.x) / d0;
|
||||||
|
return d3 >= 0.0 && d3 <= 1.0 ? new Vector3(this.x + d0 * d3, this.y + d1 * d3, this.z + d2 * d3) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new vector with y value equal to the second parameter, along the line between this vector and the
|
||||||
|
* passed in vector, or null if not possible.
|
||||||
|
*/
|
||||||
|
getIntermediateWithYValue(vec, y) {
|
||||||
|
let d0 = vec.x - this.x;
|
||||||
|
let d1 = vec.y - this.y;
|
||||||
|
let d2 = vec.z - this.z;
|
||||||
|
|
||||||
|
if (d1 * d1 < 1.0000000116860974E-7) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
let d3 = (y - this.y) / d1;
|
||||||
|
return d3 >= 0.0 && d3 <= 1.0 ? new Vector3(this.x + d0 * d3, this.y + d1 * d3, this.z + d2 * d3) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new vector with z value equal to the second parameter, along the line between this vector and the
|
||||||
|
* passed in vector, or null if not possible.
|
||||||
|
*/
|
||||||
|
getIntermediateWithZValue(vec, z) {
|
||||||
|
let d0 = vec.x - this.x;
|
||||||
|
let d1 = vec.y - this.y;
|
||||||
|
let d2 = vec.z - this.z;
|
||||||
|
|
||||||
|
if (d2 * d2 < 1.0000000116860974E-7) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
let d3 = (z - this.z) / d2;
|
||||||
|
return d3 >= 0.0 && d3 <= 1.0 ? new Vector3(this.x + d0 * d3, this.y + d1 * d3, this.z + d2 * d3) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -49,6 +49,8 @@ loadScripts([
|
|||||||
// Minecraft Source
|
// Minecraft Source
|
||||||
"src/js/net/minecraft/util/EnumBlockFace.js",
|
"src/js/net/minecraft/util/EnumBlockFace.js",
|
||||||
"src/js/net/minecraft/util/Timer.js",
|
"src/js/net/minecraft/util/Timer.js",
|
||||||
|
"src/js/net/minecraft/util/Vector3.js",
|
||||||
|
"src/js/net/minecraft/util/MovingObjectPosition.js",
|
||||||
"src/js/net/minecraft/util/MathHelper.js",
|
"src/js/net/minecraft/util/MathHelper.js",
|
||||||
"src/js/net/minecraft/util/BoundingBox.js",
|
"src/js/net/minecraft/util/BoundingBox.js",
|
||||||
"src/js/net/minecraft/util/Keyboard.js",
|
"src/js/net/minecraft/util/Keyboard.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user