forked from LeenkxTeam/Leenkx_Templates
186 lines
4.5 KiB
Haxe
186 lines
4.5 KiB
Haxe
package lnx;
|
|
|
|
import iron.math.Vec4;
|
|
import iron.math.Vec2;
|
|
import iron.math.RayCaster;
|
|
import iron.Scene;
|
|
import iron.object.Object;
|
|
import iron.object.BoneAnimation;
|
|
import iron.system.Time;
|
|
import iron.system.Audio;
|
|
import iron.system.Input;
|
|
import leenkx.trait.physics.RigidBody;
|
|
|
|
class PlayerController extends iron.Trait {
|
|
|
|
#if (!lnx_physics)
|
|
public function new() { super(); }
|
|
#else
|
|
|
|
var soundStep0:kha.Sound = null;
|
|
var soundStep1:kha.Sound = null;
|
|
var soundsLoaded = 0;
|
|
|
|
var mouse:Mouse = null;
|
|
var keyboard:Keyboard = null;
|
|
var gamepad:Gamepad = null;
|
|
|
|
var body:RigidBody;
|
|
var anim:BoneAnimation;
|
|
var armature:Object;
|
|
|
|
var stepTime = 0.0;
|
|
var turnTime = 0.0;
|
|
var dir = new Vec4();
|
|
var lastLook:Vec4;
|
|
var state = "idle";
|
|
|
|
public function new() {
|
|
super();
|
|
|
|
// Load sounds
|
|
iron.data.Data.getSound("step0.wav", function(sound:kha.Sound) { soundStep0 = sound; soundsLoaded++; });
|
|
iron.data.Data.getSound("step1.wav", function(sound:kha.Sound) { soundStep1 = sound; soundsLoaded++; });
|
|
|
|
notifyOnInit(init);
|
|
notifyOnUpdate(update);
|
|
}
|
|
|
|
function init() {
|
|
// Get input devices
|
|
mouse = Input.getMouse();
|
|
keyboard = Input.getKeyboard();
|
|
gamepad = Input.getGamepad(0);
|
|
|
|
// Store references
|
|
body = object.getTrait(RigidBody);
|
|
armature = object.getChild("Armature");
|
|
anim = cast armature.children[0].animation;
|
|
lastLook = armature.transform.look().normalize();
|
|
}
|
|
|
|
function update() {
|
|
// Movement
|
|
dir.set(0, 0, 0);
|
|
if (keyboard.down("w")) dir.y = 1.0;
|
|
if (keyboard.down("s")) dir.y = -1.0;
|
|
if (keyboard.down("a")) dir.x = -1.0;
|
|
if (keyboard.down("d")) dir.x = 1.0;
|
|
if (gamepad != null && Math.abs(gamepad.leftStick.x) > 0.1) dir.x = gamepad.leftStick.x;
|
|
if (gamepad != null && Math.abs(gamepad.leftStick.y) > 0.1) dir.y = gamepad.leftStick.y;
|
|
dir.normalize();
|
|
|
|
// Mouse control
|
|
var mouse_pos = new Vec2(mouse.x,mouse.y);
|
|
var hit_pos = project_mouse_pos(mouse_pos);
|
|
|
|
if (hit_pos != null)
|
|
{
|
|
var center = new Vec4(hit_pos.x,hit_pos.y,0);
|
|
var eye = armature.transform.world.getLoc();
|
|
eye.set(eye.x,eye.y,0);
|
|
|
|
var target = center.sub(eye);
|
|
|
|
armature.transform.rot.fromTo(Vec4.yAxis(), target.normalize());
|
|
}
|
|
|
|
// Gamepad control
|
|
if (gamepad != null) {
|
|
if (Math.abs(gamepad.rightStick.x) > 0.7 || Math.abs(gamepad.rightStick.y) > 0.7) {
|
|
armature.transform.rot.fromTo(Vec4.yAxis(), new Vec4(gamepad.rightStick.x, gamepad.rightStick.y, 0.0));
|
|
}
|
|
}
|
|
|
|
armature.transform.buildMatrix();
|
|
updateAnim();
|
|
updateBody();
|
|
}
|
|
|
|
function project_mouse_pos(input:Vec2){
|
|
var camera = Scene.active.camera;
|
|
|
|
var start = new Vec4();
|
|
var end = new Vec4();
|
|
|
|
var hit_pos = RayCaster.planeIntersect(Vec4.zAxis(),new Vec4(0,0,1),input.x,input.y,camera);
|
|
return hit_pos;
|
|
}
|
|
|
|
function getAngle(va:Vec4, vb:Vec4) {
|
|
var vn = Vec4.zAxis();
|
|
var dot = va.dot(vb);
|
|
var det = va.x * vb.y * vn.z +
|
|
vb.x * vn.y * va.z +
|
|
vn.x * va.y * vb.z -
|
|
va.z * vb.y * vn.x -
|
|
vb.z * vn.y * va.x -
|
|
vn.z * va.y * vb.x;
|
|
return Math.atan2(det, dot);
|
|
}
|
|
|
|
function updateAnim() {
|
|
var look = armature.transform.look().normalize();
|
|
|
|
// Move
|
|
if (dir.length() > 0) {
|
|
var action = "";
|
|
// Angle from look direction to move direction
|
|
// 0 to PI * 2
|
|
var angle = getAngle(dir, look) + Math.PI;
|
|
var step = Math.PI / 4;
|
|
if (angle < step) action = "back";
|
|
else if (angle < step * 3) action = "left";
|
|
else if (angle < step * 5) action = "run";
|
|
else if (angle < step * 7) action = "right";
|
|
else action = "back";
|
|
|
|
setState(action, 1.0);
|
|
|
|
// Step sounds
|
|
stepTime += Time.delta;
|
|
if (stepTime > 0.3) {
|
|
stepTime = 0;
|
|
if (soundsLoaded == 2) {
|
|
Audio.play(Std.random(2) == 0 ? soundStep0 : soundStep1);
|
|
}
|
|
}
|
|
}
|
|
// Shoot
|
|
else if (mouse.down("left") || (gamepad != null && gamepad.down("r2") > 0.0)) {
|
|
setState("fire", 2.0);
|
|
}
|
|
// Idle
|
|
else {
|
|
var angle = getAngle(look, lastLook);
|
|
if (Math.abs(angle) > 0.01) {
|
|
setState("turn", angle > 0 ? 1 : -1, 0);
|
|
turnTime = 0;
|
|
}
|
|
else if (turnTime > 0.25){
|
|
setState("idle", 2.0);
|
|
}
|
|
else turnTime += Time.delta;
|
|
}
|
|
|
|
lastLook.setFrom(look);
|
|
}
|
|
|
|
function updateBody() {
|
|
if (!body.ready) return;
|
|
|
|
body.syncTransform();
|
|
body.activate();
|
|
var linvel = body.getLinearVelocity();
|
|
body.setLinearVelocity(dir.x * 6, dir.y * 6, linvel.z - 1.0); // Push down
|
|
body.setAngularFactor(0, 0, 0); // Keep vertical
|
|
}
|
|
|
|
function setState(s:String, speed:Float, blend = 0.2) {
|
|
if (s == state) return;
|
|
state = s;
|
|
anim.play(s, null, blend, speed);
|
|
}
|
|
#end
|
|
}
|