Final product
This commit is contained in:
commit
313bc87210
34 changed files with 3161 additions and 0 deletions
419
src/com/gnarwhal/ld48/game/Player.java
Normal file
419
src/com/gnarwhal/ld48/game/Player.java
Normal file
|
@ -0,0 +1,419 @@
|
|||
package com.gnarwhal.ld48.game;
|
||||
|
||||
import com.gnarwhal.ld48.engine.display.Camera;
|
||||
import com.gnarwhal.ld48.engine.display.Window;
|
||||
import com.gnarwhal.ld48.engine.model.Vao;
|
||||
import com.gnarwhal.ld48.engine.shaders.PlayerShader;
|
||||
import com.gnarwhal.ld48.engine.texture.Texture;
|
||||
import org.joml.Vector2f;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.lwjgl.glfw.GLFW.*;
|
||||
|
||||
public class Player {
|
||||
private static class Particle {
|
||||
public Vector2f position;
|
||||
public Vector2f velocity;
|
||||
public float dimensions;
|
||||
|
||||
public float kill_hour;
|
||||
public float clock;
|
||||
}
|
||||
|
||||
public static final float PLAYER_DIMS = 64.0f;
|
||||
|
||||
public static final int
|
||||
EXPR_NORMAL = 0,
|
||||
EXPR_THREE_SMOAKS = 1,
|
||||
EXPR_CONFUSED = 2,
|
||||
EXPR_SQUINT = 3;
|
||||
|
||||
private static final float
|
||||
HOVER_FLUCTUATION = 42.0f,
|
||||
HOVER_CYCLE_RATE = 2.5f;
|
||||
|
||||
private static final int
|
||||
NO_ACTION = 0,
|
||||
QUICK_ATTACK = 1,
|
||||
DASH = 2;
|
||||
|
||||
public float hover_offset;
|
||||
public float hover_clock;
|
||||
public Vector2f base_position;
|
||||
public Vector2f position;
|
||||
public Vector2f velocity;
|
||||
|
||||
private static PlayerShader shader;
|
||||
private static Vao vao;
|
||||
|
||||
private Texture body;
|
||||
private Texture[] eyes;
|
||||
private Texture particle;
|
||||
|
||||
private int expression;
|
||||
private float eye_rotation;
|
||||
private float direction;
|
||||
|
||||
private float rate_bias;
|
||||
private float spawn_trigger;
|
||||
private float position_bias;
|
||||
private float target_interp_clock;
|
||||
private float particle_spawn_offset;
|
||||
private Vector2f particle_base_target;
|
||||
private Vector2f particle_target;
|
||||
private ArrayList<Particle> particles;
|
||||
|
||||
private int performing_action;
|
||||
private float action_clock;
|
||||
private float action_progress;
|
||||
private boolean cancel_action;
|
||||
|
||||
private float quick_attack_rotation;
|
||||
private float vertical_offset;
|
||||
private Vector2f quick_attack_direction;
|
||||
|
||||
private Vector2f dash_direction;
|
||||
|
||||
public Player() {
|
||||
if (vao == null) {
|
||||
shader = new PlayerShader();
|
||||
vao = new Vao(
|
||||
new float[] {
|
||||
0.5f, -0.5f, 0, // Top left
|
||||
0.5f, 0.5f, 0, // Bottom left
|
||||
-0.5f, 0.5f, 0, // Bottom right
|
||||
-0.5f, -0.5f, 0 // Top right
|
||||
},
|
||||
new int[] {
|
||||
0, 1, 3,
|
||||
1, 2, 3
|
||||
}
|
||||
);
|
||||
vao.addAttrib(
|
||||
new float[] {
|
||||
1, 0,
|
||||
1, 1,
|
||||
0, 1,
|
||||
0, 0
|
||||
},
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
body = new Texture("res/img/player/body.png");
|
||||
eyes = new Texture[] {
|
||||
new Texture("res/img/player/normal_eyes.png"),
|
||||
new Texture("res/img/player/three_smoaks_eyes.png"),
|
||||
new Texture("res/img/player/confused_eyes.png"),
|
||||
new Texture("res/img/player/squint_eyes.png")
|
||||
};
|
||||
particle = new Texture("res/img/player/particle.png");
|
||||
|
||||
hover_offset = 0.0f;
|
||||
base_position = new Vector2f(5 * Map.TILE_DIMS + PLAYER_DIMS * 0.5f, 8 * Map.TILE_DIMS);
|
||||
position = new Vector2f(base_position);
|
||||
velocity = new Vector2f();
|
||||
|
||||
expression = EXPR_NORMAL;
|
||||
direction = 1.0f;
|
||||
|
||||
particles = new ArrayList<>();
|
||||
rate_bias = 1.0f;
|
||||
spawn_trigger = 0.0f;
|
||||
target_interp_clock = 1.0f;
|
||||
particle_spawn_offset = 0.0f;
|
||||
particle_base_target = new Vector2f(-PLAYER_DIMS, -PLAYER_DIMS * 1.5f);
|
||||
particle_target = new Vector2f(particle_base_target);
|
||||
}
|
||||
|
||||
public float rescale(float progress, float start, float end) {
|
||||
return (progress - start) / (end - start);
|
||||
}
|
||||
|
||||
public void move(Window window) {
|
||||
final float RUN_VELOCITY = Map.TILE_DIMS * 3.5f;
|
||||
final float WALK_VELOCITY = Map.TILE_DIMS * 1.5f;
|
||||
final float QUICK_ATTACK_VELOCITY = Map.TILE_DIMS * 0.5f;
|
||||
final float VERTICAL_VELOCITY_SCALAR = 0.75f;
|
||||
|
||||
float target_velocity = RUN_VELOCITY;
|
||||
if (window.keyPressed(GLFW.GLFW_KEY_LEFT_CONTROL) >= Window.BUTTON_PRESSED || window.controllerButtonPressed(GLFW_GAMEPAD_BUTTON_B) >= Window.BUTTON_PRESSED) {
|
||||
target_velocity = WALK_VELOCITY;
|
||||
}
|
||||
if (performing_action == QUICK_ATTACK) {
|
||||
target_velocity = QUICK_ATTACK_VELOCITY;
|
||||
} else if (performing_action == DASH) {
|
||||
target_velocity = 0.0f;
|
||||
}
|
||||
|
||||
Vector2f input_velocity = new Vector2f(0);
|
||||
if (window.joystick(GLFW_JOYSTICK_1)) {
|
||||
input_velocity.x = window.getJoystickAxis(GLFW_GAMEPAD_AXIS_LEFT_X);
|
||||
input_velocity.y = window.getJoystickAxis(GLFW_GAMEPAD_AXIS_LEFT_Y);
|
||||
if (Math.abs(input_velocity.x) < 0.25f) { input_velocity.x = 0; }
|
||||
if (Math.abs(input_velocity.y) < 0.25f) { input_velocity.y = 0; }
|
||||
}
|
||||
|
||||
if (input_velocity.lengthSquared() == 0) {
|
||||
if (window.keyPressed(GLFW.GLFW_KEY_A) >= Window.BUTTON_PRESSED) {
|
||||
input_velocity.x -= 1;
|
||||
}
|
||||
if (window.keyPressed(GLFW.GLFW_KEY_D) >= Window.BUTTON_PRESSED) {
|
||||
input_velocity.x += 1;
|
||||
}
|
||||
if (window.keyPressed(GLFW.GLFW_KEY_W) >= Window.BUTTON_PRESSED) {
|
||||
input_velocity.y -= 1;
|
||||
}
|
||||
if (window.keyPressed(GLFW.GLFW_KEY_S) >= Window.BUTTON_PRESSED) {
|
||||
input_velocity.y += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (input_velocity.lengthSquared() != 0) {
|
||||
input_velocity.normalize(target_velocity);
|
||||
input_velocity.y *= VERTICAL_VELOCITY_SCALAR;
|
||||
}
|
||||
|
||||
if (action_clock < 0.0f) {
|
||||
action_clock += Main.dtime;
|
||||
} else if (performing_action == NO_ACTION) {
|
||||
if (window.keyPressed(GLFW.GLFW_KEY_SPACE) == Window.BUTTON_PRESSED || window.controllerButtonPressed(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER) == Window.BUTTON_PRESSED) {
|
||||
performing_action = QUICK_ATTACK;
|
||||
action_clock = 0.0f;
|
||||
if (input_velocity.lengthSquared() != 0) {
|
||||
quick_attack_direction = input_velocity.normalize(new Vector2f());
|
||||
} else {
|
||||
quick_attack_direction = new Vector2f(direction, 0);
|
||||
}
|
||||
} else if (window.keyPressed(GLFW.GLFW_KEY_LEFT_SHIFT) == Window.BUTTON_PRESSED || window.controllerButtonPressed(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER) == Window.BUTTON_PRESSED) {
|
||||
performing_action = DASH;
|
||||
action_clock = 0.0f;
|
||||
if (input_velocity.lengthSquared() != 0) {
|
||||
dash_direction = input_velocity.normalize(new Vector2f());
|
||||
} else {
|
||||
dash_direction = new Vector2f(direction, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final float MAX_BIAS = 0.25f;
|
||||
rate_bias = Math.max(MAX_BIAS, lerp(MAX_BIAS, 1.0f, 1 - (input_velocity.length() / RUN_VELOCITY)));
|
||||
|
||||
if (performing_action == DASH) {
|
||||
action_clock += Main.dtime;
|
||||
|
||||
final float DASH_TIME = 0.15f;
|
||||
final float DASH_COOLDOWN = 0.25f;
|
||||
if (cancel_action) {
|
||||
action_clock = DASH_TIME;
|
||||
cancel_action = false;
|
||||
}
|
||||
if (action_clock >= DASH_TIME) {
|
||||
performing_action = NO_ACTION;
|
||||
action_clock = -DASH_COOLDOWN;
|
||||
expression = EXPR_NORMAL;
|
||||
rate_bias = 1.0f;
|
||||
|
||||
particle_spawn_offset = 0;
|
||||
} else {
|
||||
rate_bias = 0.01f;
|
||||
particle_spawn_offset = dash_direction.angle(new Vector2f(direction, -1)) * 2.0f / (float) Math.PI;
|
||||
final float DASH_SPEED = Map.TILE_DIMS * 15;
|
||||
input_velocity.set(dash_direction).mul(DASH_SPEED);
|
||||
}
|
||||
}
|
||||
|
||||
if (performing_action == NO_ACTION && direction * input_velocity.x < 0) {
|
||||
direction = -direction;
|
||||
target_interp_clock = 0.0f;
|
||||
}
|
||||
|
||||
velocity = input_velocity.mul((float) Main.dtime);
|
||||
|
||||
if (window.keyPressed(GLFW_KEY_Q) == Window.BUTTON_PRESSED) {
|
||||
velocity.x = -400;
|
||||
velocity.y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void proc_collision() {}
|
||||
|
||||
private float lerp(float start, float end, float lerp) {
|
||||
return start + (end - start) * lerp;
|
||||
}
|
||||
|
||||
public void update(Camera camera) {
|
||||
camera.setCenter(base_position.x, base_position.y);
|
||||
|
||||
if (performing_action == NO_ACTION) {
|
||||
hover_clock = (hover_clock + (float) Main.dtime) % HOVER_CYCLE_RATE;
|
||||
hover_offset = (float) Math.sin(2 * Math.PI * hover_clock * (1 / HOVER_CYCLE_RATE)) * HOVER_FLUCTUATION * 0.5f;
|
||||
}
|
||||
|
||||
position.set(base_position);
|
||||
if (performing_action == QUICK_ATTACK) {
|
||||
action_clock += Main.dtime;
|
||||
|
||||
final float QUICK_ATTACK_TIME = 0.5f;
|
||||
final float QUICK_ATTACK_COOLDOWN = 0.1f;
|
||||
if (cancel_action) {
|
||||
action_clock = QUICK_ATTACK_TIME;
|
||||
cancel_action = false;
|
||||
}
|
||||
if (action_clock >= QUICK_ATTACK_TIME) {
|
||||
performing_action = NO_ACTION;
|
||||
action_clock = -QUICK_ATTACK_COOLDOWN;
|
||||
expression = EXPR_NORMAL;
|
||||
}
|
||||
|
||||
action_progress = action_clock / QUICK_ATTACK_TIME;
|
||||
|
||||
vertical_offset = 0;
|
||||
quick_attack_rotation = 0;
|
||||
eye_rotation = 0;
|
||||
particle_spawn_offset = 0;
|
||||
particle_target.set(particle_base_target);
|
||||
|
||||
if (action_progress < 0.5f) {
|
||||
float smooth = (1 - (float) Math.cos(Math.PI * 2 * rescale(action_progress, 0, 0.6f))) * 0.5f;
|
||||
|
||||
final float RECOIL_AMOUNT = PLAYER_DIMS * 0.4f;
|
||||
vertical_offset = -smooth * RECOIL_AMOUNT;
|
||||
|
||||
position.y += vertical_offset;
|
||||
}
|
||||
|
||||
if (action_progress > 0.25f) {
|
||||
float progress = rescale(action_progress, 0.15f, 1);
|
||||
quick_attack_rotation = (float) Math.PI * 2 * progress * direction;
|
||||
eye_rotation = progress;
|
||||
particle_spawn_offset = progress * 4 * -direction;
|
||||
|
||||
final float PARTICLE_BOOST = 2;
|
||||
|
||||
rate_bias = 0.1f;
|
||||
float sin = (float) Math.sin(quick_attack_rotation);
|
||||
float cos = (float) Math.cos(quick_attack_rotation);
|
||||
particle_target.set(
|
||||
cos * particle_base_target.x - sin * particle_base_target.y,
|
||||
sin * particle_base_target.x + cos * particle_base_target.y
|
||||
).mul(PARTICLE_BOOST);
|
||||
|
||||
final float ORTHOGONAL = PLAYER_DIMS * 0.5f;
|
||||
final float PARALLEL = PLAYER_DIMS * 1.15f;
|
||||
|
||||
position
|
||||
.add(quick_attack_direction.mul((1 - (float) Math.cos(quick_attack_rotation)) * PARALLEL, new Vector2f()))
|
||||
.add(new Vector2f(-quick_attack_direction.y, quick_attack_direction.x).mul((float) Math.sin(quick_attack_rotation) * ORTHOGONAL));
|
||||
}
|
||||
}
|
||||
|
||||
//////// PARTICLE SYSTEM ////////
|
||||
|
||||
for (int i = 0; i < particles.size(); ++i) {
|
||||
Particle p = particles.get(i);
|
||||
p.clock += Main.dtime;
|
||||
if (p.clock >= p.kill_hour) {
|
||||
particles.remove(i);
|
||||
--i;
|
||||
} else {
|
||||
final float PARTICLE_MIN_DIMS = 16.0f;
|
||||
final float PARTICLE_MAX_DIMS = 28.0f;
|
||||
|
||||
float interp = p.clock / p.kill_hour;
|
||||
p.dimensions = lerp(PARTICLE_MAX_DIMS, PARTICLE_MIN_DIMS, interp);
|
||||
p.position.add(p.velocity.mul((float) Main.dtime, new Vector2f()));
|
||||
}
|
||||
}
|
||||
|
||||
final float TURN_RATE = 0.7f;
|
||||
target_interp_clock = Math.min(target_interp_clock + (float) Main.dtime / TURN_RATE, 1);
|
||||
|
||||
spawn_trigger -= Main.dtime;
|
||||
if (spawn_trigger < 0) {
|
||||
Particle p = new Particle();
|
||||
|
||||
final float PARTICLE_MIN_LIFETIME = 0.5f;
|
||||
final float PARTICLE_MAX_LIFETIME = 1.0f;
|
||||
p.kill_hour = lerp(PARTICLE_MIN_LIFETIME, PARTICLE_MAX_LIFETIME, (float) Math.random());
|
||||
|
||||
Vector2f spawn_position = new Vector2f(position).add(0, hover_offset);
|
||||
position_bias = (4.5f + direction * 0.5f + (float) Math.random() * 2 - 1 + particle_spawn_offset) % 4;
|
||||
if (0 <= position_bias && position_bias < 1) {
|
||||
spawn_position.add(
|
||||
-PLAYER_DIMS * 0.4f * (position_bias * 2.0f - 1.0f),
|
||||
-PLAYER_DIMS * 0.4f
|
||||
);
|
||||
} else if (1 <= position_bias && position_bias < 2) {
|
||||
position_bias -= 1;
|
||||
spawn_position.add(
|
||||
-PLAYER_DIMS * 0.4f,
|
||||
PLAYER_DIMS * 0.4f * (position_bias * 2.0f - 1.0f)
|
||||
);
|
||||
} else if (2 <= position_bias && position_bias < 3) {
|
||||
position_bias -= 2;
|
||||
spawn_position.add(
|
||||
PLAYER_DIMS * 0.4f * (position_bias * 2.0f - 1.0f),
|
||||
PLAYER_DIMS * 0.4f
|
||||
);
|
||||
} else {
|
||||
position_bias -= 3;
|
||||
spawn_position.add(
|
||||
PLAYER_DIMS * 0.4f,
|
||||
-PLAYER_DIMS * 0.4f * (position_bias * 2.0f - 1.0f)
|
||||
);
|
||||
}
|
||||
p.position = spawn_position;
|
||||
|
||||
p.velocity = new Vector2f(particle_target).mul((2 * target_interp_clock - 1) * direction, 1).add(position).sub(spawn_position).add(velocity.mul(0.1f, new Vector2f()));
|
||||
|
||||
particles.add(p);
|
||||
|
||||
final float BASE_SPAWN_RATE = 0.15f;
|
||||
spawn_trigger = BASE_SPAWN_RATE * rate_bias;
|
||||
}
|
||||
}
|
||||
|
||||
public void render(Camera camera) {
|
||||
shader.enable();
|
||||
|
||||
particle.bind();
|
||||
for (int i = 0; i < particles.size(); ++i) {
|
||||
Particle p = particles.get(i);
|
||||
shader.setMVP(
|
||||
camera
|
||||
.getMatrix()
|
||||
.translate(
|
||||
p.position.x,
|
||||
p.position.y,
|
||||
0
|
||||
)
|
||||
.scaleXY(
|
||||
p.dimensions,
|
||||
p.dimensions
|
||||
)
|
||||
);
|
||||
vao.render();
|
||||
}
|
||||
|
||||
shader.setMVP(
|
||||
camera
|
||||
.getMatrix()
|
||||
.translate(
|
||||
position.x,
|
||||
position.y + hover_offset,
|
||||
0
|
||||
)
|
||||
.scaleXY(direction * PLAYER_DIMS, PLAYER_DIMS));
|
||||
|
||||
shader.setRotation(0);
|
||||
body.bind();
|
||||
vao.render();
|
||||
|
||||
shader.setRotation(eye_rotation);
|
||||
eyes[expression].bind();
|
||||
vao.render();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue