Merge pull request 'update' (#1) from Onek8/Leenkx_Examples:main into main

Reviewed-on: LeenkxTeam/Leenkx_Examples#1
This commit is contained in:
2026-05-07 00:55:51 +00:00
402 changed files with 3758 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
*/build*
*/*.blend?
*/Sources/Main.hx
*/Sources/arm/node/*
*.pyc
*.DS_Store
khafile.js
node_update_failure.*
.vscode/
config.arm
_*/

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.

BIN
RaycastRay/RaycastRay.blend Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
Press keyboard `1`, `2`, `3` to change the animation action

View File

@ -0,0 +1,39 @@
package lnx;
class ActionPlayer extends iron.Trait {
function getAnim() {
// Trait placed on mesh object
var anim = object.animation;
// Trait placed on armature object - retrieve animation from child mesh
if (anim == null) anim = object.children[0].animation;
return anim;
}
public function new() {
super();
notifyOnInit(function() {
var anim = getAnim();
anim.notifyOnMarker("my_marker", function() {
trace("Marker!");
});
});
notifyOnUpdate(function() {
var kb = iron.system.Input.getKeyboard();
var anim = getAnim();
if (kb.started("1")) anim.play("idle");
else if (kb.started("2")) anim.play("run");
else if (kb.started("3")) anim.play("slash", onSlash);
else if (kb.started("6")) anim.pause();
else if (kb.started("7")) anim.resume();
});
}
function onSlash() {
trace("Slash animation played!");
}
}

Binary file not shown.

View File

@ -0,0 +1 @@
{"name":"untitled","x":0,"y":0,"width":1280,"height":720,"elements":[{"id":0,"type":0,"name":"Text","event":"","x":0,"y":0,"width":383,"height":44,"rotation":0,"text":"Hold W/S to blend","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true}],"assets":[],"theme":"Default Light"}

View File

@ -0,0 +1 @@
[{"NAME":"Default Light","WINDOW_BG_COL":-1052689,"WINDOW_TINT_COL":-14540254,"ACCENT_COL":-1118482,"ACCENT_HOVER_COL":-4473925,"ACCENT_SELECT_COL":-5592406,"BUTTON_COL":-3355444,"BUTTON_TEXT_COL":-14540254,"BUTTON_HOVER_COL":-5000269,"BUTTON_PRESSED_COL":-5131855,"TEXT_COL":-14144472,"LABEL_COL":-5592406,"SEPARATOR_COL":-6710887,"HIGHLIGHT_COL":-14656100,"CONTEXT_COL":-5592406,"PANEL_BG_COL":-5592406,"FONT_SIZE":26,"ELEMENT_W":200,"ELEMENT_H":48,"ELEMENT_OFFSET":8,"ARROW_SIZE":10,"BUTTON_H":44,"CHECK_SIZE":30,"CHECK_SELECT_SIZE":16,"SCROLL_W":12,"TEXT_OFFSET":16,"TAB_W":24,"FILL_WINDOW_BG":false,"FILL_BUTTON_BG":true,"FILL_ACCENT_BG":false,"LINK_STYLE":0,"FULL_TABS":false}]

View File

@ -0,0 +1 @@
Hold keyboard `W`, `S` to blend between animations

View File

@ -0,0 +1,30 @@
package lnx;
class MyTrait extends iron.Trait {
var factor = 0.0;
public function new() {
super();
notifyOnUpdate(function() {
var anim:iron.object.BoneAnimation = cast object.children[0].animation;
var kb = iron.system.Input.getKeyboard();
// Blend idle and run actions
// factor 0.0 -> 100% idle
// factor 0.5 -> 50% idle, 50% run
// factor 1.0 -> 100% run
if (kb.down("w")) {
if (factor <= 0.99) factor += 0.01;
anim.blend("idle", "run", factor);
}
if (kb.down("s")) {
if (factor >= 0.01) factor -= 0.01;
anim.blend("idle", "run", factor);
}
});
}
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
- Hand object is parented to armature bone
- Sword is parented to Hand object
- Press `X` to swap weapons

View File

@ -0,0 +1,40 @@
package lnx;
class SwapWeapon extends iron.Trait {
var weapon = 0;
var hand:iron.object.Object;
var sword:iron.object.Object;
var axe:iron.object.Object;
public function new() {
super();
notifyOnInit(function() {
var sc = iron.Scene.active;
hand = sc.getChild("Hand");
sword = sc.getChild("Sword");
axe = sc.getChild("Axe");
});
notifyOnUpdate(function() {
var kb = iron.system.Input.getKeyboard();
if (kb.started("x")) {
var a = weapon == 0 ? sword : axe; // Currently equipped weapon
var b = weapon == 0 ? axe : sword; // The other weapon
// Remove current weapon from hand
hand.removeChild(a);
a.visible = false;
// Add the other weapon to hand
hand.addChild(b);
b.visible = true;
// Swap weapon
weapon = weapon == 0 ? 1 : 0;
}
});
}
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Use instancing for fast rendering of linked object duplicates.
https://github.com/leenkx3d/leenkx/wiki/instancing

Binary file not shown.

View File

@ -0,0 +1,3 @@
The left lnx is controlled by Inverse Kinematics with a finger following a ball movement.
Use `W` `S` `A` and `D` keys to move the ball.
The right lnx is controlled by Forward Kinematics with a Haxe script.

View File

@ -0,0 +1,46 @@
package lnx;
import iron.math.Vec4;
import iron.math.Quat;
import iron.object.BoneAnimation;
import iron.math.Mat4;
// Moving a bone - forward kinematics
class MoveBoneFK extends iron.Trait {
public function new() {
super();
notifyOnInit(function() {
// Fetch armature animation
var anim = cast(object.children[0].animation, BoneAnimation);
// Fetch bone
var bone = anim.getBone("mixamorig:RightLnx");
// Manipulating bone in local space
//var m = anim.getBoneMat(bone);
// anim.notifyOnUpdate(function() {
// var offset = new Quat().fromEuler(0, Math.sin(iron.system.Time.time()), 0);
// m.applyQuat(offset);
//});
// Manipulating bone in world space
anim.notifyOnUpdate(function() {
// Get bone mat in world space
var m = anim.getAbsWorldMat(bone);
// Decompose transform
var loc = new Vec4();
var scl = new Vec4();
var rot = new Quat();
m.decompose(loc, rot, scl);
// Apply rotation
var offset = new Quat().fromEuler(Math.sin(iron.system.Time.time()), 0, 0);
rot.multquats(offset, rot);
// Compose world matrix
m.compose(loc, rot, scl);
// Set bone matrix from world matrix
anim.setBoneMatFromWorldMat(m, bone);
});
});
}
}

View File

@ -0,0 +1,28 @@
package lnx;
import iron.object.BoneAnimation;
// Moving a bone - inverse kinematics
class MoveBoneIK extends iron.Trait {
public function new() {
super();
iron.Scene.active.notifyOnInit(function() {
// Fetch armature animation
var anim = cast(object.children[0].animation, BoneAnimation);
// Fetch bone
var bone = anim.getBone("mixamorig:LeftHandIndex4");
// Fetch goal
var tr = iron.Scene.active.getChild("Goal").transform;
var goal = new iron.math.Vec4();
anim.notifyOnUpdate(function() {
goal.set(tr.worldx(), tr.worldy(), tr.worldz());
// Align skeleton to touch the goal
anim.solveIK(bone, goal);
});
});
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,14 @@
// Call Plugin class exposed from Haxe
var plugin = new arm.Plugin();
plugin.hello();
var scene = plugin.scene();
var rot = 0.0;
plugin.update = function() {
rot += 0.01;
var o = scene.getChild("Cube");
o.transform.setRotation(0, 0, rot);
}

2
call_hx/README.md Normal file
View File

@ -0,0 +1,2 @@
Check console.
https://github.com/leenkx3d/leenkx/wiki/js

View File

@ -0,0 +1,11 @@
package lnx;
class EvalJS {
public function new() {
// Evaluate bundled JS, usually you would embed JS into .html file instead
iron.data.Data.getBlob("my_plugin.js", function(blob:kha.Blob) {
js.Syntax.code("(1, eval)({0})", blob.toString());
});
}
}

View File

@ -0,0 +1,24 @@
package lnx;
// Expose this class for easy access from JS
@:expose
class Plugin extends iron.Trait {
var update:Void->Void = null;
public function new() {
super();
notifyOnUpdate(function() {
if (update != null) update();
});
}
public function hello() {
trace("world");
}
public function scene() {
return iron.Scene.active;
}
}

BIN
call_hx/call_hx.blend Normal file

Binary file not shown.

6
call_js/README.md Normal file
View File

@ -0,0 +1,6 @@
Shows how to call js after clicking on a `Cube` object.
- Requires html5 target and physics enabled.
- Check devtools for output.
https://github.com/leenkx3d/leenkx/wiki/js

View File

@ -0,0 +1,33 @@
package lnx;
import leenkx.trait.physics.PhysicsWorld;
import iron.system.Input;
// This example shows how to call JavaScript after clicking on a Cube object
// Requires physics enabled and browser target
class CallJS extends iron.Trait {
public function new() {
super();
var mouse = Input.getMouse();
notifyOnUpdate(function() {
// Check mouse button
if (!mouse.started()) return;
// Pick object at mouse coords
var rb = PhysicsWorld.active.pickClosest(mouse.x, mouse.y);
// Check if picked object is our Cube
if (rb != null && rb.object.name == 'Cube') {
// Raw JS calls
js.Syntax.code('console.log("Cube clicked");');
js.Syntax.code('document.title = "Cube clicked";');
js.Syntax.code('window.alert("Cube clicked");');
} else {
js.Syntax.code('console.log("click");');
}
});
}
}

BIN
call_js/call_js.blend Normal file

Binary file not shown.

1
debug_draw/README.md Normal file
View File

@ -0,0 +1 @@
To see debug drawing, `Leenkx Project - Debug Console` option has to be enabled.

View File

@ -0,0 +1,24 @@
package lnx;
#if lnx_debug
import leenkx.trait.internal.DebugDraw;
#end
class MyTrait extends iron.Trait {
public function new() {
super();
notifyOnInit( () -> {
var plane = iron.Scene.active.getChild("Plane");
var suzanne = iron.Scene.active.getChild("Suzanne");
// To see debug drawing, `Leenkx Project - Debug Console` option has to be enabled
#if lnx_debug
DebugDraw.notifyOnRender( (draw:DebugDraw) -> {
if(plane != null) draw.bounds(plane.transform);
if(suzanne != null) draw.bounds(suzanne.transform);
// draw.line();
});
#end
});
}
}

BIN
debug_draw/debug_draw.blend Normal file

Binary file not shown.

View File

@ -0,0 +1,16 @@
package leenkx.logicnode;
class TestNode extends LogicNode {
public function new(tree:LogicTree) {
super(tree);
}
override function run(from:Int) {
// Logic for this node
trace("Hello, World!");
// Execute next action linked to this node
runOutput(0);
}
}

View File

@ -0,0 +1,38 @@
from bpy.types import Node
from lnx.logicnode.lnx_nodes import *
import lnx.nodes_logic
class TestNode(LnxLogicTreeNode):
"""Test node"""
bl_idname = 'LNTestNode'
bl_label = 'Test'
# Use this as a tooltip in the add node menu.
# If `bl_description` does not exist, the docstring of this node is used instead.
bl_description = 'This is a test node'
# The category in which this node is listed in the user interface
lnx_category = 'Custom Nodes'
# Set the version of this node. If you update the node's Python
# code later, increment this version so that older projects get
# updated automatically.
# See https://github.com/leenkx3d/leenkx/wiki/logicnodes#node-versioning
lnx_version = 0
def init(self, context):
self.add_input('LnxNodeSocketAction', 'In')
self.add_output('LnxNodeSocketAction', 'Out')
def register():
"""This function is called when Leenkx loads this library."""
# Add a new category of nodes in which we will put the TestNode.
# This step is optional, you can also add nodes to Leenkx's default
# categories.
add_category('Custom Nodes', icon='EVENT_C')
# Register the TestNode
TestNode.on_register()

Binary file not shown.

2
ease/README.md Normal file
View File

@ -0,0 +1,2 @@
- https://api.leenkx3d.org/iron/system/Ease.html
- https://api.leenkx3d.org/iron/system/Tween.html

View File

@ -0,0 +1,33 @@
package lnx;
import iron.system.Tween;
#if lnx_debug
import leenkx.trait.internal.DebugDraw;
#end
class TweenTest extends iron.Trait {
@prop var ease : Int = 0;
public function new() {
super();
notifyOnInit(() -> {
#if lnx_debug
//DebugDraw.notifyOnRender( draw -> draw.bounds( object.transform) );
#end
doTween(10);
});
}
function doTween( v : Float ) {
Tween.to({
target: object.transform.loc,
props: { z: v },
delay: 0.5,
duration: 2.0,
ease: ease,
tick: object.transform.buildMatrix,
done: () -> doTween(-v)
});
}
}

BIN
ease/ease.blend Normal file

Binary file not shown.

View File

View File

@ -0,0 +1 @@
{"name":"untitled","x":0,"y":0,"width":1280,"height":720,"elements":[{"id":0,"type":0,"name":"Text","event":"","x":0,"y":0,"width":372,"height":44,"rotation":0,"text":"My Text","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true,"color_text":-16744449}],"assets":[],"theme":"Default Light"}

View File

@ -0,0 +1 @@
[{"NAME":"Default Light","WINDOW_BG_COL":-1052689,"WINDOW_TINT_COL":-14540254,"ACCENT_COL":-1118482,"ACCENT_HOVER_COL":-4473925,"ACCENT_SELECT_COL":-5592406,"BUTTON_COL":-3355444,"BUTTON_TEXT_COL":-14540254,"BUTTON_HOVER_COL":-5000269,"BUTTON_PRESSED_COL":-5131855,"TEXT_COL":-6710887,"LABEL_COL":-5592406,"SEPARATOR_COL":-6710887,"HIGHLIGHT_COL":-14656100,"CONTEXT_COL":-5592406,"PANEL_BG_COL":-5592406,"FONT_SIZE":26,"ELEMENT_W":200,"ELEMENT_H":48,"ELEMENT_OFFSET":8,"ARROW_SIZE":10,"BUTTON_H":44,"CHECK_SIZE":30,"CHECK_SELECT_SIZE":16,"SCROLL_W":12,"TEXT_OFFSET":16,"TAB_W":24,"FILL_WINDOW_BG":false,"FILL_BUTTON_BG":true,"FILL_ACCENT_BG":false,"LINK_STYLE":0}]

View File

@ -0,0 +1,3 @@
{
"my_text": "Hello from json!"
}

1
file_read/README.md Normal file
View File

@ -0,0 +1 @@
Loads a json file from the `Bundled/` directory.

View File

@ -0,0 +1,34 @@
package lnx;
import leenkx.trait.internal.CanvasScript;
import iron.data.Data;
import iron.Scene;
class ReadFile extends iron.Trait {
public function new() {
super();
notifyOnInit(function() {
// Relative or absolute path to file
// In this case we load the file placed in the "Bundled/" directory
var file = "my_file.json";
// Load the file asynchronously
Data.getBlob(file, function(b:kha.Blob) {
// File is now loaded
// Get string from loaded bytes
var string = b.toString();
// Get json from string
var json = haxe.Json.parse(string);
// Get canvas trait
var canvas = Scene.active.getTrait(CanvasScript);
// Display "my_text" entry found in the loaded json file
canvas.getElement("Text").text = json.my_text;
});
});
}
}

BIN
file_read/file_read.blend Normal file

Binary file not shown.

4
file_storage/README.md Normal file
View File

@ -0,0 +1,4 @@
Increments a number every time you start the application.
Check console.
https://api.leenkx3d.org/kha/Storage.html

View File

@ -0,0 +1,55 @@
package lnx;
import iron.system.Storage;
class StorageTest extends iron.Trait {
public function new() {
super();
notifyOnInit(() -> {
// Retrieve storage
var data = Storage.data;
if (data == null)
return;
// First run - init integer variable named 'count'
var count: Dynamic = data.mycount;
if (count == null) {
data.mycount = 0;
// Init more variables as needed
// data.test1 = "String";
// data.test2 = 1.23;
// data.test3 = true;
// data.test4 = [3, 5, 7];
// data.test5 = {a: 3, b: "value"};
}
trace("Count is " + data.mycount);
// Increase count on every run
data.mycount++;
Storage.save();
var d = 10;
var s = 1;
var ox = 0;
var oy = 0;
notifyOnRender2D(g -> {
g.end();
g.color = 0xff101010;
ox = oy = 0;
for(i in 0...data.mycount) {
g.fillRect(d+ox, d+oy, d, d);
ox += (d+1);
if(ox+d > kha.System.windowWidth()) {
ox = 0;
oy += d+1;
}
}
g.begin(false);
});
});
}
}

Binary file not shown.

1
file_write/README.md Normal file
View File

@ -0,0 +1 @@
https://github.com/leenkx3d/leenkx/wiki/reference#write-json

View File

@ -0,0 +1,28 @@
package lnx;
class WriteFile extends iron.Trait {
public function new() {
super();
notifyOnInit(function() {
// File writing in Krom
// To save data in HTML5, see file_storage example
#if kha_krom
// Data to save
var o = { test: "Hello" };
var s = haxe.Json.stringify(o);
// Save file into game build folder
// Playing from Blender the file will be saved at
// file_write/build_file/debug/krom/my_file.json
var path = Krom.getFilesLocation() + "/my_file.json";
// Write file
var bytes = haxe.io.Bytes.ofString(s);
Krom.fileSaveBytes(path, bytes.getData());
#end
});
}
}

BIN
file_write/file_write.blend Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,3 @@
../../Assets/ui_exit.png
../../Assets/ui_refresh.png
../../Assets/keys.png

View File

@ -0,0 +1 @@
{"name":"untitled","x":0,"y":0,"width":1280,"height":720,"elements":[{"id":0,"type":1,"name":"Exit","event":"exit","x":15,"y":13,"width":64,"height":64,"text":"Image","asset":"ui_exit.png","color":-1,"anchor":0,"children":[],"visible":true,"rotation":0},{"id":1,"type":1,"name":"Refresh","event":"refresh","x":15,"y":91,"width":64,"height":64,"text":"Image","asset":"ui_refresh.png","color":-1,"anchor":0,"children":[],"visible":true,"rotation":0,"alignment":0},{"id":4,"type":1,"name":"Image","event":"","x":340,"y":620,"width":600,"height":70,"text":"Image","asset":"keys.png","color":-1,"anchor":0,"children":[],"visible":true,"rotation":0,"alignment":0}],"assets":[{"name":"ui_exit.png","file":"../../Assets/ui_exit.png","id":0},{"name":"ui_refresh.png","file":"../../Assets/ui_refresh.png","id":1},{"name":"keys.png","file":"../../Assets/keys.png","id":2}],"theme":"Default Light"}

View File

@ -0,0 +1,2 @@
../../Assets/ui_play.png
../../Assets/menu.jpg

View File

@ -0,0 +1 @@
{"name":"untitled","x":0,"y":0,"width":1280,"height":720,"elements":[{"id":4,"type":1,"name":"Image","event":"","x":0,"y":0,"width":1280,"height":720,"rotation":0,"text":"My Image","asset":"menu.jpg","progress_at":0,"progress_total":100,"strength":1,"alignment":0,"anchor":0,"parent":null,"children":[],"visible":true},{"id":3,"type":1,"name":"Button","event":"play","x":580,"y":280,"width":160,"height":160,"rotation":0,"text":"My Image.002","asset":"ui_play.png","progress_at":0,"progress_total":100,"strength":1,"alignment":0,"anchor":0,"parent":null,"children":[],"visible":true}],"assets":[{"name":"ui_play.png","file":"../../Assets/ui_play.png","id":0},{"name":"menu.jpg","file":"../../Assets/menu.jpg","id":1}],"theme":"Default Light"}

View File

@ -0,0 +1 @@
[{"NAME":"Default Light","WINDOW_BG_COL":-1052689,"WINDOW_TINT_COL":-14540254,"ACCENT_COL":-1118482,"ACCENT_HOVER_COL":-4473925,"ACCENT_SELECT_COL":-5592406,"BUTTON_COL":-3355444,"BUTTON_TEXT_COL":-14540254,"BUTTON_HOVER_COL":-5000269,"BUTTON_PRESSED_COL":-5131855,"TEXT_COL":-6710887,"LABEL_COL":-5592406,"SEPARATOR_COL":-6710887,"HIGHLIGHT_COL":-14656100,"CONTEXT_COL":-5592406,"PANEL_BG_COL":-5592406,"FONT_SIZE":26,"ELEMENT_W":200,"ELEMENT_H":48,"ELEMENT_OFFSET":8,"ARROW_SIZE":10,"BUTTON_H":44,"CHECK_SIZE":30,"CHECK_SELECT_SIZE":16,"SCROLL_W":12,"TEXT_OFFSET":16,"TAB_W":24,"FILL_WINDOW_BG":false,"FILL_BUTTON_BG":true,"FILL_ACCENT_BG":false,"LINK_STYLE":0,"FULL_TABS":false},{"NAME":"New Theme","WINDOW_BG_COL":-1052689,"WINDOW_TINT_COL":-14540254,"ACCENT_COL":-1118482,"ACCENT_HOVER_COL":-4473925,"ACCENT_SELECT_COL":-5592406,"BUTTON_COL":-3355444,"BUTTON_TEXT_COL":-14540254,"BUTTON_HOVER_COL":-5000269,"BUTTON_PRESSED_COL":-5131855,"TEXT_COL":-6710887,"LABEL_COL":-5592406,"SEPARATOR_COL":-6710887,"HIGHLIGHT_COL":-14656100,"CONTEXT_COL":-5592406,"PANEL_BG_COL":-5592406,"FONT_SIZE":26,"ELEMENT_W":200,"ELEMENT_H":48,"ELEMENT_OFFSET":8,"ARROW_SIZE":10,"BUTTON_H":44,"CHECK_SIZE":30,"CHECK_SELECT_SIZE":16,"SCROLL_W":12,"TEXT_OFFSET":16,"TAB_W":24,"FILL_WINDOW_BG":false,"FILL_BUTTON_BG":true,"FILL_ACCENT_BG":false,"LINK_STYLE":0,"FULL_TABS":false},{"NAME":"New Theme.001","WINDOW_BG_COL":-1052689,"WINDOW_TINT_COL":-14540254,"ACCENT_COL":-1118482,"ACCENT_HOVER_COL":-4473925,"ACCENT_SELECT_COL":-5592406,"BUTTON_COL":-3355444,"BUTTON_TEXT_COL":-14540254,"BUTTON_HOVER_COL":-5000269,"BUTTON_PRESSED_COL":-5131855,"TEXT_COL":-6710887,"LABEL_COL":-5592406,"SEPARATOR_COL":-6710887,"HIGHLIGHT_COL":-14656100,"CONTEXT_COL":-5592406,"PANEL_BG_COL":-5592406,"FONT_SIZE":26,"ELEMENT_W":200,"ELEMENT_H":48,"ELEMENT_OFFSET":8,"ARROW_SIZE":10,"BUTTON_H":44,"CHECK_SIZE":30,"CHECK_SELECT_SIZE":16,"SCROLL_W":12,"TEXT_OFFSET":16,"TAB_W":24,"FILL_WINDOW_BG":false,"FILL_BUTTON_BG":true,"FILL_ACCENT_BG":false,"LINK_STYLE":0,"FULL_TABS":false}]

1
game_bowling/README.md Normal file
View File

@ -0,0 +1 @@
Keyboard `space` to bowl

View File

@ -0,0 +1,55 @@
package lnx;
import iron.math.Vec4;
import leenkx.trait.physics.RigidBody;
class BallTrait extends iron.Trait {
@prop
var impulse = 65.0;
var fired = false;
var rb:RigidBody;
var start = new Vec4();
public function new() {
super();
notifyOnInit(function() {
rb = object.getTrait(RigidBody);
start.setFrom(object.transform.loc);
});
notifyOnUpdate(function() {
var kb = iron.system.Input.getKeyboard();
var tr = object.transform;
if (!fired) {
if (kb.started("x") || kb.started("space")) {
rb.applyImpulse(new Vec4(0, impulse, 0));
fired = true;
}
else if (kb.down("left") && tr.loc.x > -0.9) {
tr.loc.x -= 0.02;
tr.buildMatrix();
rb.syncTransform();
}
else if (kb.down("right") && tr.loc.x < 0.9) {
tr.loc.x += 0.02;
tr.buildMatrix();
rb.syncTransform();
}
}
if (fired && tr.loc.z < -10) {
tr.loc.setFrom(start);
tr.buildMatrix();
rb.setLinearVelocity(0, 0, 0);
rb.setAngularVelocity(0, 0, 0);
rb.syncTransform();
fired = false;
}
});
}
}

View File

@ -0,0 +1,24 @@
package lnx;
class PinTrait extends iron.Trait {
public static var pinsRemoved = 0;
public function new() {
super();
pinsRemoved = 0;
notifyOnUpdate(function() {
if (object.transform.loc.z < - 20) {
object.remove();
if (++pinsRemoved >= 10) {
leenkx.system.Event.send("exit");
}
}
});
}
}

Binary file not shown.

BIN
game_bowling/pin.blend Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@ -0,0 +1 @@
{"name":"untitled","x":0,"y":0,"width":960,"height":540,"elements":[{"id":0,"type":0,"name":"Score","event":"","x":0,"y":0,"width":150,"height":48,"text":"0","asset":"","color":-16777216,"anchor":0,"children":[]}],"assets":[]}

View File

@ -0,0 +1,31 @@
package lnx;
class GemTrait extends iron.Trait {
static var gemsCollected = 0;
var player:iron.object.Object = null;
public function new() {
super();
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.6) {
gemsCollected++;
object.remove();
// Update UI
var canvas = iron.Scene.active.getTrait(leenkx.trait.internal.CanvasScript);
canvas.getElement("Score").text = gemsCollected + "";
}
});
}
}

View File

@ -0,0 +1,22 @@
package lnx;
class PlayerController extends iron.Trait {
public function new() {
super();
notifyOnUpdate(function() {
var kb = iron.system.Input.getKeyboard();
var x = object.transform.loc.x;
// Move player
if ((kb.down("left") || kb.down("a")) && x > -1.8) {
object.transform.loc.x -= 0.06;
object.transform.dirty = true;
}
if ((kb.down("right") || kb.down("d")) && x < 1.8) {
object.transform.loc.x += 0.06;
object.transform.dirty = true;
}
});
}
}

View File

@ -0,0 +1,51 @@
package lnx;
class SceneBuilder extends iron.Trait {
var dist = 0.0;
var tileNum = 0;
var tilesVisible = 14;
var tiles:Array<iron.object.Object> = [];
var empty:iron.object.Object;
function spawnTile(num:Int) {
iron.Scene.active.spawnObject("Tile" + Std.random(2), null, function(o) {
// Remove old tile
if (tiles[num % tilesVisible] != null) {
tiles[num % tilesVisible].remove();
}
// Spawn new tile
tiles[num % tilesVisible] = o;
o.transform.loc.x = 0;
o.transform.loc.y = num * 4.0;
o.transform.buildMatrix();
// Spawn gem
if (Std.random(3) == 0) {
iron.Scene.active.spawnObject("Gem", o, function(go) {
go.transform.loc.x = (Math.random() - 0.5) * 1.8;
go.transform.loc.z = 0.2;
go.transform.buildMatrix();
});
}
});
}
public function new() {
super();
notifyOnUpdate(function() {
if (empty == null) empty = iron.Scene.active.getChild("Empty");
// Spawn new tiles
while (tileNum < Std.int(dist / 4 + 13)) spawnTile(tileNum++);
// Travel forward
dist += 0.1;
empty.transform.loc.y = dist;
empty.transform.buildMatrix();
});
}
}

Binary file not shown.

BIN
game_endlessrun/grid.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1 @@
{"name":"untitled","x":0,"y":0,"width":1280,"height":720,"elements":[{"id":2,"type":6,"name":"SSR","event":"","x":20,"y":260,"width":150,"height":34,"rotation":0,"text":"SSR","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true},{"id":3,"type":6,"name":"SSAO","event":"","x":20,"y":300,"width":150,"height":40,"rotation":0,"text":"SSAO","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true},{"id":4,"type":6,"name":"Fullscreen","event":"","x":20,"y":80,"width":191,"height":14,"rotation":0,"text":"Fullscreen","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true},{"id":6,"type":6,"name":"Bloom","event":"","x":20,"y":220,"width":150,"height":44,"rotation":0,"text":"Bloom","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true},{"id":7,"type":6,"name":"MotionBlur","event":"","x":20,"y":180,"width":177,"height":44,"rotation":0,"text":"Motion Blur","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true},{"id":8,"type":8,"name":"Shadows","event":"","x":20,"y":130,"width":160,"height":60,"rotation":0,"text":"High;Medium;Low","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true},{"id":9,"type":10,"name":"ViewDistance","event":"","x":20,"y":360,"width":250,"height":44,"rotation":0,"text":"View Distance","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true},{"id":11,"type":0,"name":"Title","event":"","x":10,"y":10,"width":540,"height":60,"rotation":0,"text":"Graphics Settings","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true},{"id":12,"type":0,"name":"ShadowsTitle","event":"","x":185,"y":130,"width":184,"height":20,"rotation":0,"text":"Shadows","asset":"","color":-6381922,"anchor":0,"parent":null,"children":[],"visible":true},{"id":13,"type":2,"name":"Apply","event":"apply_settings","x":22,"y":479,"width":80,"height":50,"rotation":0,"text":"Apply","asset":"","color":-1,"anchor":0,"parent":null,"children":[],"visible":true},{"id":14,"type":9,"name":"FoV","event":"","x":20,"y":420,"width":249,"height":48,"rotation":0,"text":"FoV","asset":"","progress_at":0,"progress_total":100,"strength":1,"alignment":2,"anchor":0,"parent":null,"children":[],"visible":true,"color_text":null,"color":null,"color_hover":null}],"assets":[],"theme":"Default Light"}

View File

@ -0,0 +1 @@
[{"NAME":"Default Light","WINDOW_BG_COL":-1052689,"WINDOW_TINT_COL":-14540254,"ACCENT_COL":-1118482,"ACCENT_HOVER_COL":-4473925,"ACCENT_SELECT_COL":-5592406,"BUTTON_COL":-3355444,"BUTTON_TEXT_COL":-14540254,"BUTTON_HOVER_COL":-5000269,"BUTTON_PRESSED_COL":-5131855,"TEXT_COL":-16645630,"LABEL_COL":-5592406,"SEPARATOR_COL":-6710887,"HIGHLIGHT_COL":-14656100,"CONTEXT_COL":-5592406,"PANEL_BG_COL":-5592406,"FONT_SIZE":26,"ELEMENT_W":200,"ELEMENT_H":48,"ELEMENT_OFFSET":8,"ARROW_SIZE":10,"BUTTON_H":44,"CHECK_SIZE":30,"CHECK_SELECT_SIZE":16,"SCROLL_W":12,"TEXT_OFFSET":16,"TAB_W":24,"FILL_WINDOW_BG":false,"FILL_BUTTON_BG":true,"FILL_ACCENT_BG":false,"LINK_STYLE":0,"FULL_TABS":false}]

View File

@ -0,0 +1,20 @@
{
"rp_bloom": true,
"rp_dynres": false,
"rp_gi": false,
"rp_motionblur": true,
"rp_shadowmap_cascade": 1024,
"rp_shadowmap_cube": 512,
"rp_ssgi": true,
"rp_ssr": true,
"rp_supersample": 1.0,
"window_h": 540,
"window_maximizable": true,
"window_minimizable": true,
"window_mode": 0,
"window_msaa": 1,
"window_resizable": true,
"window_scale": 1.0,
"window_vsync": true,
"window_w": 960
}

View File

@ -0,0 +1,3 @@
To generate config.lnx file, enable `Leenkx Project - Write Config`.
https://api.leenkx3d.org/leenkx/data/Config.html

View File

@ -0,0 +1,71 @@
package lnx;
import iron.Scene;
import leenkx.system.Event;
import leenkx.data.Config;
import leenkx.trait.internal.CanvasScript;
import leenkx.renderpath.RenderPathCreator;
// WIP
// To generate config.lnx file, enable 'Leenkx Project - Write Config'
// Fullscreen option will take effect on next game start up (will be resolved)
class MyTrait extends iron.Trait {
var canvas:CanvasScript;
public function new() {
super();
notifyOnInit(function() {
canvas = Scene.active.getTrait(CanvasScript);
// Init UI to values loaded from config.lnx file
canvas.notifyOnReady(function() {
canvas.getHandle("Fullscreen").selected = Config.raw.window_mode == 1;
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("MotionBlur").selected = Config.raw.rp_motionblur;
canvas.getHandle("Shadows").position = getShadowQuality(Config.raw.rp_shadowmap_cascade);
var cam = Scene.active.camera;
canvas.getHandle("ViewDistance").text = Std.string(Math.round(cam.data.raw.far_plane));
canvas.getHandle("FoV").value = cam.data.raw.fov;
});
// Apply button clicked
Event.add("apply_settings", applySettings);
});
}
function applySettings() {
// Apply render path settings
Config.raw.window_mode = canvas.getHandle("Fullscreen").selected ? 1 : 0;
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_motionblur = canvas.getHandle("MotionBlur").selected;
Config.raw.rp_shadowmap_cascade = getShadowMapSize(canvas.getHandle("Shadows").position);
Config.raw.rp_shadowmap_cube = getShadowMapSize(canvas.getHandle("Shadows").position);
RenderPathCreator.applyConfig();
// Apply camera settings
var cam = Scene.active.camera;
cam.data.raw.far_plane = Std.parseFloat(canvas.getHandle("ViewDistance").text);
cam.data.raw.fov = canvas.getHandle("FoV").value;
cam.buildProjection();
// Save config.lnx file
Config.save();
}
function getShadowQuality(i:Int):Int {
// 0 - High, 1 - Medium, 2 - Low
return i == 2048 ? 0 : i == 1024 ? 1 : 2;
}
function getShadowMapSize(i:Int):Int {
// High - 2048, Medium - 1024, Low - 512
return i == 0 ? 2048 : i == 1 ? 1024 : 512;
}
}

Binary file not shown.

View File

@ -0,0 +1,3 @@
Keyboard `Escape` to toggle mouse lock.
https://api.leenkx3d.org/iron/system/Mouse.html

View File

@ -0,0 +1,28 @@
package lnx;
import iron.math.Vec4;
import iron.system.Input;
class LockTrait extends iron.Trait {
public function new() {
super();
var mouse = Input.getMouse();
var kb = Input.getKeyboard();
notifyOnUpdate(() -> {
if (mouse.started("left")) {
mouse.lock();
} else if (kb.started("escape")) {
mouse.unlock();
}
var cube = iron.Scene.active.getChild("Cube");
if (cube != null) {
cube.transform.rotate(Vec4.zAxis(), mouse.movementX * 0.002);
cube.transform.rotate(Vec4.xAxis(), mouse.movementY * 0.002);
}
});
}
}

Binary file not shown.

View File

@ -0,0 +1,38 @@
package lnx;
import iron.system.Time;
import iron.math.Vec4;
class TouchTrait extends iron.Trait {
var touches = [false, false, false];
public function new() {
super();
notifyOnInit(function() {
var surface = kha.input.Surface.get();
if (surface != null) surface.notify(touchStart, touchEnd, touchMove);
notifyOnUpdate(update);
});
}
function update() {
if (touches[0]) object.transform.rotate(Vec4.zAxis(), 0.05);
if (touches[1]) object.transform.loc.x = Math.sin(Time.time()) * 3.0;
if (touches[2]) object.transform.loc.z = Math.cos(Time.time());
object.transform.dirty = true;
}
function touchStart(index:Int, x:Int, y:Int) {
if (index > 2) return;
touches[index] = true;
}
function touchEnd(index:Int, x:Int, y:Int) {
if (index > 2) return;
touches[index] = false;
}
function touchMove(index:Int, x:Int, y:Int) {}
}

Binary file not shown.

View File

@ -0,0 +1,20 @@
package lnx;
import iron.math.Vec4;
class SensorTrait extends iron.Trait {
public function new() {
super();
notifyOnInit(function() {
var gyro = kha.input.Sensor.get(kha.input.SensorType.Gyroscope);
if (gyro != null) gyro.notify(onGyroscope);
});
}
function onGyroscope(x:Float, y:Float, z:Float) {
object.transform.rotate(Vec4.xAxis(), x / 20);
object.transform.rotate(Vec4.yAxis(), y / 20);
object.transform.rotate(Vec4.zAxis(), z / 20);
}
}

Binary file not shown.

6
instancing/README.md Normal file
View File

@ -0,0 +1,6 @@
#### Enable instancing
- Select object and set `Properties - Object - Leenkx Props - Instanced Children` property
- Create linked duplicates and parent them to object being instanced
https://github.com/leenkx3d/leenkx/wiki/instancing

BIN
instancing/instancing.blend Normal file

Binary file not shown.

BIN
light_area/checker.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

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