Added human player model
- Extracted NPedModel out of QuadripedModel - Both are now configurable - Added HumanoidModel - Added human model - Changed NPedModel animation logic - Added a few skins including first sketch of Pyotr by WarDreg - Decreased walking speed
This commit is contained in:
parent
38a8a885c8
commit
f2e28161a8
@ -122,4 +122,13 @@ public class LambdaModel extends DynamicModel {
|
||||
|
||||
}
|
||||
|
||||
public static LambdaModel animate(Renderable model, TransformGetter transform) {
|
||||
return new LambdaModel(
|
||||
new Renderable[] { model },
|
||||
new Mat4[] { new Mat4() },
|
||||
new boolean[] { true },
|
||||
new TransformGetter[] { transform }
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,10 +19,10 @@ public class ComplexTexture {
|
||||
this.primitive = primitive;
|
||||
|
||||
this.assumedWidth = abstractWidth
|
||||
* primitive.getWidth() / (float) primitive.getBufferWidth();
|
||||
/ (float) primitive.getWidth() * primitive.getBufferWidth();
|
||||
|
||||
this.assumedHeight = abstractHeight
|
||||
* primitive.getHeight() / (float) primitive.getBufferHeight();
|
||||
/ (float) primitive.getHeight() * primitive.getBufferHeight();
|
||||
}
|
||||
|
||||
public Texture get(int x, int y, int width, int height) {
|
||||
|
@ -0,0 +1,116 @@
|
||||
package ru.windcorp.progressia.client.world.entity;
|
||||
|
||||
import static java.lang.Math.*;
|
||||
import static ru.windcorp.progressia.common.util.FloatMathUtils.*;
|
||||
|
||||
import glm.mat._4.Mat4;
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class HumanoidModel extends NPedModel {
|
||||
|
||||
protected static abstract class Limb extends BodyPart {
|
||||
private final float animationOffset;
|
||||
|
||||
public Limb(
|
||||
Renderable renderable, Vec3 joint,
|
||||
float animationOffset
|
||||
) {
|
||||
super(renderable, joint);
|
||||
this.animationOffset = animationOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransform(Mat4 mat, NPedModel model) {
|
||||
float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset;
|
||||
float value = sin(phase);
|
||||
float amplitude = getSwingAmplitude((HumanoidModel) model) * model.getVelocityParameter();
|
||||
mat.rotateY(value * amplitude);
|
||||
}
|
||||
|
||||
protected abstract float getSwingAmplitude(HumanoidModel model);
|
||||
|
||||
}
|
||||
|
||||
public static class Leg extends Limb {
|
||||
public Leg(
|
||||
Renderable renderable, Vec3 joint,
|
||||
float animationOffset
|
||||
) {
|
||||
super(renderable, joint, animationOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getSwingAmplitude(HumanoidModel model) {
|
||||
return model.walkingLegSwing;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Arm extends Limb {
|
||||
public Arm(
|
||||
Renderable renderable, Vec3 joint,
|
||||
float animationOffset
|
||||
) {
|
||||
super(renderable, joint, animationOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float getSwingAmplitude(HumanoidModel model) {
|
||||
return model.walkingArmSwing;
|
||||
}
|
||||
}
|
||||
|
||||
private final Arm leftArm;
|
||||
private final Arm rightArm;
|
||||
private final Leg leftLeg;
|
||||
private final Leg rightLeg;
|
||||
|
||||
private float walkingLegSwing;
|
||||
private float walkingArmSwing;
|
||||
|
||||
public HumanoidModel(
|
||||
EntityData entity,
|
||||
|
||||
Body body, Head head,
|
||||
Arm leftArm, Arm rightArm,
|
||||
Leg leftLeg, Leg rightLeg,
|
||||
|
||||
float scale
|
||||
) {
|
||||
super(entity, body, head, scale);
|
||||
this.leftArm = leftArm;
|
||||
this.rightArm = rightArm;
|
||||
this.leftLeg = leftLeg;
|
||||
this.rightLeg = rightLeg;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderBodyParts(ShapeRenderHelper renderer) {
|
||||
super.renderBodyParts(renderer);
|
||||
leftArm.render(renderer, this);
|
||||
rightArm.render(renderer, this);
|
||||
leftLeg.render(renderer, this);
|
||||
rightLeg.render(renderer, this);
|
||||
}
|
||||
|
||||
public float getWalkingArmSwing() {
|
||||
return walkingArmSwing;
|
||||
}
|
||||
|
||||
public float getWalkingLegSwing() {
|
||||
return walkingLegSwing;
|
||||
}
|
||||
|
||||
public HumanoidModel setWalkingLegSwing(float walkingLegSwing) {
|
||||
this.walkingLegSwing = walkingLegSwing;
|
||||
return this;
|
||||
}
|
||||
|
||||
public HumanoidModel setWalkingArmSwing(float walkingArmSwing) {
|
||||
this.walkingArmSwing = walkingArmSwing;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,284 @@
|
||||
package ru.windcorp.progressia.client.world.entity;
|
||||
|
||||
import static java.lang.Math.atan2;
|
||||
import static java.lang.Math.min;
|
||||
import static java.lang.Math.pow;
|
||||
import static java.lang.Math.toRadians;
|
||||
import static ru.windcorp.progressia.common.util.FloatMathUtils.normalizeAngle;
|
||||
|
||||
import glm.Glm;
|
||||
import glm.mat._4.Mat4;
|
||||
import glm.vec._3.Vec3;
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||
import ru.windcorp.progressia.common.Units;
|
||||
import ru.windcorp.progressia.common.util.Matrices;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public abstract class NPedModel extends EntityRenderable {
|
||||
|
||||
protected static abstract class BodyPart {
|
||||
private final Renderable renderable;
|
||||
private final Vec3 translation = new Vec3();
|
||||
|
||||
public BodyPart(Renderable renderable, Vec3 joint) {
|
||||
this.renderable = renderable;
|
||||
if (joint != null) {
|
||||
this.translation.set(joint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void render(
|
||||
ShapeRenderHelper renderer, NPedModel model
|
||||
) {
|
||||
renderer.pushTransform().translate(translation);
|
||||
applyTransform(renderer.pushTransform(), model);
|
||||
renderable.render(renderer);
|
||||
renderer.popTransform();
|
||||
renderer.popTransform();
|
||||
}
|
||||
|
||||
protected abstract void applyTransform(Mat4 mat, NPedModel model);
|
||||
|
||||
public Vec3 getTranslation() {
|
||||
return translation;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Body extends BodyPart {
|
||||
public Body(Renderable renderable) {
|
||||
super(renderable, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransform(Mat4 mat, NPedModel model) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
public static class Head extends BodyPart {
|
||||
private final float maxYaw;
|
||||
private final float maxPitch;
|
||||
|
||||
private final Vec3 viewPoint;
|
||||
|
||||
public Head(
|
||||
Renderable renderable, Vec3 joint,
|
||||
double maxYawDegrees, double maxPitchDegrees,
|
||||
Vec3 viewPoint
|
||||
) {
|
||||
super(renderable, joint);
|
||||
this.maxYaw = (float) toRadians(maxYawDegrees);
|
||||
this.maxPitch = (float) toRadians(maxPitchDegrees);
|
||||
this.viewPoint = viewPoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransform(Mat4 mat, NPedModel model) {
|
||||
mat.rotateZ(model.getHeadYaw()).rotateY(model.getHeadPitch());
|
||||
}
|
||||
|
||||
public Vec3 getViewPoint() {
|
||||
return viewPoint;
|
||||
}
|
||||
}
|
||||
|
||||
protected final Body body;
|
||||
protected final Head head;
|
||||
|
||||
private float walkingParameter = 0;
|
||||
private float velocityParameter = 0;
|
||||
private float velocity = 0;
|
||||
|
||||
/**
|
||||
* If {@link #velocity} is greater than this value, {@link #velocityParameter} is 1.0.
|
||||
*/
|
||||
private float maxEffectiveVelocity = 5 * Units.METERS_PER_SECOND;
|
||||
|
||||
/**
|
||||
* If {@link #velocity} is less than {@link #maxEffectiveVelocity}, then
|
||||
* {@code velocityCoeff = exp(velocity / maxEffectiveVelocity, velocityCoeffPower)}.
|
||||
*/
|
||||
private float velocityCoeffPower = 1;
|
||||
|
||||
private final float scale;
|
||||
|
||||
private float walkingFrequency;
|
||||
|
||||
private float bodyYaw = Float.NaN;
|
||||
private float headYaw;
|
||||
private float headPitch;
|
||||
|
||||
public NPedModel(EntityData data, Body body, Head head, float scale) {
|
||||
super(data);
|
||||
this.body = body;
|
||||
this.head = head;
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(ShapeRenderHelper renderer) {
|
||||
renderer.pushTransform().scale(scale).rotateZ(bodyYaw);
|
||||
renderBodyParts(renderer);
|
||||
renderer.popTransform();
|
||||
|
||||
accountForVelocity();
|
||||
evaluateAngles();
|
||||
}
|
||||
|
||||
protected void renderBodyParts(ShapeRenderHelper renderer) {
|
||||
body.render(renderer, this);
|
||||
head.render(renderer, this);
|
||||
}
|
||||
|
||||
private void evaluateAngles() {
|
||||
float globalYaw = normalizeAngle(getData().getYaw());
|
||||
|
||||
if (Float.isNaN(bodyYaw)) {
|
||||
bodyYaw = globalYaw;
|
||||
headYaw = 0;
|
||||
} else {
|
||||
headYaw = normalizeAngle(globalYaw - bodyYaw);
|
||||
|
||||
if (headYaw > +head.maxYaw) {
|
||||
bodyYaw += headYaw - +head.maxYaw;
|
||||
headYaw = +head.maxYaw;
|
||||
} else if (headYaw < -head.maxYaw) {
|
||||
bodyYaw += headYaw - -head.maxYaw;
|
||||
headYaw = -head.maxYaw;
|
||||
}
|
||||
}
|
||||
|
||||
bodyYaw = normalizeAngle(bodyYaw);
|
||||
|
||||
headPitch = Glm.clamp(
|
||||
getData().getPitch(),
|
||||
-head.maxPitch, head.maxPitch
|
||||
);
|
||||
}
|
||||
|
||||
private void accountForVelocity() {
|
||||
Vec3 horizontal = Vectors.grab3();
|
||||
horizontal.set(getData().getVelocity());
|
||||
horizontal.z = 0;
|
||||
|
||||
velocity = horizontal.length();
|
||||
|
||||
evaluateVelocityCoeff();
|
||||
|
||||
// TODO switch to world time
|
||||
walkingParameter += velocity * GraphicsInterface.getFrameLength() * 1000;
|
||||
|
||||
bodyYaw += velocityParameter * normalizeAngle(
|
||||
(float) (atan2(horizontal.y, horizontal.x) - bodyYaw)
|
||||
) * min(1, GraphicsInterface.getFrameLength() * 10);
|
||||
Vectors.release(horizontal);
|
||||
}
|
||||
|
||||
private void evaluateVelocityCoeff() {
|
||||
if (velocity > maxEffectiveVelocity) {
|
||||
velocityParameter = 1;
|
||||
} else {
|
||||
velocityParameter = (float) pow(velocity / maxEffectiveVelocity, velocityCoeffPower);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getViewPoint(Vec3 output) {
|
||||
Mat4 m = Matrices.grab4();
|
||||
Vec4 v = Vectors.grab4();
|
||||
|
||||
m.identity()
|
||||
.scale(scale)
|
||||
.rotateZ(bodyYaw)
|
||||
.translate(head.getTranslation())
|
||||
.rotateZ(headYaw)
|
||||
.rotateY(headPitch);
|
||||
|
||||
v.set(head.getViewPoint(), 1);
|
||||
m.mul(v);
|
||||
|
||||
output.set(v.x, v.y, v.z);
|
||||
|
||||
Vectors.release(v);
|
||||
Matrices.release(m);
|
||||
}
|
||||
|
||||
public Body getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public Head getHead() {
|
||||
return head;
|
||||
}
|
||||
|
||||
public float getBodyYaw() {
|
||||
return bodyYaw;
|
||||
}
|
||||
|
||||
public float getHeadYaw() {
|
||||
return headYaw;
|
||||
}
|
||||
|
||||
public float getHeadPitch() {
|
||||
return headPitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a number in the range [0; 1] that can be used to scale animation effects that depend on speed.
|
||||
* This parameter is 0 when the entity is not moving and 1 when it's moving "fast".
|
||||
* @return velocity parameter
|
||||
*/
|
||||
protected float getVelocityParameter() {
|
||||
return velocityParameter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a number that can be used to parameterize animation effects that depend on walking.
|
||||
* This parameter increases when the entity moves (e.g. this can be total traveled distance).
|
||||
* @return walking parameter
|
||||
*/
|
||||
protected float getWalkingParameter() {
|
||||
return walkingParameter;
|
||||
}
|
||||
|
||||
protected float getVelocity() {
|
||||
return velocity;
|
||||
}
|
||||
|
||||
public float getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
protected float getWalkingFrequency() {
|
||||
return walkingFrequency;
|
||||
}
|
||||
|
||||
public NPedModel setWalkingFrequency(float walkingFrequency) {
|
||||
this.walkingFrequency = walkingFrequency;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getMaxEffectiveVelocity() {
|
||||
return maxEffectiveVelocity;
|
||||
}
|
||||
|
||||
public float getVelocityCoeffPower() {
|
||||
return velocityCoeffPower;
|
||||
}
|
||||
|
||||
public NPedModel setMaxEffectiveVelocity(float maxEffectiveVelocity) {
|
||||
this.maxEffectiveVelocity = maxEffectiveVelocity;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NPedModel setVelocityCoeffPower(float velocityCoeffPower) {
|
||||
this.velocityCoeffPower = velocityCoeffPower;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@ -2,86 +2,15 @@ package ru.windcorp.progressia.client.world.entity;
|
||||
|
||||
import static java.lang.Math.*;
|
||||
import static ru.windcorp.progressia.common.util.FloatMathUtils.*;
|
||||
import static ru.windcorp.progressia.common.util.FloatMathUtils.sin;
|
||||
|
||||
import glm.Glm;
|
||||
import glm.mat._4.Mat4;
|
||||
import glm.vec._3.Vec3;
|
||||
import glm.vec._4.Vec4;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||
import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
|
||||
import ru.windcorp.progressia.common.util.Matrices;
|
||||
import ru.windcorp.progressia.common.util.Vectors;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
public class QuadripedModel extends EntityRenderable {
|
||||
|
||||
private static abstract class BodyPart {
|
||||
private final Renderable renderable;
|
||||
private final Vec3 translation = new Vec3();
|
||||
|
||||
public BodyPart(Renderable renderable, Vec3 joint) {
|
||||
this.renderable = renderable;
|
||||
if (joint != null) {
|
||||
this.translation.set(joint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void render(
|
||||
ShapeRenderHelper renderer, QuadripedModel model
|
||||
) {
|
||||
renderer.pushTransform().translate(translation);
|
||||
applyTransform(renderer.pushTransform(), model);
|
||||
renderable.render(renderer);
|
||||
renderer.popTransform();
|
||||
renderer.popTransform();
|
||||
}
|
||||
|
||||
protected abstract void applyTransform(Mat4 mat, QuadripedModel model);
|
||||
|
||||
public Vec3 getTranslation() {
|
||||
return translation;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Body extends BodyPart {
|
||||
public Body(Renderable renderable) {
|
||||
super(renderable, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransform(Mat4 mat, QuadripedModel model) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
public static class Head extends BodyPart {
|
||||
private final float maxYaw;
|
||||
private final float maxPitch;
|
||||
|
||||
private final Vec3 viewPoint;
|
||||
|
||||
public Head(
|
||||
Renderable renderable, Vec3 joint,
|
||||
double maxYawDegrees, double maxPitchDegrees,
|
||||
Vec3 viewPoint
|
||||
) {
|
||||
super(renderable, joint);
|
||||
this.maxYaw = (float) toRadians(maxYawDegrees);
|
||||
this.maxPitch = (float) toRadians(maxPitchDegrees);
|
||||
this.viewPoint = viewPoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransform(Mat4 mat, QuadripedModel model) {
|
||||
mat.rotateZ(model.headYaw).rotateY(model.headPitch);
|
||||
}
|
||||
|
||||
public Vec3 getViewPoint() {
|
||||
return viewPoint;
|
||||
}
|
||||
}
|
||||
public class QuadripedModel extends NPedModel {
|
||||
|
||||
public static class Leg extends BodyPart {
|
||||
private final float animationOffset;
|
||||
@ -95,34 +24,20 @@ public class QuadripedModel extends EntityRenderable {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransform(Mat4 mat, QuadripedModel model) {
|
||||
mat.rotateY(sin(model.walkingFrequency * model.walkingAnimationParameter + animationOffset) * model.walkingSwing * model.velocityCoeff);
|
||||
}
|
||||
protected void applyTransform(Mat4 mat, NPedModel model) {
|
||||
float phase = model.getWalkingFrequency() * model.getWalkingParameter() + animationOffset;
|
||||
float value = sin(phase);
|
||||
float amplitude = ((QuadripedModel) model).getWalkingSwing() * model.getVelocityParameter();
|
||||
mat.rotateY(value * amplitude);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final Body body;
|
||||
private final Head head;
|
||||
private final Leg leftForeLeg, rightForeLeg;
|
||||
private final Leg leftHindLeg, rightHindLeg;
|
||||
|
||||
private final float scale;
|
||||
|
||||
private float walkingAnimationParameter = 0;
|
||||
private float velocityCoeff = 0;
|
||||
private float velocity = 0;
|
||||
|
||||
/**
|
||||
* Controls how quickly velocityCoeff approaches 1
|
||||
*/
|
||||
private float velocityCutoff = 10;
|
||||
|
||||
private float walkingFrequency = 0.15f / 60.0f;
|
||||
private float walkingSwing = (float) toRadians(30);
|
||||
|
||||
private float bodyYaw = Float.NaN;
|
||||
private float headYaw;
|
||||
private float headPitch;
|
||||
|
||||
public QuadripedModel(
|
||||
EntityData entity,
|
||||
|
||||
@ -132,105 +47,30 @@ public class QuadripedModel extends EntityRenderable {
|
||||
|
||||
float scale
|
||||
) {
|
||||
super(entity);
|
||||
super(entity, body, head, scale);
|
||||
|
||||
this.body = body;
|
||||
this.head = head;
|
||||
this.leftForeLeg = leftForeLeg;
|
||||
this.rightForeLeg = rightForeLeg;
|
||||
this.leftHindLeg = leftHindLeg;
|
||||
this.rightHindLeg = rightHindLeg;
|
||||
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(ShapeRenderHelper renderer) {
|
||||
renderer.pushTransform().scale(scale).rotateZ(bodyYaw);
|
||||
body.render(renderer, this);
|
||||
head.render(renderer, this);
|
||||
leftForeLeg.render(renderer, this);
|
||||
rightForeLeg.render(renderer, this);
|
||||
leftHindLeg.render(renderer, this);
|
||||
rightHindLeg.render(renderer, this);
|
||||
renderer.popTransform();
|
||||
|
||||
accountForVelocity();
|
||||
evaluateAngles();
|
||||
protected void renderBodyParts(ShapeRenderHelper renderer) {
|
||||
super.renderBodyParts(renderer);
|
||||
this.leftForeLeg.render(renderer, this);
|
||||
this.rightForeLeg.render(renderer, this);
|
||||
this.leftHindLeg.render(renderer, this);
|
||||
this.rightHindLeg.render(renderer, this);
|
||||
}
|
||||
|
||||
private void evaluateAngles() {
|
||||
float globalYaw = normalizeAngle(getData().getYaw());
|
||||
|
||||
if (Float.isNaN(bodyYaw)) {
|
||||
bodyYaw = globalYaw;
|
||||
headYaw = 0;
|
||||
} else {
|
||||
headYaw = normalizeAngle(globalYaw - bodyYaw);
|
||||
|
||||
if (headYaw > +head.maxYaw) {
|
||||
bodyYaw += headYaw - +head.maxYaw;
|
||||
headYaw = +head.maxYaw;
|
||||
} else if (headYaw < -head.maxYaw) {
|
||||
bodyYaw += headYaw - -head.maxYaw;
|
||||
headYaw = -head.maxYaw;
|
||||
}
|
||||
public float getWalkingSwing() {
|
||||
return walkingSwing;
|
||||
}
|
||||
|
||||
bodyYaw = normalizeAngle(bodyYaw);
|
||||
|
||||
headPitch = Glm.clamp(
|
||||
getData().getPitch(),
|
||||
-head.maxPitch, head.maxPitch
|
||||
);
|
||||
}
|
||||
|
||||
private void accountForVelocity() {
|
||||
Vec3 horizontal = Vectors.grab3();
|
||||
horizontal.set(getData().getVelocity());
|
||||
horizontal.z = 0;
|
||||
|
||||
velocity = horizontal.length();
|
||||
|
||||
evaluateVelocityCoeff();
|
||||
|
||||
// TODO switch to world time
|
||||
walkingAnimationParameter += velocity * GraphicsInterface.getFrameLength() * 1000;
|
||||
|
||||
bodyYaw += velocityCoeff * normalizeAngle(
|
||||
(float) (atan2(horizontal.y, horizontal.x) - bodyYaw)
|
||||
) * min(1, GraphicsInterface.getFrameLength() * 10);
|
||||
Vectors.release(horizontal);
|
||||
}
|
||||
|
||||
private void evaluateVelocityCoeff() {
|
||||
if (velocity * velocityCutoff > 1) {
|
||||
velocityCoeff = 1;
|
||||
} else {
|
||||
velocityCoeff = velocity * velocityCutoff;
|
||||
velocityCoeff *= velocityCoeff;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getViewPoint(Vec3 output) {
|
||||
Mat4 m = Matrices.grab4();
|
||||
Vec4 v = Vectors.grab4();
|
||||
|
||||
m.identity()
|
||||
.scale(scale)
|
||||
.rotateZ(bodyYaw)
|
||||
.translate(head.getTranslation())
|
||||
.rotateZ(headYaw)
|
||||
.rotateY(headPitch);
|
||||
|
||||
v.set(head.getViewPoint(), 1);
|
||||
m.mul(v);
|
||||
|
||||
output.set(v.x, v.y, v.z);
|
||||
|
||||
Vectors.release(v);
|
||||
Matrices.release(m);
|
||||
public QuadripedModel setWalkingSwing(float walkingSwing) {
|
||||
this.walkingSwing = walkingSwing;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ public class ChunkData {
|
||||
TileData flowers = TileDataRegistry.getInstance().get("Test:YellowFlowers");
|
||||
TileData sand = TileDataRegistry.getInstance().get("Test:Sand");
|
||||
|
||||
Vec3i aPoint = new Vec3i(5, 0, BLOCKS_PER_CHUNK + BLOCKS_PER_CHUNK/2);
|
||||
Vec3i aPoint = new Vec3i(5, 0, BLOCKS_PER_CHUNK + BLOCKS_PER_CHUNK/2).sub(getPosition());
|
||||
Vec3i pos = new Vec3i();
|
||||
|
||||
for (int x = 0; x < BLOCKS_PER_CHUNK; ++x) {
|
||||
@ -132,19 +132,29 @@ public class ChunkData {
|
||||
}
|
||||
}
|
||||
|
||||
EntityData javapony = EntityDataRegistry.getInstance().create("Test:Javapony");
|
||||
javapony.setEntityId(0x42);
|
||||
javapony.setPosition(new Vec3(-6, -6, 20));
|
||||
javapony.setDirection(new Vec2(
|
||||
if (!getPosition().any()) {
|
||||
// EntityData javapony = EntityDataRegistry.getInstance().create("Test:Javapony");
|
||||
// javapony.setEntityId(0x42);
|
||||
// javapony.setPosition(new Vec3(-6, -6, 20));
|
||||
// javapony.setDirection(new Vec2(
|
||||
// (float) Math.toRadians(40), (float) Math.toRadians(45)
|
||||
// ));
|
||||
// getEntities().add(javapony);
|
||||
|
||||
EntityData player = EntityDataRegistry.getInstance().create("Test:Player");
|
||||
player.setEntityId(0x42);
|
||||
player.setPosition(new Vec3(-6, -6, 20));
|
||||
player.setDirection(new Vec2(
|
||||
(float) Math.toRadians(40), (float) Math.toRadians(45)
|
||||
));
|
||||
getEntities().add(javapony);
|
||||
getEntities().add(player);
|
||||
|
||||
EntityData statie = EntityDataRegistry.getInstance().create("Test:Statie");
|
||||
statie.setEntityId(0xDEADBEEF);
|
||||
statie.setPosition(new Vec3(0, 15, 16));
|
||||
getEntities().add(statie);
|
||||
}
|
||||
}
|
||||
|
||||
public BlockData getBlock(Vec3i posInChunk) {
|
||||
return blocks[getBlockIndex(posInChunk)];
|
||||
|
@ -87,9 +87,14 @@ public class TestContent {
|
||||
}
|
||||
|
||||
private static void registerEntities() {
|
||||
registerEntityData("Test", "Javapony", e -> e.setCollisionModel(new AABB(0, 0, -0.05f, 0.75f, 0.75f, 1.2f)));
|
||||
register(new TestEntityRenderJavapony());
|
||||
register(new EntityLogic("Test", "Javapony"));
|
||||
// registerEntityData("Test", "Javapony", e -> e.setCollisionModel(new AABB(0, 0, -0.05f, 0.75f, 0.75f, 1.2f)));
|
||||
// register(new TestEntityRenderJavapony());
|
||||
// register(new EntityLogic("Test", "Javapony"));
|
||||
|
||||
float scale = 1.8f / 8;
|
||||
registerEntityData("Test", "Player", e -> e.setCollisionModel(new AABB(0, 0, 4*scale, 0.75f, 0.75f, 1.8f)));
|
||||
register(new TestEntityRenderHuman());
|
||||
register(new EntityLogic("Test", "Player"));
|
||||
|
||||
register("Test", "Statie", TestEntityDataStatie::new);
|
||||
register(new TestEntityRenderStatie());
|
||||
|
@ -0,0 +1,164 @@
|
||||
package ru.windcorp.progressia.test;
|
||||
|
||||
import static java.lang.Math.toRadians;
|
||||
|
||||
import glm.vec._3.Vec3;
|
||||
import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
|
||||
import ru.windcorp.progressia.client.graphics.model.LambdaModel;
|
||||
import ru.windcorp.progressia.client.graphics.model.Renderable;
|
||||
import ru.windcorp.progressia.client.graphics.model.Shapes.PppBuilder;
|
||||
import ru.windcorp.progressia.client.graphics.model.StaticModel;
|
||||
import ru.windcorp.progressia.client.graphics.texture.ComplexTexture;
|
||||
import ru.windcorp.progressia.client.graphics.world.WorldRenderProgram;
|
||||
import ru.windcorp.progressia.client.world.entity.HumanoidModel;
|
||||
import ru.windcorp.progressia.client.world.entity.EntityRender;
|
||||
import ru.windcorp.progressia.client.world.entity.EntityRenderRegistry;
|
||||
import ru.windcorp.progressia.client.world.entity.EntityRenderable;
|
||||
import ru.windcorp.progressia.common.util.FloatMathUtils;
|
||||
import ru.windcorp.progressia.common.world.entity.EntityData;
|
||||
|
||||
import static java.lang.Math.*;
|
||||
|
||||
public class TestEntityRenderHuman extends EntityRender {
|
||||
|
||||
private static final float SECOND_LAYER_OFFSET = 1 / 12f;
|
||||
|
||||
private final Renderable body;
|
||||
private final Renderable head;
|
||||
private final Renderable leftArm;
|
||||
private final Renderable rightArm;
|
||||
private final Renderable leftLeg;
|
||||
private final Renderable rightLeg;
|
||||
|
||||
public TestEntityRenderHuman() {
|
||||
super("Test", "Player");
|
||||
|
||||
ComplexTexture texture = new ComplexTexture(
|
||||
EntityRenderRegistry.getEntityTexture("pyotr"),
|
||||
16, 16
|
||||
);
|
||||
|
||||
this.body = createBody(texture);
|
||||
this.head = createHead(texture);
|
||||
|
||||
this.leftArm = createLimb(texture, 8, 0, 12, 0, true, true);
|
||||
this.rightArm = createLimb(texture, 10, 8, 10, 4, true, false);
|
||||
this.leftLeg = createLimb(texture, 4, 0, 0, 0, false, true);
|
||||
this.rightLeg = createLimb(texture, 0, 8, 0, 4, false, false);
|
||||
}
|
||||
|
||||
private Renderable createBody(ComplexTexture texture) {
|
||||
return createLayeredCuboid(
|
||||
texture,
|
||||
4, 8,
|
||||
4, 4,
|
||||
2, 3, 1,
|
||||
-0.5f, -1, 3,
|
||||
1, 2, 3
|
||||
);
|
||||
}
|
||||
|
||||
private Renderable createHead(ComplexTexture texture) {
|
||||
return createLayeredCuboid(
|
||||
texture,
|
||||
0, 12,
|
||||
8, 12,
|
||||
2, 2, 2,
|
||||
-1, -1, 0,
|
||||
2, 2, 2
|
||||
);
|
||||
}
|
||||
|
||||
private Renderable createLimb(
|
||||
ComplexTexture texture,
|
||||
int tx, int ty,
|
||||
int tx2, int ty2,
|
||||
boolean isArm, boolean isLeft
|
||||
) {
|
||||
Renderable model = createLayeredCuboid(
|
||||
texture,
|
||||
tx, ty,
|
||||
tx2, ty2,
|
||||
1, 3, 1,
|
||||
-0.5f, -0.5f, isArm ? -2.5f : -3f,
|
||||
1, 1, 3
|
||||
);
|
||||
|
||||
if (isArm) {
|
||||
return LambdaModel.animate(
|
||||
model,
|
||||
mat -> {
|
||||
double phase = GraphicsInterface.getTime() + (isLeft ? 0 : Math.PI / 3);
|
||||
mat.rotateX((isLeft ? +1 : -1) * 1/40f * (sin(phase) + 1));
|
||||
mat.rotateY(1/20f * sin(Math.PI / 3 * phase));
|
||||
}
|
||||
);
|
||||
} else {
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
private Renderable createLayeredCuboid(
|
||||
ComplexTexture texture,
|
||||
int tx, int ty,
|
||||
int tx2, int ty2,
|
||||
int tw, int th, int td,
|
||||
float ox, float oy, float oz,
|
||||
float sx, float sy, float sz
|
||||
) {
|
||||
WorldRenderProgram program = WorldRenderProgram.getDefault();
|
||||
StaticModel.Builder b = StaticModel.builder();
|
||||
|
||||
// First layer
|
||||
b.addPart(new PppBuilder(
|
||||
program,
|
||||
texture.getCuboidTextures(tx, ty, tw, th, td)
|
||||
).setOrigin(ox, oy, oz).setSize(sx, sy, sz).create());
|
||||
|
||||
ox -= SECOND_LAYER_OFFSET;
|
||||
oy -= SECOND_LAYER_OFFSET;
|
||||
oz -= SECOND_LAYER_OFFSET;
|
||||
|
||||
sx += SECOND_LAYER_OFFSET * 2;
|
||||
sy += SECOND_LAYER_OFFSET * 2;
|
||||
sz += SECOND_LAYER_OFFSET * 2;
|
||||
|
||||
// Second layer
|
||||
b.addPart(new PppBuilder(
|
||||
program,
|
||||
texture.getCuboidTextures(tx2, ty2, tw, th, td)
|
||||
).setOrigin(ox, oy, oz).setSize(sx, sy, sz).create());
|
||||
|
||||
return new StaticModel(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityRenderable createRenderable(EntityData entity) {
|
||||
return new HumanoidModel(
|
||||
entity,
|
||||
|
||||
new HumanoidModel.Body(body),
|
||||
new HumanoidModel.Head(
|
||||
head, new Vec3(0, 0, 6), 70, 25, new Vec3(1.2f, 0, 1.5f)
|
||||
),
|
||||
new HumanoidModel.Arm(
|
||||
leftArm, new Vec3(0, +1.5f, 3 + 3 - 0.5f), 0.0f
|
||||
),
|
||||
new HumanoidModel.Arm(
|
||||
rightArm, new Vec3(0, -1.5f, 3 + 3 - 0.5f), FloatMathUtils.PI_F
|
||||
),
|
||||
new HumanoidModel.Leg(
|
||||
leftLeg, new Vec3(0, +0.5f, 3), FloatMathUtils.PI_F
|
||||
),
|
||||
new HumanoidModel.Leg(
|
||||
rightLeg, new Vec3(0, -0.5f, 3), 0.0f
|
||||
),
|
||||
|
||||
1.8f / (3 + 3 + 2)
|
||||
)
|
||||
.setWalkingArmSwing((float) toRadians(30))
|
||||
.setWalkingLegSwing((float) toRadians(50))
|
||||
.setWalkingFrequency(0.15f / 60.0f);
|
||||
}
|
||||
|
||||
}
|
@ -39,7 +39,7 @@ public class TestPlayerControls {
|
||||
private static final float FLYING_CONTROL_AUTHORITY = 0.05f;
|
||||
|
||||
// Horizontal and vertical max control speed when walking
|
||||
private static final float WALKING_SPEED = 5.0f * Units.METERS_PER_SECOND;
|
||||
private static final float WALKING_SPEED = 4.0f * Units.METERS_PER_SECOND;
|
||||
|
||||
// (0; 1], 1 is instant change, 0 is no control authority
|
||||
private static final float WALKING_CONTROL_AUTHORITY = 0.1f;
|
||||
|
BIN
src/main/resources/assets/textures/entities/pyotr.png
Normal file
BIN
src/main/resources/assets/textures/entities/pyotr.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
BIN
src/main/resources/assets/textures/entities/test_skin.png
Normal file
BIN
src/main/resources/assets/textures/entities/test_skin.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
src/main/resources/assets/textures/entities/test_skin_layout.png
Normal file
BIN
src/main/resources/assets/textures/entities/test_skin_layout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 KiB |
Reference in New Issue
Block a user