mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-23 21:38: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);
|
||||
}
|
||||
|
||||
return getPredicate().flatMap(e -> e.getTargetDimensions(pony)).orElseGet(() -> {
|
||||
if (physics.isFlyingSurvival && physics.isRainboom()) {
|
||||
return flyingDimensions;
|
||||
}
|
||||
|
||||
return defaultDimensions;
|
||||
});
|
||||
return getPredicate()
|
||||
.flatMap(e -> e.getTargetDimensions(pony))
|
||||
.orElseGet(() -> physics.isFlyingSurvival ? flyingDimensions : defaultDimensions);
|
||||
}
|
||||
|
||||
private float calculateTargetEyeHeight() {
|
||||
|
@ -65,10 +61,6 @@ public final class PlayerDimensions {
|
|||
return height;
|
||||
}
|
||||
|
||||
if (physics.isFlyingSurvival && physics.isRainboom()) {
|
||||
return 0.5F;
|
||||
}
|
||||
|
||||
return defaultEyeHeight;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,20 +15,21 @@ import net.minecraft.entity.player.PlayerEntity;
|
|||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.sound.SoundCategory;
|
||||
import net.minecraft.sound.SoundEvent;
|
||||
import net.minecraft.sound.SoundEvents;
|
||||
import net.minecraft.util.Tickable;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Motion, NbtSerialisable {
|
||||
|
||||
private int ticksInAir;
|
||||
|
||||
private float thrustScale = 0;
|
||||
|
||||
public boolean isFlyingEither = false;
|
||||
public boolean isFlyingSurvival = false;
|
||||
|
||||
private double lastTickPosX = 0;
|
||||
private double lastTickPosZ = 0;
|
||||
private Vec3d lastPos = Vec3d.ZERO;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
public PlayerDimensions getDimensions() {
|
||||
return dimensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlying() {
|
||||
return isFlyingSurvival && !pony.getOwner().isFallFlying() && !pony.getOwner().hasVehicle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
PlayerEntity entity = pony.getOwner();
|
||||
|
@ -83,32 +70,37 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
|
|||
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();
|
||||
|
||||
entity.abilities.allowFlying = checkCanFly();
|
||||
boolean canFly = checkCanFly();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
isFlyingSurvival = entity.abilities.flying && !creative;
|
||||
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;
|
||||
|
||||
if (ticksInAir > (level * 100)) {
|
||||
if (ticksInAir++ > (level * 100)) {
|
||||
Bar mana = pony.getMagicalReserves().getMana();
|
||||
|
||||
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) {
|
||||
entity.playSound(getWingSound(), 0.5F, 1);
|
||||
moveFlying(entity, velocity);
|
||||
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 {
|
||||
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();
|
||||
lastTickPosZ = entity.getZ();
|
||||
lastPos = new Vec3d(entity.getX(), 0, entity.getZ());
|
||||
|
||||
entity.setVelocity(velocity.toImmutable());
|
||||
}
|
||||
|
||||
public SoundEvent getWingSound() {
|
||||
private SoundEvent getWingSound() {
|
||||
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));
|
||||
boolean sneak = !player.isSneaking();
|
||||
double motion = getHorizontalMotion(player);
|
||||
|
||||
float forward = 0.000015F * (1 + (pony.getLevel().get() / 10F)) * (float)Math.sqrt(motion);
|
||||
|
||||
// vertical drop due to gravity
|
||||
if (sneak) {
|
||||
velocity.y -= (0.005F - getHorizontalMotion(player) / 100) * getGravitySignum();
|
||||
} else {
|
||||
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.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();
|
||||
|
||||
|
||||
forward = 0.015F * player.world.random.nextFloat() * player.world.getRainGradient(1);
|
||||
float forward = 0.015F * player.world.random.nextFloat() * player.world.getRainGradient(1);
|
||||
|
||||
if (player.world.random.nextInt(30) == 0) {
|
||||
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.z += forward * MathHelper.cos((player.yaw + glance) * 0.017453292F);
|
||||
}
|
||||
}
|
||||
|
||||
protected double getHorizontalMotion(Entity e) {
|
||||
double motionX = e.getX() - lastTickPosX;
|
||||
double motionZ = e.getZ() - lastTickPosZ;
|
||||
|
||||
return (motionX * motionX) + (motionZ * motionZ);
|
||||
return Entity.squaredHorizontalLength(e.getPos().subtract(lastPos));
|
||||
}
|
||||
|
||||
protected SoundEvent getFallSound(int distance) {
|
||||
return distance > 4 ? SoundEvents.ENTITY_PLAYER_BIG_FALL : SoundEvents.ENTITY_PLAYER_SMALL_FALL;
|
||||
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();
|
||||
}
|
||||
|
||||
public void updateFlightStat(boolean flying) {
|
||||
PlayerEntity entity = pony.getOwner();
|
||||
|
||||
entity.abilities.allowFlying = checkCanFly();
|
||||
boolean canFly = checkCanFly();
|
||||
|
||||
if (entity.abilities.allowFlying) {
|
||||
if (canFly || entity.abilities.allowFlying) {
|
||||
entity.abilities.flying |= flying;
|
||||
|
||||
isFlyingSurvival = entity.abilities.flying;
|
||||
|
@ -248,9 +283,4 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
|
|||
|
||||
pony.getOwner().calculateDimensions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFlying() {
|
||||
return isFlyingSurvival;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue