This commit is contained in:
2026-05-06 19:12:34 -07:00
parent cf19776262
commit 9a2430edfa
111 changed files with 2085 additions and 1 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*/build*
*/*.blend?
*/Sources/Main.hx
*/Sources/arm/node/*
*/khafile.js
config.arm
_themes.json

7
LICENSE.md Normal file
View 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.

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

BIN
archery/Assets/finger.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
archery/Assets/grid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

BIN
archery/Assets/grid_b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

BIN
archery/Bundled/bow_hit.wav Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
../../Assets/aim.png

View 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"}

View 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

Binary file not shown.

BIN
first_person/Assets/aim.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

View File

@ -0,0 +1 @@
../../Assets/aim.png

View 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"}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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
}

View 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
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
platformer/Assets/grid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

View 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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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);
}
});
}
}

View 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

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
race_track/Assets/grid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

View File

View 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":[]}

View 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;
}
}

View 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

Binary file not shown.

BIN
third_person/Assets/aim.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

View File

@ -0,0 +1 @@
../../Assets/aim.png

View 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"}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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
}

View 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
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

View File

@ -0,0 +1 @@
../../Assets/aim.png

View 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"}

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,2 @@
Please check the following example to learn about the terrain construction:
https://github.com/leenkx3d/leenkx_examples/terrain

View 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
}

View 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
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

BIN
top_down/Assets/finger.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
top_down/Assets/grid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

BIN
top_down/Assets/grid_b.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

View File

View 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":[]}

View 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

Binary file not shown.

BIN
top_down/Bundled/step1.wav Normal file

Binary file not shown.

BIN
top_down/Bundled/sword0.wav Normal file

Binary file not shown.

BIN
top_down/Bundled/sword1.wav Normal file

Binary file not shown.

View 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
}

View 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

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
twin_stick/Assets/grid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Some files were not shown because too many files have changed in this diff Show More