mirror of
https://github.com/MineLittlePony/MineLittlePony.git
synced 2024-11-26 22:38:00 +01:00
Implement proper tweening for certain animations
This commit is contained in:
parent
845f3536ad
commit
2a32b74b5b
10 changed files with 114 additions and 31 deletions
|
@ -224,6 +224,8 @@ public abstract class AbstractPonyModel extends ModelPlayer implements IModel {
|
||||||
|
|
||||||
float legRPX = cos - getLegOutset();
|
float legRPX = cos - getLegOutset();
|
||||||
|
|
||||||
|
legRPX = metadata.getInterpolator().interpolate("legOffset", legRPX, 3);
|
||||||
|
|
||||||
bipedRightArm.rotationPointX = -legRPX;
|
bipedRightArm.rotationPointX = -legRPX;
|
||||||
bipedRightLeg.rotationPointX = -legRPX;
|
bipedRightLeg.rotationPointX = -legRPX;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package com.minelittlepony.model.anim;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class BasicEasingInterpolator implements IInterpolator {
|
||||||
|
|
||||||
|
private final Map<String, Float> properties = new HashMap<String, Float>();
|
||||||
|
|
||||||
|
private float getLast(String key, float to) {
|
||||||
|
if (properties.containsKey(key)) {
|
||||||
|
return properties.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float interpolate(String key, float to, float scalingFactor) {
|
||||||
|
float from = getLast(key, to);
|
||||||
|
|
||||||
|
from += (to - from) / scalingFactor;
|
||||||
|
|
||||||
|
properties.put(key, from);
|
||||||
|
|
||||||
|
return from;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.minelittlepony.model.anim;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interpolator function for handling transitions between animation states.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface IInterpolator {
|
||||||
|
/**
|
||||||
|
* Interpolates a value between the requested final destination and what it was last.
|
||||||
|
*
|
||||||
|
* @param key Identifier to track previous values
|
||||||
|
* @param to The new values
|
||||||
|
* @param scalingFactor Scaling factor to control how quickly values change
|
||||||
|
*/
|
||||||
|
float interpolate(String key, float to, float scalingFactor);
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
@MethodsReturnNonnullByDefault
|
||||||
|
@ParametersAreNonnullByDefault
|
||||||
|
package com.minelittlepony.model.anim;
|
||||||
|
|
||||||
|
import mcp.MethodsReturnNonnullByDefault;
|
||||||
|
|
||||||
|
import javax.annotation.ParametersAreNonnullByDefault;
|
|
@ -61,15 +61,22 @@ public class PegasusWings<T extends AbstractPonyModel & IModelPegasus> implement
|
||||||
getLeft().rotateWalking(flap);
|
getLeft().rotateWalking(flap);
|
||||||
getRight().rotateWalking(-flap);
|
getRight().rotateWalking(-flap);
|
||||||
|
|
||||||
|
float flapAngle = ROTATE_270;
|
||||||
|
|
||||||
if (pegasus.wingsAreOpen()) {
|
if (pegasus.wingsAreOpen()) {
|
||||||
float flapAngle = pegasus.getWingRotationFactor(ticks);
|
flapAngle = pegasus.getWingRotationFactor(ticks);
|
||||||
if (!pegasus.isCrouching() && pegasus.isWearing(PonyWearable.SADDLE_BAGS)) {
|
if (!pegasus.isCrouching() && pegasus.isWearing(PonyWearable.SADDLE_BAGS)) {
|
||||||
flapAngle -= 1F;
|
flapAngle -= 1F;
|
||||||
}
|
}
|
||||||
getLeft().rotateFlying(flapAngle);
|
|
||||||
getRight().rotateFlying(-flapAngle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pegasus.isFlying()) {
|
||||||
|
flapAngle = pegasus.getMetadata().getInterpolator().interpolate("wingFlap", flapAngle, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLeft().rotateFlying(flapAngle);
|
||||||
|
getRight().rotateFlying(-flapAngle);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -19,7 +19,7 @@ public class PonyElytra extends ModelBase {
|
||||||
private PonyRenderer leftWing = new PonyRenderer(this, 22, 0);
|
private PonyRenderer leftWing = new PonyRenderer(this, 22, 0);
|
||||||
|
|
||||||
public PonyElytra() {
|
public PonyElytra() {
|
||||||
leftWing .box(-10, 0, 0, 10, 20, 2, 1);
|
leftWing .box(-10, 0, 0, 10, 20, 2, 1);
|
||||||
rightWing.flip().box( 0, 0, 0, 10, 20, 2, 1);
|
rightWing.flip().box( 0, 0, 0, 10, 20, 2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package com.minelittlepony.pony.data;
|
package com.minelittlepony.pony.data;
|
||||||
|
|
||||||
|
import com.minelittlepony.model.anim.IInterpolator;
|
||||||
|
|
||||||
import net.minecraft.client.resources.data.IMetadataSection;
|
import net.minecraft.client.resources.data.IMetadataSection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,5 +38,13 @@ public interface IPonyData extends IMetadataSection {
|
||||||
*/
|
*/
|
||||||
boolean hasMagic();
|
boolean hasMagic();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks it this pony is wearing the given accessory.
|
||||||
|
*/
|
||||||
boolean isWearing(PonyWearable wearable);
|
boolean isWearing(PonyWearable wearable);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets an interpolator for interpolating values.
|
||||||
|
*/
|
||||||
|
IInterpolator getInterpolator();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package com.minelittlepony.pony.data;
|
||||||
|
|
||||||
import com.google.common.base.MoreObjects;
|
import com.google.common.base.MoreObjects;
|
||||||
import com.minelittlepony.MineLittlePony;
|
import com.minelittlepony.MineLittlePony;
|
||||||
|
import com.minelittlepony.model.anim.BasicEasingInterpolator;
|
||||||
|
import com.minelittlepony.model.anim.IInterpolator;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import javax.annotation.concurrent.Immutable;
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
@ -21,6 +23,8 @@ public class PonyData implements IPonyData {
|
||||||
|
|
||||||
private final boolean[] wearables;
|
private final boolean[] wearables;
|
||||||
|
|
||||||
|
private final IInterpolator interpolator = new BasicEasingInterpolator();
|
||||||
|
|
||||||
public PonyData() {
|
public PonyData() {
|
||||||
race = PonyRace.HUMAN;
|
race = PonyRace.HUMAN;
|
||||||
tailSize = TailLengths.FULL;
|
tailSize = TailLengths.FULL;
|
||||||
|
@ -43,7 +47,7 @@ public class PonyData implements IPonyData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PonyRace getRace() {
|
public PonyRace getRace() {
|
||||||
return race;
|
return race.isHuman() ? race : PonyRace.PEGASUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -73,7 +77,7 @@ public class PonyData implements IPonyData {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isWearing(PonyWearable wearable) {
|
public boolean isWearing(PonyWearable wearable) {
|
||||||
return wearables[wearable.ordinal()];
|
return true;//wearables[wearable.ordinal()];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -88,6 +92,11 @@ public class PonyData implements IPonyData {
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IInterpolator getInterpolator() {
|
||||||
|
return interpolator;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses an image buffer into a new IPonyData representing the values stored in it's individual trigger pixels.
|
* Parses an image buffer into a new IPonyData representing the values stored in it's individual trigger pixels.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -30,11 +30,22 @@ public class RenderPonyPlayer extends RenderPonyBase {
|
||||||
GlStateManager.translate(0, player.isSneaking() ? 0.2F : -1, 0);
|
GlStateManager.translate(0, player.isSneaking() ? 0.2F : -1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float sensibleAngle(float angle) {
|
private double calculateRoll(AbstractClientPlayer player, double motionX, double motionY, double motionZ) {
|
||||||
angle %= 360; // if you need to copy-paste a portion of code more than 2 times - make a function
|
|
||||||
if (angle > 180) angle -= 360;
|
// since model roll should probably be calculated from model rotation rather than entity rotation...
|
||||||
if (angle < -180) angle += 360;
|
double roll = MathUtil.sensibleAngle(player.prevRenderYawOffset - player.renderYawOffset);
|
||||||
return angle;
|
double horMotion = Math.sqrt(motionX * motionX + motionZ * motionZ);
|
||||||
|
float modelYaw = MathUtil.sensibleAngle(player.renderYawOffset);
|
||||||
|
|
||||||
|
// detecting that we're flying backwards and roll must be inverted
|
||||||
|
if (Math.abs(MathUtil.sensibleAngle((float) Math.toDegrees(Math.atan2(motionX, motionZ)) + modelYaw)) > 90) {
|
||||||
|
roll *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ayyy magic numbers (after 5 - an approximation of nice looking coefficients calculated by hand)
|
||||||
|
roll *= horMotion * 5 * (3.6884f * Math.pow(Math.abs(roll), -0.191));
|
||||||
|
|
||||||
|
return MathHelper.clamp(roll, -54, 54);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -56,27 +67,9 @@ public class RenderPonyPlayer extends RenderPonyBase {
|
||||||
|
|
||||||
GlStateManager.rotate(ponyModel.motionPitch, 1, 0, 0);
|
GlStateManager.rotate(ponyModel.motionPitch, 1, 0, 0);
|
||||||
|
|
||||||
double horMotion = Math.sqrt(motionX * motionX + motionZ * motionZ);
|
float roll = getPony().getMetadata().getInterpolator().interpolate("pegasusRoll", (float)calculateRoll(player, motionX, motionY, motionZ), 10);
|
||||||
|
|
||||||
if (horMotion > 0) {
|
GlStateManager.rotate((float)roll, 0, 0, 1);
|
||||||
yaw = sensibleAngle(player.cameraYaw - player.rotationYawHead); // will need later
|
|
||||||
// since model roll should probably be calculated from model rotation rather than entity rotation...
|
|
||||||
double roll = sensibleAngle(player.prevRenderYawOffset - player.renderYawOffset);
|
|
||||||
float modelYaw = sensibleAngle(player.renderYawOffset);
|
|
||||||
// filtering ugly jitter that occurs in Vanilla code if motion changes from sideways to diagonal
|
|
||||||
if (Math.abs(roll) > 0.5f && Math.abs(sensibleAngle(modelYaw + yaw)) > 40) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// detecting that we're flying backwards and roll must be inverted
|
|
||||||
if (Math.abs(sensibleAngle((float) Math.toDegrees(Math.atan2(motionX, motionZ)) + modelYaw)) > 90) {
|
|
||||||
roll *= -1; // because inline ifs are not in favor
|
|
||||||
}
|
|
||||||
// ayyy magic numbers (after 5 - an approximation of nice looking coefficients calculated by hand)
|
|
||||||
roll *= horMotion * 5 * (3.6884f * Math.pow(Math.abs(roll), -0.191));
|
|
||||||
roll = MathHelper.clamp(roll, -54, 54); // safety measure, shouldn't be required anymore
|
|
||||||
|
|
||||||
GlStateManager.rotate((float)roll, 0, 0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,4 +7,13 @@ public class MathUtil {
|
||||||
public static double clampLimit(double num, double limit) {
|
public static double clampLimit(double num, double limit) {
|
||||||
return MathHelper.clamp(num, -limit, limit);
|
return MathHelper.clamp(num, -limit, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float sensibleAngle(float angle) {
|
||||||
|
angle %= 360;
|
||||||
|
|
||||||
|
if (angle > 180) angle -= 360;
|
||||||
|
if (angle < -180) angle += 360;
|
||||||
|
|
||||||
|
return angle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue