mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 23:47:38 +01:00
Actually playable
- Fixed some left-over math bugs - Greatly improved contraption-player collision response, especially with rotating structures
This commit is contained in:
parent
1ea7eeb040
commit
c58310b293
5 changed files with 124 additions and 73 deletions
|
@ -6,7 +6,7 @@ org.gradle.daemon=false
|
||||||
# mod version info
|
# mod version info
|
||||||
mod_version=0.3
|
mod_version=0.3
|
||||||
minecraft_version=1.15.2
|
minecraft_version=1.15.2
|
||||||
forge_version=31.2.21
|
forge_version=31.2.31
|
||||||
|
|
||||||
# dependency versions
|
# dependency versions
|
||||||
registrate_version=0.0.4.18
|
registrate_version=0.0.4.18
|
||||||
|
|
|
@ -8,7 +8,7 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
import org.apache.commons.lang3.mutable.MutableObject;
|
||||||
|
|
||||||
import com.google.common.base.Predicates;
|
import com.google.common.base.Predicates;
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
|
@ -29,6 +29,7 @@ import net.minecraft.entity.EntityType;
|
||||||
import net.minecraft.entity.MoverType;
|
import net.minecraft.entity.MoverType;
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||||
|
import net.minecraft.nbt.CompoundNBT;
|
||||||
import net.minecraft.util.Direction;
|
import net.minecraft.util.Direction;
|
||||||
import net.minecraft.util.Direction.Axis;
|
import net.minecraft.util.Direction.Axis;
|
||||||
import net.minecraft.util.Direction.AxisDirection;
|
import net.minecraft.util.Direction.AxisDirection;
|
||||||
|
@ -41,6 +42,7 @@ import net.minecraft.world.World;
|
||||||
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
import net.minecraft.world.gen.feature.template.Template.BlockInfo;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.common.util.Constants.NBT;
|
||||||
import net.minecraftforge.event.TickEvent.ClientTickEvent;
|
import net.minecraftforge.event.TickEvent.ClientTickEvent;
|
||||||
import net.minecraftforge.event.TickEvent.Phase;
|
import net.minecraftforge.event.TickEvent.Phase;
|
||||||
import net.minecraftforge.event.TickEvent.WorldTickEvent;
|
import net.minecraftforge.event.TickEvent.WorldTickEvent;
|
||||||
|
@ -118,7 +120,11 @@ public class ContraptionCollider {
|
||||||
if (bounds == null)
|
if (bounds == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (Entity entity : world.getEntitiesWithinAABB((EntityType<?>) null, bounds.grow(1),
|
double conRotX = contraptionRotation.z;
|
||||||
|
double conRotY = contraptionRotation.y;
|
||||||
|
double conRotZ = contraptionRotation.x;
|
||||||
|
|
||||||
|
for (Entity entity : world.getEntitiesWithinAABB((EntityType<?>) null, bounds.grow(2),
|
||||||
contraptionEntity::canCollideWith)) {
|
contraptionEntity::canCollideWith)) {
|
||||||
if (entity instanceof PlayerEntity && !world.isRemote)
|
if (entity instanceof PlayerEntity && !world.isRemote)
|
||||||
return;
|
return;
|
||||||
|
@ -127,11 +133,13 @@ public class ContraptionCollider {
|
||||||
Vec3d entityPosition = entity.getPositionVec();
|
Vec3d entityPosition = entity.getPositionVec();
|
||||||
Vec3d centerY = new Vec3d(0, entity.getBoundingBox()
|
Vec3d centerY = new Vec3d(0, entity.getBoundingBox()
|
||||||
.getYSize() / 2, 0);
|
.getYSize() / 2, 0);
|
||||||
Vec3d position = entityPosition.subtract(contraptionPosition)
|
|
||||||
.subtract(contraptionEntity.stationary ? centerOfBlock : Vec3d.ZERO.add(0, 0.5, 0))
|
Vec3d position =
|
||||||
.add(centerY);
|
entityPosition.subtract(contraptionEntity.stationary ? centerOfBlock : Vec3d.ZERO.add(0, 0.5, 0))
|
||||||
position =
|
.add(centerY);
|
||||||
VecHelper.rotate(position, -contraptionRotation.z, -contraptionRotation.y, -contraptionRotation.x);
|
|
||||||
|
position = position.subtract(contraptionPosition);
|
||||||
|
position = VecHelper.rotate(position, -conRotX, -conRotY, -conRotZ);
|
||||||
position = position.add(centerOfBlock)
|
position = position.add(centerOfBlock)
|
||||||
.subtract(centerY)
|
.subtract(centerY)
|
||||||
.subtract(entityPosition);
|
.subtract(entityPosition);
|
||||||
|
@ -139,6 +147,16 @@ public class ContraptionCollider {
|
||||||
.offset(position)
|
.offset(position)
|
||||||
.grow(1.0E-7D);
|
.grow(1.0E-7D);
|
||||||
|
|
||||||
|
String nbtMotionKey = "ContraptionCollisionFeedback";
|
||||||
|
CompoundNBT entityData = entity.getPersistentData();
|
||||||
|
Vec3d previousIntersection = Vec3d.ZERO;
|
||||||
|
if (entityData.contains(nbtMotionKey)) {
|
||||||
|
previousIntersection = VecHelper.readNBT(entityData.getList(nbtMotionKey, NBT.TAG_DOUBLE));
|
||||||
|
entity.setMotion(entity.getMotion()
|
||||||
|
.subtract(previousIntersection.mul(1, 0, 1)));
|
||||||
|
entityData.remove(nbtMotionKey);
|
||||||
|
}
|
||||||
|
|
||||||
ReuseableStream<VoxelShape> potentialHits = getPotentiallyCollidedShapes(world, contraption, localBB);
|
ReuseableStream<VoxelShape> potentialHits = getPotentiallyCollidedShapes(world, contraption, localBB);
|
||||||
if (potentialHits.createStream()
|
if (potentialHits.createStream()
|
||||||
.count() == 0)
|
.count() == 0)
|
||||||
|
@ -147,51 +165,72 @@ public class ContraptionCollider {
|
||||||
OrientedBB obb = new OrientedBB(localBB);
|
OrientedBB obb = new OrientedBB(localBB);
|
||||||
if (!contraptionRotation.equals(Vec3d.ZERO)) {
|
if (!contraptionRotation.equals(Vec3d.ZERO)) {
|
||||||
Matrix3d rotation = new Matrix3d().asIdentity();
|
Matrix3d rotation = new Matrix3d().asIdentity();
|
||||||
rotation.multiply(new Matrix3d().asXRotation(AngleHelper.rad(contraptionRotation.z)));
|
rotation.multiply(new Matrix3d().asXRotation(AngleHelper.rad(-conRotX)));
|
||||||
rotation.multiply(new Matrix3d().asYRotation(AngleHelper.rad(contraptionRotation.y)));
|
rotation.multiply(new Matrix3d().asYRotation(AngleHelper.rad(conRotY)));
|
||||||
rotation.multiply(new Matrix3d().asZRotation(AngleHelper.rad(contraptionRotation.x)));
|
rotation.multiply(new Matrix3d().asZRotation(AngleHelper.rad(-conRotZ)));
|
||||||
obb.setRotation(rotation);
|
obb.setRotation(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
MutableBoolean onCollide = new MutableBoolean(true);
|
MutableObject<Vec3d> collisionResponse = new MutableObject<>(Vec3d.ZERO);
|
||||||
|
Vec3d obbCenter = obb.getCenter();
|
||||||
|
|
||||||
potentialHits.createStream()
|
potentialHits.createStream()
|
||||||
.forEach(shape -> {
|
.forEach(shape -> {
|
||||||
AxisAlignedBB bb = shape.getBoundingBox();
|
Vec3d currentResponse = collisionResponse.getValue();
|
||||||
Vec3d intersect = obb.intersect(bb);
|
shape.toBoundingBoxList()
|
||||||
if (intersect == null)
|
.parallelStream()
|
||||||
return;
|
.forEach(bb -> {
|
||||||
intersect = VecHelper.rotate(intersect, contraptionRotation.z, contraptionRotation.y,
|
obb.setCenter(obbCenter.add(currentResponse));
|
||||||
contraptionRotation.x);
|
Vec3d intersect = obb.intersect(bb);
|
||||||
|
if (intersect != null)
|
||||||
obb.setCenter(obb.getCenter()
|
collisionResponse.setValue(currentResponse.add(intersect));
|
||||||
.add(intersect));
|
});
|
||||||
entity.move(MoverType.PISTON, intersect);
|
|
||||||
|
|
||||||
Vec3d entityMotion = entity.getMotion();
|
|
||||||
if (entityMotion.getX() > 0 == intersect.getX() < 0)
|
|
||||||
entityMotion = entityMotion.mul(0, 1, 1);
|
|
||||||
if (entityMotion.getY() > 0 == intersect.getY() < 0)
|
|
||||||
entityMotion = entityMotion.mul(1, 0, 1);
|
|
||||||
if (entityMotion.getZ() > 0 == intersect.getZ() < 0)
|
|
||||||
entityMotion = entityMotion.mul(1, 1, 0);
|
|
||||||
entity.setMotion(entityMotion);
|
|
||||||
|
|
||||||
if (onCollide.isTrue()) {
|
|
||||||
onCollide.setFalse();
|
|
||||||
contraptionEntity.collidingEntities.add(entity);
|
|
||||||
entity.velocityChanged = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (intersect.y > 0) {
|
|
||||||
entity.handleFallDamage(entity.fallDistance, 1);
|
|
||||||
entity.fallDistance = 0;
|
|
||||||
entity.onGround = true;
|
|
||||||
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> checkForClientPlayerCollision(entity));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity instanceof ServerPlayerEntity)
|
|
||||||
((ServerPlayerEntity) entity).connection.floatingTickCount = 0;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Vec3d entityMotion = entity.getMotion();
|
||||||
|
Vec3d totalResponse = collisionResponse.getValue();
|
||||||
|
|
||||||
|
if (totalResponse == Vec3d.ZERO)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
totalResponse = VecHelper.rotate(totalResponse, conRotX, Axis.X);
|
||||||
|
totalResponse = VecHelper.rotate(totalResponse, conRotY, Axis.Y);
|
||||||
|
totalResponse = VecHelper.rotate(totalResponse, conRotZ, Axis.Z);
|
||||||
|
|
||||||
|
double motionX = entityMotion.getX();
|
||||||
|
double motionY = entityMotion.getY();
|
||||||
|
double motionZ = entityMotion.getZ();
|
||||||
|
double intersectX = totalResponse.getX();
|
||||||
|
double intersectY = totalResponse.getY();
|
||||||
|
double intersectZ = totalResponse.getZ();
|
||||||
|
|
||||||
|
double horizonalEpsilon = 1 / 128f;
|
||||||
|
|
||||||
|
if (motionX != 0 && Math.abs(intersectX) > horizonalEpsilon && motionX > 0 == intersectX < 0)
|
||||||
|
entityMotion = entityMotion.mul(0, 1, 1);
|
||||||
|
if (motionY != 0 && intersectY != 0 && motionY > 0 == intersectY < 0)
|
||||||
|
entityMotion = entityMotion.mul(1, 0, 1);
|
||||||
|
if (motionZ != 0 && Math.abs(intersectZ) > horizonalEpsilon && motionZ > 0 == intersectZ < 0)
|
||||||
|
entityMotion = entityMotion.mul(1, 1, 0);
|
||||||
|
|
||||||
|
entityMotion = entityMotion.add(totalResponse.mul(1, 0, 1));
|
||||||
|
contraptionEntity.collidingEntities.add(entity);
|
||||||
|
entity.velocityChanged = true;
|
||||||
|
|
||||||
|
if (totalResponse.y > 0) {
|
||||||
|
entity.handleFallDamage(entity.fallDistance, 1);
|
||||||
|
entity.fallDistance = 0;
|
||||||
|
entity.onGround = true;
|
||||||
|
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> checkForClientPlayerCollision(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity instanceof ServerPlayerEntity)
|
||||||
|
((ServerPlayerEntity) entity).connection.floatingTickCount = 0;
|
||||||
|
|
||||||
|
entity.setMotion(entityMotion);
|
||||||
|
Vec3d epos = entityPosition;
|
||||||
|
entity.setPosition(epos.x, epos.y + totalResponse.y, epos.z);
|
||||||
|
entityData.put(nbtMotionKey, VecHelper.writeNBT(totalResponse));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -266,7 +305,14 @@ public class ContraptionCollider {
|
||||||
|
|
||||||
public static ReuseableStream<VoxelShape> getPotentiallyCollidedShapes(World world, Contraption contraption,
|
public static ReuseableStream<VoxelShape> getPotentiallyCollidedShapes(World world, Contraption contraption,
|
||||||
AxisAlignedBB localBB) {
|
AxisAlignedBB localBB) {
|
||||||
|
|
||||||
|
double height = localBB.getYSize();
|
||||||
|
double width = localBB.getXSize();
|
||||||
|
double horizontalFactor = (height > width && width != 0) ? height / width : 1;
|
||||||
|
double verticalFactor = (width > height && height != 0) ? width / height : 1;
|
||||||
AxisAlignedBB blockScanBB = localBB.grow(.5f);
|
AxisAlignedBB blockScanBB = localBB.grow(.5f);
|
||||||
|
blockScanBB = blockScanBB.grow(horizontalFactor, verticalFactor, horizontalFactor);
|
||||||
|
|
||||||
BlockPos min = new BlockPos(blockScanBB.minX, blockScanBB.minY, blockScanBB.minZ);
|
BlockPos min = new BlockPos(blockScanBB.minX, blockScanBB.minY, blockScanBB.minZ);
|
||||||
BlockPos max = new BlockPos(blockScanBB.maxX, blockScanBB.maxY, blockScanBB.maxZ);
|
BlockPos max = new BlockPos(blockScanBB.maxX, blockScanBB.maxY, blockScanBB.maxZ);
|
||||||
|
|
||||||
|
|
|
@ -4,34 +4,31 @@ import com.mojang.blaze3d.matrix.MatrixStack;
|
||||||
import com.simibubi.create.AllSpecialTextures;
|
import com.simibubi.create.AllSpecialTextures;
|
||||||
import com.simibubi.create.CreateClient;
|
import com.simibubi.create.CreateClient;
|
||||||
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
|
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
|
||||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
|
||||||
import com.simibubi.create.foundation.utility.MatrixStacker;
|
import com.simibubi.create.foundation.utility.MatrixStacker;
|
||||||
import com.simibubi.create.foundation.utility.outliner.AABBOutline;
|
import com.simibubi.create.foundation.utility.outliner.AABBOutline;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.util.math.AxisAlignedBB;
|
import net.minecraft.util.math.AxisAlignedBB;
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.util.math.BlockRayTraceResult;
|
|
||||||
import net.minecraft.util.math.RayTraceResult;
|
|
||||||
import net.minecraft.util.math.RayTraceResult.Type;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
public class CollisionDebugger {
|
public class CollisionDebugger {
|
||||||
|
|
||||||
static AxisAlignedBB staticBB = new AxisAlignedBB(BlockPos.ZERO.up(10));
|
public static AxisAlignedBB AABB = null;
|
||||||
static OrientedBB movingBB = new OrientedBB(new AxisAlignedBB(BlockPos.ZERO));
|
public static OrientedBB OBB = null;
|
||||||
static Vec3d seperation;
|
static Vec3d seperation;
|
||||||
static double angle = 0;
|
static double angle = 0;
|
||||||
static AABBOutline outline;
|
static AABBOutline outline;
|
||||||
|
|
||||||
public static void onScroll(double delta) {
|
public static void onScroll(double delta) {
|
||||||
angle += delta;
|
// angle += delta;
|
||||||
movingBB.setRotation(new Matrix3d().asZRotation(AngleHelper.rad(angle)));
|
// movingBB = new OrientedBB(new AxisAlignedBB(BlockPos.ZERO).expand(0, 1, 0));
|
||||||
|
// movingBB.setRotation(new Matrix3d().asZRotation(AngleHelper.rad(angle)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) {
|
public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) {
|
||||||
|
if (OBB == null)
|
||||||
|
return;
|
||||||
ms.push();
|
ms.push();
|
||||||
outline = new AABBOutline(movingBB.getAsAxisAlignedBB());
|
outline = new AABBOutline(OBB.getAsAxisAlignedBB());
|
||||||
outline.getParams()
|
outline.getParams()
|
||||||
.withFaceTexture(seperation == null ? AllSpecialTextures.CHECKERED : null)
|
.withFaceTexture(seperation == null ? AllSpecialTextures.CHECKERED : null)
|
||||||
.colored(0xffffff);
|
.colored(0xffffff);
|
||||||
|
@ -40,12 +37,12 @@ public class CollisionDebugger {
|
||||||
.lineWidth(1 / 64f)
|
.lineWidth(1 / 64f)
|
||||||
.colored(0xff6544);
|
.colored(0xff6544);
|
||||||
MatrixStacker.of(ms)
|
MatrixStacker.of(ms)
|
||||||
.translate(movingBB.center);
|
.translate(OBB.center);
|
||||||
ms.peek()
|
ms.peek()
|
||||||
.getModel()
|
.getModel()
|
||||||
.multiply(movingBB.rotation.getAsMatrix4f());
|
.multiply(OBB.rotation.getAsMatrix4f());
|
||||||
MatrixStacker.of(ms)
|
MatrixStacker.of(ms)
|
||||||
.translateBack(movingBB.center);
|
.translateBack(OBB.center);
|
||||||
outline.render(ms, buffer);
|
outline.render(ms, buffer);
|
||||||
ms.pop();
|
ms.pop();
|
||||||
|
|
||||||
|
@ -56,26 +53,24 @@ public class CollisionDebugger {
|
||||||
.lineWidth(1 / 32f);
|
.lineWidth(1 / 32f);
|
||||||
MatrixStacker.of(ms)
|
MatrixStacker.of(ms)
|
||||||
.translate(seperation)
|
.translate(seperation)
|
||||||
.translate(movingBB.center);
|
.translate(OBB.center);
|
||||||
ms.peek()
|
ms.peek()
|
||||||
.getModel()
|
.getModel()
|
||||||
.multiply(movingBB.rotation.getAsMatrix4f());
|
.multiply(OBB.rotation.getAsMatrix4f());
|
||||||
MatrixStacker.of(ms)
|
MatrixStacker.of(ms)
|
||||||
.translateBack(movingBB.center);
|
.translateBack(OBB.center);
|
||||||
outline.render(ms, buffer);
|
outline.render(ms, buffer);
|
||||||
}
|
}
|
||||||
ms.pop();
|
ms.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void tick() {
|
public static void tick() {
|
||||||
staticBB = new AxisAlignedBB(BlockPos.ZERO.up(60));
|
if (OBB == null)
|
||||||
RayTraceResult mouse = Minecraft.getInstance().objectMouseOver;
|
return;
|
||||||
if (mouse != null && mouse.getType() == Type.BLOCK) {
|
if (AABB == null)
|
||||||
BlockRayTraceResult hit = (BlockRayTraceResult) mouse;
|
return;
|
||||||
movingBB.setCenter(hit.getHitVec());
|
seperation = OBB.intersect(AABB);
|
||||||
seperation = movingBB.intersect(staticBB);
|
CreateClient.outliner.showAABB(AABB, AABB)
|
||||||
}
|
|
||||||
CreateClient.outliner.showAABB(staticBB, staticBB)
|
|
||||||
.withFaceTexture(seperation == null ? AllSpecialTextures.CHECKERED : null);
|
.withFaceTexture(seperation == null ? AllSpecialTextures.CHECKERED : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,10 @@ public class OrientedBB {
|
||||||
this.extents = extents;
|
this.extents = extents;
|
||||||
this.setRotation(rotation);
|
this.setRotation(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OrientedBB copy() {
|
||||||
|
return new OrientedBB(center, extents, rotation);
|
||||||
|
}
|
||||||
|
|
||||||
public Vec3d intersect(AxisAlignedBB bb) {
|
public Vec3d intersect(AxisAlignedBB bb) {
|
||||||
Vec3d extentsA = extentsFromBB(bb);
|
Vec3d extentsA = extentsFromBB(bb);
|
||||||
|
@ -152,7 +156,7 @@ public class OrientedBB {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void showDebugLine(Vec3d relativeStart, Vec3d relativeEnd, int color, String id, int offset) {
|
static void showDebugLine(Vec3d relativeStart, Vec3d relativeEnd, int color, String id, int offset) {
|
||||||
Vec3d center = CollisionDebugger.staticBB.getCenter()
|
Vec3d center = CollisionDebugger.AABB.getCenter()
|
||||||
.add(0, 1 + offset / 16f, 0);
|
.add(0, 1 + offset / 16f, 0);
|
||||||
CreateClient.outliner.showLine(id + checkCount, center.add(relativeStart), center.add(relativeEnd))
|
CreateClient.outliner.showLine(id + checkCount, center.add(relativeStart), center.add(relativeEnd))
|
||||||
.colored(color)
|
.colored(color)
|
||||||
|
@ -174,6 +178,10 @@ public class OrientedBB {
|
||||||
public void setCenter(Vec3d center) {
|
public void setCenter(Vec3d center) {
|
||||||
this.center = center;
|
this.center = center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void move(Vec3d offset) {
|
||||||
|
setCenter(getCenter().add(offset));
|
||||||
|
}
|
||||||
|
|
||||||
public AxisAlignedBB getAsAxisAlignedBB() {
|
public AxisAlignedBB getAsAxisAlignedBB() {
|
||||||
return new AxisAlignedBB(0, 0, 0, 0, 0, 0).offset(center)
|
return new AxisAlignedBB(0, 0, 0, 0, 0, 0).offset(center)
|
||||||
|
|
|
@ -26,6 +26,8 @@ public class VecHelper {
|
||||||
public static Vec3d rotate(Vec3d vec, double deg, Axis axis) {
|
public static Vec3d rotate(Vec3d vec, double deg, Axis axis) {
|
||||||
if (deg == 0)
|
if (deg == 0)
|
||||||
return vec;
|
return vec;
|
||||||
|
if (vec == Vec3d.ZERO)
|
||||||
|
return vec;
|
||||||
|
|
||||||
float angle = (float) (deg / 180f * Math.PI);
|
float angle = (float) (deg / 180f * Math.PI);
|
||||||
double sin = MathHelper.sin(angle);
|
double sin = MathHelper.sin(angle);
|
||||||
|
|
Loading…
Reference in a new issue