implement first person hand
(cherry picked from commit bfe5a2eaca2858a7ccde1df847e2148dd79f4045)
This commit is contained in:
@@ -3,8 +3,10 @@ export default class GameSettings {
|
||||
constructor() {
|
||||
this.crouching = 'ShiftLeft';
|
||||
this.sprinting = 'ControlLeft';
|
||||
this.togglePerspective = 'F5';
|
||||
this.togglePerspective = 'F5';
|
||||
this.thirdPersonView = 0;
|
||||
this.fov = 70;
|
||||
this.viewBobbing = true;
|
||||
}
|
||||
|
||||
load() {
|
||||
@@ -15,7 +17,11 @@ export default class GameSettings {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) === ' ') c = c.substring(1, c.length);
|
||||
if (c.indexOf(nameEQ) === 0) {
|
||||
this[prop] = c.substring(nameEQ.length, c.length);
|
||||
let value = c.substring(nameEQ.length, c.length);
|
||||
if (value.match(/^[0-9]+$/)) {
|
||||
value = parseInt(value);
|
||||
}
|
||||
this[prop] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,7 +29,7 @@ export default class GameSettings {
|
||||
|
||||
save() {
|
||||
for (let prop in this) {
|
||||
document.cookie = prop + "=" + (this[prop] || "") + "; path=/; expires=Fri, 31 Dec 9999 23:59:59 GMT";
|
||||
document.cookie = prop + "=" + this[prop] + "; path=/; expires=Fri, 31 Dec 9999 23:59:59 GMT";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ export default class GameWindow {
|
||||
});
|
||||
|
||||
// Mouse buttons
|
||||
document.addEventListener('click', function (event) {
|
||||
document.addEventListener('mousedown', function (event) {
|
||||
// Create sound engine (It has to be created after user interaction)
|
||||
if (!minecraft.soundManager.isCreated()) {
|
||||
minecraft.soundManager.create(minecraft.worldRenderer);
|
||||
|
||||
@@ -192,6 +192,9 @@ export default class Minecraft {
|
||||
// Tick world
|
||||
this.world.onTick();
|
||||
|
||||
// Tick renderer
|
||||
this.worldRenderer.onTick();
|
||||
|
||||
// Tick the player
|
||||
this.player.onUpdate();
|
||||
}
|
||||
@@ -218,6 +221,7 @@ export default class Minecraft {
|
||||
|
||||
if (button === this.settings.togglePerspective) {
|
||||
this.settings.thirdPersonView = (this.settings.thirdPersonView + 1) % 3;
|
||||
this.settings.save();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ export default class Entity {
|
||||
this.minecraft = minecraft;
|
||||
this.world = world;
|
||||
|
||||
this.group = new THREE.Object3D();
|
||||
this.renderer = this.minecraft.worldRenderer.entityRenderManager.createEntityRendererByEntity(this);
|
||||
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
@@ -30,6 +30,7 @@ export default class Entity {
|
||||
this.prevRotationYaw = 0;
|
||||
this.prevRotationPitch = 0;
|
||||
|
||||
this.prevDistanceWalked = 0;
|
||||
this.distanceWalked = 0;
|
||||
this.nextStepDistance = 1;
|
||||
|
||||
@@ -47,6 +48,8 @@ export default class Entity {
|
||||
this.prevY = this.y;
|
||||
this.prevZ = this.z;
|
||||
|
||||
this.prevDistanceWalked = this.distanceWalked;
|
||||
|
||||
this.prevRotationPitch = this.rotationPitch;
|
||||
this.prevRotationYaw = this.rotationYaw;
|
||||
|
||||
|
||||
@@ -24,9 +24,11 @@ export default class EntityLiving extends Entity {
|
||||
this.prevRotationYawHead = 0;
|
||||
this.prevRenderYawOffset = 0;
|
||||
|
||||
this.limbSwing = 0;
|
||||
this.limbSwingAmount = 0;
|
||||
this.prevLimbSwingAmount = 0;
|
||||
this.limbSwingProgress = 0;
|
||||
this.limbSwingStrength = 0;
|
||||
this.prevLimbSwingStrength = 0;
|
||||
|
||||
this.health = 20.0;
|
||||
}
|
||||
|
||||
onUpdate() {
|
||||
@@ -112,7 +114,7 @@ export default class EntityLiving extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
this.prevLimbSwingAmount = this.limbSwingAmount;
|
||||
this.prevLimbSwingStrength = this.limbSwingStrength;
|
||||
|
||||
let motionX = this.x - this.prevX;
|
||||
let motionZ = this.z - this.prevZ;
|
||||
@@ -121,8 +123,8 @@ export default class EntityLiving extends Entity {
|
||||
if (distance > 1.0) {
|
||||
distance = 1.0;
|
||||
}
|
||||
this.limbSwingAmount += (distance - this.limbSwingAmount) * 0.4;
|
||||
this.limbSwing += this.limbSwingAmount;
|
||||
this.limbSwingStrength += (distance - this.limbSwingStrength) * 0.4;
|
||||
this.limbSwingProgress += this.limbSwingStrength;
|
||||
}
|
||||
|
||||
onEntityUpdate() {
|
||||
@@ -130,6 +132,11 @@ export default class EntityLiving extends Entity {
|
||||
this.prevRotationYawHead = this.rotationYawHead;
|
||||
this.prevSwingProgress = this.swingProgress;
|
||||
|
||||
this.prevRenderArmYaw = this.renderArmYaw;
|
||||
this.prevRenderArmPitch = this.renderArmPitch;
|
||||
this.renderArmPitch = (this.renderArmPitch + (this.rotationPitch - this.renderArmPitch) * 0.5);
|
||||
this.renderArmYaw = (this.renderArmYaw + (this.rotationYaw - this.renderArmYaw) * 0.5);
|
||||
|
||||
this.updateArmSwingProgress();
|
||||
|
||||
super.onEntityUpdate();
|
||||
@@ -191,6 +198,14 @@ export default class EntityLiving extends Entity {
|
||||
this.swingProgress = this.swingProgressInt / swingAnimationEnd;
|
||||
}
|
||||
|
||||
getSwingProgress(partialTicks) {
|
||||
let swingProgressDiff = this.swingProgress - this.prevSwingProgress;
|
||||
if (swingProgressDiff < 0.0) {
|
||||
swingProgressDiff++;
|
||||
}
|
||||
return this.prevSwingProgress + swingProgressDiff * partialTicks;
|
||||
}
|
||||
|
||||
computeAngleWithBound(value, subtract, limit) {
|
||||
let wrapped = MathHelper.wrapAngleTo180(value - subtract);
|
||||
if (wrapped < -limit) {
|
||||
|
||||
@@ -31,6 +31,18 @@ export default class PlayerEntity extends EntityLiving {
|
||||
this.prevFovModifier = 0;
|
||||
this.fovModifier = 0;
|
||||
this.timeFovChanged = 0;
|
||||
|
||||
this.renderArmPitch = 0;
|
||||
this.renderArmYaw = 0;
|
||||
|
||||
this.prevRenderArmPitch = 0;
|
||||
this.prevRenderArmYaw = 0;
|
||||
|
||||
// For first person bobbing
|
||||
this.cameraYaw = 0;
|
||||
this.cameraPitch = 0;
|
||||
this.prevCameraYaw = 0;
|
||||
this.prevCameraPitch = 0;
|
||||
}
|
||||
|
||||
respawn() {
|
||||
@@ -78,6 +90,9 @@ export default class PlayerEntity extends EntityLiving {
|
||||
}
|
||||
|
||||
onLivingUpdate() {
|
||||
this.prevCameraYaw = this.cameraYaw;
|
||||
this.prevCameraPitch = this.cameraPitch;
|
||||
|
||||
if (this.sprintToggleTimer > 0) {
|
||||
--this.sprintToggleTimer;
|
||||
}
|
||||
@@ -127,6 +142,21 @@ export default class PlayerEntity extends EntityLiving {
|
||||
if (this.sprinting) {
|
||||
this.jumpMovementFactor = this.jumpMovementFactor + this.speedInAir * 0.3;
|
||||
}
|
||||
|
||||
let speedXZ = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ);
|
||||
let speedY = (Math.atan(-this.motionY * 0.2) * 15.0);
|
||||
|
||||
if (speedXZ > 0.1) {
|
||||
speedXZ = 0.1;
|
||||
}
|
||||
if (!this.onGround || this.health <= 0.0) {
|
||||
speedXZ = 0.0;
|
||||
}
|
||||
if (this.onGround || this.health <= 0.0) {
|
||||
speedY = 0.0;
|
||||
}
|
||||
this.cameraYaw += (speedXZ - this.cameraYaw) * 0.4;
|
||||
this.cameraPitch += (speedY - this.cameraPitch) * 0.8;
|
||||
}
|
||||
|
||||
isInWater() {
|
||||
|
||||
@@ -18,11 +18,6 @@ export default class IngameOverlay extends Gui {
|
||||
this.renderCrosshair(stack, this.window.width / 2, this.window.height / 2)
|
||||
}
|
||||
|
||||
// Render holding item
|
||||
if (this.minecraft.settings.thirdPersonView === 0) {
|
||||
this.minecraft.itemRenderer.renderItemInHand();
|
||||
}
|
||||
|
||||
// Render hotbar
|
||||
this.renderHotbar(stack, this.window.width / 2 - 91, this.window.height - 22);
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ export default class BlockRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
renderBlockInHand(group, block, brightness) {
|
||||
renderBlockInHandThirdPerson(group, block, brightness) {
|
||||
this.tessellator.startDrawing();
|
||||
|
||||
// Render block
|
||||
|
||||
@@ -35,6 +35,10 @@ export default class WorldRenderer {
|
||||
// Entity render manager
|
||||
this.entityRenderManager = new EntityRenderManager(this);
|
||||
|
||||
this.equippedProgress = 0;
|
||||
this.prevEquippedProgress = 0;
|
||||
this.itemToRender = 0;
|
||||
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
@@ -51,6 +55,10 @@ export default class WorldRenderer {
|
||||
this.scene = new THREE.Scene();
|
||||
this.scene.matrixAutoUpdate = false;
|
||||
|
||||
// Create overlay for first person model rendering
|
||||
this.overlay = new THREE.Scene();
|
||||
this.overlay.matrixAutoUpdate = false;
|
||||
|
||||
// Create web renderer
|
||||
this.webRenderer = new THREE.WebGLRenderer({
|
||||
canvas: this.window.canvas,
|
||||
@@ -77,6 +85,9 @@ export default class WorldRenderer {
|
||||
color: 0x000000,
|
||||
}));
|
||||
this.scene.add(this.blockHitBox);
|
||||
|
||||
// Hand group
|
||||
this.handGroup = new THREE.Object3D();
|
||||
}
|
||||
|
||||
render(partialTicks) {
|
||||
@@ -95,18 +106,57 @@ export default class WorldRenderer {
|
||||
// Render target block
|
||||
this.renderBlockHitBox(player, partialTicks);
|
||||
|
||||
// Hide all entities and make them visible during rendering
|
||||
for (let entity of this.minecraft.world.entities) {
|
||||
entity.renderer.group.visible = false;
|
||||
}
|
||||
|
||||
// Render entities
|
||||
for (let entity of this.minecraft.world.entities) {
|
||||
if (entity === player && this.minecraft.settings.thirdPersonView === 0) {
|
||||
entity.group.clear(); // Remove entity from scene
|
||||
delete entity.group.buildMeta; // To trigger a rebuild on the next render
|
||||
continue;
|
||||
}
|
||||
this.renderEntity(entity, partialTicks);
|
||||
|
||||
// Render entity
|
||||
entity.renderer.render(entity, partialTicks);
|
||||
entity.renderer.group.visible = true;
|
||||
}
|
||||
|
||||
// Render hand
|
||||
this.renderHand(partialTicks);
|
||||
|
||||
// Render actual scene
|
||||
this.webRenderer.render(this.scene, this.camera);
|
||||
|
||||
// Render overlay with a static FOV
|
||||
this.camera.fov = this.minecraft.settings.fov;
|
||||
this.camera.updateProjectionMatrix();
|
||||
this.webRenderer.render(this.overlay, this.camera);
|
||||
}
|
||||
|
||||
onTick() {
|
||||
this.prevEquippedProgress = this.equippedProgress;
|
||||
|
||||
let player = this.minecraft.player;
|
||||
let itemStack = player.inventory.getItemInSelectedSlot();
|
||||
|
||||
let showHand = false;
|
||||
if (this.itemToRender != null && itemStack != null) {
|
||||
if (this.itemToRender !== itemStack) {
|
||||
showHand = true;
|
||||
}
|
||||
} else if (this.itemToRender == null && itemStack == null) {
|
||||
showHand = false;
|
||||
} else {
|
||||
showHand = true;
|
||||
}
|
||||
|
||||
// Update equip progress
|
||||
this.equippedProgress += MathHelper.clamp((showHand ? 0.0 : 1.0) - this.equippedProgress, -0.4, 0.4);
|
||||
|
||||
if (this.equippedProgress < 0.1) {
|
||||
this.itemToRender = itemStack;
|
||||
}
|
||||
}
|
||||
|
||||
orientCamera(partialTicks) {
|
||||
@@ -151,7 +201,7 @@ export default class WorldRenderer {
|
||||
this.frustum.setFromProjectionMatrix(new THREE.Matrix4().multiplyMatrices(this.camera.projectionMatrix, this.camera.matrixWorldInverse));
|
||||
|
||||
// Update FOV
|
||||
this.camera.fov = 85 + player.getFOVModifier();
|
||||
this.camera.fov = this.minecraft.settings.fov + player.getFOVModifier();
|
||||
this.camera.updateProjectionMatrix();
|
||||
|
||||
// Setup fog
|
||||
@@ -294,6 +344,83 @@ export default class WorldRenderer {
|
||||
this.skyGroup.rotation.set(angle * Math.PI * 2 + Math.PI / 2, 0, 0);
|
||||
}
|
||||
|
||||
renderHand(partialTicks) {
|
||||
// Hide hand before rendering
|
||||
let player = this.minecraft.player;
|
||||
let stack = player.renderer.handGroup;
|
||||
stack.visible = false;
|
||||
|
||||
// Hide in third person
|
||||
if (this.minecraft.settings.thirdPersonView !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply matrix mode (Put object in front of camera)
|
||||
stack.position.copy(this.camera.position);
|
||||
stack.rotation.copy(this.camera.rotation);
|
||||
stack.rotation.order = 'ZYX';
|
||||
|
||||
// Scale down
|
||||
stack.scale.set(0.0625, 0.0625, 0.0625);
|
||||
|
||||
let equipProgress = this.prevEquippedProgress + (this.equippedProgress - this.prevEquippedProgress) * partialTicks;
|
||||
let swingProgress = player.getSwingProgress(partialTicks);
|
||||
|
||||
let pitchArm = player.prevRenderArmPitch + (player.renderArmPitch - player.prevRenderArmPitch) * partialTicks;
|
||||
let yawArm = player.prevRenderArmYaw + (player.renderArmYaw - player.prevRenderArmYaw) * partialTicks;
|
||||
|
||||
let factor = 0.8;
|
||||
let zOffset = Math.sin(swingProgress * Math.PI);
|
||||
let yOffset = Math.sin(Math.sqrt(swingProgress) * Math.PI * 2.0);
|
||||
let xOffset = Math.sin(Math.sqrt(swingProgress) * Math.PI);
|
||||
|
||||
let yRotation = Math.sin(Math.sqrt(swingProgress) * Math.PI);
|
||||
let zRotation = Math.sin(swingProgress * swingProgress * Math.PI);
|
||||
|
||||
// Bobbing animation
|
||||
if (this.minecraft.settings.viewBobbing) {
|
||||
let walked = -(player.prevDistanceWalked + (player.distanceWalked - player.prevDistanceWalked) * partialTicks);
|
||||
let yaw = player.prevCameraYaw + (player.cameraYaw - player.prevCameraYaw) * partialTicks;
|
||||
let pitch = player.prevCameraPitch + (player.cameraPitch - player.prevCameraPitch) * partialTicks;
|
||||
this.translate(
|
||||
stack,
|
||||
Math.sin(walked * 3.141593) * yaw * 0.5,
|
||||
-Math.abs(Math.cos(walked * Math.PI) * yaw),
|
||||
0.0
|
||||
);
|
||||
stack.rotateZ(MathHelper.toRadians(Math.sin(walked * Math.PI) * yaw * 3.0));
|
||||
stack.rotateX(MathHelper.toRadians(Math.abs(Math.cos(walked * Math.PI - 0.2) * yaw) * 5.0));
|
||||
stack.rotateX(MathHelper.toRadians(pitch));
|
||||
}
|
||||
|
||||
// Camera rotation movement
|
||||
stack.rotateX(MathHelper.toRadians((player.rotationPitch - pitchArm) * 0.1));
|
||||
stack.rotateY(MathHelper.toRadians((player.rotationYaw - yawArm) * 0.1));
|
||||
|
||||
// Initial offset on screen
|
||||
this.translate(stack, -xOffset * 0.3, yOffset * 0.4, -zOffset * 0.4);
|
||||
this.translate(stack, 0.8 * factor, -0.75 * factor - (1.0 - equipProgress) * 0.6, -0.9 * factor);
|
||||
|
||||
// Rotation of hand
|
||||
stack.rotateY(MathHelper.toRadians(45));
|
||||
stack.rotateY(MathHelper.toRadians(yRotation * 70));
|
||||
stack.rotateZ(MathHelper.toRadians(-zRotation * 20));
|
||||
|
||||
// Post transform
|
||||
this.translate(stack, -1, 3.6, 3.5);
|
||||
stack.rotateZ(MathHelper.toRadians(120));
|
||||
stack.rotateX(MathHelper.toRadians(200));
|
||||
stack.rotateY(MathHelper.toRadians(-135));
|
||||
this.translate(stack, 5.6, 0.0, 0.0);
|
||||
|
||||
if (this.itemToRender === 0) {
|
||||
// Render hand
|
||||
player.renderer.renderRightArm(player, partialTicks);
|
||||
} else {
|
||||
// Render item
|
||||
}
|
||||
}
|
||||
|
||||
renderBlockHitBox(player, partialTicks) {
|
||||
let hitResult = player.rayTrace(5, partialTicks);
|
||||
let hitBoxVisible = !(hitResult === null);
|
||||
@@ -333,8 +460,9 @@ export default class WorldRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
renderEntity(entity, partialTicks) {
|
||||
let entityRenderer = this.entityRenderManager.getEntityRendererByEntity(entity);
|
||||
entityRenderer.render(entity, partialTicks);
|
||||
translate(stack, x, y, z) {
|
||||
stack.translateX(x);
|
||||
stack.translateY(y);
|
||||
stack.translateZ(z);
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,14 @@ export default class EntityRenderManager {
|
||||
this.worldRenderer = worldRenderer;
|
||||
|
||||
this.renderers = [];
|
||||
this.push(PlayerEntity, new PlayerRenderer(worldRenderer));
|
||||
this.push(PlayerEntity, PlayerRenderer);
|
||||
}
|
||||
|
||||
push(entityType, entityRenderer) {
|
||||
this.renderers[entityType.name] = entityRenderer;
|
||||
}
|
||||
|
||||
getEntityRendererByEntity(entity) {
|
||||
return this.renderers[entity.constructor.name];
|
||||
createEntityRendererByEntity(entity) {
|
||||
return new this.renderers[entity.constructor.name].prototype.constructor(this.worldRenderer);
|
||||
}
|
||||
}
|
||||
@@ -6,22 +6,22 @@ export default class EntityRenderer {
|
||||
constructor(model) {
|
||||
this.model = model;
|
||||
this.tessellator = new Tessellator();
|
||||
this.group = new THREE.Object3D();
|
||||
}
|
||||
|
||||
rebuild(entity) {
|
||||
// Create meta for group
|
||||
let group = entity.group;
|
||||
let meta = {};
|
||||
this.fillMeta(entity, meta);
|
||||
group.buildMeta = meta;
|
||||
this.group.buildMeta = meta;
|
||||
|
||||
// Clear meshes
|
||||
group.clear();
|
||||
this.group.clear();
|
||||
|
||||
// Apply brightness and rebuild
|
||||
let brightness = group.buildMeta.brightness;
|
||||
let brightness = this.group.buildMeta.brightness;
|
||||
this.tessellator.setColor(brightness, brightness, brightness);
|
||||
this.model.rebuild(this.tessellator, group);
|
||||
this.model.rebuild(this.tessellator, this.group);
|
||||
}
|
||||
|
||||
fillMeta(entity, meta) {
|
||||
@@ -30,30 +30,25 @@ export default class EntityRenderer {
|
||||
}
|
||||
|
||||
isRebuildRequired(entity) {
|
||||
let group = entity.group;
|
||||
if (typeof group.buildMeta === "undefined") {
|
||||
if (typeof this.group.buildMeta === "undefined") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Compare meta of group
|
||||
let currentMeta = {};
|
||||
this.fillMeta(entity, currentMeta);
|
||||
let previousMeta = group.buildMeta;
|
||||
let previousMeta = this.group.buildMeta;
|
||||
return JSON.stringify(currentMeta) !== JSON.stringify(previousMeta);
|
||||
}
|
||||
|
||||
render(entity, partialTicks) {
|
||||
if (this.isRebuildRequired(entity)) {
|
||||
this.rebuild(entity);
|
||||
}
|
||||
|
||||
let group = entity.group;
|
||||
this.prepareModel(entity);
|
||||
|
||||
let rotationBody = this.interpolateRotation(entity.prevRenderYawOffset, entity.renderYawOffset, partialTicks);
|
||||
let rotationHead = this.interpolateRotation(entity.prevRotationYawHead, entity.rotationYawHead, partialTicks);
|
||||
|
||||
let limbSwing = entity.prevLimbSwingAmount + (entity.limbSwingAmount - entity.prevLimbSwingAmount) * partialTicks;
|
||||
let limbSwingAmount = entity.limbSwing - entity.limbSwingAmount * (1.0 - partialTicks);
|
||||
let limbSwingStrength = entity.prevLimbSwingStrength + (entity.limbSwingStrength - entity.prevLimbSwingStrength) * partialTicks;
|
||||
let limbSwing = entity.limbSwingProgress - entity.limbSwingStrength * (1.0 - partialTicks);
|
||||
|
||||
let yaw = rotationHead - rotationBody;
|
||||
let pitch = entity.prevRotationPitch + (entity.rotationPitch - entity.prevRotationPitch) * partialTicks;
|
||||
@@ -64,20 +59,21 @@ export default class EntityRenderer {
|
||||
let interpolatedZ = entity.prevZ + (entity.z - entity.prevZ) * partialTicks;
|
||||
|
||||
// Translate using interpolated position
|
||||
group.position.setX(interpolatedX);
|
||||
group.position.setY(interpolatedY + 1.4);
|
||||
group.position.setZ(interpolatedZ);
|
||||
this.group.position.setX(interpolatedX);
|
||||
this.group.position.setY(interpolatedY + 1.4);
|
||||
this.group.position.setZ(interpolatedZ);
|
||||
|
||||
// Actual size of the entity
|
||||
let scale = 7.0 / 120.0;
|
||||
group.scale.set(-scale, -scale, scale);
|
||||
this.group.scale.set(-scale, -scale, scale);
|
||||
|
||||
// Rotate entity model
|
||||
group.rotation.y = MathHelper.toRadians(-rotationBody + 180);
|
||||
this.group.rotation.y = MathHelper.toRadians(-rotationBody + 180);
|
||||
|
||||
// Render entity model
|
||||
let timeAlive = entity.ticksExisted + partialTicks;
|
||||
this.model.render(entity, limbSwingAmount, limbSwing, timeAlive, yaw, pitch, partialTicks);
|
||||
let stack = entity.renderer.group;
|
||||
this.model.render(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks);
|
||||
}
|
||||
|
||||
interpolateRotation(prevValue, value, partialTicks) {
|
||||
@@ -90,4 +86,10 @@ export default class EntityRenderer {
|
||||
return prevValue + partialTicks * factor;
|
||||
}
|
||||
|
||||
prepareModel(entity) {
|
||||
if (this.isRebuildRequired(entity)) {
|
||||
this.rebuild(entity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,11 @@ export default class PlayerRenderer extends EntityRenderer {
|
||||
this.textureCharacter = new THREE.TextureLoader().load('src/resources/char.png');
|
||||
this.textureCharacter.magFilter = THREE.NearestFilter;
|
||||
this.textureCharacter.minFilter = THREE.NearestFilter;
|
||||
|
||||
// First person right-hand holder
|
||||
this.handModel = null;
|
||||
this.handGroup = new THREE.Object3D();
|
||||
this.worldRenderer.overlay.add(this.handGroup);
|
||||
}
|
||||
|
||||
rebuild(entity) {
|
||||
@@ -22,16 +27,52 @@ export default class PlayerRenderer extends EntityRenderer {
|
||||
// Render item in hand
|
||||
let group = this.model.rightArm.bone;
|
||||
let id = entity.inventory.getItemInSelectedSlot();
|
||||
if (id !== 0) {
|
||||
if (id !== 0 && this.worldRenderer.minecraft.settings.thirdPersonView !== 0) {
|
||||
let block = Block.getById(id);
|
||||
this.worldRenderer.blockRenderer.renderBlockInHand(group, block, entity.getEntityBrightness());
|
||||
this.worldRenderer.blockRenderer.renderBlockInHandThirdPerson(group, block, entity.getEntityBrightness());
|
||||
}
|
||||
|
||||
// Create first person right hand and attach it to the holder
|
||||
this.handGroup.clear();
|
||||
this.handModel = this.model.rightArm.clone();
|
||||
this.handGroup.add(this.handModel.bone);
|
||||
|
||||
// Copy material and update depth test of the hand
|
||||
let mesh = this.handModel.bone.children[0];
|
||||
mesh.renerOrder = 999;
|
||||
mesh.material = mesh.material.clone();
|
||||
mesh.material.depthTest = false;
|
||||
mesh.material.depthWrite = false;
|
||||
}
|
||||
|
||||
render(entity, partialTicks) {
|
||||
let swingProgress = entity.swingProgress - entity.prevSwingProgress;
|
||||
if (swingProgress < 0.0) {
|
||||
swingProgress++;
|
||||
}
|
||||
this.model.swingProgress = entity.prevSwingProgress + swingProgress * partialTicks;
|
||||
this.model.hasItemInHand = entity.inventory.getItemInSelectedSlot() !== 0;
|
||||
this.model.isSneaking = entity.sneaking;
|
||||
|
||||
super.render(entity, partialTicks);
|
||||
}
|
||||
|
||||
renderRightArm(player, partialTicks) {
|
||||
// Make sure the model is created
|
||||
this.prepareModel(player);
|
||||
|
||||
// Set transform of renderer
|
||||
this.model.swingProgress = 0;
|
||||
this.model.hasItemInHand = false;
|
||||
this.model.isSneaking = false;
|
||||
this.model.setRotationAngles(player, 0, 0, 0, 0, 0, 0);
|
||||
this.handModel.copyTransformOf(this.model.rightArm);
|
||||
|
||||
// Render the model
|
||||
this.handGroup.visible = true;
|
||||
this.handModel.render();
|
||||
}
|
||||
|
||||
fillMeta(entity, meta) {
|
||||
super.fillMeta(entity, meta);
|
||||
meta.itemInHand = entity.inventory.getItemInSelectedSlot();
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import Block from "../../world/block/Block.js";
|
||||
|
||||
export default class ItemRenderer {
|
||||
|
||||
constructor(minecraft, window) {
|
||||
@@ -7,15 +5,13 @@ export default class ItemRenderer {
|
||||
this.window = window;
|
||||
|
||||
this.items = [];
|
||||
this.itemInHand = null;
|
||||
this.itemInHandGroup = new THREE.Object3D();
|
||||
}
|
||||
|
||||
initialize() {
|
||||
// Create item camera
|
||||
this.camera = new THREE.OrthographicCamera(0, 0, 0, 0, 0, 300);
|
||||
this.camera.near = 0;
|
||||
this.camera.far = 15;
|
||||
this.camera.far = 100;
|
||||
this.camera.rotation.order = 'ZYX';
|
||||
this.camera.up = new THREE.Vector3(0, 1, 0);
|
||||
|
||||
@@ -37,8 +33,6 @@ export default class ItemRenderer {
|
||||
this.webRenderer.sortObjects = false;
|
||||
this.webRenderer.setClearColor(0x000000, 0);
|
||||
this.webRenderer.clear();
|
||||
|
||||
this.scene.add(this.itemInHandGroup);
|
||||
}
|
||||
|
||||
render(partialTicks) {
|
||||
@@ -54,28 +48,6 @@ export default class ItemRenderer {
|
||||
this.webRenderer.render(this.scene, this.camera);
|
||||
}
|
||||
|
||||
renderItemInHand() {
|
||||
let typeId = this.minecraft.player.inventory.getItemInSelectedSlot();
|
||||
if (typeId === this.itemInHand) {
|
||||
return; // Skip rebuilding if the item hasn't changed
|
||||
}
|
||||
|
||||
// Clear previous mesh
|
||||
this.itemInHandGroup.clear();
|
||||
|
||||
// Should render hand or item
|
||||
if (typeId === 0) {
|
||||
|
||||
} else {
|
||||
let block = Block.getById(typeId);
|
||||
|
||||
// this.minecraft.worldRenderer.blockRenderer.renderBlockInHand(block, this.itemInHandGroup, 1);
|
||||
}
|
||||
|
||||
// Store item in hand meta
|
||||
this.itemInHand = typeId;
|
||||
}
|
||||
|
||||
renderItemInGui(renderId, block, x, y) {
|
||||
let meta = this.items[renderId];
|
||||
if (typeof meta === "undefined") {
|
||||
|
||||
@@ -10,8 +10,12 @@ export default class ModelBase {
|
||||
|
||||
}
|
||||
|
||||
render(entity, limbSwingAmount, limbSwing, timeAlive, yaw, pitch) {
|
||||
entity.group.updateMatrix();
|
||||
render(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks) {
|
||||
stack.updateMatrix();
|
||||
}
|
||||
|
||||
setRotationAngles(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,10 @@ export default class ModelPlayer extends ModelBase {
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.swingProgress = 0;
|
||||
this.hasItemInHand = false;
|
||||
this.isSneaking = false;
|
||||
|
||||
let width = 64;
|
||||
let height = 32;
|
||||
|
||||
@@ -59,20 +63,32 @@ export default class ModelPlayer extends ModelBase {
|
||||
this.rightLeg.rebuild(tessellator, group);
|
||||
}
|
||||
|
||||
render(entity, limbSwingAmount, limbSwing, timeAlive, yaw, pitch, partialTicks) {
|
||||
let group = entity.group;
|
||||
render(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks) {
|
||||
this.setRotationAngles(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks);
|
||||
|
||||
// Render cubes
|
||||
this.head.render();
|
||||
this.body.render();
|
||||
this.rightArm.render();
|
||||
this.leftArm.render();
|
||||
this.rightLeg.render();
|
||||
this.leftLeg.render();
|
||||
|
||||
super.render(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks);
|
||||
}
|
||||
|
||||
setRotationAngles(stack, limbSwing, limbSwingStrength, timeAlive, yaw, pitch, partialTicks) {
|
||||
// Head rotation
|
||||
this.head.rotateAngleY = MathHelper.toRadians(yaw);
|
||||
this.head.rotateAngleX = MathHelper.toRadians(pitch);
|
||||
|
||||
// Limb swing leg animation
|
||||
this.rightArm.rotateAngleX = Math.cos(limbSwingAmount * 0.6662 + Math.PI) * 2.0 * limbSwing * 0.5;
|
||||
this.leftArm.rotateAngleX = Math.cos(limbSwingAmount * 0.6662) * 2.0 * limbSwing * 0.5;
|
||||
this.rightArm.rotateAngleX = Math.cos(limbSwing * 0.6662 + Math.PI) * 2.0 * limbSwingStrength * 0.5;
|
||||
this.leftArm.rotateAngleX = Math.cos(limbSwing * 0.6662) * 2.0 * limbSwingStrength * 0.5;
|
||||
this.rightArm.rotateAngleZ = 0.0;
|
||||
this.leftArm.rotateAngleZ = 0.0;
|
||||
this.rightLeg.rotateAngleX = Math.cos(limbSwingAmount * 0.6662) * 1.4 * limbSwing;
|
||||
this.leftLeg.rotateAngleX = Math.cos(limbSwingAmount * 0.6662 + Math.PI) * 1.4 * limbSwing;
|
||||
this.rightLeg.rotateAngleX = Math.cos(limbSwing * 0.6662) * 1.4 * limbSwingStrength;
|
||||
this.leftLeg.rotateAngleX = Math.cos(limbSwing * 0.6662 + Math.PI) * 1.4 * limbSwingStrength;
|
||||
this.rightLeg.rotateAngleY = 0.0;
|
||||
this.leftLeg.rotateAngleY = 0.0;
|
||||
|
||||
@@ -82,18 +98,12 @@ export default class ModelPlayer extends ModelBase {
|
||||
this.leftArm.rotateAngleY = 0.0;
|
||||
|
||||
// Held item animation
|
||||
if (entity.inventory.getItemInSelectedSlot() !== 0) {
|
||||
if (this.hasItemInHand) {
|
||||
this.rightArm.rotateAngleX = this.rightArm.rotateAngleX * 0.5 - (Math.PI / 10);
|
||||
}
|
||||
|
||||
// Swing progress
|
||||
let swingProgress = entity.swingProgress - entity.prevSwingProgress;
|
||||
if (swingProgress < 0.0) {
|
||||
swingProgress++;
|
||||
}
|
||||
let interpolatedSwingProgress = entity.prevSwingProgress + swingProgress * partialTicks;
|
||||
if (interpolatedSwingProgress > -9990.0) {
|
||||
let swingProgress = interpolatedSwingProgress;
|
||||
if (this.swingProgress > -9990.0) {
|
||||
let swingProgress = this.swingProgress;
|
||||
|
||||
this.body.rotateAngleY = Math.sin(Math.sqrt(swingProgress) * Math.PI * 2.0) * 0.2;
|
||||
|
||||
@@ -106,21 +116,21 @@ export default class ModelPlayer extends ModelBase {
|
||||
this.leftArm.rotateAngleY += this.body.rotateAngleY;
|
||||
this.leftArm.rotateAngleX += this.body.rotateAngleY;
|
||||
|
||||
swingProgress = 1.0 - interpolatedSwingProgress;
|
||||
swingProgress = 1.0 - swingProgress;
|
||||
swingProgress = swingProgress * swingProgress;
|
||||
swingProgress = swingProgress * swingProgress;
|
||||
swingProgress = 1.0 - swingProgress;
|
||||
|
||||
let value1 = Math.sin(swingProgress * Math.PI);
|
||||
let value2 = Math.sin(interpolatedSwingProgress * Math.PI) * -(this.head.rotateAngleX - 0.7) * 0.75;
|
||||
let value2 = Math.sin(swingProgress * Math.PI) * -(this.head.rotateAngleX - 0.7) * 0.75;
|
||||
|
||||
this.rightArm.rotateAngleX = (this.rightArm.rotateAngleX - (value1 * 1.2 + value2));
|
||||
this.rightArm.rotateAngleY += this.body.rotateAngleY * 2.0;
|
||||
this.rightArm.rotateAngleZ += Math.sin(interpolatedSwingProgress * Math.PI) * -0.4;
|
||||
this.rightArm.rotateAngleZ += Math.sin(swingProgress * Math.PI) * -0.4;
|
||||
}
|
||||
|
||||
// Sneaking animation
|
||||
if (entity.sneaking) {
|
||||
if (this.isSneaking) {
|
||||
this.body.rotateAngleX = 0.5;
|
||||
this.rightArm.rotateAngleX += 0.4;
|
||||
this.leftArm.rotateAngleX += 0.4;
|
||||
@@ -130,7 +140,7 @@ export default class ModelPlayer extends ModelBase {
|
||||
this.leftLeg.rotationPointY = 9.0;
|
||||
this.head.rotationPointY = 1.0;
|
||||
|
||||
group.translateY(-0.2);
|
||||
stack.translateY(-0.2);
|
||||
} else {
|
||||
this.body.rotateAngleX = 0.0;
|
||||
this.rightLeg.rotationPointZ = 0.1;
|
||||
@@ -145,16 +155,6 @@ export default class ModelPlayer extends ModelBase {
|
||||
this.leftArm.rotateAngleZ -= Math.cos(timeAlive * 0.09) * 0.05 + 0.05;
|
||||
this.rightArm.rotateAngleX += Math.sin(timeAlive * 0.067) * 0.05;
|
||||
this.leftArm.rotateAngleX -= Math.sin(timeAlive * 0.067) * 0.05;
|
||||
|
||||
// Render cubes
|
||||
this.head.render();
|
||||
this.body.render();
|
||||
this.rightArm.render();
|
||||
this.leftArm.render();
|
||||
this.rightLeg.render();
|
||||
this.leftLeg.render();
|
||||
|
||||
super.render(entity, limbSwingAmount, limbSwing, timeAlive, yaw, pitch);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -262,4 +262,31 @@ export default class ModelRenderer {
|
||||
this.bone.updateMatrix();
|
||||
}
|
||||
|
||||
clone() {
|
||||
let modelRenderer = new ModelRenderer(this.name, this.textureWidth, this.textureHeight);
|
||||
modelRenderer.bone = this.bone.clone();
|
||||
modelRenderer.textureOffsetX = this.textureOffsetX;
|
||||
modelRenderer.textureOffsetY = this.textureOffsetY;
|
||||
modelRenderer.cubes = this.cubes;
|
||||
modelRenderer.copyTransformOf(this);
|
||||
|
||||
for (let i = 0; i < this.children.length; i++) {
|
||||
let child = this.children[i];
|
||||
modelRenderer.addChild(child.clone());
|
||||
}
|
||||
|
||||
return modelRenderer;
|
||||
}
|
||||
|
||||
copyTransformOf(modelRenderer) {
|
||||
this.rotationPointX = modelRenderer.rotationPointX;
|
||||
this.rotationPointY = modelRenderer.rotationPointY;
|
||||
this.rotationPointZ = modelRenderer.rotationPointZ;
|
||||
this.scaleX = modelRenderer.scaleX;
|
||||
this.scaleY = modelRenderer.scaleY;
|
||||
this.scaleZ = modelRenderer.scaleZ;
|
||||
this.rotateAngleX = modelRenderer.rotateAngleX;
|
||||
this.rotateAngleY = modelRenderer.rotateAngleY;
|
||||
this.rotateAngleZ = modelRenderer.rotateAngleZ;
|
||||
}
|
||||
}
|
||||
@@ -521,13 +521,13 @@ export default class World {
|
||||
|
||||
addEntity(entity) {
|
||||
this.entities.push(entity);
|
||||
this.group.add(entity.group);
|
||||
this.group.add(entity.renderer.group);
|
||||
}
|
||||
|
||||
removeEntityById(id) {
|
||||
let entity = this.getEntityById(id);
|
||||
this.entities.remove(entity);
|
||||
this.group.remove(entity.group);
|
||||
this.group.remove(entity.renderer.group);
|
||||
}
|
||||
|
||||
getEntityById(id) {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
export default class MathHelper {
|
||||
|
||||
static clamp(number, min, max) {
|
||||
return Math.min(Math.max(number, min), max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the greatest integer less than or equal to the double argument
|
||||
*/
|
||||
@@ -14,7 +18,7 @@ export default class MathHelper {
|
||||
|
||||
static toRadians(degree) {
|
||||
return degree * (Math.PI / 180);
|
||||
};
|
||||
}
|
||||
|
||||
static calculateCelestialAngle(time, partialTicks) {
|
||||
let modTime = (time % 24000);
|
||||
|
||||
Reference in New Issue
Block a user