Update
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
*/build*
|
||||
*/*.blend?
|
||||
*/Sources/Main.hx
|
||||
*/Sources/arm/node/*
|
||||
*/khafile.js
|
||||
config.arm
|
||||
_themes.json
|
||||
7
LICENSE.md
Normal file
@ -0,0 +1,7 @@
|
||||
# The zlib/libpng License
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||
The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
This notice may not be removed or altered from any source distribution.
|
||||
@ -1 +1,5 @@
|
||||
Leenkx template projects migrated from armory
|
||||
# leenkx_templates
|
||||
|
||||
Templates to accompany Leenkx SDK. Check out the [manual](https://github.com/leenkx3d/leenkx/wiki).
|
||||
|
||||
Note: Download the package from [releases](https://github.com/leenkx3d/leenkx_templates/releases). Only use the latest revision of this repository if you are using [git Leenkx](https://github.com/leenkx3d/leenkx/wiki/gitversion).
|
||||
|
||||
BIN
archery/Assets/aim.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
archery/Assets/checker_rough.png
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
archery/Assets/finger.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
archery/Assets/grid.png
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
archery/Assets/grid_b.png
Normal file
|
After Width: | Height: | Size: 672 B |
BIN
archery/Bundled/bow_draw.wav
Normal file
BIN
archery/Bundled/bow_hit.wav
Normal file
BIN
archery/Bundled/bow_shoot.wav
Normal file
1
archery/Bundled/canvas/MyCanvas.files
Normal file
@ -0,0 +1 @@
|
||||
../../Assets/aim.png
|
||||
1
archery/Bundled/canvas/MyCanvas.json
Normal file
@ -0,0 +1 @@
|
||||
{"name":"untitled","x":0,"y":0,"width":960,"height":540,"elements":[{"id":0,"type":1,"name":"Image","event":"","x":0,"y":0,"width":64,"height":64,"text":"Image","asset":"aim.png","color":-1,"anchor":4,"children":[],"visible":true,"rotation":0}],"assets":[{"name":"aim.png","file":"../../Assets/aim.png","id":0}],"theme":"Default Light"}
|
||||
167
archery/Sources/lnx/FirstPersonController.hx
Normal file
@ -0,0 +1,167 @@
|
||||
package lnx;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Mat4;
|
||||
import iron.system.Input;
|
||||
import iron.object.Object;
|
||||
import iron.object.BoneAnimation;
|
||||
import leenkx.trait.physics.PhysicsWorld;
|
||||
import leenkx.trait.internal.CameraController;
|
||||
|
||||
class FirstPersonController extends CameraController {
|
||||
|
||||
#if (!lnx_physics)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
static inline var rotationSpeed = 0.5;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
notifyOnInit(function() {
|
||||
PhysicsWorld.active.notifyOnPreUpdate(preUpdate);
|
||||
notifyOnUpdate(update);
|
||||
|
||||
notifyOnRemove(function() {
|
||||
PhysicsWorld.active.removePreUpdate(preUpdate);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function findAnimation(o:Object):BoneAnimation {
|
||||
if (o.animation != null) return cast o.animation;
|
||||
for (c in o.children) {
|
||||
var co = findAnimation(c);
|
||||
if (co != null) return co;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var xVec = Vec4.xAxis();
|
||||
var zVec = Vec4.zAxis();
|
||||
var angle = 0.0;
|
||||
var nextFrameRot = 0.0;
|
||||
var anim:BoneAnimation = null;
|
||||
var q = new Quat();
|
||||
var mat = Mat4.identity();
|
||||
|
||||
function preUpdate() {
|
||||
if (Input.occupied || !body.ready) return;
|
||||
|
||||
var mouse = Input.getMouse();
|
||||
var kb = Input.getKeyboard();
|
||||
|
||||
if (mouse.started() && !mouse.locked) mouse.lock();
|
||||
else if (kb.started("escape") && mouse.locked) mouse.unlock();
|
||||
|
||||
if (nextFrameRot != 0.0) {
|
||||
var origin = object.getChild("CameraOrigin");
|
||||
origin.transform.rotate(xVec, nextFrameRot);
|
||||
origin.transform.buildMatrix();
|
||||
}
|
||||
nextFrameRot = 0;
|
||||
|
||||
if (mouse.moved) {
|
||||
var d = mouse.movementY / 250;
|
||||
if (angle + d < 0.25 && angle + d > -0.25) {
|
||||
angle += d;
|
||||
nextFrameRot = mouse.movementY / 250 * rotationSpeed;
|
||||
}
|
||||
}
|
||||
|
||||
if (anim == null) {
|
||||
anim = findAnimation(object.getChild("Armature"));
|
||||
anim.notifyOnUpdate(updateBones);
|
||||
}
|
||||
|
||||
if (mouse.moved) transform.rotate(zVec, -mouse.movementX / 250 * rotationSpeed);
|
||||
body.syncTransform();
|
||||
}
|
||||
|
||||
function updateBones() {
|
||||
// Fetch bone
|
||||
var bone1 = anim.getBone("mixamorig:LeftForeLnx");
|
||||
var bone2 = anim.getBone("mixamorig:RightForeLnx");
|
||||
// Fetch bone matrix - this is in local bone space for now
|
||||
var m1 = anim.getBoneMat(bone1);
|
||||
var m2 = anim.getBoneMat(bone2);
|
||||
var m1b = anim.getBoneMatBlend(bone1);
|
||||
var m2b = anim.getBoneMatBlend(bone2);
|
||||
var a1 = anim.getAbsMat(bone1.parent);
|
||||
var a2 = anim.getAbsMat(bone2.parent);
|
||||
|
||||
// Rotate hand bones to aim with gun
|
||||
// Some raw math follows..
|
||||
var tx = m1._30;
|
||||
var ty = m1._31;
|
||||
var tz = m1._32;
|
||||
m1._30 = 0;
|
||||
m1._31 = 0;
|
||||
m1._32 = 0;
|
||||
mat.getInverse(a1);
|
||||
q.fromAxisAngle(mat.right(), angle);
|
||||
m1.applyQuat(q);
|
||||
m1._30 = tx;
|
||||
m1._31 = ty;
|
||||
m1._32 = tz;
|
||||
|
||||
var tx = m2._30;
|
||||
var ty = m2._31;
|
||||
var tz = m2._32;
|
||||
m2._30 = 0;
|
||||
m2._31 = 0;
|
||||
m2._32 = 0;
|
||||
mat.getInverse(a2);
|
||||
var v = mat.right();
|
||||
v.mult(-1);
|
||||
// Todo: We do not do inverse kinematics just yet, right hand moves unnaturally
|
||||
// Point the hand down to the ground for now
|
||||
q.fromAxisAngle(v, -angle / 3.0);
|
||||
m2.applyQuat(q);
|
||||
m2._30 = tx;
|
||||
m2._31 = ty;
|
||||
m2._32 = tz;
|
||||
|
||||
// Animation blending is in progress, we need to rotate those bones too
|
||||
if (m1b != null && m2b != null) {
|
||||
var tx = m1b._30;
|
||||
var ty = m1b._31;
|
||||
var tz = m1b._32;
|
||||
m1b._30 = 0;
|
||||
m1b._31 = 0;
|
||||
m1b._32 = 0;
|
||||
mat.getInverse(a1);
|
||||
q.fromAxisAngle(mat.right(), angle);
|
||||
m1b.applyQuat(q);
|
||||
m1b._30 = tx;
|
||||
m1b._31 = ty;
|
||||
m1b._32 = tz;
|
||||
|
||||
var tx = m2b._30;
|
||||
var ty = m2b._31;
|
||||
var tz = m2b._32;
|
||||
m2b._30 = 0;
|
||||
m2b._31 = 0;
|
||||
m2b._32 = 0;
|
||||
mat.getInverse(a2);
|
||||
var v = mat.right();
|
||||
v.mult(-1);
|
||||
q.fromAxisAngle(v, -angle / 3.0);
|
||||
m2b.applyQuat(q);
|
||||
m2b._30 = tx;
|
||||
m2b._31 = ty;
|
||||
m2b._32 = tz;
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (!body.ready) return;
|
||||
|
||||
// Keep vertical
|
||||
body.setAngularFactor(0, 0, 0);
|
||||
camera.buildMatrix();
|
||||
}
|
||||
#end
|
||||
}
|
||||
BIN
archery/archery.blend
Normal file
BIN
first_person/Assets/aim.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
first_person/Assets/checker_rough.png
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
first_person/Assets/decal1.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
first_person/Assets/decal2.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
first_person/Assets/finger.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
first_person/Assets/grid.png
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
first_person/Assets/grid_b.png
Normal file
|
After Width: | Height: | Size: 672 B |
1
first_person/Bundled/canvas/MyCanvas.files
Normal file
@ -0,0 +1 @@
|
||||
../../Assets/aim.png
|
||||
1
first_person/Bundled/canvas/MyCanvas.json
Normal file
@ -0,0 +1 @@
|
||||
{"name":"untitled","x":0,"y":0,"width":1920,"height":1080,"elements":[{"id":0,"type":1,"name":"Image","event":"","x":0,"y":0,"width":60,"height":60,"rotation":0,"text":"Image","asset":"aim.png","progress_at":0,"progress_total":100,"strength":1,"alignment":0,"anchor":4,"parent":null,"children":[],"visible":true}],"assets":[{"name":"aim.png","file":"../../Assets/aim.png","id":0}],"theme":"Default Light"}
|
||||
BIN
first_person/Bundled/fire0.wav
Normal file
BIN
first_person/Bundled/fire1.wav
Normal file
BIN
first_person/Bundled/step0.wav
Normal file
BIN
first_person/Bundled/step1.wav
Normal file
277
first_person/Sources/lnx/FirstPersonController.hx
Normal file
@ -0,0 +1,277 @@
|
||||
package lnx;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Mat4;
|
||||
import iron.system.Input;
|
||||
import iron.object.Object;
|
||||
import iron.object.BoneAnimation;
|
||||
import iron.system.Time;
|
||||
import iron.system.Audio;
|
||||
import leenkx.trait.physics.PhysicsWorld;
|
||||
import leenkx.trait.internal.CameraController;
|
||||
|
||||
class FirstPersonController extends CameraController {
|
||||
|
||||
#if (!lnx_physics)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
static inline var rotationSpeed = 1.0;
|
||||
|
||||
var stepTime = 0.0;
|
||||
var turnTime = 0.0;
|
||||
|
||||
var soundStep0:kha.Sound = null;
|
||||
var soundStep1:kha.Sound = null;
|
||||
var soundsLoaded = 0;
|
||||
|
||||
var xVec = Vec4.xAxis();
|
||||
var zVec = Vec4.zAxis();
|
||||
var angle = 0.0;
|
||||
var nextFrameRot = 0.0;
|
||||
var armature:Object;
|
||||
var anim:BoneAnimation;
|
||||
var q = new Quat();
|
||||
var mat = Mat4.identity();
|
||||
|
||||
var nextIdle = false;
|
||||
var jumpTime = 0.0;
|
||||
var firingTime = 0.0;
|
||||
var speed = 1.0;
|
||||
var dir = new Vec4();
|
||||
var lastLook:Vec4;
|
||||
var state = "idle";
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
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(function() {
|
||||
PhysicsWorld.active.notifyOnPreUpdate(preUpdate);
|
||||
notifyOnUpdate(update);
|
||||
|
||||
notifyOnRemove(function() {
|
||||
PhysicsWorld.active.removePreUpdate(preUpdate);
|
||||
});
|
||||
|
||||
armature = object.getChild("Armature");
|
||||
anim = findAnimation(armature);
|
||||
anim.notifyOnUpdate(updateBones);
|
||||
lastLook = armature.transform.look().normalize();
|
||||
});
|
||||
}
|
||||
|
||||
function findAnimation(o:Object):BoneAnimation {
|
||||
if (o.animation != null) return cast o.animation;
|
||||
for (c in o.children) {
|
||||
var co = findAnimation(c);
|
||||
if (co != null) return co;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function updateBones() {
|
||||
|
||||
// Fetch bone
|
||||
var bone1 = anim.getBone("mixamorig:LeftForeLnx");
|
||||
var bone2 = anim.getBone("mixamorig:RightForeLnx");
|
||||
|
||||
// Fetch bone matrix - this is in local bone space for now
|
||||
var m1 = anim.getBoneMat(bone1);
|
||||
var m2 = anim.getBoneMat(bone2);
|
||||
var m1b = anim.getBoneMatBlend(bone1);
|
||||
var m2b = anim.getBoneMatBlend(bone2);
|
||||
var a1 = anim.getAbsMat(bone1.parent);
|
||||
var a2 = anim.getAbsMat(bone2.parent);
|
||||
|
||||
// Rotate hand bones to aim with gun
|
||||
// Some raw math follows..
|
||||
var tx = m1._30;
|
||||
var ty = m1._31;
|
||||
var tz = m1._32;
|
||||
m1._30 = 0;
|
||||
m1._31 = 0;
|
||||
m1._32 = 0;
|
||||
mat.getInverse(a1);
|
||||
q.fromAxisAngle(mat.right(), -angle);
|
||||
m1.applyQuat(q);
|
||||
m1._30 = tx;
|
||||
m1._31 = ty;
|
||||
m1._32 = tz;
|
||||
|
||||
var tx = m2._30;
|
||||
var ty = m2._31;
|
||||
var tz = m2._32;
|
||||
m2._30 = 0;
|
||||
m2._31 = 0;
|
||||
m2._32 = 0;
|
||||
mat.getInverse(a2);
|
||||
var v = mat.right();
|
||||
v.mult(-1);
|
||||
// Todo: Do inverse kinematics here, right hand moves unnaturally
|
||||
q.fromAxisAngle(v, -1.6);
|
||||
// q.fromAxisAngle(v, angle);
|
||||
m2.applyQuat(q);
|
||||
m2._30 = tx;
|
||||
m2._31 = ty;
|
||||
m2._32 = tz;
|
||||
|
||||
// Animation blending is in progress, we need to rotate those bones too
|
||||
if (m1b != null && m2b != null) {
|
||||
var tx = m1b._30;
|
||||
var ty = m1b._31;
|
||||
var tz = m1b._32;
|
||||
m1b._30 = 0;
|
||||
m1b._31 = 0;
|
||||
m1b._32 = 0;
|
||||
mat.getInverse(a1);
|
||||
q.fromAxisAngle(mat.right(), -angle);
|
||||
m1b.applyQuat(q);
|
||||
m1b._30 = tx;
|
||||
m1b._31 = ty;
|
||||
m1b._32 = tz;
|
||||
|
||||
var tx = m2b._30;
|
||||
var ty = m2b._31;
|
||||
var tz = m2b._32;
|
||||
m2b._30 = 0;
|
||||
m2b._31 = 0;
|
||||
m2b._32 = 0;
|
||||
mat.getInverse(a2);
|
||||
var v = mat.right();
|
||||
v.mult(-1);
|
||||
q.fromAxisAngle(v, -1.6);
|
||||
// q.fromAxisAngle(v, angle);
|
||||
m2b.applyQuat(q);
|
||||
m2b._30 = tx;
|
||||
m2b._31 = ty;
|
||||
m2b._32 = tz;
|
||||
}
|
||||
}
|
||||
|
||||
function preUpdate() {
|
||||
if (Input.occupied || !body.ready) return;
|
||||
|
||||
var mouse = Input.getMouse();
|
||||
var kb = Input.getKeyboard();
|
||||
|
||||
if (mouse.started() && !mouse.locked) mouse.lock();
|
||||
else if (kb.started("escape") && mouse.locked) mouse.unlock();
|
||||
|
||||
if (nextFrameRot != 0.0) {
|
||||
var origin = object.getChild("CameraOrigin");
|
||||
origin.transform.rotate(xVec, nextFrameRot);
|
||||
origin.transform.buildMatrix();
|
||||
}
|
||||
nextFrameRot = 0;
|
||||
|
||||
if (mouse.moved) {
|
||||
var d = mouse.movementY / 250;
|
||||
if (angle + d > 1.5) return;
|
||||
if (angle + d < -0.25) return;
|
||||
angle += d;
|
||||
nextFrameRot = -mouse.movementY / 250 * rotationSpeed;
|
||||
}
|
||||
|
||||
if (mouse.moved) transform.rotate(zVec, -mouse.movementX / 250 * rotationSpeed);
|
||||
body.syncTransform();
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (!body.ready) return;
|
||||
var look = armature.transform.look().normalize();
|
||||
|
||||
if (jump) {
|
||||
if (jumpTime >= 0.4){
|
||||
body.applyImpulse(new Vec4(0, 0, 16));
|
||||
jumpTime = 0;
|
||||
jump = false;
|
||||
}
|
||||
}
|
||||
jumpTime += Time.delta;
|
||||
|
||||
// Move
|
||||
dir.set(0, 0, 0);
|
||||
if (moveForward) dir.add(transform.look());
|
||||
if (moveBackward) dir.add(transform.look().mult(-1));
|
||||
if (moveLeft) dir.add(transform.right().mult(-1));
|
||||
if (moveRight) dir.add(transform.right());
|
||||
|
||||
// Push down
|
||||
var btvec = body.getLinearVelocity();
|
||||
body.setLinearVelocity(0.0, 0.0, btvec.z - 1.0);
|
||||
|
||||
if (moveForward || moveBackward || moveLeft || moveRight) {
|
||||
var action = moveForward ? "run" :
|
||||
moveBackward ? "back" :
|
||||
moveLeft ? "left" : "right";
|
||||
setState(action);
|
||||
|
||||
var kb = iron.system.Input.getKeyboard();
|
||||
if (kb.down("shift")) speed = 1.6;
|
||||
else speed = 1.0;
|
||||
|
||||
dir.mult(speed * 5);
|
||||
body.activate();
|
||||
body.setLinearVelocity(dir.x, dir.y, btvec.z - 1.0);
|
||||
|
||||
stepTime += Time.delta;
|
||||
if (stepTime > 0.38 / speed) {
|
||||
stepTime = 0;
|
||||
if (soundsLoaded == 2) {
|
||||
Audio.play(Std.random(2) == 0 ? soundStep0 : soundStep1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Play correct state
|
||||
else if (state != "fire" || state != "idle" || state != "turn") {
|
||||
var mouse = iron.system.Input.getMouse();
|
||||
if (mouse.down("left")) {
|
||||
firingTime = 0.0;
|
||||
setState("fire", 2.0);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == "fire") firingTime += Time.delta;
|
||||
else firingTime = 0.0;
|
||||
|
||||
// Keep vertical
|
||||
body.setAngularFactor(0, 0, 0);
|
||||
camera.buildMatrix();
|
||||
|
||||
lastLook.setFrom(look);
|
||||
}
|
||||
|
||||
// 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 setState(s:String, speed = 1.0, blend = 0.2) {
|
||||
if (s == state) return;
|
||||
state = s;
|
||||
anim.play(s, null, blend, speed);
|
||||
}
|
||||
#end
|
||||
}
|
||||
71
first_person/Sources/lnx/GunController.hx
Normal file
@ -0,0 +1,71 @@
|
||||
package lnx;
|
||||
|
||||
import iron.Trait;
|
||||
import iron.system.Input;
|
||||
import iron.object.Object;
|
||||
import iron.object.Transform;
|
||||
import iron.system.Audio;
|
||||
import iron.system.Time;
|
||||
import leenkx.trait.physics.RigidBody;
|
||||
|
||||
@:keep
|
||||
class GunController extends Trait {
|
||||
|
||||
#if (!lnx_physics)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
@prop
|
||||
public var fireFreq = 0.2;
|
||||
|
||||
var firePoint:Transform;
|
||||
var fireStrength = 25;
|
||||
var lastFire = 0.0;
|
||||
|
||||
var soundFire0:kha.Sound = null;
|
||||
var soundFire1:kha.Sound = null;
|
||||
var soundsLoaded = 0;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
iron.data.Data.getSound("fire0.wav", function(sound:kha.Sound) { soundFire0 = sound; soundsLoaded++; });
|
||||
iron.data.Data.getSound("fire1.wav", function(sound:kha.Sound) { soundFire1 = sound; soundsLoaded++; });
|
||||
|
||||
notifyOnInit(function() {
|
||||
firePoint = object.getChild("ProjectileSpawn").transform;
|
||||
});
|
||||
|
||||
notifyOnUpdate(function() {
|
||||
var mouse = Input.getMouse();
|
||||
lastFire += Time.delta;
|
||||
if ((mouse.down("left") && lastFire > fireFreq) || mouse.started("left")) {
|
||||
shoot();
|
||||
if (soundsLoaded == 2) {
|
||||
Audio.play(Std.random(3) == 0 ? soundFire1 : soundFire0);
|
||||
}
|
||||
lastFire = 0.0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function shoot() {
|
||||
// Spawn projectile
|
||||
iron.Scene.active.spawnObject("Projectile", null, function(o:Object) {
|
||||
o.transform.loc.x = firePoint.worldx();
|
||||
o.transform.loc.y = firePoint.worldy();
|
||||
o.transform.loc.z = firePoint.worldz();
|
||||
o.transform.buildMatrix();
|
||||
// Apply force
|
||||
var rb:RigidBody = o.getTrait(RigidBody);
|
||||
rb.syncTransform();
|
||||
var look = object.transform.look().normalize();
|
||||
rb.setLinearVelocity(look.x * fireStrength, look.y * fireStrength, look.z * fireStrength);
|
||||
// Remove projectile after a period of time
|
||||
kha.Scheduler.addTimeTask(function() {
|
||||
o.remove();
|
||||
}, 10);
|
||||
});
|
||||
}
|
||||
#end
|
||||
}
|
||||
BIN
first_person/first_person.blend
Normal file
BIN
platformer/Assets/checker_rough.png
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
platformer/Assets/finger.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
platformer/Assets/grid.png
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
platformer/Assets/grid_b.png
Normal file
|
After Width: | Height: | Size: 672 B |
1
platformer/Bundled/canvas/MyCanvas.json
Normal file
@ -0,0 +1 @@
|
||||
{"name":"untitled","x":0,"y":0,"width":960,"height":540,"elements":[{"id":0,"type":0,"name":"Gems","event":"","x":0,"y":0,"width":150,"height":44,"rotation":0,"text":"0","color":-1,"anchor":0,"parent":null,"children":[],"visible":true}],"assets":[]}
|
||||
BIN
platformer/Bundled/coin.wav
Normal file
BIN
platformer/Bundled/step0.wav
Normal file
BIN
platformer/Bundled/step1.wav
Normal file
41
platformer/Sources/lnx/GemTrait.hx
Normal file
@ -0,0 +1,41 @@
|
||||
package lnx;
|
||||
|
||||
class GemTrait extends iron.Trait {
|
||||
|
||||
static var gemsCollected = 0;
|
||||
static var player:iron.object.Object = null;
|
||||
static var coinSound:kha.Sound = null;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
if (coinSound == null) {
|
||||
notifyOnInit(function() {
|
||||
iron.data.Data.getSound("coin.wav", function(sound:kha.Sound) {
|
||||
coinSound = sound;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
notifyOnUpdate(function() {
|
||||
object.transform.rotate(iron.math.Vec4.zAxis(), 0.05);
|
||||
|
||||
if (player == null) player = iron.Scene.active.getChild("Player");
|
||||
var w1 = object.transform.world;
|
||||
var w2 = player.transform.world;
|
||||
var d = iron.math.Vec4.distance(w1.getLoc(), w2.getLoc());
|
||||
|
||||
// Collect gem
|
||||
if (d < 0.8) {
|
||||
gemsCollected++;
|
||||
object.remove();
|
||||
|
||||
// Update UI
|
||||
var canvas = iron.Scene.active.getTrait(leenkx.trait.internal.CanvasScript);
|
||||
canvas.getElement("Gems").text = gemsCollected + "";
|
||||
|
||||
if (coinSound != null) iron.system.Audio.play(coinSound);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
153
platformer/Sources/lnx/ThirdPersonController.hx
Normal file
@ -0,0 +1,153 @@
|
||||
package lnx;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Mat4;
|
||||
import iron.system.Input;
|
||||
import iron.object.Object;
|
||||
import iron.object.BoneAnimation;
|
||||
import iron.system.Time;
|
||||
import iron.system.Audio;
|
||||
import leenkx.trait.physics.PhysicsWorld;
|
||||
import leenkx.trait.internal.CameraController;
|
||||
|
||||
class ThirdPersonController extends CameraController {
|
||||
|
||||
#if (!lnx_physics)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
static inline var rotationSpeed = 1.0;
|
||||
|
||||
var stepTime = 0.0;
|
||||
var soundStep0:kha.Sound = null;
|
||||
var soundStep1:kha.Sound = null;
|
||||
var soundsLoaded = 0;
|
||||
|
||||
var xVec = Vec4.xAxis();
|
||||
var zVec = Vec4.zAxis();
|
||||
var nextFrameRot = 0.0;
|
||||
var armature:Object;
|
||||
var anim:BoneAnimation;
|
||||
|
||||
var speed = 1.0;
|
||||
var dir = new Vec4();
|
||||
var state = "idle";
|
||||
var jumping = false;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
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(function() {
|
||||
PhysicsWorld.active.notifyOnPreUpdate(preUpdate);
|
||||
notifyOnUpdate(update);
|
||||
|
||||
notifyOnRemove(function() {
|
||||
PhysicsWorld.active.removePreUpdate(preUpdate);
|
||||
});
|
||||
|
||||
armature = object.getChild("Armature");
|
||||
anim = findAnimation(armature);
|
||||
});
|
||||
}
|
||||
|
||||
function findAnimation(o:Object):BoneAnimation {
|
||||
if (o.animation != null) return cast o.animation;
|
||||
for (c in o.children) {
|
||||
var co = findAnimation(c);
|
||||
if (co != null) return co;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function preUpdate() {
|
||||
if (Input.occupied || !body.ready) return;
|
||||
|
||||
var mouse = Input.getMouse();
|
||||
var kb = Input.getKeyboard();
|
||||
|
||||
if (mouse.started() && !mouse.locked) mouse.lock();
|
||||
else if (kb.started("escape") && mouse.locked) mouse.unlock();
|
||||
|
||||
if (nextFrameRot != 0.0) {
|
||||
var origin = object.getChild("CameraOrigin");
|
||||
origin.transform.rotate(xVec, nextFrameRot);
|
||||
origin.transform.buildMatrix();
|
||||
}
|
||||
nextFrameRot = 0;
|
||||
|
||||
if (mouse.moved) {
|
||||
nextFrameRot = -mouse.movementY / 250 * rotationSpeed;
|
||||
transform.rotate(zVec, -mouse.movementX / 250 * rotationSpeed);
|
||||
}
|
||||
|
||||
body.syncTransform();
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (!body.ready) return;
|
||||
|
||||
var kb = iron.system.Input.getKeyboard();
|
||||
|
||||
// Move
|
||||
dir.set(0, 0, 0);
|
||||
if (moveForward) dir.add(transform.look());
|
||||
if (moveBackward) dir.add(transform.look().mult(-1));
|
||||
if (moveLeft) dir.add(transform.right().mult(-1));
|
||||
if (moveRight) dir.add(transform.right());
|
||||
|
||||
// Push down
|
||||
var btvec = body.getLinearVelocity();
|
||||
body.setLinearVelocity(0.0, 0.0, btvec.z - 1.0);
|
||||
|
||||
if (moveForward || moveBackward || moveLeft || moveRight) {
|
||||
var action = moveForward ? "run" :
|
||||
moveBackward ? "back" :
|
||||
moveLeft ? "left" : "right";
|
||||
setState(action);
|
||||
|
||||
if (kb.down("shift")) speed = 1.6;
|
||||
else speed = 1.0;
|
||||
|
||||
dir.mult(speed * 5);
|
||||
body.activate();
|
||||
body.setLinearVelocity(dir.x, dir.y, btvec.z - 1.0);
|
||||
|
||||
stepTime += Time.delta;
|
||||
if (stepTime > 0.38 / speed) {
|
||||
stepTime = 0;
|
||||
if (soundsLoaded == 2) {
|
||||
Audio.play(Std.random(2) == 0 ? soundStep0 : soundStep1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Play correct state
|
||||
else {
|
||||
setState("idle", 1.0);
|
||||
}
|
||||
|
||||
if (jump && !jumping) {
|
||||
jumping = true;
|
||||
state = "jump";
|
||||
body.applyImpulse(new Vec4(0, 0, 20));
|
||||
anim.time = 0;
|
||||
anim.frameIndex = 0;
|
||||
// anim.play(state, function() { jumping = false; }, 0.0, 1.2);
|
||||
iron.system.Tween.timer(0.5, () -> jumping = false);
|
||||
}
|
||||
|
||||
// Keep vertical
|
||||
body.setAngularFactor(0, 0, 0);
|
||||
camera.buildMatrix();
|
||||
}
|
||||
|
||||
function setState(s:String, speed = 1.0, blend = 0.2) {
|
||||
if (s == state || jumping) return;
|
||||
state = s;
|
||||
anim.play(s, null, blend, speed);
|
||||
}
|
||||
#end
|
||||
}
|
||||
BIN
platformer/platformer.blend
Normal file
BIN
race_track/Assets/checker_rough.png
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
race_track/Assets/finger.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
race_track/Assets/grid.png
Normal file
|
After Width: | Height: | Size: 409 B |
BIN
race_track/Assets/grid_b.png
Normal file
|
After Width: | Height: | Size: 672 B |
0
race_track/Bundled/canvas/MyCanvas.files
Normal file
1
race_track/Bundled/canvas/MyCanvas.json
Normal file
@ -0,0 +1 @@
|
||||
{"name":"untitled","x":0,"y":0,"width":1280,"height":720,"elements":[{"id":15,"type":9,"name":"MenuContainer","event":"","x":935,"y":61,"width":332,"height":402,"rotation":0,"text":"My Shape","asset":"","color":-1258291200,"anchor":5,"parent":null,"children":[2,3,6,8,11,12,13,14],"visible":true},{"id":2,"type":6,"name":"SSR","event":"","x":24,"y":179,"width":150,"height":44,"rotation":0,"text":"SSR","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":3,"type":6,"name":"SSAO","event":"","x":24,"y":229,"width":150,"height":44,"rotation":0,"text":"SSAO","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":6,"type":6,"name":"Bloom","event":"","x":24,"y":129,"width":150,"height":44,"rotation":0,"text":"Bloom","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":8,"type":8,"name":"Shadows","event":"","x":24,"y":79,"width":150,"height":44,"rotation":0,"text":"High;Medium;Low","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":11,"type":0,"name":"Title","event":"","x":4,"y":9,"width":377,"height":44,"rotation":0,"text":"Graphics Settings","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":12,"type":0,"name":"ShadowsTitle","event":"","x":164,"y":79,"width":184,"height":28,"rotation":0,"text":"Shadows","asset":"","color":-6381922,"anchor":0,"parent":15,"children":[],"visible":true},{"id":13,"type":2,"name":"Apply","event":"apply_settings","x":24,"y":329,"width":150,"height":44,"rotation":0,"text":"Apply","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":14,"type":6,"name":"Voxels","event":"","x":24,"y":279,"width":150,"height":44,"rotation":0,"text":"Voxels","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":16,"type":2,"name":"Menu","event":"toggle_menu","x":1120,"y":5,"width":150,"height":44,"rotation":0,"text":"Menu","asset":"","color":-1,"anchor":2,"parent":null,"children":[],"visible":true},{"id":17,"type":0,"name":"Time","event":"","x":0,"y":0,"width":202,"height":65,"rotation":0,"text":"0:0","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true}],"assets":[]}
|
||||
68
race_track/Sources/lnx/SettingsTrait.hx
Normal file
@ -0,0 +1,68 @@
|
||||
package lnx;
|
||||
|
||||
import iron.Scene;
|
||||
import leenkx.system.Event;
|
||||
import leenkx.data.Config;
|
||||
import leenkx.trait.internal.CanvasScript;
|
||||
import leenkx.renderpath.RenderPathCreator;
|
||||
|
||||
class SettingsTrait extends iron.Trait {
|
||||
|
||||
var canvas:CanvasScript;
|
||||
var envStrength = 0.0;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
notifyOnInit(function() {
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
|
||||
// Init UI to values loaded from config.lnx file
|
||||
canvas.notifyOnReady(function() {
|
||||
canvas.getElement("MenuContainer").visible = false;
|
||||
canvas.getHandle("SSAO").selected = Config.raw.rp_ssgi;
|
||||
canvas.getHandle("SSR").selected = Config.raw.rp_ssr;
|
||||
canvas.getHandle("Bloom").selected = Config.raw.rp_bloom;
|
||||
canvas.getHandle("Voxels").selected = Config.raw.rp_gi;
|
||||
canvas.getHandle("Shadows").position = getShadowQuality(Config.raw.rp_shadowmap_cascade);
|
||||
});
|
||||
|
||||
// Button events
|
||||
Event.add("toggle_menu", toggleMenu);
|
||||
Event.add("apply_settings", applySettings);
|
||||
});
|
||||
}
|
||||
|
||||
function toggleMenu() {
|
||||
var e = canvas.getElement("MenuContainer");
|
||||
e.visible = !e.visible;
|
||||
}
|
||||
|
||||
function applySettings() {
|
||||
|
||||
// Apply render path settings
|
||||
Config.raw.rp_ssgi = canvas.getHandle("SSAO").selected;
|
||||
Config.raw.rp_ssr = canvas.getHandle("SSR").selected;
|
||||
Config.raw.rp_bloom = canvas.getHandle("Bloom").selected;
|
||||
Config.raw.rp_gi = canvas.getHandle("Voxels").selected;
|
||||
Config.raw.rp_shadowmap_cascade = getShadowMapSize(canvas.getHandle("Shadows").position);
|
||||
RenderPathCreator.applyConfig();
|
||||
|
||||
// Lower envmap strength when voxel ao is disabled
|
||||
var p = iron.Scene.active.world.probe.raw;
|
||||
if (envStrength == 0) envStrength = p.strength;
|
||||
p.strength = Config.raw.rp_gi ? envStrength : envStrength / 3;
|
||||
|
||||
// Save config.lnx file
|
||||
Config.save();
|
||||
}
|
||||
|
||||
inline function getShadowQuality(i:Int):Int {
|
||||
// 0 - High, 1 - Medium, 2 - Low
|
||||
return i == 4096 ? 0 : i == 2048 ? 1 : 2;
|
||||
}
|
||||
|
||||
inline function getShadowMapSize(i:Int):Int {
|
||||
return i == 0 ? 4096 : i == 1 ? 2048 : 1024;
|
||||
}
|
||||
}
|
||||
55
race_track/Sources/lnx/TrackTimer.hx
Normal file
@ -0,0 +1,55 @@
|
||||
package lnx;
|
||||
|
||||
import iron.Scene;
|
||||
import iron.object.Transform;
|
||||
using leenkx.object.TransformExtension;
|
||||
|
||||
class TrackTimer extends iron.Trait {
|
||||
|
||||
var time = 0.0;
|
||||
var running = false;
|
||||
var finished = false;
|
||||
var triggers:Array<Transform> = [];
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
notifyOnInit(function() {
|
||||
var canvas = Scene.active.getTrait(leenkx.trait.internal.CanvasScript);
|
||||
var t = object.transform;
|
||||
|
||||
// Retrieve triggers
|
||||
var t0 = Scene.active.getChild("Trigger0").transform; // Start line
|
||||
var t1 = Scene.active.getChild("Trigger1").transform;
|
||||
var t2 = Scene.active.getChild("Trigger2").transform;
|
||||
var t3 = Scene.active.getChild("Trigger3").transform;
|
||||
|
||||
notifyOnUpdate(function() {
|
||||
|
||||
if (!running && !finished) {
|
||||
// Start line crossed, begin lap
|
||||
running = t.overlap(t0);
|
||||
}
|
||||
else {
|
||||
// Update timer
|
||||
if (!finished) {
|
||||
time += iron.system.Time.delta;
|
||||
var s = Std.int(time);
|
||||
var ms = Std.int((time - s) * 100);
|
||||
canvas.getElement("Time").text = s + "." + ms;
|
||||
}
|
||||
|
||||
// Mark touched triggers
|
||||
if (t.overlap(t1) && triggers.indexOf(t1) == -1) triggers.push(t1);
|
||||
if (t.overlap(t2) && triggers.indexOf(t2) == -1) triggers.push(t2);
|
||||
if (t.overlap(t3) && triggers.indexOf(t3) == -1) triggers.push(t3);
|
||||
|
||||
// Crossed finish line
|
||||
if (t.overlap(t0) && triggers.length == 3) {
|
||||
finished = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
BIN
race_track/race_track.blend
Normal file
BIN
third_person/Assets/aim.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
third_person/Assets/checker_rough.png
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
third_person/Assets/decal1.png
Normal file
|
After Width: | Height: | Size: 109 KiB |
BIN
third_person/Assets/decal2.png
Normal file
|
After Width: | Height: | Size: 129 KiB |
BIN
third_person/Assets/finger.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
third_person/Assets/grid.png
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
third_person/Assets/grid_b.png
Normal file
|
After Width: | Height: | Size: 672 B |
1
third_person/Bundled/canvas/MyCanvas.files
Normal file
@ -0,0 +1 @@
|
||||
../../Assets/aim.png
|
||||
1
third_person/Bundled/canvas/MyCanvas.json
Normal file
@ -0,0 +1 @@
|
||||
{"name":"untitled","x":0,"y":0,"width":1920,"height":1080,"elements":[{"id":1,"type":1,"name":"Crosshair","event":"","x":0,"y":0,"width":60,"height":60,"rotation":0,"text":"","asset":"aim.png","progress_at":0,"progress_total":100,"strength":1,"alignment":0,"anchor":4,"parent":null,"children":[],"visible":true}],"assets":[{"name":"aim.png","file":"../../Assets/aim.png","id":0}],"theme":"Default Light"}
|
||||
BIN
third_person/Bundled/fire0.wav
Normal file
BIN
third_person/Bundled/fire1.wav
Normal file
BIN
third_person/Bundled/step0.wav
Normal file
BIN
third_person/Bundled/step1.wav
Normal file
71
third_person/Sources/lnx/GunController.hx
Normal file
@ -0,0 +1,71 @@
|
||||
package lnx;
|
||||
|
||||
import iron.Trait;
|
||||
import iron.system.Input;
|
||||
import iron.object.Object;
|
||||
import iron.object.Transform;
|
||||
import iron.system.Audio;
|
||||
import iron.system.Time;
|
||||
import leenkx.trait.physics.RigidBody;
|
||||
|
||||
@:keep
|
||||
class GunController extends Trait {
|
||||
|
||||
#if (!lnx_physics)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
@prop
|
||||
public var fireFreq = 0.2;
|
||||
|
||||
var firePoint:Transform;
|
||||
var fireStrength = 25;
|
||||
var lastFire = 0.0;
|
||||
|
||||
var soundFire0:kha.Sound = null;
|
||||
var soundFire1:kha.Sound = null;
|
||||
var soundsLoaded = 0;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
iron.data.Data.getSound("fire0.wav", function(sound:kha.Sound) { soundFire0 = sound; soundsLoaded++; });
|
||||
iron.data.Data.getSound("fire1.wav", function(sound:kha.Sound) { soundFire1 = sound; soundsLoaded++; });
|
||||
|
||||
notifyOnInit(function() {
|
||||
firePoint = object.getChild("ProjectileSpawn").transform;
|
||||
});
|
||||
|
||||
notifyOnUpdate(function() {
|
||||
var mouse = Input.getMouse();
|
||||
lastFire += Time.delta;
|
||||
if ((mouse.down("left") && lastFire > fireFreq) || mouse.started("left")) {
|
||||
shoot();
|
||||
if (soundsLoaded == 2) {
|
||||
Audio.play(Std.random(3) == 0 ? soundFire1 : soundFire0);
|
||||
}
|
||||
lastFire = 0.0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function shoot() {
|
||||
// Spawn projectile
|
||||
iron.Scene.active.spawnObject("Projectile", null, function(o:Object) {
|
||||
o.transform.loc.x = firePoint.worldx();
|
||||
o.transform.loc.y = firePoint.worldy();
|
||||
o.transform.loc.z = firePoint.worldz();
|
||||
o.transform.buildMatrix();
|
||||
// Apply force
|
||||
var rb:RigidBody = o.getTrait(RigidBody);
|
||||
rb.syncTransform();
|
||||
var look = object.transform.look().normalize();
|
||||
rb.setLinearVelocity(look.x * fireStrength, look.y * fireStrength, look.z * fireStrength);
|
||||
// Remove projectile after a period of time
|
||||
kha.Scheduler.addTimeTask(function() {
|
||||
o.remove();
|
||||
}, 10);
|
||||
});
|
||||
}
|
||||
#end
|
||||
}
|
||||
264
third_person/Sources/lnx/ThirdPersonController.hx
Normal file
@ -0,0 +1,264 @@
|
||||
package lnx;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Mat4;
|
||||
import iron.system.Input;
|
||||
import iron.object.Object;
|
||||
import iron.object.BoneAnimation;
|
||||
import iron.system.Time;
|
||||
import iron.system.Audio;
|
||||
import leenkx.trait.physics.PhysicsWorld;
|
||||
import leenkx.trait.internal.CameraController;
|
||||
|
||||
class ThirdPersonController extends CameraController {
|
||||
|
||||
#if (!lnx_physics)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
static inline var rotationSpeed = 1.0;
|
||||
|
||||
var stepTime = 0.0;
|
||||
var turnTime = 0.0;
|
||||
|
||||
var soundStep0:kha.Sound = null;
|
||||
var soundStep1:kha.Sound = null;
|
||||
var soundsLoaded = 0;
|
||||
|
||||
var xVec = Vec4.xAxis();
|
||||
var zVec = Vec4.zAxis();
|
||||
var angle = 0.0;
|
||||
var nextFrameRot = 0.0;
|
||||
var armature:Object;
|
||||
var anim:BoneAnimation;
|
||||
var q = new Quat();
|
||||
var mat = Mat4.identity();
|
||||
|
||||
var nextIdle = false;
|
||||
var firingTime = 0.0;
|
||||
var speed = 1.0;
|
||||
var dir = new Vec4();
|
||||
var lastLook:Vec4;
|
||||
var state = "idle";
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
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(function() {
|
||||
PhysicsWorld.active.notifyOnPreUpdate(preUpdate);
|
||||
notifyOnUpdate(update);
|
||||
|
||||
notifyOnRemove(function() {
|
||||
PhysicsWorld.active.removePreUpdate(preUpdate);
|
||||
});
|
||||
|
||||
armature = object.getChild("Armature");
|
||||
anim = findAnimation(armature);
|
||||
anim.notifyOnUpdate(updateBones);
|
||||
lastLook = armature.transform.look().normalize();
|
||||
});
|
||||
}
|
||||
|
||||
function findAnimation(o:Object):BoneAnimation {
|
||||
if (o.animation != null) return cast o.animation;
|
||||
for (c in o.children) {
|
||||
var co = findAnimation(c);
|
||||
if (co != null) return co;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function updateBones() {
|
||||
|
||||
// Fetch bone
|
||||
var bone1 = anim.getBone("mixamorig:LeftForeLnx");
|
||||
var bone2 = anim.getBone("mixamorig:RightForeLnx");
|
||||
|
||||
// Fetch bone matrix - this is in local bone space for now
|
||||
var m1 = anim.getBoneMat(bone1);
|
||||
var m2 = anim.getBoneMat(bone2);
|
||||
var m1b = anim.getBoneMatBlend(bone1);
|
||||
var m2b = anim.getBoneMatBlend(bone2);
|
||||
var a1 = anim.getAbsMat(bone1.parent);
|
||||
var a2 = anim.getAbsMat(bone2.parent);
|
||||
|
||||
// Rotate hand bones to aim with gun
|
||||
// Some raw math follows..
|
||||
var tx = m1._30;
|
||||
var ty = m1._31;
|
||||
var tz = m1._32;
|
||||
m1._30 = 0;
|
||||
m1._31 = 0;
|
||||
m1._32 = 0;
|
||||
mat.getInverse(a1);
|
||||
q.fromAxisAngle(mat.right(), -angle);
|
||||
m1.applyQuat(q);
|
||||
m1._30 = tx;
|
||||
m1._31 = ty;
|
||||
m1._32 = tz;
|
||||
|
||||
var tx = m2._30;
|
||||
var ty = m2._31;
|
||||
var tz = m2._32;
|
||||
m2._30 = 0;
|
||||
m2._31 = 0;
|
||||
m2._32 = 0;
|
||||
mat.getInverse(a2);
|
||||
var v = mat.right();
|
||||
v.mult(-1);
|
||||
q.fromAxisAngle(v, angle);
|
||||
m2.applyQuat(q);
|
||||
m2._30 = tx;
|
||||
m2._31 = ty;
|
||||
m2._32 = tz;
|
||||
|
||||
// Animation blending is in progress, we need to rotate those bones too
|
||||
if (m1b != null && m2b != null) {
|
||||
var tx = m1b._30;
|
||||
var ty = m1b._31;
|
||||
var tz = m1b._32;
|
||||
m1b._30 = 0;
|
||||
m1b._31 = 0;
|
||||
m1b._32 = 0;
|
||||
mat.getInverse(a1);
|
||||
q.fromAxisAngle(mat.right(), -angle);
|
||||
m1b.applyQuat(q);
|
||||
m1b._30 = tx;
|
||||
m1b._31 = ty;
|
||||
m1b._32 = tz;
|
||||
|
||||
var tx = m2b._30;
|
||||
var ty = m2b._31;
|
||||
var tz = m2b._32;
|
||||
m2b._30 = 0;
|
||||
m2b._31 = 0;
|
||||
m2b._32 = 0;
|
||||
mat.getInverse(a2);
|
||||
var v = mat.right();
|
||||
v.mult(-1);
|
||||
q.fromAxisAngle(v, angle);
|
||||
m2b.applyQuat(q);
|
||||
m2b._30 = tx;
|
||||
m2b._31 = ty;
|
||||
m2b._32 = tz;
|
||||
}
|
||||
}
|
||||
|
||||
function preUpdate() {
|
||||
if (Input.occupied || !body.ready) return;
|
||||
|
||||
var mouse = Input.getMouse();
|
||||
var kb = Input.getKeyboard();
|
||||
|
||||
if (mouse.started() && !mouse.locked) mouse.lock();
|
||||
else if (kb.started("escape") && mouse.locked) mouse.unlock();
|
||||
|
||||
if (nextFrameRot != 0.0) {
|
||||
var origin = object.getChild("CameraOrigin");
|
||||
origin.transform.rotate(xVec, nextFrameRot);
|
||||
origin.transform.buildMatrix();
|
||||
}
|
||||
nextFrameRot = 0;
|
||||
|
||||
if (mouse.moved) {
|
||||
var d = mouse.movementY / 250;
|
||||
if (angle + d > 1.5) return;
|
||||
if (angle + d < -0.25) return;
|
||||
angle += d;
|
||||
nextFrameRot = -mouse.movementY / 250 * rotationSpeed;
|
||||
}
|
||||
|
||||
if (mouse.moved) transform.rotate(zVec, -mouse.movementX / 250 * rotationSpeed);
|
||||
body.syncTransform();
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (!body.ready) return;
|
||||
var look = armature.transform.look().normalize();
|
||||
|
||||
// Move
|
||||
dir.set(0, 0, 0);
|
||||
if (moveForward) dir.add(transform.look());
|
||||
if (moveBackward) dir.add(transform.look().mult(-1));
|
||||
if (moveLeft) dir.add(transform.right().mult(-1));
|
||||
if (moveRight) dir.add(transform.right());
|
||||
|
||||
// Push down
|
||||
var btvec = body.getLinearVelocity();
|
||||
body.setLinearVelocity(0.0, 0.0, btvec.z - 1.0);
|
||||
|
||||
if (moveForward || moveBackward || moveLeft || moveRight) {
|
||||
var action = moveForward ? "run" :
|
||||
moveBackward ? "back" :
|
||||
moveLeft ? "left" : "right";
|
||||
setState(action);
|
||||
|
||||
var kb = iron.system.Input.getKeyboard();
|
||||
if (kb.down("shift")) speed = 1.6;
|
||||
else speed = 1.0;
|
||||
|
||||
dir.mult(speed * 5);
|
||||
body.activate();
|
||||
body.setLinearVelocity(dir.x, dir.y, btvec.z - 1.0);
|
||||
|
||||
stepTime += Time.delta;
|
||||
if (stepTime > 0.38 / speed) {
|
||||
stepTime = 0;
|
||||
if (soundsLoaded == 2) {
|
||||
Audio.play(Std.random(2) == 0 ? soundStep0 : soundStep1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Play correct state
|
||||
else if (state != "fire" || state != "idle" || state != "turn") {
|
||||
var mouse = iron.system.Input.getMouse();
|
||||
if (mouse.down("left")) {
|
||||
firingTime = 0.0;
|
||||
setState("fire", 2.0);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == "fire") firingTime += Time.delta;
|
||||
else firingTime = 0.0;
|
||||
|
||||
// Keep vertical
|
||||
body.setAngularFactor(0, 0, 0);
|
||||
camera.buildMatrix();
|
||||
|
||||
lastLook.setFrom(look);
|
||||
}
|
||||
|
||||
// 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 setState(s:String, speed = 1.0, blend = 0.2) {
|
||||
if (s == state) return;
|
||||
state = s;
|
||||
anim.play(s, null, blend, speed);
|
||||
}
|
||||
#end
|
||||
}
|
||||
BIN
third_person/third_person.blend
Normal file
BIN
third_person_terrain/Assets/aim.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
third_person_terrain/Assets/checker_rough.png
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
third_person_terrain/Assets/finger.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
third_person_terrain/Assets/grid.png
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
third_person_terrain/Assets/grid_b.png
Normal file
|
After Width: | Height: | Size: 672 B |
1
third_person_terrain/Bundled/canvas/MyCanvas.files
Normal file
@ -0,0 +1 @@
|
||||
../../Assets/aim.png
|
||||
1
third_person_terrain/Bundled/canvas/MyCanvas.json
Normal file
@ -0,0 +1 @@
|
||||
{"name":"untitled","x":0,"y":0,"width":1920,"height":1080,"elements":[{"id":0,"type":1,"name":"Image","event":"","x":0,"y":0,"width":60,"height":60,"rotation":0,"text":"Image","asset":"aim.png","progress_at":0,"progress_total":100,"strength":1,"alignment":0,"anchor":4,"parent":null,"children":[],"visible":true}],"assets":[{"name":"aim.png","file":"../../Assets/aim.png","id":0}],"theme":"Default Light"}
|
||||
BIN
third_person_terrain/Bundled/fire0.wav
Normal file
BIN
third_person_terrain/Bundled/fire1.wav
Normal file
BIN
third_person_terrain/Bundled/slices/heightmap_01.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
third_person_terrain/Bundled/step0.wav
Normal file
BIN
third_person_terrain/Bundled/step1.wav
Normal file
2
third_person_terrain/README.md
Normal file
@ -0,0 +1,2 @@
|
||||
Please check the following example to learn about the terrain construction:
|
||||
https://github.com/leenkx3d/leenkx_examples/terrain
|
||||
71
third_person_terrain/Sources/lnx/GunController.hx
Normal file
@ -0,0 +1,71 @@
|
||||
package lnx;
|
||||
|
||||
import iron.Trait;
|
||||
import iron.system.Input;
|
||||
import iron.object.Object;
|
||||
import iron.object.Transform;
|
||||
import iron.system.Audio;
|
||||
import iron.system.Time;
|
||||
import leenkx.trait.physics.RigidBody;
|
||||
|
||||
@:keep
|
||||
class GunController extends Trait {
|
||||
|
||||
#if (!lnx_physics)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
@prop
|
||||
public var fireFreq = 0.2;
|
||||
|
||||
var firePoint:Transform;
|
||||
var fireStrength = 25;
|
||||
var lastFire = 0.0;
|
||||
|
||||
var soundFire0:kha.Sound = null;
|
||||
var soundFire1:kha.Sound = null;
|
||||
var soundsLoaded = 0;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
iron.data.Data.getSound("fire0.wav", function(sound:kha.Sound) { soundFire0 = sound; soundsLoaded++; });
|
||||
iron.data.Data.getSound("fire1.wav", function(sound:kha.Sound) { soundFire1 = sound; soundsLoaded++; });
|
||||
|
||||
notifyOnInit(function() {
|
||||
firePoint = object.getChild("ProjectileSpawn").transform;
|
||||
});
|
||||
|
||||
notifyOnUpdate(function() {
|
||||
var mouse = Input.getMouse();
|
||||
lastFire += Time.delta;
|
||||
if ((mouse.down("left") && lastFire > fireFreq) || mouse.started("left")) {
|
||||
shoot();
|
||||
if (soundsLoaded == 2) {
|
||||
Audio.play(Std.random(3) == 0 ? soundFire1 : soundFire0);
|
||||
}
|
||||
lastFire = 0.0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function shoot() {
|
||||
// Spawn projectile
|
||||
iron.Scene.active.spawnObject("Projectile", null, function(o:Object) {
|
||||
o.transform.loc.x = firePoint.worldx();
|
||||
o.transform.loc.y = firePoint.worldy();
|
||||
o.transform.loc.z = firePoint.worldz();
|
||||
o.transform.buildMatrix();
|
||||
// Apply force
|
||||
var rb:RigidBody = o.getTrait(RigidBody);
|
||||
rb.syncTransform();
|
||||
var look = object.transform.look().normalize();
|
||||
rb.setLinearVelocity(look.x * fireStrength, look.y * fireStrength, look.z * fireStrength);
|
||||
// Remove projectile after a period of time
|
||||
kha.Scheduler.addTimeTask(function() {
|
||||
o.remove();
|
||||
}, 10);
|
||||
});
|
||||
}
|
||||
#end
|
||||
}
|
||||
264
third_person_terrain/Sources/lnx/ThirdPersonController.hx
Normal file
@ -0,0 +1,264 @@
|
||||
package lnx;
|
||||
|
||||
import iron.math.Vec4;
|
||||
import iron.math.Quat;
|
||||
import iron.math.Mat4;
|
||||
import iron.system.Input;
|
||||
import iron.object.Object;
|
||||
import iron.object.BoneAnimation;
|
||||
import iron.system.Time;
|
||||
import iron.system.Audio;
|
||||
import leenkx.trait.physics.PhysicsWorld;
|
||||
import leenkx.trait.internal.CameraController;
|
||||
|
||||
class ThirdPersonController extends CameraController {
|
||||
|
||||
#if (!lnx_physics)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
static inline var rotationSpeed = 1.0;
|
||||
|
||||
var stepTime = 0.0;
|
||||
var turnTime = 0.0;
|
||||
|
||||
var soundStep0:kha.Sound = null;
|
||||
var soundStep1:kha.Sound = null;
|
||||
var soundsLoaded = 0;
|
||||
|
||||
var xVec = Vec4.xAxis();
|
||||
var zVec = Vec4.zAxis();
|
||||
var angle = 0.0;
|
||||
var nextFrameRot = 0.0;
|
||||
var armature:Object;
|
||||
var anim:BoneAnimation;
|
||||
var q = new Quat();
|
||||
var mat = Mat4.identity();
|
||||
|
||||
var nextIdle = false;
|
||||
var firingTime = 0.0;
|
||||
var speed = 1.0;
|
||||
var dir = new Vec4();
|
||||
var lastLook:Vec4;
|
||||
var state = "idle";
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
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(function() {
|
||||
PhysicsWorld.active.notifyOnPreUpdate(preUpdate);
|
||||
notifyOnUpdate(update);
|
||||
|
||||
notifyOnRemove(function() {
|
||||
PhysicsWorld.active.removePreUpdate(preUpdate);
|
||||
});
|
||||
|
||||
armature = object.getChild("Armature");
|
||||
anim = findAnimation(armature);
|
||||
anim.notifyOnUpdate(updateBones);
|
||||
lastLook = armature.transform.look().normalize();
|
||||
});
|
||||
}
|
||||
|
||||
function findAnimation(o:Object):BoneAnimation {
|
||||
if (o.animation != null) return cast o.animation;
|
||||
for (c in o.children) {
|
||||
var co = findAnimation(c);
|
||||
if (co != null) return co;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function updateBones() {
|
||||
|
||||
// Fetch bone
|
||||
var bone1 = anim.getBone("mixamorig:LeftForeLnx");
|
||||
var bone2 = anim.getBone("mixamorig:RightForeLnx");
|
||||
|
||||
// Fetch bone matrix - this is in local bone space for now
|
||||
var m1 = anim.getBoneMat(bone1);
|
||||
var m2 = anim.getBoneMat(bone2);
|
||||
var m1b = anim.getBoneMatBlend(bone1);
|
||||
var m2b = anim.getBoneMatBlend(bone2);
|
||||
var a1 = anim.getAbsMat(bone1.parent);
|
||||
var a2 = anim.getAbsMat(bone2.parent);
|
||||
|
||||
// Rotate hand bones to aim with gun
|
||||
// Some raw math follows..
|
||||
var tx = m1._30;
|
||||
var ty = m1._31;
|
||||
var tz = m1._32;
|
||||
m1._30 = 0;
|
||||
m1._31 = 0;
|
||||
m1._32 = 0;
|
||||
mat.getInverse(a1);
|
||||
q.fromAxisAngle(mat.right(), -angle);
|
||||
m1.applyQuat(q);
|
||||
m1._30 = tx;
|
||||
m1._31 = ty;
|
||||
m1._32 = tz;
|
||||
|
||||
var tx = m2._30;
|
||||
var ty = m2._31;
|
||||
var tz = m2._32;
|
||||
m2._30 = 0;
|
||||
m2._31 = 0;
|
||||
m2._32 = 0;
|
||||
mat.getInverse(a2);
|
||||
var v = mat.right();
|
||||
v.mult(-1);
|
||||
q.fromAxisAngle(v, angle);
|
||||
m2.applyQuat(q);
|
||||
m2._30 = tx;
|
||||
m2._31 = ty;
|
||||
m2._32 = tz;
|
||||
|
||||
// Animation blending is in progress, we need to rotate those bones too
|
||||
if (m1b != null && m2b != null) {
|
||||
var tx = m1b._30;
|
||||
var ty = m1b._31;
|
||||
var tz = m1b._32;
|
||||
m1b._30 = 0;
|
||||
m1b._31 = 0;
|
||||
m1b._32 = 0;
|
||||
mat.getInverse(a1);
|
||||
q.fromAxisAngle(mat.right(), -angle);
|
||||
m1b.applyQuat(q);
|
||||
m1b._30 = tx;
|
||||
m1b._31 = ty;
|
||||
m1b._32 = tz;
|
||||
|
||||
var tx = m2b._30;
|
||||
var ty = m2b._31;
|
||||
var tz = m2b._32;
|
||||
m2b._30 = 0;
|
||||
m2b._31 = 0;
|
||||
m2b._32 = 0;
|
||||
mat.getInverse(a2);
|
||||
var v = mat.right();
|
||||
v.mult(-1);
|
||||
q.fromAxisAngle(v, angle);
|
||||
m2b.applyQuat(q);
|
||||
m2b._30 = tx;
|
||||
m2b._31 = ty;
|
||||
m2b._32 = tz;
|
||||
}
|
||||
}
|
||||
|
||||
function preUpdate() {
|
||||
if (Input.occupied || !body.ready) return;
|
||||
|
||||
var mouse = Input.getMouse();
|
||||
var kb = Input.getKeyboard();
|
||||
|
||||
if (mouse.started() && !mouse.locked) mouse.lock();
|
||||
else if (kb.started("escape") && mouse.locked) mouse.unlock();
|
||||
|
||||
if (nextFrameRot != 0.0) {
|
||||
var origin = object.getChild("CameraOrigin");
|
||||
origin.transform.rotate(xVec, nextFrameRot);
|
||||
origin.transform.buildMatrix();
|
||||
}
|
||||
nextFrameRot = 0;
|
||||
|
||||
if (mouse.moved) {
|
||||
var d = mouse.movementY / 250;
|
||||
if (angle + d > 1.5) return;
|
||||
if (angle + d < -0.25) return;
|
||||
angle += d;
|
||||
nextFrameRot = -mouse.movementY / 250 * rotationSpeed;
|
||||
}
|
||||
|
||||
if (mouse.moved) transform.rotate(zVec, -mouse.movementX / 250 * rotationSpeed);
|
||||
body.syncTransform();
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (!body.ready) return;
|
||||
var look = armature.transform.look().normalize();
|
||||
|
||||
// Move
|
||||
dir.set(0, 0, 0);
|
||||
if (moveForward) dir.add(transform.look());
|
||||
if (moveBackward) dir.add(transform.look().mult(-1));
|
||||
if (moveLeft) dir.add(transform.right().mult(-1));
|
||||
if (moveRight) dir.add(transform.right());
|
||||
|
||||
// Push down
|
||||
var btvec = body.getLinearVelocity();
|
||||
body.setLinearVelocity(0.0, 0.0, btvec.z - 1.0);
|
||||
|
||||
if (moveForward || moveBackward || moveLeft || moveRight) {
|
||||
var action = moveForward ? "run" :
|
||||
moveBackward ? "back" :
|
||||
moveLeft ? "left" : "right";
|
||||
setState(action);
|
||||
|
||||
var kb = iron.system.Input.getKeyboard();
|
||||
if (kb.down("shift")) speed = 1.6;
|
||||
else speed = 1.0;
|
||||
|
||||
dir.mult(speed * 5);
|
||||
body.activate();
|
||||
body.setLinearVelocity(dir.x, dir.y, btvec.z - 1.0);
|
||||
|
||||
stepTime += Time.delta;
|
||||
if (stepTime > 0.38 / speed) {
|
||||
stepTime = 0;
|
||||
if (soundsLoaded == 2) {
|
||||
Audio.play(Std.random(2) == 0 ? soundStep0 : soundStep1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Play correct state
|
||||
else if (state != "fire" || state != "idle" || state != "turn") {
|
||||
var mouse = iron.system.Input.getMouse();
|
||||
if (mouse.down("left")) {
|
||||
firingTime = 0.0;
|
||||
setState("fire", 2.0);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == "fire") firingTime += Time.delta;
|
||||
else firingTime = 0.0;
|
||||
|
||||
// Keep vertical
|
||||
body.setAngularFactor(0, 0, 0);
|
||||
camera.buildMatrix();
|
||||
|
||||
lastLook.setFrom(look);
|
||||
}
|
||||
|
||||
// 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 setState(s:String, speed = 1.0, blend = 0.2) {
|
||||
if (s == state) return;
|
||||
state = s;
|
||||
anim.play(s, null, blend, speed);
|
||||
}
|
||||
#end
|
||||
}
|
||||
BIN
third_person_terrain/third_person_terrain.blend
Normal file
BIN
top_down/Assets/checker_rough.png
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
top_down/Assets/finger.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
top_down/Assets/grid.png
Normal file
|
After Width: | Height: | Size: 414 B |
BIN
top_down/Assets/grid_b.png
Normal file
|
After Width: | Height: | Size: 672 B |
0
top_down/Bundled/canvas/MyCanvas.files
Normal file
1
top_down/Bundled/canvas/MyCanvas.json
Normal file
@ -0,0 +1 @@
|
||||
{"name":"untitled","x":0,"y":0,"width":1280,"height":720,"elements":[{"id":15,"type":9,"name":"MenuContainer","event":"","x":10,"y":61,"width":332,"height":402,"rotation":0,"text":"My Shape","asset":"","color":-1258291200,"anchor":0,"parent":null,"children":[2,3,6,8,11,12,13,14],"visible":true},{"id":2,"type":6,"name":"SSR","event":"","x":24,"y":179,"width":150,"height":44,"rotation":0,"text":"SSR","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":3,"type":6,"name":"SSAO","event":"","x":24,"y":229,"width":150,"height":44,"rotation":0,"text":"SSAO","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":6,"type":6,"name":"Bloom","event":"","x":24,"y":129,"width":150,"height":44,"rotation":0,"text":"Bloom","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":8,"type":8,"name":"Shadows","event":"","x":24,"y":79,"width":150,"height":44,"rotation":0,"text":"High;Medium;Low","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":11,"type":0,"name":"Title","event":"","x":4,"y":9,"width":377,"height":44,"rotation":0,"text":"Graphics Settings","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":12,"type":0,"name":"ShadowsTitle","event":"","x":164,"y":79,"width":184,"height":28,"rotation":0,"text":"Shadows","asset":"","color":-6381922,"anchor":0,"parent":15,"children":[],"visible":true},{"id":13,"type":2,"name":"Apply","event":"apply_settings","x":24,"y":329,"width":150,"height":44,"rotation":0,"text":"Apply","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":14,"type":6,"name":"Voxels","event":"","x":24,"y":279,"width":150,"height":44,"rotation":0,"text":"Voxels","asset":"","color":-1,"anchor":0,"parent":15,"children":[],"visible":true},{"id":16,"type":2,"name":"Menu","event":"toggle_menu","x":5,"y":5,"width":150,"height":44,"rotation":0,"text":"Menu","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true}],"assets":[]}
|
||||
20
top_down/Bundled/config.lnx
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"rp_bloom": true,
|
||||
"rp_dynres": false,
|
||||
"rp_gi": true,
|
||||
"rp_motionblur": false,
|
||||
"rp_shadowmap_cascade": 2048,
|
||||
"rp_shadowmap_cube": 512,
|
||||
"rp_ssgi": true,
|
||||
"rp_ssr": true,
|
||||
"rp_supersample": 1.0,
|
||||
"window_h": 720,
|
||||
"window_maximizable": false,
|
||||
"window_minimizable": true,
|
||||
"window_mode": 0,
|
||||
"window_msaa": 1,
|
||||
"window_resizable": false,
|
||||
"window_scale": 1.0,
|
||||
"window_vsync": true,
|
||||
"window_w": 1280
|
||||
}
|
||||
BIN
top_down/Bundled/step0.wav
Normal file
BIN
top_down/Bundled/step1.wav
Normal file
BIN
top_down/Bundled/sword0.wav
Normal file
BIN
top_down/Bundled/sword1.wav
Normal file
136
top_down/Sources/lnx/PlayerController.hx
Normal file
@ -0,0 +1,136 @@
|
||||
package lnx;
|
||||
|
||||
import iron.math.Vec4;
|
||||
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 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 dir = new Vec4();
|
||||
var lastDir = new Vec4();
|
||||
var lastLook:Vec4;
|
||||
var state = "idle";
|
||||
|
||||
var soundStep0:kha.Sound = null;
|
||||
var soundStep1:kha.Sound = null;
|
||||
var soundSword0:kha.Sound = null;
|
||||
var soundSword1:kha.Sound = null;
|
||||
var stepSoundsLoaded = 0;
|
||||
var swordSoundsLoaded = 0;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
// Load sounds
|
||||
iron.data.Data.getSound("step0.wav", function(sound:kha.Sound) { soundStep0 = sound; stepSoundsLoaded++; });
|
||||
iron.data.Data.getSound("step1.wav", function(sound:kha.Sound) { soundStep1 = sound; stepSoundsLoaded++; });
|
||||
iron.data.Data.getSound("sword0.wav", function(sound:kha.Sound) { soundSword0 = sound; swordSoundsLoaded++; });
|
||||
iron.data.Data.getSound("sword1.wav", function(sound:kha.Sound) { soundSword1 = sound; swordSoundsLoaded++; });
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// Rotate
|
||||
var q = new iron.math.Quat();
|
||||
q.fromTo(Vec4.yAxis(), new Vec4(lastDir.x, lastDir.y, 0.0));
|
||||
armature.transform.rot.lerp(armature.transform.rot, q, 0.25);
|
||||
armature.transform.buildMatrix();
|
||||
|
||||
updateAnim();
|
||||
updateBody();
|
||||
|
||||
if (dir.length() > 0) lastDir.setFrom(dir);
|
||||
}
|
||||
|
||||
function updateAnim() {
|
||||
var look = armature.transform.look().normalize();
|
||||
|
||||
// Move
|
||||
if (dir.length() > 0) {
|
||||
setState("run", 1.0);
|
||||
|
||||
// Step sounds
|
||||
stepTime += Time.delta;
|
||||
if (stepTime > 0.3) {
|
||||
stepTime = 0;
|
||||
if (stepSoundsLoaded == 2) {
|
||||
Audio.play(Std.random(2) == 0 ? soundStep0 : soundStep1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Slash
|
||||
else if (state == "idle") {
|
||||
if (mouse.down("left") || (gamepad != null && gamepad.down("r2") > 0.0)) {
|
||||
var r = Std.random(2);
|
||||
setState(r == 0 ? "slash" : "slash2", 1.5, 0.0, function() { setState("idle", 1.0, 0.0); });
|
||||
iron.system.Tween.timer(0.3, function() {
|
||||
if (swordSoundsLoaded == 2) {
|
||||
Audio.play(r == 0 ? soundSword0 : soundSword1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
// Idle
|
||||
else if (state != "slash" && state != "slash2") {
|
||||
setState("idle", 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
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, onComplete:Void->Void = null) {
|
||||
if (s == state) return;
|
||||
state = s;
|
||||
anim.play(s, onComplete, blend, speed);
|
||||
}
|
||||
#end
|
||||
}
|
||||
68
top_down/Sources/lnx/SettingsTrait.hx
Normal file
@ -0,0 +1,68 @@
|
||||
package lnx;
|
||||
|
||||
import iron.Scene;
|
||||
import leenkx.system.Event;
|
||||
import leenkx.data.Config;
|
||||
import leenkx.trait.internal.CanvasScript;
|
||||
import leenkx.renderpath.RenderPathCreator;
|
||||
|
||||
class SettingsTrait extends iron.Trait {
|
||||
|
||||
var canvas:CanvasScript;
|
||||
var envStrength = 0.0;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
notifyOnInit(function() {
|
||||
canvas = Scene.active.getTrait(CanvasScript);
|
||||
|
||||
// Init UI to values loaded from config.lnx file
|
||||
canvas.notifyOnReady(function() {
|
||||
canvas.getElement("MenuContainer").visible = false;
|
||||
canvas.getHandle("SSAO").selected = Config.raw.rp_ssgi;
|
||||
canvas.getHandle("SSR").selected = Config.raw.rp_ssr;
|
||||
canvas.getHandle("Bloom").selected = Config.raw.rp_bloom;
|
||||
canvas.getHandle("Voxels").selected = Config.raw.rp_gi;
|
||||
canvas.getHandle("Shadows").position = getShadowQuality(Config.raw.rp_shadowmap_cascade);
|
||||
});
|
||||
|
||||
// Button events
|
||||
Event.add("toggle_menu", toggleMenu);
|
||||
Event.add("apply_settings", applySettings);
|
||||
});
|
||||
}
|
||||
|
||||
function toggleMenu() {
|
||||
var e = canvas.getElement("MenuContainer");
|
||||
e.visible = !e.visible;
|
||||
}
|
||||
|
||||
function applySettings() {
|
||||
|
||||
// Apply render path settings
|
||||
Config.raw.rp_ssgi = canvas.getHandle("SSAO").selected;
|
||||
Config.raw.rp_ssr = canvas.getHandle("SSR").selected;
|
||||
Config.raw.rp_bloom = canvas.getHandle("Bloom").selected;
|
||||
Config.raw.rp_gi = canvas.getHandle("Voxels").selected;
|
||||
Config.raw.rp_shadowmap_cascade = getShadowMapSize(canvas.getHandle("Shadows").position);
|
||||
RenderPathCreator.applyConfig();
|
||||
|
||||
// Lower envmap strength when voxel ao is disabled
|
||||
var p = iron.Scene.active.world.probe.raw;
|
||||
if (envStrength == 0) envStrength = p.strength;
|
||||
p.strength = Config.raw.rp_gi ? envStrength : envStrength / 3;
|
||||
|
||||
// Save config.lnx file
|
||||
Config.save();
|
||||
}
|
||||
|
||||
inline function getShadowQuality(i:Int):Int {
|
||||
// 0 - High, 1 - Medium, 2 - Low
|
||||
return i == 4096 ? 0 : i == 2048 ? 1 : 2;
|
||||
}
|
||||
|
||||
inline function getShadowMapSize(i:Int):Int {
|
||||
return i == 0 ? 4096 : i == 1 ? 2048 : 1024;
|
||||
}
|
||||
}
|
||||
BIN
top_down/top_down.blend
Normal file
BIN
twin_stick/Assets/checker_rough.png
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
twin_stick/Assets/finger.jpg
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
twin_stick/Assets/grid.png
Normal file
|
After Width: | Height: | Size: 414 B |