implement block break particles, version 1.0.2
This commit is contained in:
@@ -31,6 +31,7 @@ Click [here](https://labystudio.de/page/minecraft/) for a demo!
|
|||||||
- Arm swing animation
|
- Arm swing animation
|
||||||
- Walking animation
|
- Walking animation
|
||||||
- Crouch animation
|
- Crouch animation
|
||||||
|
- Block break particles
|
||||||
- World
|
- World
|
||||||
- 16x16x16 Chunks
|
- 16x16x16 Chunks
|
||||||
- Block type, data, sky & block lightning
|
- Block type, data, sky & block lightning
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ import GrassColorizer from "./render/GrassColorizer.js";
|
|||||||
import GuiMainMenu from "./gui/screens/GuiMainMenu.js";
|
import GuiMainMenu from "./gui/screens/GuiMainMenu.js";
|
||||||
import GuiLoadingScreen from "./gui/screens/GuiLoadingScreen.js";
|
import GuiLoadingScreen from "./gui/screens/GuiLoadingScreen.js";
|
||||||
import * as THREE from "../../../../../libraries/three.module.js";
|
import * as THREE from "../../../../../libraries/three.module.js";
|
||||||
|
import ParticleRenderer from "./render/particle/ParticleRenderer.js";
|
||||||
|
|
||||||
export default class Minecraft {
|
export default class Minecraft {
|
||||||
|
|
||||||
static VERSION = "1.0.1"
|
static VERSION = "1.0.2"
|
||||||
static URL_GITHUB = "https://github.com/labystudio/js-minecraft";
|
static URL_GITHUB = "https://github.com/labystudio/js-minecraft";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,6 +66,8 @@ export default class Minecraft {
|
|||||||
// Grass colorizer
|
// Grass colorizer
|
||||||
this.grassColorizer = new GrassColorizer(this);
|
this.grassColorizer = new GrassColorizer(this);
|
||||||
|
|
||||||
|
this.particleRenderer = new ParticleRenderer(this);
|
||||||
|
|
||||||
// Update window size
|
// Update window size
|
||||||
this.window.updateWindowSize();
|
this.window.updateWindowSize();
|
||||||
|
|
||||||
@@ -219,6 +222,9 @@ export default class Minecraft {
|
|||||||
|
|
||||||
// Tick the player
|
// Tick the player
|
||||||
this.player.onUpdate();
|
this.player.onUpdate();
|
||||||
|
|
||||||
|
// Tick particle renderer
|
||||||
|
this.particleRenderer.onTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tick the screen
|
// Tick the screen
|
||||||
@@ -293,6 +299,9 @@ export default class Minecraft {
|
|||||||
1.0
|
1.0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Spawn particle
|
||||||
|
this.particleRenderer.spawnBlockBreakParticle(this.world, hitResult.x, hitResult.y, hitResult.z);
|
||||||
|
|
||||||
// Destroy block
|
// Destroy block
|
||||||
this.world.setBlockAt(hitResult.x, hitResult.y, hitResult.z, 0);
|
this.world.setBlockAt(hitResult.x, hitResult.y, hitResult.z, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import BoundingBox from "../../util/BoundingBox.js";
|
import BoundingBox from "../../util/BoundingBox.js";
|
||||||
import MathHelper from "../../util/MathHelper.js";
|
import MathHelper from "../../util/MathHelper.js";
|
||||||
|
import Random from "../../util/Random.js";
|
||||||
|
|
||||||
export default class Entity {
|
export default class Entity {
|
||||||
|
|
||||||
constructor(minecraft, world) {
|
constructor(minecraft, world) {
|
||||||
this.minecraft = minecraft;
|
this.minecraft = minecraft;
|
||||||
this.world = world;
|
this.world = world;
|
||||||
|
this.random = new Random();
|
||||||
|
|
||||||
this.renderer = this.minecraft.worldRenderer.entityRenderManager.createEntityRendererByEntity(this);
|
this.renderer = this.minecraft.worldRenderer.entityRenderManager.createEntityRendererByEntity(this);
|
||||||
|
|
||||||
@@ -13,10 +15,15 @@ export default class Entity {
|
|||||||
this.y = 0;
|
this.y = 0;
|
||||||
this.z = 0;
|
this.z = 0;
|
||||||
|
|
||||||
|
this.width = 0.0;
|
||||||
|
this.height = 0.0;
|
||||||
|
|
||||||
this.motionX = 0;
|
this.motionX = 0;
|
||||||
this.motionY = 0;
|
this.motionY = 0;
|
||||||
this.motionZ = 0;
|
this.motionZ = 0;
|
||||||
|
|
||||||
|
this.stepHeight = 0.0;
|
||||||
|
|
||||||
this.onGround = false;
|
this.onGround = false;
|
||||||
this.sneaking = false;
|
this.sneaking = false;
|
||||||
|
|
||||||
@@ -35,8 +42,36 @@ export default class Entity {
|
|||||||
this.nextStepDistance = 1;
|
this.nextStepDistance = 1;
|
||||||
|
|
||||||
this.ticksExisted = 0;
|
this.ticksExisted = 0;
|
||||||
|
this.isDead = false;
|
||||||
|
|
||||||
this.boundingBox = new BoundingBox();
|
this.boundingBox = new BoundingBox();
|
||||||
|
this.setPosition(this.x, this.y, this.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
setPosition(x, y, z) {
|
||||||
|
// Update position
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
|
||||||
|
// Update bounding box
|
||||||
|
let width = this.width / 2;
|
||||||
|
this.boundingBox = new BoundingBox(
|
||||||
|
x - width,
|
||||||
|
y,
|
||||||
|
z - width,
|
||||||
|
x + width,
|
||||||
|
y + this.height,
|
||||||
|
z + width
|
||||||
|
);
|
||||||
|
|
||||||
|
this.motionX = 0;
|
||||||
|
this.motionY = 0;
|
||||||
|
this.motionZ = 0;
|
||||||
|
|
||||||
|
this.prevX = this.x;
|
||||||
|
this.prevY = this.y;
|
||||||
|
this.prevZ = this.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
onUpdate() {
|
onUpdate() {
|
||||||
@@ -67,4 +102,97 @@ export default class Entity {
|
|||||||
return this.boundingBox.height() * 0.8;
|
return this.boundingBox.height() * 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moveCollide(targetX, targetY, targetZ) {
|
||||||
|
// Target position
|
||||||
|
let originalTargetX = targetX;
|
||||||
|
let originalTargetY = targetY;
|
||||||
|
let originalTargetZ = targetZ;
|
||||||
|
|
||||||
|
if (this.onGround && this.sneaking) {
|
||||||
|
for (; targetX !== 0.0 && this.world.getCollisionBoxes(this.boundingBox.offset(targetX, -this.stepHeight, 0.0)).length === 0; originalTargetX = targetX) {
|
||||||
|
if (targetX < 0.05 && targetX >= -0.05) {
|
||||||
|
targetX = 0.0;
|
||||||
|
} else if (targetX > 0.0) {
|
||||||
|
targetX -= 0.05;
|
||||||
|
} else {
|
||||||
|
targetX += 0.05;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; targetZ !== 0.0 && this.world.getCollisionBoxes(this.boundingBox.offset(0.0, -this.stepHeight, targetZ)).length === 0; originalTargetZ = targetZ) {
|
||||||
|
if (targetZ < 0.05 && targetZ >= -0.05) {
|
||||||
|
targetZ = 0.0;
|
||||||
|
} else if (targetZ > 0.0) {
|
||||||
|
targetZ -= 0.05;
|
||||||
|
} else {
|
||||||
|
targetZ += 0.05;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; targetX !== 0.0 && targetZ !== 0.0 && this.world.getCollisionBoxes(this.boundingBox.offset(targetX, -this.stepHeight, targetZ)).length === 0; originalTargetZ = targetZ) {
|
||||||
|
if (targetX < 0.05 && targetX >= -0.05) {
|
||||||
|
targetX = 0.0;
|
||||||
|
} else if (targetX > 0.0) {
|
||||||
|
targetX -= 0.05;
|
||||||
|
} else {
|
||||||
|
targetX += 0.05;
|
||||||
|
}
|
||||||
|
|
||||||
|
originalTargetX = targetX;
|
||||||
|
|
||||||
|
if (targetZ < 0.05 && targetZ >= -0.05) {
|
||||||
|
targetZ = 0.0;
|
||||||
|
} else if (targetZ > 0.0) {
|
||||||
|
targetZ -= 0.05;
|
||||||
|
} else {
|
||||||
|
targetZ += 0.05;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get level tiles as bounding boxes
|
||||||
|
let boundingBoxList = this.world.getCollisionBoxes(this.boundingBox.expand(targetX, targetY, targetZ));
|
||||||
|
|
||||||
|
// Move bounding box
|
||||||
|
for (let aABB in boundingBoxList) {
|
||||||
|
targetY = boundingBoxList[aABB].clipYCollide(this.boundingBox, targetY);
|
||||||
|
}
|
||||||
|
this.boundingBox.move(0.0, targetY, 0.0);
|
||||||
|
|
||||||
|
for (let aABB in boundingBoxList) {
|
||||||
|
targetX = boundingBoxList[aABB].clipXCollide(this.boundingBox, targetX);
|
||||||
|
}
|
||||||
|
this.boundingBox.move(targetX, 0.0, 0.0);
|
||||||
|
|
||||||
|
for (let aABB in boundingBoxList) {
|
||||||
|
targetZ = boundingBoxList[aABB].clipZCollide(this.boundingBox, targetZ);
|
||||||
|
}
|
||||||
|
this.boundingBox.move(0.0, 0.0, targetZ);
|
||||||
|
|
||||||
|
this.onGround = originalTargetY !== targetY && originalTargetY < 0.0;
|
||||||
|
|
||||||
|
// Stop motion on collision
|
||||||
|
if (originalTargetX !== targetX) {
|
||||||
|
this.motionX = 0.0;
|
||||||
|
}
|
||||||
|
if (originalTargetY !== targetY) {
|
||||||
|
this.motionY = 0.0;
|
||||||
|
}
|
||||||
|
if (originalTargetZ !== targetZ) {
|
||||||
|
this.motionZ = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update position
|
||||||
|
this.x = (this.boundingBox.minX + this.boundingBox.maxX) / 2.0;
|
||||||
|
this.y = this.boundingBox.minY;
|
||||||
|
this.z = (this.boundingBox.minZ + this.boundingBox.maxZ) / 2.0;
|
||||||
|
|
||||||
|
// Horizontal collision?
|
||||||
|
return originalTargetX !== targetX || originalTargetZ !== targetZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
kill() {
|
||||||
|
this.isDead = true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import Inventory from "../inventory/Inventory.js";
|
import Inventory from "../inventory/Inventory.js";
|
||||||
import EntityLiving from "./EntityLiving.js";
|
import EntityLiving from "./EntityLiving.js";
|
||||||
import BoundingBox from "../../util/BoundingBox.js";
|
|
||||||
import Block from "../world/block/Block.js";
|
import Block from "../world/block/Block.js";
|
||||||
import MathHelper from "../../util/MathHelper.js";
|
import MathHelper from "../../util/MathHelper.js";
|
||||||
import Keyboard from "../../util/Keyboard.js";
|
import Keyboard from "../../util/Keyboard.js";
|
||||||
@@ -44,6 +43,9 @@ export default class PlayerEntity extends EntityLiving {
|
|||||||
this.cameraPitch = 0;
|
this.cameraPitch = 0;
|
||||||
this.prevCameraYaw = 0;
|
this.prevCameraYaw = 0;
|
||||||
this.prevCameraPitch = 0;
|
this.prevCameraPitch = 0;
|
||||||
|
|
||||||
|
this.width = 0.6;
|
||||||
|
this.height = 1.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
respawn() {
|
respawn() {
|
||||||
@@ -51,28 +53,6 @@ export default class PlayerEntity extends EntityLiving {
|
|||||||
this.setPosition(spawn.x, spawn.y, spawn.z);
|
this.setPosition(spawn.x, spawn.y, spawn.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
setPosition(x, y, z) {
|
|
||||||
let width = 0.3;
|
|
||||||
let height = 0.9;
|
|
||||||
this.boundingBox = new BoundingBox(
|
|
||||||
x - width,
|
|
||||||
y - height,
|
|
||||||
z - width,
|
|
||||||
x + width,
|
|
||||||
y + height,
|
|
||||||
z + width
|
|
||||||
);
|
|
||||||
|
|
||||||
this.motionX = 0;
|
|
||||||
this.motionY = 0;
|
|
||||||
this.motionZ = 0;
|
|
||||||
|
|
||||||
// Update position
|
|
||||||
this.x = (this.boundingBox.minX + this.boundingBox.maxX) / 2.0;
|
|
||||||
this.y = this.boundingBox.minY;
|
|
||||||
this.z = (this.boundingBox.minZ + this.boundingBox.maxZ) / 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
turn(motionX, motionY) {
|
turn(motionX, motionY) {
|
||||||
let sensitivity = this.minecraft.settings.sensitivity / 500;
|
let sensitivity = this.minecraft.settings.sensitivity / 500;
|
||||||
this.rotationYaw = this.rotationYaw + motionX * sensitivity;
|
this.rotationYaw = this.rotationYaw + motionX * sensitivity;
|
||||||
@@ -366,95 +346,6 @@ export default class PlayerEntity extends EntityLiving {
|
|||||||
this.sneaking = sneaking;
|
this.sneaking = sneaking;
|
||||||
}
|
}
|
||||||
|
|
||||||
moveCollide(targetX, targetY, targetZ) {
|
|
||||||
// Target position
|
|
||||||
let originalTargetX = targetX;
|
|
||||||
let originalTargetY = targetY;
|
|
||||||
let originalTargetZ = targetZ;
|
|
||||||
|
|
||||||
if (this.onGround && this.sneaking) {
|
|
||||||
for (; targetX !== 0.0 && this.world.getCollisionBoxes(this.boundingBox.offset(targetX, -this.stepHeight, 0.0)).length === 0; originalTargetX = targetX) {
|
|
||||||
if (targetX < 0.05 && targetX >= -0.05) {
|
|
||||||
targetX = 0.0;
|
|
||||||
} else if (targetX > 0.0) {
|
|
||||||
targetX -= 0.05;
|
|
||||||
} else {
|
|
||||||
targetX += 0.05;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; targetZ !== 0.0 && this.world.getCollisionBoxes(this.boundingBox.offset(0.0, -this.stepHeight, targetZ)).length === 0; originalTargetZ = targetZ) {
|
|
||||||
if (targetZ < 0.05 && targetZ >= -0.05) {
|
|
||||||
targetZ = 0.0;
|
|
||||||
} else if (targetZ > 0.0) {
|
|
||||||
targetZ -= 0.05;
|
|
||||||
} else {
|
|
||||||
targetZ += 0.05;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; targetX !== 0.0 && targetZ !== 0.0 && this.world.getCollisionBoxes(this.boundingBox.offset(targetX, -this.stepHeight, targetZ)).length === 0; originalTargetZ = targetZ) {
|
|
||||||
if (targetX < 0.05 && targetX >= -0.05) {
|
|
||||||
targetX = 0.0;
|
|
||||||
} else if (targetX > 0.0) {
|
|
||||||
targetX -= 0.05;
|
|
||||||
} else {
|
|
||||||
targetX += 0.05;
|
|
||||||
}
|
|
||||||
|
|
||||||
originalTargetX = targetX;
|
|
||||||
|
|
||||||
if (targetZ < 0.05 && targetZ >= -0.05) {
|
|
||||||
targetZ = 0.0;
|
|
||||||
} else if (targetZ > 0.0) {
|
|
||||||
targetZ -= 0.05;
|
|
||||||
} else {
|
|
||||||
targetZ += 0.05;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get level tiles as bounding boxes
|
|
||||||
let boundingBoxList = this.world.getCollisionBoxes(this.boundingBox.expand(targetX, targetY, targetZ));
|
|
||||||
|
|
||||||
// Move bounding box
|
|
||||||
for (let aABB in boundingBoxList) {
|
|
||||||
targetY = boundingBoxList[aABB].clipYCollide(this.boundingBox, targetY);
|
|
||||||
}
|
|
||||||
this.boundingBox.move(0.0, targetY, 0.0);
|
|
||||||
|
|
||||||
for (let aABB in boundingBoxList) {
|
|
||||||
targetX = boundingBoxList[aABB].clipXCollide(this.boundingBox, targetX);
|
|
||||||
}
|
|
||||||
this.boundingBox.move(targetX, 0.0, 0.0);
|
|
||||||
|
|
||||||
for (let aABB in boundingBoxList) {
|
|
||||||
targetZ = boundingBoxList[aABB].clipZCollide(this.boundingBox, targetZ);
|
|
||||||
}
|
|
||||||
this.boundingBox.move(0.0, 0.0, targetZ);
|
|
||||||
|
|
||||||
this.onGround = originalTargetY !== targetY && originalTargetY < 0.0;
|
|
||||||
|
|
||||||
// Stop motion on collision
|
|
||||||
if (originalTargetX !== targetX) {
|
|
||||||
this.motionX = 0.0;
|
|
||||||
}
|
|
||||||
if (originalTargetY !== targetY) {
|
|
||||||
this.motionY = 0.0;
|
|
||||||
}
|
|
||||||
if (originalTargetZ !== targetZ) {
|
|
||||||
this.motionZ = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update position
|
|
||||||
this.x = (this.boundingBox.minX + this.boundingBox.maxX) / 2.0;
|
|
||||||
this.y = this.boundingBox.minY;
|
|
||||||
this.z = (this.boundingBox.minZ + this.boundingBox.maxZ) / 2.0;
|
|
||||||
|
|
||||||
// Horizontal collision?
|
|
||||||
return originalTargetX !== targetX || originalTargetZ !== targetZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
getEyeHeight() {
|
getEyeHeight() {
|
||||||
return this.sneaking ? 1.50 : 1.62;
|
return this.sneaking ? 1.50 : 1.62;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,6 +117,9 @@ export default class WorldRenderer {
|
|||||||
// Render target block
|
// Render target block
|
||||||
this.renderBlockHitBox(player, partialTicks);
|
this.renderBlockHitBox(player, partialTicks);
|
||||||
|
|
||||||
|
// Render particles
|
||||||
|
this.minecraft.particleRenderer.renderParticles(player, partialTicks);
|
||||||
|
|
||||||
// Hide all entities and make them visible during rendering
|
// Hide all entities and make them visible during rendering
|
||||||
for (let entity of this.minecraft.world.entities) {
|
for (let entity of this.minecraft.world.entities) {
|
||||||
entity.renderer.group.visible = false;
|
entity.renderer.group.visible = false;
|
||||||
@@ -615,7 +618,7 @@ export default class WorldRenderer {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Flush by rebuilding 8 chunk sections
|
// Flush by rebuilding 8 chunk sections
|
||||||
if(this.flushRebuild) {
|
if (this.flushRebuild) {
|
||||||
this.flushRebuild = false;
|
this.flushRebuild = false;
|
||||||
|
|
||||||
for (let i = 0; i < 8; i++) {
|
for (let i = 0; i < 8; i++) {
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ export default class EntityRenderManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createEntityRendererByEntity(entity) {
|
createEntityRendererByEntity(entity) {
|
||||||
|
if (!(entity.constructor.name in this.renderers)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return new this.renderers[entity.constructor.name].prototype.constructor(this.worldRenderer);
|
return new this.renderers[entity.constructor.name].prototype.constructor(this.worldRenderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
import Entity from "../../entity/Entity.js";
|
||||||
|
import * as THREE from "../../../../../../../libraries/three.module.js";
|
||||||
|
import Tessellator from "../Tessellator.js";
|
||||||
|
|
||||||
|
export default class Particle extends Entity {
|
||||||
|
|
||||||
|
constructor(minecraft, world, x, y, z, motionX, motionY, motionZ) {
|
||||||
|
super(minecraft, world);
|
||||||
|
|
||||||
|
this.setPosition(x, y, z);
|
||||||
|
|
||||||
|
this.textureIndex = 0;
|
||||||
|
|
||||||
|
this.randomX = this.random.nextFloat() * 3;
|
||||||
|
this.randomY = this.random.nextFloat() * 3;
|
||||||
|
this.randomZ = (this.random.nextFloat() * 0.5 + 0.5) * 2.0;
|
||||||
|
|
||||||
|
this.motionX = motionX + (Math.random() * 2 - 1.0) * 0.4;
|
||||||
|
this.motionY = motionY + (Math.random() * 2 - 1.0) * 0.4;
|
||||||
|
this.motionZ = motionZ + (Math.random() * 2 - 1.0) * 0.4;
|
||||||
|
|
||||||
|
let strength = (Math.random() + Math.random() + 1.0) * 0.15;
|
||||||
|
let length = Math.sqrt(this.motionX * this.motionX + this.motionY * this.motionY + this.motionZ * this.motionZ);
|
||||||
|
this.motionX = (this.motionX / length) * strength * 0.4;
|
||||||
|
this.motionY = (this.motionY / length) * strength * 0.4 + 0.1;
|
||||||
|
this.motionZ = (this.motionZ / length) * strength * 0.4;
|
||||||
|
|
||||||
|
this.maxTicksExisted = Math.floor(4 / (this.random.nextFloat() * 0.9 + 0.1))
|
||||||
|
this.color = -1;
|
||||||
|
|
||||||
|
this.group = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
onUpdate() {
|
||||||
|
super.onUpdate();
|
||||||
|
|
||||||
|
if (this.ticksExisted >= this.maxTicksExisted) {
|
||||||
|
this.kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.motionY -= 0.04;
|
||||||
|
|
||||||
|
this.moveCollide(this.motionX, this.motionY, this.motionZ);
|
||||||
|
|
||||||
|
this.motionX *= 0.98;
|
||||||
|
this.motionY *= 0.98;
|
||||||
|
this.motionZ *= 0.98;
|
||||||
|
|
||||||
|
if (this.onGround) {
|
||||||
|
this.motionX *= 0.7;
|
||||||
|
this.motionZ *= 0.7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(rotationX, rotationY, rotationZ, partialTicks) {
|
||||||
|
let x = ((this.prevX + (this.x - this.prevX) * partialTicks));
|
||||||
|
let y = ((this.prevY + (this.y - this.prevY) * partialTicks));
|
||||||
|
let z = ((this.prevZ + (this.z - this.prevZ) * partialTicks));
|
||||||
|
|
||||||
|
// Create mesh
|
||||||
|
if (this.group === null) {
|
||||||
|
this.rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
let factor = 0.1 * this.randomZ;
|
||||||
|
this.group.scale.x = factor;
|
||||||
|
this.group.scale.y = factor;
|
||||||
|
this.group.scale.z = factor;
|
||||||
|
|
||||||
|
this.group.rotation.x = rotationX;
|
||||||
|
this.group.rotation.y = rotationY;
|
||||||
|
this.group.rotation.z = rotationZ;
|
||||||
|
|
||||||
|
this.group.position.x = x;
|
||||||
|
this.group.position.y = y;
|
||||||
|
this.group.position.z = z;
|
||||||
|
this.group.updateMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
rebuild() {
|
||||||
|
this.group = new THREE.Object3D();
|
||||||
|
this.group.rotation.order = 'ZYX';
|
||||||
|
|
||||||
|
let tessellator = new Tessellator();
|
||||||
|
tessellator.bindTexture(this.minecraft.worldRenderer.textureTerrain);
|
||||||
|
|
||||||
|
let minU = ((this.textureIndex % 16) + this.randomX / 4) / 16.0;
|
||||||
|
let maxU = minU + (16 / 256 / 4);
|
||||||
|
let minV = (Math.floor(this.textureIndex / 16) + this.randomX / 4) / 16.0;
|
||||||
|
let maxV = minV + (16 / 256 / 4);
|
||||||
|
|
||||||
|
// Flip V
|
||||||
|
minV = 1 - minV;
|
||||||
|
maxV = 1 - maxV;
|
||||||
|
|
||||||
|
let red = (this.color >> 16 & 255) / 255.0;
|
||||||
|
let green = (this.color >> 8 & 255) / 255.0;
|
||||||
|
let blue = (this.color & 255) / 255.0;
|
||||||
|
|
||||||
|
let brightness = this.getEntityBrightness();
|
||||||
|
|
||||||
|
// Render particle
|
||||||
|
tessellator.startDrawing();
|
||||||
|
tessellator.setColor(red * brightness, green * brightness, blue * brightness);
|
||||||
|
tessellator.addVertexWithUV(0, 1, 0, minU, minV);
|
||||||
|
tessellator.addVertexWithUV(0, 0, 0, minU, maxV);
|
||||||
|
tessellator.addVertexWithUV(1, 0, 0, maxU, maxV);
|
||||||
|
tessellator.addVertexWithUV(1, 1, 0, maxU, minV);
|
||||||
|
let mesh = tessellator.draw(this.group);
|
||||||
|
mesh.geometry.center();
|
||||||
|
|
||||||
|
this.minecraft.worldRenderer.scene.add(this.group);
|
||||||
|
}
|
||||||
|
|
||||||
|
kill() {
|
||||||
|
super.kill();
|
||||||
|
|
||||||
|
if (this.group !== null) {
|
||||||
|
this.minecraft.worldRenderer.scene.remove(this.group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import MathHelper from "../../../util/MathHelper.js";
|
||||||
|
import Block from "../../world/block/Block.js";
|
||||||
|
import ParticleDigging from "./particle/ParticleDigging.js";
|
||||||
|
|
||||||
|
export default class ParticleRenderer {
|
||||||
|
|
||||||
|
constructor(minecraft) {
|
||||||
|
this.minecraft = minecraft;
|
||||||
|
this.particles = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
spawnParticle(particle) {
|
||||||
|
this.particles.push(particle);
|
||||||
|
}
|
||||||
|
|
||||||
|
onTick() {
|
||||||
|
for (let i = 0; i < this.particles.length; i++) {
|
||||||
|
const particle = this.particles[i];
|
||||||
|
particle.onUpdate();
|
||||||
|
|
||||||
|
if (particle.isDead) {
|
||||||
|
this.particles.splice(i, 1);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderParticles(cameraEntity, partialTicks) {
|
||||||
|
let yaw = cameraEntity.prevRotationYaw + (cameraEntity.rotationYaw - cameraEntity.prevRotationYaw) * partialTicks;
|
||||||
|
let pitch = cameraEntity.prevRotationPitch + (cameraEntity.rotationPitch - cameraEntity.prevRotationPitch) * partialTicks;
|
||||||
|
|
||||||
|
let rotationX = MathHelper.toRadians(pitch);
|
||||||
|
let rotationY = -MathHelper.toRadians(yaw);
|
||||||
|
|
||||||
|
for (let i = 0; i < this.particles.length; i++) {
|
||||||
|
const particle = this.particles[i];
|
||||||
|
|
||||||
|
particle.render(rotationX, rotationY, 0, partialTicks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spawnBlockBreakParticle(world, x, y, z) {
|
||||||
|
let typeId = world.getBlockAt(x, y, z);
|
||||||
|
if (typeId === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let block = Block.getById(typeId);
|
||||||
|
let range = 4;
|
||||||
|
for (let offsetX = 0; offsetX < range; offsetX++) {
|
||||||
|
for (let offsetY = 0; offsetY < range; offsetY++) {
|
||||||
|
for (let offsetZ = 0; offsetZ < range; offsetZ++) {
|
||||||
|
|
||||||
|
let targetX = x + (offsetX + 0.5) / range;
|
||||||
|
let targetY = y + (offsetY + 0.5) / range;
|
||||||
|
let targetZ = z + (offsetZ + 0.5) / range;
|
||||||
|
|
||||||
|
let motionX = targetX - x - 0.5;
|
||||||
|
let motionY = targetY - y - 0.5;
|
||||||
|
let motionZ = targetZ - z - 0.5;
|
||||||
|
|
||||||
|
this.spawnParticle(new ParticleDigging(
|
||||||
|
this.minecraft,
|
||||||
|
world,
|
||||||
|
targetX,
|
||||||
|
targetY,
|
||||||
|
targetZ,
|
||||||
|
motionX,
|
||||||
|
motionY,
|
||||||
|
motionZ,
|
||||||
|
block
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import Particle from "../Particle.js";
|
||||||
|
|
||||||
|
export default class ParticleDigging extends Particle {
|
||||||
|
|
||||||
|
constructor(minecraft, world, x, y, z, motionX, motionY, motionZ, block) {
|
||||||
|
super(minecraft, world, x, y, z, motionX, motionY, motionZ);
|
||||||
|
|
||||||
|
// Get color multiplier
|
||||||
|
let color = block.getParticleColor(world, x, y, z);
|
||||||
|
let red = color >> 16 & 0xFF;
|
||||||
|
let green = color >> 8 & 0xFF;
|
||||||
|
let blue = color & 0xFF;
|
||||||
|
|
||||||
|
red *= 0.6;
|
||||||
|
green *= 0.6;
|
||||||
|
blue *= 0.6;
|
||||||
|
|
||||||
|
this.color = red << 16 | green << 8 | blue;
|
||||||
|
|
||||||
|
this.textureIndex = block.getTextureForFace(block.getParticleTextureFace());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -31,6 +31,10 @@ export default class Block {
|
|||||||
return BlockRenderType.BLOCK;
|
return BlockRenderType.BLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getParticleTextureFace() {
|
||||||
|
return EnumBlockFace.TOP;
|
||||||
|
}
|
||||||
|
|
||||||
getTextureForFace(face) {
|
getTextureForFace(face) {
|
||||||
return this.textureSlotId;
|
return this.textureSlotId;
|
||||||
}
|
}
|
||||||
@@ -52,6 +56,10 @@ export default class Block {
|
|||||||
return 0xffffff;
|
return 0xffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getParticleColor(world, x, y, z) {
|
||||||
|
return this.getColor(world, x, y, z, this.getParticleTextureFace());
|
||||||
|
}
|
||||||
|
|
||||||
getLightValue() {
|
getLightValue() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ export default class BlockGrass extends Block {
|
|||||||
return world.minecraft.grassColorizer.getColor(temperature, humidity);
|
return world.minecraft.grassColorizer.getColor(temperature, humidity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getParticleTextureFace() {
|
||||||
|
return EnumBlockFace.NORTH;
|
||||||
|
}
|
||||||
|
|
||||||
getTextureForFace(face) {
|
getTextureForFace(face) {
|
||||||
switch (face) {
|
switch (face) {
|
||||||
case EnumBlockFace.TOP:
|
case EnumBlockFace.TOP:
|
||||||
|
|||||||
Reference in New Issue
Block a user