From 29f810eb04ae97e29485b60a12be59cc38f45bfd Mon Sep 17 00:00:00 2001 From: Atsuishio <842960157@qq.com> Date: Sun, 13 Jul 2025 02:25:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A063=E5=BC=8F=E7=81=AB=E7=AE=AD?= =?UTF-8?q?=E7=82=AE=E7=9A=84OBB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../renderer/entity/Type63Renderer.java | 17 ++ .../entity/vehicle/Type63Entity.java | 216 +++++++++++++++++- .../event/ClientEventHandler.java | 22 +- .../atsuishio/superbwarfare/tools/OBB.java | 24 ++ .../superbwarfare/tools/VectorTool.java | 8 + 5 files changed, 276 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Type63Renderer.java b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Type63Renderer.java index 736c9c7ca..5d2ba10a3 100644 --- a/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Type63Renderer.java +++ b/src/main/java/com/atsuishio/superbwarfare/client/renderer/entity/Type63Renderer.java @@ -54,6 +54,23 @@ public class Type63Renderer extends GeoEntityRenderer { if (name.equals("wheel2")) { bone.setRotX(Mth.lerp(partialTick, animatable.rightWheelRotO, animatable.getRightWheelRot())); } + + if (name.equals("main")) { + bone.setRotY(Mth.lerp(partialTick, animatable.turretYRotO, animatable.getTurretYRot()) * Mth.DEG_TO_RAD); + } + + if (name.equals("paotou")) { + bone.setRotX(-Mth.lerp(partialTick, animatable.turretXRotO, animatable.getTurretXRot()) * Mth.DEG_TO_RAD); + } + + if (name.equals("shoulunx")) { + bone.setRotX(-Mth.lerp(partialTick, animatable.turretXRotO, animatable.getTurretXRot()) * 3); + } + + if (name.equals("shouluny")) { + bone.setRotZ(-Mth.lerp(partialTick, animatable.turretYRotO, animatable.getTurretYRot()) * 6); + } + super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color); } } diff --git a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Type63Entity.java b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Type63Entity.java index f1b94e6c7..925ea337b 100644 --- a/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Type63Entity.java +++ b/src/main/java/com/atsuishio/superbwarfare/entity/vehicle/Type63Entity.java @@ -9,20 +9,29 @@ import com.atsuishio.superbwarfare.item.SmallShellItem; import com.atsuishio.superbwarfare.tools.CustomExplosion; import com.atsuishio.superbwarfare.tools.OBB; import com.atsuishio.superbwarfare.tools.ParticleTool; +import com.atsuishio.superbwarfare.tools.VectorTool; +import com.mojang.math.Axis; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Mth; import net.minecraft.world.Container; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Explosion; import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; import net.neoforged.neoforge.event.EventHooks; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.joml.*; import org.joml.Math; -import org.joml.Matrix4f; import software.bernie.geckolib.animatable.GeoEntity; import software.bernie.geckolib.animatable.instance.AnimatableInstanceCache; import software.bernie.geckolib.animation.AnimatableManager; @@ -32,6 +41,8 @@ import java.util.List; public class Type63Entity extends MobileVehicleEntity implements GeoEntity, OBBEntity, Container { + public static final EntityDataAccessor PITCH = SynchedEntityData.defineId(Type63Entity.class, EntityDataSerializers.FLOAT); + public static final EntityDataAccessor YAW = SynchedEntityData.defineId(Type63Entity.class, EntityDataSerializers.FLOAT); private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); public OBB barrel0; public OBB barrel1; @@ -50,17 +61,94 @@ public class Type63Entity extends MobileVehicleEntity implements GeoEntity, OBBE public OBB hoe1; public OBB hoe2; + public double interactionTick; + public ItemStack stack = ItemStack.EMPTY; public Type63Entity(EntityType type, Level world) { super(type, world); + this.barrel0 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel1 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel2 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel3 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel4 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel5 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel6 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel7 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel8 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel9 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel10 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.barrel11 = new OBB(this.position().toVector3f(), new Vector3f(0.09375f, 0.09375f, 0.0625f), new Quaternionf(), OBB.Part.BODY); + this.pitchController = new OBB(this.position().toVector3f(), new Vector3f(0.15625f, 0.21875f, 0.21875f), new Quaternionf(), OBB.Part.BODY); + this.yawController = new OBB(this.position().toVector3f(), new Vector3f(0.125f, 0.125f, 0.125f), new Quaternionf(), OBB.Part.BODY); + this.hoe1 = new OBB(this.position().toVector3f(), new Vector3f(0.125f, 0.125f, 0.875f), new Quaternionf(), OBB.Part.BODY); + this.hoe2 = new OBB(this.position().toVector3f(), new Vector3f(0.125f, 0.125f, 0.875f), new Quaternionf(), OBB.Part.BODY); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + super.defineSynchedData(builder); + + builder.define(PITCH, 0F) + .define(YAW, 0F); + } + + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); + compound.putFloat("Pitch", this.entityData.get(PITCH)); + compound.putFloat("Yaw", this.entityData.get(YAW)); + } + + @Override + protected void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.entityData.set(PITCH, compound.getFloat("Pitch")); + this.entityData.set(YAW, compound.getFloat("Yaw")); + } + + @Override + public @NotNull InteractionResult interact(Player player, @NotNull InteractionHand hand) { + ItemStack stack = player.getMainHandItem(); + + if (stack.isEmpty()) { + if (OBB.getLookingObb(player, player.entityInteractionRange()) == hoe1) { + if (player.level() instanceof ServerLevel) { + setYRot(getYRot() + (float) interactionTick); + interactionTick++; + } + player.swing(InteractionHand.MAIN_HAND); + } + if (OBB.getLookingObb(player, player.entityInteractionRange()) == hoe2) { + if (player.level() instanceof ServerLevel) { + setYRot(getYRot() - (float) interactionTick); + interactionTick++; + } + player.swing(InteractionHand.MAIN_HAND); + } + if (OBB.getLookingObb(player, player.entityInteractionRange()) == yawController) { + if (player.level() instanceof ServerLevel) { + interactionTick++; + } + entityData.set(YAW, Mth.clamp(entityData.get(YAW) + (player.isShiftKeyDown() ? -0.07f : 0.07f) * (float) interactionTick, -15, 15)); + player.swing(InteractionHand.MAIN_HAND); + } + if (OBB.getLookingObb(player, player.entityInteractionRange()) == pitchController) { + if (player.level() instanceof ServerLevel) { + interactionTick++; + } + entityData.set(PITCH, Mth.clamp(entityData.get(PITCH) + (player.isShiftKeyDown() ? 0.15f : -0.15f) * (float) interactionTick, -60, 5)); + player.swing(InteractionHand.MAIN_HAND); + } + } + + return InteractionResult.FAIL; } @Override public void baseTick() { turretYRotO = this.getTurretYRot(); turretXRotO = this.getTurretXRot(); - rudderRotO = this.getRudderRot(); leftWheelRotO = this.getLeftWheelRot(); rightWheelRotO = this.getRightWheelRot(); @@ -83,6 +171,12 @@ public class Type63Entity extends MobileVehicleEntity implements GeoEntity, OBBE this.setDeltaMovement(this.getDeltaMovement().add(this.getViewVector(1).normalize().scale(0.04 * getDeltaMovement().dot(getViewVector(1))))); this.setDeltaMovement(this.getDeltaMovement().multiply(f1, 0.85, f1)); } + +// setTurretYRot(getTurretYRot() + 1); +// setTurretXRot(getTurretXRot() + 1); + + interactionTick *= 0.9; + this.refreshDimensions(); } @@ -104,12 +198,48 @@ public class Type63Entity extends MobileVehicleEntity implements GeoEntity, OBBE @Override public void travel() { - float diffY = 0; + float diffY = entityData.get(YAW) - getTurretYRot(); + this.setTurretYRot(Mth.clamp(this.getTurretYRot() + 0.25f * diffY, -15, 15)); + + float diffX = entityData.get(PITCH) - getTurretXRot(); + this.setTurretXRot(Mth.clamp(this.getTurretXRot() + 0.25f * diffX, -60, 5)); double s0 = getDeltaMovement().dot(this.getViewVector(1)); - this.setLeftWheelRot((float) (this.getLeftWheelRot() - 1.75 * s0) - 0.015f * Mth.clamp(0.4f * diffY, -5f, 5f)); - this.setRightWheelRot((float) (this.getRightWheelRot() - 1.75 * s0) + 0.015f * Mth.clamp(0.4f * diffY, -5f, 5f)); + this.setLeftWheelRot((float) (this.getLeftWheelRot() - 1.75 * s0)); + this.setRightWheelRot((float) (this.getRightWheelRot() - 1.75 * s0)); + } + + public Vec3 getTurretVector(float pPartialTicks) { + Matrix4f transform = getTurretTransform(pPartialTicks); + Vector4f rootPosition = transformPosition(transform, 0, 0, 0); + Vector4f targetPosition = transformPosition(transform, 0, 0, 1); + return new Vec3(rootPosition.x, rootPosition.y, rootPosition.z).vectorTo(new Vec3(targetPosition.x, targetPosition.y, targetPosition.z)); + } + + @Override + public Matrix4f getTurretTransform(float ticks) { + Matrix4f transformV = getVehicleTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0, 0.45703125f, -0.1625f); + + transformV.translate(worldPosition.x, worldPosition.y, worldPosition.z); + transformV.rotate(Axis.YP.rotationDegrees(Mth.lerp(ticks, turretYRotO, getTurretYRot()))); + return transformV; + } + + public Matrix4f getBarrelTransform(float ticks) { + Matrix4f transformT = getTurretTransform(ticks); + + Matrix4f transform = new Matrix4f(); + Vector4f worldPosition = transformPosition(transform, 0, 0.65f, -0.203125f); + + transformT.translate(worldPosition.x, worldPosition.y, worldPosition.z); + + float x = Mth.lerp(ticks, turretXRotO, getTurretXRot()); + transformT.rotate(Axis.XP.rotationDegrees(x)); + return transformT; } @Override @@ -197,12 +327,86 @@ public class Type63Entity extends MobileVehicleEntity implements GeoEntity, OBBE @Override public List getOBBs() { - return List.of(); + return List.of(this.barrel0, this.barrel1, this.barrel2, this.barrel3, this.barrel4, this.barrel5, this.barrel6, this.barrel7, this.barrel8, this.barrel9, this.barrel10, this.barrel11, + this.hoe1, this.hoe2, this.yawController, this.pitchController); } @Override public void updateOBB() { Matrix4f transform = getVehicleTransform(1); + + // 驻锄位置 + Vector4f worldPosition = transformPosition(transform, 0.875f, 0.1875f, -1.625f); + this.hoe1.center().set(new Vector3f(worldPosition.x, worldPosition.y, worldPosition.z)); + this.hoe1.setRotation(VectorTool.combineRotations(1, this)); + + Vector4f worldPosition2 = transformPosition(transform, -0.875f, 0.1875f, -1.625f); + this.hoe2.center().set(new Vector3f(worldPosition2.x, worldPosition2.y, worldPosition2.z)); + this.hoe2.setRotation(VectorTool.combineRotations(1, this)); + + Matrix4f transformT = getTurretTransform(1); + + Vector4f worldPositionYaw = transformPosition(transformT, 0.62625f, 0.0396875f, -0.5f); + this.yawController.center().set(new Vector3f(worldPositionYaw.x, worldPositionYaw.y, worldPositionYaw.z)); + this.yawController.setRotation(VectorTool.combineRotationsTurret(1, this)); + + Vector4f worldPositionPitch = transformPosition(transformT, 0.7825f, 0.5771875f, -0.024375f); + this.pitchController.center().set(new Vector3f(worldPositionPitch.x, worldPositionPitch.y, worldPositionPitch.z)); + this.pitchController.setRotation(VectorTool.combineRotationsTurret(1, this)); + + Matrix4f transformB = getBarrelTransform(1); + + float i = 0.24375f; + + Vector4f worldPositionBarrel0 = transformPosition(transformB, -0.3659375f, 0.244375f, -0.44625f); + this.barrel0.center().set(new Vector3f(worldPositionBarrel0.x, worldPositionBarrel0.y, worldPositionBarrel0.z)); + this.barrel0.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + Vector4f worldPositionBarrel1 = transformPosition(transformB, -0.3659375f + i, 0.244375f, -0.44625f); + this.barrel1.center().set(new Vector3f(worldPositionBarrel1.x, worldPositionBarrel1.y, worldPositionBarrel1.z)); + this.barrel1.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + Vector4f worldPositionBarrel2 = transformPosition(transformB, -0.3659375f + 2 * i, 0.244375f, -0.44625f); + this.barrel2.center().set(new Vector3f(worldPositionBarrel2.x, worldPositionBarrel2.y, worldPositionBarrel2.z)); + this.barrel2.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + Vector4f worldPositionBarrel3 = transformPosition(transformB, -0.3659375f + 3 * i, 0.244375f, -0.44625f); + this.barrel3.center().set(new Vector3f(worldPositionBarrel3.x, worldPositionBarrel3.y, worldPositionBarrel3.z)); + this.barrel3.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + + Vector4f worldPositionBarrel4 = transformPosition(transformB, -0.3659375f, 0.244375f - i, -0.44625f); + this.barrel4.center().set(new Vector3f(worldPositionBarrel4.x, worldPositionBarrel4.y, worldPositionBarrel4.z)); + this.barrel4.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + Vector4f worldPositionBarrel5 = transformPosition(transformB, -0.3659375f + i, 0.244375f - i, -0.44625f); + this.barrel5.center().set(new Vector3f(worldPositionBarrel5.x, worldPositionBarrel5.y, worldPositionBarrel5.z)); + this.barrel5.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + Vector4f worldPositionBarrel6 = transformPosition(transformB, -0.3659375f + 2 * i, 0.244375f - i, -0.44625f); + this.barrel6.center().set(new Vector3f(worldPositionBarrel6.x, worldPositionBarrel6.y, worldPositionBarrel6.z)); + this.barrel6.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + Vector4f worldPositionBarrel7 = transformPosition(transformB, -0.3659375f + 3 * i, 0.244375f - i, -0.44625f); + this.barrel7.center().set(new Vector3f(worldPositionBarrel7.x, worldPositionBarrel7.y, worldPositionBarrel7.z)); + this.barrel7.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + + Vector4f worldPositionBarrel8 = transformPosition(transformB, -0.3659375f, 0.244375f - 2 * i, -0.44625f); + this.barrel8.center().set(new Vector3f(worldPositionBarrel8.x, worldPositionBarrel8.y, worldPositionBarrel8.z)); + this.barrel8.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + Vector4f worldPositionBarrel9 = transformPosition(transformB, -0.3659375f + i, 0.244375f - 2 * i, -0.44625f); + this.barrel9.center().set(new Vector3f(worldPositionBarrel9.x, worldPositionBarrel9.y, worldPositionBarrel9.z)); + this.barrel9.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + Vector4f worldPositionBarrel10 = transformPosition(transformB, -0.3659375f + 2 * i, 0.244375f - 2 * i, -0.44625f); + this.barrel10.center().set(new Vector3f(worldPositionBarrel10.x, worldPositionBarrel10.y, worldPositionBarrel10.z)); + this.barrel10.setRotation(VectorTool.combineRotationsBarrel(1, this)); + + Vector4f worldPositionBarrel11 = transformPosition(transformB, -0.3659375f + 3 * i, 0.244375f - 2 * i, -0.44625f); + this.barrel11.center().set(new Vector3f(worldPositionBarrel11.x, worldPositionBarrel11.y, worldPositionBarrel11.z)); + this.barrel11.setRotation(VectorTool.combineRotationsBarrel(1, this)); } @Override diff --git a/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java b/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java index 61d2f260d..7653211a5 100644 --- a/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java +++ b/src/main/java/com/atsuishio/superbwarfare/event/ClientEventHandler.java @@ -179,12 +179,24 @@ public class ClientEventHandler { return; } float xRotOffset = Mth.lerp(event.getPartialTick(), player.xBobO, player.xBob); - float yRotOffset = Mth.lerp(event.getPartialTick(), player.yBobO, player.yBob); float xRot = player.getViewXRot(event.getPartialTick()) - xRotOffset; - float yRot = player.getViewYRot(event.getPartialTick()) - yRotOffset; - turnRot[0] = Mth.clamp(0.05 * xRot, -5, 5) * (1 - 0.75 * zoomTime); - turnRot[1] = Mth.clamp(0.05 * yRot, -10, 10) * (1 - 0.75 * zoomTime); - turnRot[2] = Mth.clamp(0.1 * yRot, -10, 10) * (1 - zoomTime); + + var fromY = player.yRotO; + var toY = player.getYRot(); + + if (fromY > 135 && toY < -135) { + toY += 360; + } + if (fromY < -135 && toY > 135) { + fromY += 360; + } + + float yRotOffset = Mth.lerp(event.getPartialTick(), 0, toY - fromY); +// float yRot = Mth.wrapDegrees(player.getYRot() + yRotOffset); + + turnRot[0] = Mth.clamp(0.05 * yRotOffset, -5, 5) * (1 - 0.75 * zoomTime); + turnRot[1] = Mth.clamp(0.05 * yRotOffset, -10, 10) * (1 - 0.75 * zoomTime); + turnRot[2] = Mth.clamp(0.1 * yRotOffset, -10, 10) * (1 - zoomTime); } private static boolean notInGame() { diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/OBB.java b/src/main/java/com/atsuishio/superbwarfare/tools/OBB.java index 7e09c2cc0..b4d3ca729 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/OBB.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/OBB.java @@ -1,5 +1,8 @@ package com.atsuishio.superbwarfare.tools; +import com.atsuishio.superbwarfare.entity.OBBEntity; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; @@ -438,6 +441,27 @@ public record OBB(Vector3f center, Vector3f extents, Quaternionf rotation, Part public record ClosestFaceResult(OBB obb, int faceIndex, float distance, Vector3f faceCenter, Vector3f faceNormal) { } + //获取玩家看向的某个OBB + + // TODO 修复看向的第一个OBB后方如果还有另外的OBB时,无法正确返回看向的第一个OBB的BUG + + public static OBB getLookingObb(Player player, double range) { + OBB lookingOBB = null; + Entity lookingEntity = TraceTool.findLookingEntity(player, range); + if (lookingEntity instanceof OBBEntity obbEntity) { + var obbList = obbEntity.getOBBs(); + for (OBB obb : obbList) { + Vec3 hitPos = TraceTool.playerFindLookingPos(player, lookingEntity, range); + if (hitPos != null && obb.contains(hitPos.add(player.getViewVector(1).scale(0.02)))) { +// player.displayClientMessage(Component.literal(String.valueOf(obb)), true); + lookingOBB = obb; + break; + } + } + } + return lookingOBB; + } + public enum Part { EMPTY, WHEEL_LEFT, diff --git a/src/main/java/com/atsuishio/superbwarfare/tools/VectorTool.java b/src/main/java/com/atsuishio/superbwarfare/tools/VectorTool.java index 4828465ec..30f3feb15 100644 --- a/src/main/java/com/atsuishio/superbwarfare/tools/VectorTool.java +++ b/src/main/java/com/atsuishio/superbwarfare/tools/VectorTool.java @@ -56,6 +56,14 @@ public class VectorTool { return combined; } + public static Quaternionf combineRotationsBarrel(float partialTicks, VehicleEntity entity) { + Quaternionf turretPitchRot = Axis.XP.rotationDegrees(Mth.lerp(partialTicks, entity.turretXRotO, entity.getTurretXRot())); + Quaternionf combined = combineRotationsTurret(partialTicks, entity); + combined.mul(turretPitchRot); + + return combined; + } + public static Vec3 randomPos(Vec3 originPos, int radius) { return originPos.add(new Vec3(Math.random() * radius, 0, 0).yRot((float) (360 * Math.random()) * Mth.DEG_TO_RAD)); }