Primitive navmeshes.
This commit is contained in:
parent
9c3add2075
commit
695d0bf69b
|
@ -2,7 +2,7 @@ package armory.logicnode;
|
|||
|
||||
class BoolNode extends Node {
|
||||
|
||||
public var val:Bool;
|
||||
public var val:Bool = false;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
|
16
Sources/armory/logicnode/DynamicNode.hx
Normal file
16
Sources/armory/logicnode/DynamicNode.hx
Normal file
|
@ -0,0 +1,16 @@
|
|||
package armory.logicnode;
|
||||
|
||||
class DynamicNode extends Node {
|
||||
|
||||
public var val:Dynamic;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static function create(d:Dynamic) {
|
||||
var n = new DynamicNode();
|
||||
n.val = d;
|
||||
return n;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ package armory.logicnode;
|
|||
|
||||
class FloatNode extends Node {
|
||||
|
||||
public var val:Float;
|
||||
public var val:Float = 0.0;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
|
40
Sources/armory/logicnode/GetTransformNode.hx
Executable file
40
Sources/armory/logicnode/GetTransformNode.hx
Executable file
|
@ -0,0 +1,40 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.trait.internal.NodeExecutor;
|
||||
|
||||
class GetTransformNode extends TransformNode {
|
||||
|
||||
public static inline var _target = 0; // Target
|
||||
|
||||
public function new() {
|
||||
super(false);
|
||||
}
|
||||
|
||||
public override function start(executor:NodeExecutor, parent:Node = null) {
|
||||
super.start(executor, parent);
|
||||
|
||||
executor.notifyOnNodeInit(init);
|
||||
}
|
||||
|
||||
public override function inputChanged() {
|
||||
var t = inputs[_target].target;
|
||||
if (t != null && matrix == null) {
|
||||
var tr = t.transform;
|
||||
matrix = tr.matrix;
|
||||
loc = tr.loc;
|
||||
rot = tr.rot;
|
||||
scale = tr.scale;
|
||||
super.inputChanged();
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
inputChanged();
|
||||
}
|
||||
|
||||
public static function create(target:iron.object.Object):GetTransformNode {
|
||||
var n = new GetTransformNode();
|
||||
n.inputs.push(target);
|
||||
return n;
|
||||
}
|
||||
}
|
43
Sources/armory/logicnode/GoToNode.hx
Executable file
43
Sources/armory/logicnode/GoToNode.hx
Executable file
|
@ -0,0 +1,43 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.trait.internal.NodeExecutor;
|
||||
|
||||
#if arm_navigation
|
||||
import armory.trait.internal.Navigation;
|
||||
#end
|
||||
|
||||
class GoToNode extends Node {
|
||||
|
||||
public static inline var _trigger = 0; // Bool
|
||||
public static inline var _target = 1; // Target
|
||||
public static inline var _transform = 2; // Transform
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
}
|
||||
|
||||
public override function inputChanged() {
|
||||
if (!inputs[_trigger].val || inputs[_target].target == null || inputs[_transform].matrix == null) return;
|
||||
|
||||
#if arm_navigation
|
||||
// Assume navmesh exists..
|
||||
var from = inputs[_target].target.transform.loc;
|
||||
var to = inputs[_transform].loc;
|
||||
Navigation.active.navMeshes[0].findPath(from, to, function(path:Array<iron.math.Vec4>) {
|
||||
|
||||
var agent:armory.trait.NavAgent = inputs[_target].target.getTrait(armory.trait.NavAgent);
|
||||
agent.setPath(path);
|
||||
|
||||
//super.inputChanged();
|
||||
});
|
||||
#end
|
||||
}
|
||||
|
||||
public static function create(trigger:Bool, target:iron.object.Object, transform:iron.object.Transform):GoToNode {
|
||||
var n = new GoToNode();
|
||||
n.inputs.push(BoolNode.create(trigger));
|
||||
n.inputs.push(target);
|
||||
n.inputs.push(transform);
|
||||
return n;
|
||||
}
|
||||
}
|
32
Sources/armory/logicnode/InputStartedNode.hx
Normal file
32
Sources/armory/logicnode/InputStartedNode.hx
Normal file
|
@ -0,0 +1,32 @@
|
|||
package armory.logicnode;
|
||||
|
||||
import armory.system.Input;
|
||||
import armory.trait.internal.NodeExecutor;
|
||||
|
||||
class InputStartedNode extends BoolNode {
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
}
|
||||
|
||||
public override function start(executor:NodeExecutor, parent:Node = null) {
|
||||
super.start(executor, parent);
|
||||
executor.notifyOnNodeUpdate(update);
|
||||
}
|
||||
|
||||
function update() {
|
||||
if (Input.started) {
|
||||
val = Input.started;
|
||||
inputChanged();
|
||||
}
|
||||
else if (val) {
|
||||
val = false;
|
||||
inputChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public static function create(value:Float) {
|
||||
var n = new InputStartedNode();
|
||||
return n;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ package armory.logicnode;
|
|||
|
||||
class IntNode extends Node {
|
||||
|
||||
public var val:Int;
|
||||
public var val:Int = 0;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
|
|
@ -4,7 +4,7 @@ import armory.trait.internal.NodeExecutor;
|
|||
|
||||
class PickerNode extends Node {
|
||||
|
||||
public var target:iron.node.Node;
|
||||
public var target:iron.object.Object;
|
||||
public var property0:String;
|
||||
|
||||
public function new() {
|
||||
|
@ -18,6 +18,7 @@ class PickerNode extends Node {
|
|||
|
||||
function init() {
|
||||
target = armory.Scene.active.getChild(property0);
|
||||
inputChanged();
|
||||
}
|
||||
|
||||
public static function create(_property0:String):PickerNode {
|
||||
|
|
|
@ -4,40 +4,25 @@ import armory.trait.internal.NodeExecutor;
|
|||
|
||||
class SetTransformNode extends Node {
|
||||
|
||||
public static inline var _target = 0; // Target
|
||||
public static inline var _transform = 1; // Transform
|
||||
public static inline var _trigger = 0; // Bool
|
||||
public static inline var _target = 1; // Target
|
||||
public static inline var _transform = 2; // Transform
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
}
|
||||
|
||||
public override function start(executor:NodeExecutor, parent:Node = null) {
|
||||
super.start(executor, parent);
|
||||
|
||||
executor.notifyOnNodeInit(init);
|
||||
}
|
||||
|
||||
function init() {
|
||||
var target:iron.object.Object = inputs[_target].target;
|
||||
if (target != null) {
|
||||
var matrix:iron.math.Mat4 = inputs[_transform].matrix;
|
||||
target.transform.prependMatrix(matrix);
|
||||
}
|
||||
}
|
||||
|
||||
public override function inputChanged() {
|
||||
if (inputs[_target].target == null) { // Target not attached, check next time
|
||||
executor.notifyOnNodeInit(init);
|
||||
}
|
||||
else {
|
||||
inputs[_target].target.transform.dirty = true;
|
||||
}
|
||||
if (!inputs[_trigger].val || inputs[_target].target == null || inputs[_transform].matrix == null) return;
|
||||
|
||||
inputs[_target].target.transform.setMatrix(inputs[_transform].matrix);
|
||||
|
||||
super.inputChanged();
|
||||
}
|
||||
|
||||
public static function create(target:iron.object.Object, transform:iron.object.Transform):SetTransformNode {
|
||||
public static function create(trigger:Bool, target:iron.object.Object, transform:iron.object.Transform):SetTransformNode {
|
||||
var n = new SetTransformNode();
|
||||
n.inputs.push(BoolNode.create(trigger));
|
||||
n.inputs.push(target);
|
||||
n.inputs.push(transform);
|
||||
return n;
|
||||
|
|
|
@ -2,7 +2,7 @@ package armory.logicnode;
|
|||
|
||||
class StringNode extends Node {
|
||||
|
||||
public var val:String;
|
||||
public var val:String = '';
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
|
|
@ -7,40 +7,46 @@ import iron.object.Transform;
|
|||
|
||||
class TransformNode extends Node {
|
||||
|
||||
public static inline var _position = 0; // Vector
|
||||
public static inline var _location = 0; // Vector
|
||||
public static inline var _rotation = 1; // Vector
|
||||
public static inline var _scale = 2; // Vector
|
||||
|
||||
public var matrix:Mat4;
|
||||
public var matrix:Mat4 = null;
|
||||
|
||||
var pos:Vec4;
|
||||
var rot:Quat;
|
||||
var scale:Vec4;
|
||||
var loc:Vec4 = null;
|
||||
var rot:Quat = null;
|
||||
var scale:Vec4 = null;
|
||||
|
||||
public function new() {
|
||||
var buildMatrix:Bool;
|
||||
|
||||
public function new(buildMatrix = true) {
|
||||
super();
|
||||
|
||||
matrix = Mat4.identity();
|
||||
pos = new Vec4();
|
||||
rot = new Quat();
|
||||
scale = new Vec4();
|
||||
this.buildMatrix = buildMatrix;
|
||||
if (buildMatrix) {
|
||||
matrix = Mat4.identity();
|
||||
loc = new Vec4();
|
||||
rot = new Quat();
|
||||
scale = new Vec4();
|
||||
}
|
||||
}
|
||||
|
||||
public override function inputChanged() {
|
||||
// Build matrix
|
||||
pos.set(inputs[_position].inputs[VectorNode._x].val,
|
||||
inputs[_position].inputs[VectorNode._y].val,
|
||||
inputs[_position].inputs[VectorNode._z].val);
|
||||
if (buildMatrix) {
|
||||
loc.set(inputs[_location].inputs[VectorNode._x].val,
|
||||
inputs[_location].inputs[VectorNode._y].val,
|
||||
inputs[_location].inputs[VectorNode._z].val);
|
||||
|
||||
rot.fromEuler(inputs[_rotation].inputs[VectorNode._x].val,
|
||||
inputs[_rotation].inputs[VectorNode._y].val,
|
||||
inputs[_rotation].inputs[VectorNode._z].val);
|
||||
rot.fromEuler(inputs[_rotation].inputs[VectorNode._x].val,
|
||||
inputs[_rotation].inputs[VectorNode._y].val,
|
||||
inputs[_rotation].inputs[VectorNode._z].val);
|
||||
|
||||
scale.set(inputs[_scale].inputs[VectorNode._x].val,
|
||||
inputs[_scale].inputs[VectorNode._y].val,
|
||||
inputs[_scale].inputs[VectorNode._z].val);
|
||||
scale.set(inputs[_scale].inputs[VectorNode._x].val,
|
||||
inputs[_scale].inputs[VectorNode._y].val,
|
||||
inputs[_scale].inputs[VectorNode._z].val);
|
||||
|
||||
matrix.compose(pos, rot, scale);
|
||||
matrix.compose(loc, rot, scale);
|
||||
}
|
||||
|
||||
super.inputChanged();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ class FirstPersonController extends CameraController {
|
|||
var xVec = Vec4.xAxis();
|
||||
var zVec = Vec4.zAxis();
|
||||
function preUpdate() {
|
||||
if (Input.occupied || !body.bodyReady) return;
|
||||
if (Input.occupied || !body.ready) return;
|
||||
|
||||
if (Input.started && !locked) {
|
||||
kha.SystemImpl.lockMouse();
|
||||
|
@ -58,7 +58,7 @@ class FirstPersonController extends CameraController {
|
|||
|
||||
var dir = new Vec4();
|
||||
function update() {
|
||||
if (!body.bodyReady) return;
|
||||
if (!body.ready) return;
|
||||
|
||||
if (jump) {
|
||||
body.applyImpulse(new Vec4(0, 0, 16));
|
||||
|
|
|
@ -1,31 +1,39 @@
|
|||
package armory.trait;
|
||||
|
||||
import iron.Trait;
|
||||
import iron.math.Vec4;
|
||||
import iron.system.Tween;
|
||||
|
||||
@:keep
|
||||
class NavAgent extends Trait {
|
||||
|
||||
// nav mesh
|
||||
// target object
|
||||
// behaviour
|
||||
var path:Array<Vec4> = null;
|
||||
var index = 0;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
}
|
||||
|
||||
notifyOnInit(init);
|
||||
public function setPath(path:Array<Vec4>) {
|
||||
this.path = path;
|
||||
index = 1;
|
||||
notifyOnUpdate(update);
|
||||
notifyOnRemove(removed);
|
||||
}
|
||||
|
||||
function removed() {
|
||||
|
||||
go();
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
||||
function go() {
|
||||
if (path == null || index >= path.length) return;
|
||||
var p = path[index];
|
||||
var dist = Vec4.distance3d(object.transform.loc, p);
|
||||
var speed = 0.2;
|
||||
Tween.to(object.transform.loc, dist * speed, { x: p.x, y: p.y /*, z: p.z*/ }, function() {
|
||||
index++;
|
||||
if (index < path.length) go();
|
||||
}, 0, 0);
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
object.transform.dirty = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,21 +7,5 @@ class NavCrowd extends Trait {
|
|||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
notifyOnInit(init);
|
||||
notifyOnUpdate(update);
|
||||
notifyOnRemove(removed);
|
||||
}
|
||||
|
||||
function removed() {
|
||||
|
||||
}
|
||||
|
||||
function init() {
|
||||
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,60 @@
|
|||
package armory.trait;
|
||||
|
||||
#if arm_navigation
|
||||
import armory.trait.internal.Navigation;
|
||||
import haxerecast.Recast;
|
||||
#end
|
||||
|
||||
import iron.Trait;
|
||||
import iron.data.Data;
|
||||
import iron.math.Vec4;
|
||||
|
||||
@:keep
|
||||
class NavMesh extends Trait {
|
||||
|
||||
#if (!arm_navigation)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
var recast:Recast = null;
|
||||
var ready = false;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
|
||||
notifyOnInit(init);
|
||||
notifyOnUpdate(update);
|
||||
notifyOnRemove(removed);
|
||||
}
|
||||
|
||||
function removed() {
|
||||
|
||||
}
|
||||
|
||||
function init() {
|
||||
Navigation.active.navMeshes.push(this);
|
||||
|
||||
// Load navmesh
|
||||
var name = "nav_" + cast(object, iron.object.MeshObject).data.name + ".arm";
|
||||
Data.getBlob(name, function(b:kha.Blob) {
|
||||
|
||||
recast = Navigation.active.recast;
|
||||
recast.OBJDataLoader(b.toString(), function() {
|
||||
recast.buildSolo();
|
||||
ready = true;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function update() {
|
||||
|
||||
public function findPath(from:Vec4, to:Vec4, done:Array<Vec4>->Void) {
|
||||
if (!ready) return;
|
||||
recast.findPath(from.x, from.z, from.y, to.x, to.z, to.y, 1000, untyped recast.cb(function(path:Array<RecastWaypoint>) {
|
||||
var ar:Array<Vec4> = [];
|
||||
for (p in path) ar.push(new Vec4(p.x, p.z, -p.y));
|
||||
done(ar);
|
||||
}));
|
||||
}
|
||||
|
||||
public function getRandomPoint(done:Vec4->Void) {
|
||||
if (!ready) return;
|
||||
recast.getRandomPoint(untyped recast.cb(function(x:Float, y:Float, z:Float) {
|
||||
done(new Vec4(x, z, -y));
|
||||
}));
|
||||
}
|
||||
|
||||
#end
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class SidescrollerController extends CameraController {
|
|||
|
||||
var dir = new Vec4();
|
||||
function update() {
|
||||
if (!body.bodyReady) return;
|
||||
if (!body.ready) return;
|
||||
|
||||
if (jump) {
|
||||
body.applyImpulse(new Vec4(0, 0, 20));
|
||||
|
|
|
@ -29,7 +29,7 @@ class ThirdPersonController extends CameraController {
|
|||
var xVec = Vec4.xAxis();
|
||||
var zVec = Vec4.zAxis();
|
||||
function preUpdate() {
|
||||
if (Input.occupied || !body.bodyReady) return;
|
||||
if (Input.occupied || !body.ready) return;
|
||||
|
||||
if (Input.down) {
|
||||
// kha.SystemImpl.lockMouse();
|
||||
|
@ -46,7 +46,7 @@ class ThirdPersonController extends CameraController {
|
|||
|
||||
var dir = new Vec4();
|
||||
function update() {
|
||||
if (!body.bodyReady) return;
|
||||
if (!body.ready) return;
|
||||
|
||||
if (jump) {
|
||||
body.applyImpulse(new Vec4(0, 0, 20));
|
||||
|
|
27
Sources/armory/trait/internal/Navigation.hx
Normal file
27
Sources/armory/trait/internal/Navigation.hx
Normal file
|
@ -0,0 +1,27 @@
|
|||
package armory.trait.internal;
|
||||
|
||||
#if arm_navigation
|
||||
import haxerecast.Recast;
|
||||
import armory.trait.NavMesh;
|
||||
#end
|
||||
|
||||
@:keep
|
||||
class Navigation extends iron.Trait {
|
||||
|
||||
#if (!arm_navigation)
|
||||
public function new() { super(); }
|
||||
#else
|
||||
|
||||
public static var active:Navigation = null;
|
||||
|
||||
public var navMeshes:Array<NavMesh> = [];
|
||||
public var recast:Recast;
|
||||
|
||||
public function new() {
|
||||
super();
|
||||
active = this;
|
||||
|
||||
recast = untyped __js__("(1, eval)('this').recast");
|
||||
}
|
||||
#end
|
||||
}
|
|
@ -26,7 +26,7 @@ class RigidBody extends Trait {
|
|||
public var collisionMargin:Float;
|
||||
|
||||
public var body:BtRigidBodyPointer = null;
|
||||
public var bodyReady = false;
|
||||
public var ready = false;
|
||||
public var shapeConvexCreated:Bool;
|
||||
|
||||
static var nextId = 0;
|
||||
|
@ -61,8 +61,8 @@ class RigidBody extends Trait {
|
|||
transform = object.transform;
|
||||
physics = armory.trait.internal.PhysicsWorld.active;
|
||||
|
||||
if (bodyReady) return;
|
||||
bodyReady = true;
|
||||
if (ready) return;
|
||||
ready = true;
|
||||
|
||||
var _shape:BtCollisionShapePointer = null;
|
||||
var _shapeConvex:BtConvexHullShapePointer = null;
|
||||
|
@ -156,7 +156,7 @@ class RigidBody extends Trait {
|
|||
}
|
||||
|
||||
function lateUpdate() {
|
||||
if (!bodyReady) return;
|
||||
if (!ready) return;
|
||||
if (object.animation != null) {
|
||||
syncTransform();
|
||||
}
|
||||
|
|
|
@ -2330,11 +2330,19 @@ class ArmoryExporter:
|
|||
|
||||
# Scene root traits
|
||||
if bpy.data.worlds['Arm'].arm_physics != 'Disabled':
|
||||
self.output['traits'] = []
|
||||
if not 'traits' in self.output:
|
||||
self.output['traits'] = []
|
||||
x = {}
|
||||
x['type'] = 'Script'
|
||||
x['class_name'] = 'armory.trait.internal.PhysicsWorld'
|
||||
self.output['traits'].append(x)
|
||||
if bpy.data.worlds['Arm'].arm_navigation != 'Disabled':
|
||||
if not 'traits' in self.output:
|
||||
self.output['traits'] = []
|
||||
x = {}
|
||||
x['type'] = 'Script'
|
||||
x['class_name'] = 'armory.trait.internal.Navigation'
|
||||
self.output['traits'].append(x)
|
||||
|
||||
self.export_objects(self.scene)
|
||||
|
||||
|
@ -2552,6 +2560,26 @@ class ArmoryExporter:
|
|||
x['type'] = 'Script'
|
||||
if t.type_prop == 'Bundled Script':
|
||||
trait_prefix = 'armory.trait.'
|
||||
# TODO: temporary, export single mesh navmesh as obj
|
||||
if t.class_name_prop == 'NavMesh' and bobject.type == 'MESH' and bpy.data.worlds['Arm'].arm_navigation != 'Disabled':
|
||||
nav_path = armutils.get_fp() + '/build/compiled/Assets/navigation'
|
||||
if not os.path.exists(nav_path):
|
||||
os.makedirs(nav_path)
|
||||
nav_filepath = nav_path + '/nav_' + bobject.data.name + '.arm'
|
||||
assets.add(nav_filepath)
|
||||
# TODO: Implement cache
|
||||
#if os.path.isfile(nav_filepath) == False:
|
||||
with open(nav_filepath, 'w') as f:
|
||||
for v in bobject.data.vertices:
|
||||
# f.write("v %.4f %.4f %.4f\n" % v.co[:])
|
||||
f.write("v %.4f " % (v.co[0] * bobject.scale.x))
|
||||
f.write("%.4f " % (v.co[2] * bobject.scale.z))
|
||||
f.write("%.4f\n" % (-v.co[1] * bobject.scale.y))
|
||||
for p in bobject.data.polygons:
|
||||
f.write("f")
|
||||
for i in p.vertices:
|
||||
f.write(" %d" % (i + 1))
|
||||
f.write("\n")
|
||||
else:
|
||||
trait_prefix = bpy.data.worlds['Arm'].arm_project_package + '.'
|
||||
x['class_name'] = trait_prefix + t.class_name_prop
|
||||
|
|
|
@ -101,4 +101,6 @@ def build_default_node(inp):
|
|||
inpname = 'FloatNode.create(' + str(inp.default_value) + ')'
|
||||
elif inp.type == 'BOOLEAN':
|
||||
inpname = 'BoolNode.create(' + str(inp.default_value).lower() + ')'
|
||||
else:
|
||||
inpname = 'BoolNode.create(true)' # Unlinked triggers
|
||||
return inpname
|
||||
|
|
|
@ -20,7 +20,7 @@ class TransformNode(Node, ArmLogicTreeNode):
|
|||
bl_icon = 'SOUND'
|
||||
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketVector', "Position")
|
||||
self.inputs.new('NodeSocketVector', "Location")
|
||||
self.inputs.new('NodeSocketVector', "Rotation")
|
||||
self.inputs.new('NodeSocketVector', "Scale")
|
||||
self.inputs[-1].default_value = [1.0, 1.0, 1.0]
|
||||
|
@ -112,9 +112,31 @@ class SetTransformNode(Node, ArmLogicTreeNode):
|
|||
bl_icon = 'GAME'
|
||||
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketShader', "Trigger")
|
||||
self.inputs.new('NodeSocketShader', "Target")
|
||||
self.inputs.new('NodeSocketShader', "Transform")
|
||||
|
||||
class GoToNode(Node, ArmLogicTreeNode):
|
||||
'''Navigate to location'''
|
||||
bl_idname = 'GoToNodeType'
|
||||
bl_label = 'Go To'
|
||||
bl_icon = 'GAME'
|
||||
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketShader', "Trigger")
|
||||
self.inputs.new('NodeSocketShader', "Target")
|
||||
self.inputs.new('NodeSocketShader', "Transform")
|
||||
|
||||
class GetTransformNode(Node, ArmLogicTreeNode):
|
||||
'''Get transform node'''
|
||||
bl_idname = 'GetTransformNodeType'
|
||||
bl_label = 'Get Transform'
|
||||
bl_icon = 'GAME'
|
||||
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketShader', "Target")
|
||||
self.outputs.new('NodeSocketShader', "Transform")
|
||||
|
||||
class SetVisibleNode(Node, ArmLogicTreeNode):
|
||||
'''Set visible node'''
|
||||
bl_idname = 'SetVisibleNodeType'
|
||||
|
@ -134,6 +156,15 @@ class InputDownNode(Node, ArmLogicTreeNode):
|
|||
def init(self, context):
|
||||
self.outputs.new('NodeSocketBool', "Bool")
|
||||
|
||||
class InputStartedNode(Node, ArmLogicTreeNode):
|
||||
'''Input started node'''
|
||||
bl_idname = 'InputStartedNodeType'
|
||||
bl_label = 'Input Started'
|
||||
bl_icon = 'GAME'
|
||||
|
||||
def init(self, context):
|
||||
self.outputs.new('NodeSocketBool', "Bool")
|
||||
|
||||
class GreaterThanNode(Node, ArmLogicTreeNode):
|
||||
'''Greater than node'''
|
||||
bl_idname = 'GreaterThanNodeType'
|
||||
|
@ -154,7 +185,7 @@ class ObjectNodeCategory(NodeCategory):
|
|||
def poll(cls, context):
|
||||
return context.space_data.tree_type == 'ArmLogicTreeType'
|
||||
|
||||
class TypeNodeCategory(NodeCategory):
|
||||
class ValueNodeCategory(NodeCategory):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.space_data.tree_type == 'ArmLogicTreeType'
|
||||
|
@ -174,12 +205,11 @@ node_categories = [
|
|||
NodeItem("ThisNodeType"),
|
||||
NodeItem("PickerNodeType"),
|
||||
]),
|
||||
TypeNodeCategory("LOGICTYPENODES", "Type", items=[
|
||||
ValueNodeCategory("LOGICVALUENODES", "Value", items=[
|
||||
NodeItem("TransformNodeType"),
|
||||
NodeItem("VectorNodeType"),
|
||||
]),
|
||||
MathNodeCategory("LOGICMATHNODES", "Math", items=[
|
||||
NodeItem("TimeNodeType"),
|
||||
NodeItem("ScaleValueNodeType"),
|
||||
NodeItem("SineNodeType"),
|
||||
]),
|
||||
|
@ -188,10 +218,14 @@ node_categories = [
|
|||
]),
|
||||
LogicNodeCategory("LOGICOPERATORNODES", "Operator", items=[
|
||||
NodeItem("SetTransformNodeType"),
|
||||
NodeItem("GetTransformNodeType"),
|
||||
NodeItem("GoToNodeType"),
|
||||
NodeItem("SetVisibleNodeType"),
|
||||
]),
|
||||
LogicNodeCategory("LOGICINPUTNODES", "Input", items=[
|
||||
NodeItem("TimeNodeType"),
|
||||
NodeItem("InputDownNodeType"),
|
||||
NodeItem("InputStartedNodeType"),
|
||||
]),
|
||||
]
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ class ArmoryGenerateLodButton(bpy.types.Operator):
|
|||
def execute(self, context):
|
||||
obj = context.object
|
||||
if obj == None:
|
||||
return
|
||||
return{'CANCELLED'}
|
||||
|
||||
# Clear
|
||||
mdata = context.object.data
|
||||
|
|
50
blender/props_navigation.py
Executable file
50
blender/props_navigation.py
Executable file
|
@ -0,0 +1,50 @@
|
|||
import bpy
|
||||
from bpy.types import Menu, Panel, UIList
|
||||
from bpy.props import *
|
||||
|
||||
class ArmoryGenerateNavmeshButton(bpy.types.Operator):
|
||||
'''Generate navmesh from selected meshes'''
|
||||
bl_idname = 'arm.generate_navmesh'
|
||||
bl_label = 'Generate Navmesh'
|
||||
|
||||
def execute(self, context):
|
||||
obj = context.active_object
|
||||
if obj == None or obj.type != 'MESH':
|
||||
return{'CANCELLED'}
|
||||
|
||||
# TODO: build tilecache instead
|
||||
# export_obj()
|
||||
|
||||
# For visualization
|
||||
# bpy.ops.mesh.navmesh_make('EXEC_DEFAULT')
|
||||
# obj = context.active_object
|
||||
# obj.hide_render = True
|
||||
|
||||
# Navmesh trait
|
||||
# obj.my_traitlist.add()
|
||||
# obj.my_traitlist[-1].type_prop = 'Bundled Script'
|
||||
# obj.my_traitlist[-1].class_name_prop = 'NavMesh'
|
||||
|
||||
return{'FINISHED'}
|
||||
|
||||
class ScenePropsPanel(bpy.types.Panel):
|
||||
bl_label = "Armory Navigation"
|
||||
bl_space_type = "PROPERTIES"
|
||||
bl_region_type = "WINDOW"
|
||||
bl_context = "scene"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
scene = bpy.context.scene
|
||||
if scene == None:
|
||||
return
|
||||
|
||||
layout.operator("arm.generate_navmesh")
|
||||
|
||||
|
||||
def register():
|
||||
pass
|
||||
# bpy.utils.register_module(__name__)
|
||||
|
||||
def unregister():
|
||||
bpy.utils.unregister_module(__name__)
|
|
@ -6,6 +6,7 @@ import props_traits_clip
|
|||
import props_traits_params
|
||||
import props_traits
|
||||
import props_lod
|
||||
import props_navigation
|
||||
import props
|
||||
import props_ui
|
||||
import gen_renderpath
|
||||
|
@ -27,6 +28,7 @@ def register():
|
|||
props_traits_params.register()
|
||||
props_traits.register()
|
||||
props_lod.register()
|
||||
props_navigation.register()
|
||||
space_armory.register()
|
||||
keymap.register()
|
||||
|
||||
|
@ -38,6 +40,7 @@ def unregister():
|
|||
props_traits_params.unregister()
|
||||
props_traits.unregister()
|
||||
props_lod.unregister()
|
||||
props_navigation.unregister()
|
||||
handlers.unregister()
|
||||
gen_renderpath.unregister()
|
||||
props_ui.unregister()
|
||||
|
|
|
@ -37,6 +37,15 @@ project.addSources('Sources');
|
|||
ammojs_path = ammojs_path.replace('\\', '/')
|
||||
f.write("project.addAssets('" + ammojs_path + "');\n")
|
||||
|
||||
export_navigation = wrd.arm_navigation != 'Disabled'
|
||||
if export_navigation:
|
||||
f.write("project.addDefine('arm_navigation');\n")
|
||||
f.write(add_armory_library(sdk_path + '/lib/', 'haxerecast'))
|
||||
if state.target == 'krom' or state.target == 'html5':
|
||||
recastjs_path = sdk_path + '/lib/haxerecast/js/recast/recast.js'
|
||||
recastjs_path = recastjs_path.replace('\\', '/')
|
||||
f.write("project.addAssets('" + recastjs_path + "');\n")
|
||||
|
||||
if dce_full:
|
||||
f.write("project.addParameter('-dce full');")
|
||||
|
||||
|
@ -99,20 +108,25 @@ class Main {
|
|||
static inline var projectHeight = """ + str(resy) + """;
|
||||
static inline var projectSamplesPerPixel = """ + str(wrd.arm_project_samples_per_pixel) + """;
|
||||
static inline var projectScene = '""" + scene_name + scene_ext + """';
|
||||
static var state:Int;
|
||||
static function loadLib(name:String) {
|
||||
kha.LoaderImpl.loadBlobFromDescription({ files: [name] }, function(b:kha.Blob) {
|
||||
untyped __js__("(1, eval)({0})", b.toString());
|
||||
state--;
|
||||
start();
|
||||
});
|
||||
}
|
||||
public static function main() {
|
||||
iron.system.CompileTime.importPackage('armory.trait');
|
||||
iron.system.CompileTime.importPackage('armory.renderpath');
|
||||
iron.system.CompileTime.importPackage('""" + wrd.arm_project_package + """');
|
||||
#if (js && arm_physics)
|
||||
kha.LoaderImpl.loadBlobFromDescription({ files: ["ammo.js"] }, function(b:kha.Blob) {
|
||||
untyped __js__("(1, eval)({0})", b.toString());
|
||||
start();
|
||||
});
|
||||
#else
|
||||
start();
|
||||
#end
|
||||
state = 1;
|
||||
#if (js && arm_physics) state++; loadLib("ammo.js"); #end
|
||||
#if (js && arm_navigation) state++; loadLib("recast.js"); #end
|
||||
state--; start();
|
||||
}
|
||||
static function start() {
|
||||
if (state > 0) return;
|
||||
armory.object.Uniforms.register();
|
||||
kha.System.init({title: projectName, width: projectWidth, height: projectHeight, samplesPerPixel: projectSamplesPerPixel}, function() {
|
||||
iron.App.init(function() {
|
||||
|
|
Loading…
Reference in a new issue