mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-30 16:28:00 +01:00
Implement more realistic flying mechanics
This commit is contained in:
parent
86524c10aa
commit
12a56dfe79
4 changed files with 128 additions and 229 deletions
|
@ -1,50 +0,0 @@
|
||||||
package com.minelittlepony.unicopia.entity.player;
|
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.util.MutableVector;
|
|
||||||
|
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.player.PlayerEntity;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
|
|
||||||
public class AeronauticalPlayerPhysics extends PlayerPhysics {
|
|
||||||
|
|
||||||
private final Aeronautics auronautics = new Aeronautics();
|
|
||||||
|
|
||||||
private double gravity;
|
|
||||||
|
|
||||||
private int thrustCountdown;
|
|
||||||
|
|
||||||
public AeronauticalPlayerPhysics(Pony pony) {
|
|
||||||
super(pony);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public double calcGravity(double worldConstant) {
|
|
||||||
return gravity = super.calcGravity(worldConstant);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void moveFlying(Entity player, MutableVector velocity) {
|
|
||||||
|
|
||||||
PlayerEntity ply = (PlayerEntity)player;
|
|
||||||
|
|
||||||
auronautics.pitchAngle = 0;
|
|
||||||
auronautics.rollAngle = 0;
|
|
||||||
|
|
||||||
float yaw = player.getYaw(1);
|
|
||||||
|
|
||||||
Vec3d motion = auronautics.calcGravitationalAccelleration(gravity);
|
|
||||||
|
|
||||||
if (ply.forwardSpeed != 0 && thrustCountdown-- <= 0) {
|
|
||||||
thrustCountdown = 20;
|
|
||||||
player.playSound(getWingSound(), 0.4F, 1);
|
|
||||||
motion = motion.add(auronautics.calcThrustVelocity(-100));
|
|
||||||
}
|
|
||||||
|
|
||||||
motion = motion.rotateY(yaw).add(velocity.toImmutable()).multiply(1 - auronautics.getDrag());
|
|
||||||
|
|
||||||
velocity.x = motion.x;
|
|
||||||
velocity.y = motion.y;
|
|
||||||
velocity.z = motion.z;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
package com.minelittlepony.unicopia.entity.player;
|
|
||||||
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
|
||||||
|
|
||||||
// X - forward
|
|
||||||
// Y - vertical
|
|
||||||
// Z - sideways
|
|
||||||
public class Aeronautics {
|
|
||||||
|
|
||||||
public double rollAngle;
|
|
||||||
public double pitchAngle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the normalized direction vector
|
|
||||||
*/
|
|
||||||
private Vec3d getMomentVector() {
|
|
||||||
// sine(angle) = y/h
|
|
||||||
// cos(angle) = x/h
|
|
||||||
|
|
||||||
Vec3d climbVector = new Vec3d(Math.cos(pitchAngle), Math.sin(pitchAngle), 0);
|
|
||||||
Vec3d bankVector = new Vec3d(0, Math.sin(rollAngle), Math.cos(rollAngle));
|
|
||||||
|
|
||||||
return bankVector.add(climbVector).normalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the normalized perpendicular vector.
|
|
||||||
*/
|
|
||||||
private Vec3d getNormal() {
|
|
||||||
// sine(angle) = y/h
|
|
||||||
// cos(angle) = x/h
|
|
||||||
|
|
||||||
Vec3d climbVector = new Vec3d(Math.cos(pitchAngle), Math.sin(pitchAngle), 0);
|
|
||||||
Vec3d bankVector = new Vec3d(0, Math.sin(rollAngle), Math.cos(rollAngle));
|
|
||||||
|
|
||||||
return bankVector.crossProduct(climbVector).normalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the acceleration vector due to gravity
|
|
||||||
* parallel to the slope of the incline described
|
|
||||||
* by the roll and pitch components.
|
|
||||||
*
|
|
||||||
* @param gravity The global gravitation constant C
|
|
||||||
*/
|
|
||||||
public Vec3d calcGravitationalAccelleration(double gravity) {
|
|
||||||
return getMomentVector().multiply(
|
|
||||||
-gravity * Math.signum(pitchAngle),
|
|
||||||
-gravity,
|
|
||||||
-gravity * Math.signum(rollAngle)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the added thrust vector for the given forwards motion
|
|
||||||
* and velocity projected against the direction of incline.
|
|
||||||
*
|
|
||||||
* @param forwards The forwards thrust speed
|
|
||||||
* @param velocity The current motion vector
|
|
||||||
*/
|
|
||||||
public Vec3d calcThrustVelocity(double forwards) {
|
|
||||||
return getNormal().add(getMomentVector())
|
|
||||||
.normalize()
|
|
||||||
.multiply(forwards * (1 - getDrag()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The drag due to air resistance.
|
|
||||||
*/
|
|
||||||
public double getDrag() {
|
|
||||||
return 0.0078; // magic number until I figure out what tf I'm doing
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -49,13 +49,9 @@ public final class PlayerDimensions {
|
||||||
flyingDimensions = EntityDimensions.changing(dimensions.width, dimensions.height / 2);
|
flyingDimensions = EntityDimensions.changing(dimensions.width, dimensions.height / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return getPredicate().flatMap(e -> e.getTargetDimensions(pony)).orElseGet(() -> {
|
return getPredicate()
|
||||||
if (physics.isFlyingSurvival && physics.isRainboom()) {
|
.flatMap(e -> e.getTargetDimensions(pony))
|
||||||
return flyingDimensions;
|
.orElseGet(() -> physics.isFlyingSurvival ? flyingDimensions : defaultDimensions);
|
||||||
}
|
|
||||||
|
|
||||||
return defaultDimensions;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private float calculateTargetEyeHeight() {
|
private float calculateTargetEyeHeight() {
|
||||||
|
@ -65,10 +61,6 @@ public final class PlayerDimensions {
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (physics.isFlyingSurvival && physics.isRainboom()) {
|
|
||||||
return 0.5F;
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultEyeHeight;
|
return defaultEyeHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,20 +15,21 @@ import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.sound.SoundCategory;
|
import net.minecraft.sound.SoundCategory;
|
||||||
import net.minecraft.sound.SoundEvent;
|
import net.minecraft.sound.SoundEvent;
|
||||||
import net.minecraft.sound.SoundEvents;
|
|
||||||
import net.minecraft.util.Tickable;
|
import net.minecraft.util.Tickable;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
|
||||||
public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Motion, NbtSerialisable {
|
public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Motion, NbtSerialisable {
|
||||||
|
|
||||||
private int ticksInAir;
|
private int ticksInAir;
|
||||||
|
|
||||||
|
private float thrustScale = 0;
|
||||||
|
|
||||||
public boolean isFlyingEither = false;
|
public boolean isFlyingEither = false;
|
||||||
public boolean isFlyingSurvival = false;
|
public boolean isFlyingSurvival = false;
|
||||||
|
|
||||||
private double lastTickPosX = 0;
|
private Vec3d lastPos = Vec3d.ZERO;
|
||||||
private double lastTickPosZ = 0;
|
|
||||||
|
|
||||||
private final PlayerDimensions dimensions;
|
private final PlayerDimensions dimensions;
|
||||||
|
|
||||||
|
@ -47,30 +48,16 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
|
||||||
return super.getGravityModifier() * (float)pony.getOwner().getAttributeValue(PlayerAttributes.ENTITY_GRAVTY_MODIFIER);
|
return super.getGravityModifier() * (float)pony.getOwner().getAttributeValue(PlayerAttributes.ENTITY_GRAVTY_MODIFIER);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkCanFly() {
|
|
||||||
if (pony.getOwner().abilities.creativeMode || pony.getOwner().isSpectator()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pony.hasSpell()) {
|
|
||||||
Spell effect = pony.getSpell(true);
|
|
||||||
if (!effect.isDead() && effect instanceof FlightPredicate) {
|
|
||||||
return ((FlightPredicate)effect).checkCanFly(pony);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pony.getSpecies().canFly();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isRainboom() {
|
|
||||||
return Math.sqrt(getHorizontalMotion(pony.getOwner())) > 0.4F;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PlayerDimensions getDimensions() {
|
public PlayerDimensions getDimensions() {
|
||||||
return dimensions;
|
return dimensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFlying() {
|
||||||
|
return isFlyingSurvival && !pony.getOwner().isFallFlying() && !pony.getOwner().hasVehicle();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
PlayerEntity entity = pony.getOwner();
|
PlayerEntity entity = pony.getOwner();
|
||||||
|
@ -83,32 +70,37 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
|
||||||
entity.setPose(EntityPose.STANDING);
|
entity.setPose(EntityPose.STANDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
MutableVector velocity = new MutableVector(entity.getVelocity());
|
final MutableVector velocity = new MutableVector(entity.getVelocity());
|
||||||
|
|
||||||
boolean creative = entity.abilities.creativeMode || pony.getOwner().isSpectator();
|
boolean creative = entity.abilities.creativeMode || pony.getOwner().isSpectator();
|
||||||
|
|
||||||
entity.abilities.allowFlying = checkCanFly();
|
boolean canFly = checkCanFly();
|
||||||
|
|
||||||
if (!creative) {
|
if (!creative) {
|
||||||
entity.abilities.flying |= entity.abilities.allowFlying && isFlyingEither;
|
entity.abilities.flying |= (canFly || entity.abilities.allowFlying) && isFlyingEither;
|
||||||
|
|
||||||
if ((entity.isOnGround() && entity.isSneaking()) || entity.isTouchingWater()) {
|
if ((entity.isOnGround() && entity.isSneaking()) || entity.isTouchingWater() || entity.horizontalCollision || entity.verticalCollision) {
|
||||||
entity.abilities.flying = false;
|
entity.abilities.flying = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isFlyingSurvival = entity.abilities.flying && !creative;
|
isFlyingSurvival = entity.abilities.flying && !creative;
|
||||||
isFlyingEither = isFlyingSurvival || (creative && entity.abilities.flying);
|
isFlyingEither = isFlyingSurvival || (creative && entity.abilities.flying);
|
||||||
|
|
||||||
if (!creative && !entity.isFallFlying() && isFlyingSurvival && !entity.hasVehicle()) {
|
if (pony.getPhysics().isGravityNegative()) {
|
||||||
|
entity.setOnGround(!entity.world.isAir(new BlockPos(entity.getX(), entity.getY() + entity.getHeight() + 0.5F, entity.getZ())));
|
||||||
|
|
||||||
entity.fallDistance = 0;
|
if (entity.isOnGround() || entity.horizontalCollision) {
|
||||||
|
entity.abilities.flying = false;
|
||||||
|
isFlyingEither = false;
|
||||||
|
isFlyingSurvival = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFlying()) {
|
||||||
int level = pony.getLevel().get() + 1;
|
int level = pony.getLevel().get() + 1;
|
||||||
|
|
||||||
if (ticksInAir > (level * 100)) {
|
if (ticksInAir++ > (level * 100)) {
|
||||||
Bar mana = pony.getMagicalReserves().getMana();
|
Bar mana = pony.getMagicalReserves().getMana();
|
||||||
|
|
||||||
mana.add((int)(-getHorizontalMotion(entity) * 50 / level));
|
mana.add((int)(-getHorizontalMotion(entity) * 50 / level));
|
||||||
|
@ -128,55 +120,91 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
moveFlying(entity, velocity);
|
entity.fallDistance = 0;
|
||||||
|
|
||||||
if (ticksInAir++ > 0 && ticksInAir % 30 == 0) {
|
moveFlying(entity, velocity);
|
||||||
entity.playSound(getWingSound(), 0.5F, 1);
|
if (entity.world.hasRain(entity.getBlockPos())) {
|
||||||
|
applyTurbulance(entity, velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entity.world.isClient && ticksInAir % 20 == 0 && entity.getVelocity().length() < 0.29) {
|
||||||
|
entity.playSound(getWingSound(), 0.5F, 1);
|
||||||
|
thrustScale = 1;
|
||||||
|
}
|
||||||
|
velocity.y -= 0.02;
|
||||||
} else {
|
} else {
|
||||||
ticksInAir = 0;
|
ticksInAir = 0;
|
||||||
|
|
||||||
|
if (!creative) {
|
||||||
|
|
||||||
|
double horMotion = getHorizontalMotion(entity);
|
||||||
|
double motion = entity.getPos().subtract(lastPos).lengthSquared();
|
||||||
|
|
||||||
|
if (velocity.y > 0 && (horMotion > 0.2 || (motion > 0.2 && velocity.y < -0.2))) {
|
||||||
|
entity.abilities.flying = true;
|
||||||
|
isFlyingEither = true;
|
||||||
|
isFlyingSurvival = true;
|
||||||
|
|
||||||
|
velocity.y += horMotion + 0.3;
|
||||||
|
applyThrust(entity, velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pony.getPhysics().isGravityNegative()) {
|
|
||||||
entity.setOnGround(!entity.world.isAir(new BlockPos(entity.getX(), entity.getY() + entity.getHeight() + 0.5F, entity.getZ())));
|
|
||||||
|
|
||||||
if (entity.isOnGround()) {
|
|
||||||
entity.abilities.flying = false;
|
|
||||||
isFlyingSurvival = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lastTickPosX = entity.getX();
|
lastPos = new Vec3d(entity.getX(), 0, entity.getZ());
|
||||||
lastTickPosZ = entity.getZ();
|
|
||||||
|
|
||||||
entity.setVelocity(velocity.toImmutable());
|
entity.setVelocity(velocity.toImmutable());
|
||||||
}
|
}
|
||||||
|
|
||||||
public SoundEvent getWingSound() {
|
private SoundEvent getWingSound() {
|
||||||
return pony.getSpecies() == Race.CHANGELING ? USounds.CHANGELING_BUZZ : USounds.WING_FLAP;
|
return pony.getSpecies() == Race.CHANGELING ? USounds.CHANGELING_BUZZ : USounds.WING_FLAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void moveFlying(Entity player, MutableVector velocity) {
|
protected void moveFlying(PlayerEntity player, MutableVector velocity) {
|
||||||
|
applyThrust(player, velocity);
|
||||||
|
|
||||||
float forward = 0.000015F * (1 + (pony.getLevel().get() / 10F)) * (float)Math.sqrt(getHorizontalMotion(player));
|
double motion = getHorizontalMotion(player);
|
||||||
boolean sneak = !player.isSneaking();
|
|
||||||
|
float forward = 0.000015F * (1 + (pony.getLevel().get() / 10F)) * (float)Math.sqrt(motion);
|
||||||
|
|
||||||
// vertical drop due to gravity
|
// vertical drop due to gravity
|
||||||
if (sneak) {
|
|
||||||
velocity.y -= (0.005F - getHorizontalMotion(player) / 100) * getGravitySignum();
|
|
||||||
} else {
|
|
||||||
forward += 0.005F;
|
forward += 0.005F;
|
||||||
velocity.y -= 0.0001F * getGravitySignum();
|
|
||||||
}
|
velocity.y -= (getGravityModifier() * 0.01F) / Math.max(motion * 100, 1);
|
||||||
|
|
||||||
velocity.x += - forward * MathHelper.sin(player.yaw * 0.017453292F);
|
velocity.x += - forward * MathHelper.sin(player.yaw * 0.017453292F);
|
||||||
velocity.z += forward * MathHelper.cos(player.yaw * 0.017453292F);
|
velocity.z += forward * MathHelper.cos(player.yaw * 0.017453292F);
|
||||||
|
}
|
||||||
|
|
||||||
if (player.world.hasRain(player.getBlockPos())) {
|
protected void applyThrust(PlayerEntity player, MutableVector velocity) {
|
||||||
|
if (pony.sneakingChanged() && player.isSneaking()) {
|
||||||
|
thrustScale = 1;
|
||||||
|
player.playSound(getWingSound(), 0.5F, 1);
|
||||||
|
} else {
|
||||||
|
thrustScale *= 0.1889F;
|
||||||
|
}
|
||||||
|
|
||||||
|
float thrustStrength = 0.135F * thrustScale;
|
||||||
|
Vec3d direction = player.getRotationVec(1).normalize().multiply(thrustStrength);
|
||||||
|
|
||||||
|
velocity.x += direction.x;
|
||||||
|
velocity.z += direction.z;
|
||||||
|
velocity.y += direction.y * 2.45 + Math.abs(direction.y) * 10;
|
||||||
|
|
||||||
|
if (player.isSneaking()) {
|
||||||
|
velocity.y += 0.4 - 0.25;
|
||||||
|
if (pony.sneakingChanged()) {
|
||||||
|
velocity.y += 0.75;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
velocity.y -= 0.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void applyTurbulance(Entity player, MutableVector velocity) {
|
||||||
float glance = 360 * player.world.random.nextFloat();
|
float glance = 360 * player.world.random.nextFloat();
|
||||||
|
float forward = 0.015F * player.world.random.nextFloat() * player.world.getRainGradient(1);
|
||||||
|
|
||||||
forward = 0.015F * player.world.random.nextFloat() * player.world.getRainGradient(1);
|
|
||||||
|
|
||||||
if (player.world.random.nextInt(30) == 0) {
|
if (player.world.random.nextInt(30) == 0) {
|
||||||
forward *= 10;
|
forward *= 10;
|
||||||
|
@ -203,25 +231,32 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
|
||||||
velocity.x += - forward * MathHelper.sin((player.yaw + glance) * 0.017453292F);
|
velocity.x += - forward * MathHelper.sin((player.yaw + glance) * 0.017453292F);
|
||||||
velocity.z += forward * MathHelper.cos((player.yaw + glance) * 0.017453292F);
|
velocity.z += forward * MathHelper.cos((player.yaw + glance) * 0.017453292F);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected double getHorizontalMotion(Entity e) {
|
protected double getHorizontalMotion(Entity e) {
|
||||||
double motionX = e.getX() - lastTickPosX;
|
return Entity.squaredHorizontalLength(e.getPos().subtract(lastPos));
|
||||||
double motionZ = e.getZ() - lastTickPosZ;
|
|
||||||
|
|
||||||
return (motionX * motionX) + (motionZ * motionZ);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SoundEvent getFallSound(int distance) {
|
private boolean checkCanFly() {
|
||||||
return distance > 4 ? SoundEvents.ENTITY_PLAYER_BIG_FALL : SoundEvents.ENTITY_PLAYER_SMALL_FALL;
|
if (pony.getOwner().abilities.creativeMode || pony.getOwner().isSpectator()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pony.hasSpell()) {
|
||||||
|
Spell effect = pony.getSpell(true);
|
||||||
|
if (!effect.isDead() && effect instanceof FlightPredicate) {
|
||||||
|
return ((FlightPredicate)effect).checkCanFly(pony);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pony.getSpecies().canFly();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateFlightStat(boolean flying) {
|
public void updateFlightStat(boolean flying) {
|
||||||
PlayerEntity entity = pony.getOwner();
|
PlayerEntity entity = pony.getOwner();
|
||||||
|
|
||||||
entity.abilities.allowFlying = checkCanFly();
|
boolean canFly = checkCanFly();
|
||||||
|
|
||||||
if (entity.abilities.allowFlying) {
|
if (canFly || entity.abilities.allowFlying) {
|
||||||
entity.abilities.flying |= flying;
|
entity.abilities.flying |= flying;
|
||||||
|
|
||||||
isFlyingSurvival = entity.abilities.flying;
|
isFlyingSurvival = entity.abilities.flying;
|
||||||
|
@ -248,9 +283,4 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
|
||||||
|
|
||||||
pony.getOwner().calculateDimensions();
|
pony.getOwner().calculateDimensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isFlying() {
|
|
||||||
return isFlyingSurvival;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue