forked from LeenkxTeam/LNXSDK
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 48f5575e4e | |||
| f2c4be6336 | |||
| 2ddc938db8 | |||
| 5eb735ada2 | |||
| 9894cc20f2 | |||
| dbe6d0829a | |||
| 6f383e2ab2 | |||
| 5c2d29d7ce | |||
| 28579e14d7 | |||
| 2ec6f43cc5 | |||
| 027021815a | |||
| b9b387803f | |||
| e05d9d0237 | |||
| c908e6cad2 | |||
| 506a0a0245 | |||
| 5cf33724e4 | |||
| ac5aa3d19c | |||
| 0c534ee632 | |||
| e3e7855d26 | |||
| f7917974f8 | |||
| fa2d8f05d5 |
@ -24,6 +24,9 @@ class ObjectAnimation extends Animation {
|
|||||||
|
|
||||||
public var transformMap: Map<String, FastFloat>;
|
public var transformMap: Map<String, FastFloat>;
|
||||||
|
|
||||||
|
var defaultSampler: ActionSampler = null;
|
||||||
|
static inline var DEFAULT_SAMPLER_ID = "__object_default_action__";
|
||||||
|
|
||||||
public static var trackNames: Array<String> = [ "xloc", "yloc", "zloc",
|
public static var trackNames: Array<String> = [ "xloc", "yloc", "zloc",
|
||||||
"xrot", "yrot", "zrot",
|
"xrot", "yrot", "zrot",
|
||||||
"qwrot", "qxrot", "qyrot", "qzrot",
|
"qwrot", "qxrot", "qyrot", "qzrot",
|
||||||
@ -39,7 +42,6 @@ class ObjectAnimation extends Animation {
|
|||||||
isSkinned = false;
|
isSkinned = false;
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAction(action: String): TObj {
|
function getAction(action: String): TObj {
|
||||||
for (a in oactions) if (a != null && a.objects[0].name == action) return a.objects[0];
|
for (a in oactions) if (a != null && a.objects[0].name == action) return a.objects[0];
|
||||||
return null;
|
return null;
|
||||||
@ -47,10 +49,29 @@ class ObjectAnimation extends Animation {
|
|||||||
|
|
||||||
override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.0, speed = 1.0, loop = true) {
|
override public function play(action = "", onComplete: Void->Void = null, blendTime = 0.0, speed = 1.0, loop = true) {
|
||||||
super.play(action, onComplete, blendTime, speed, loop);
|
super.play(action, onComplete, blendTime, speed, loop);
|
||||||
if (this.action == "" && oactions[0] != null) this.action = oactions[0].objects[0].name;
|
if (this.action == "" && oactions != null && oactions[0] != null){
|
||||||
|
this.action = oactions[0].objects[0].name;
|
||||||
|
}
|
||||||
oaction = getAction(this.action);
|
oaction = getAction(this.action);
|
||||||
if (oaction != null) {
|
if (oaction != null) {
|
||||||
isSampled = oaction.sampled != null && oaction.sampled;
|
isSampled = oaction.sampled != null && oaction.sampled;
|
||||||
|
if (defaultSampler != null) {
|
||||||
|
deRegisterAction(DEFAULT_SAMPLER_ID);
|
||||||
|
}
|
||||||
|
var callbacks = onComplete != null ? [onComplete] : null;
|
||||||
|
defaultSampler = new ActionSampler(this.action, speed, loop, false, callbacks);
|
||||||
|
registerAction(DEFAULT_SAMPLER_ID, defaultSampler);
|
||||||
|
if (paused) defaultSampler.paused = true;
|
||||||
|
updateAnimation = function(map: Map<String, FastFloat>) {
|
||||||
|
sampleAction(defaultSampler, map);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (defaultSampler != null) {
|
||||||
|
deRegisterAction(DEFAULT_SAMPLER_ID);
|
||||||
|
defaultSampler = null;
|
||||||
|
}
|
||||||
|
updateAnimation = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,12 +82,13 @@ class ObjectAnimation extends Animation {
|
|||||||
Animation.beginProfile();
|
Animation.beginProfile();
|
||||||
#end
|
#end
|
||||||
|
|
||||||
if(transformMap == null) transformMap = new Map();
|
if (transformMap == null) transformMap = new Map();
|
||||||
transformMap = initTransformMap();
|
transformMap = initTransformMap();
|
||||||
|
|
||||||
super.update(delta);
|
super.update(delta);
|
||||||
|
if (defaultSampler != null) defaultSampler.paused = paused;
|
||||||
if (paused) return;
|
if (paused) return;
|
||||||
if(updateAnimation == null) return;
|
if (updateAnimation == null) return;
|
||||||
if (!isSkinned) updateObjectAnimation();
|
if (!isSkinned) updateObjectAnimation();
|
||||||
|
|
||||||
#if lnx_debug
|
#if lnx_debug
|
||||||
|
|||||||
@ -71,11 +71,12 @@ class ParticleSystem {
|
|||||||
Data.getParticle(sceneName, pref.particle, function(b: ParticleData) {
|
Data.getParticle(sceneName, pref.particle, function(b: ParticleData) {
|
||||||
data = b;
|
data = b;
|
||||||
r = data.raw;
|
r = data.raw;
|
||||||
if (r.dynamic_emitter != null){
|
var dyn: Null<Bool> = r.dynamic_emitter;
|
||||||
dynamicEmitter = r.dynamic_emitter;
|
var dynValue: Bool = true;
|
||||||
} else {
|
if (dyn != null) {
|
||||||
dynamicEmitter = true;
|
dynValue = dyn;
|
||||||
}
|
}
|
||||||
|
dynamicEmitter = dynValue;
|
||||||
if (Scene.active.raw.gravity != null) {
|
if (Scene.active.raw.gravity != null) {
|
||||||
gx = Scene.active.raw.gravity[0] * r.weight_gravity;
|
gx = Scene.active.raw.gravity[0] * r.weight_gravity;
|
||||||
gy = Scene.active.raw.gravity[1] * r.weight_gravity;
|
gy = Scene.active.raw.gravity[1] * r.weight_gravity;
|
||||||
|
|||||||
48
leenkx/Sources/leenkx/logicnode/AnyContactNode.hx
Normal file
48
leenkx/Sources/leenkx/logicnode/AnyContactNode.hx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package leenkx.logicnode;
|
||||||
|
import iron.object.Object;
|
||||||
|
|
||||||
|
#if lnx_physics
|
||||||
|
import leenkx.trait.physics.PhysicsCache;
|
||||||
|
import leenkx.trait.physics.RigidBody;
|
||||||
|
#end
|
||||||
|
|
||||||
|
class AnyContactNode extends LogicNode {
|
||||||
|
|
||||||
|
public var property0: String;
|
||||||
|
var lastContact = false;
|
||||||
|
|
||||||
|
public function new(tree: LogicTree) {
|
||||||
|
super(tree);
|
||||||
|
tree.notifyOnUpdate(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
var object1: Object = inputs[0].get();
|
||||||
|
if (object1 == null) object1 = tree.object;
|
||||||
|
if (object1 == null) return;
|
||||||
|
|
||||||
|
var contact = false;
|
||||||
|
|
||||||
|
#if lnx_physics
|
||||||
|
var rb1 = PhysicsCache.getCachedRigidBody(object1);
|
||||||
|
if (rb1 != null) {
|
||||||
|
var rbs = PhysicsCache.getCachedContacts(rb1);
|
||||||
|
contact = (rbs != null && rbs.length > 0);
|
||||||
|
}
|
||||||
|
#end
|
||||||
|
|
||||||
|
var shouldTrigger = false;
|
||||||
|
switch (property0) {
|
||||||
|
case "begin":
|
||||||
|
shouldTrigger = contact && !lastContact;
|
||||||
|
case "overlap":
|
||||||
|
shouldTrigger = contact;
|
||||||
|
case "end":
|
||||||
|
shouldTrigger = !contact && lastContact;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastContact = contact;
|
||||||
|
|
||||||
|
if (shouldTrigger) runOutput(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,74 +1,32 @@
|
|||||||
package leenkx.logicnode;
|
package leenkx.logicnode;
|
||||||
|
|
||||||
import iron.object.Object;
|
import iron.object.Object;
|
||||||
|
|
||||||
|
#if lnx_physics
|
||||||
|
import leenkx.trait.physics.PhysicsCache;
|
||||||
import leenkx.trait.physics.RigidBody;
|
import leenkx.trait.physics.RigidBody;
|
||||||
|
#end
|
||||||
|
|
||||||
class HasContactNode extends LogicNode {
|
class HasContactNode extends LogicNode {
|
||||||
|
|
||||||
public var property0: Bool; // "any object" checkbox
|
|
||||||
|
|
||||||
// Performance optimization: Cache RigidBody lookups
|
|
||||||
var cachedRb1: RigidBody = null;
|
|
||||||
var cachedRb2: RigidBody = null;
|
|
||||||
var lastObject1: Object = null;
|
|
||||||
var lastObject2: Object = null;
|
|
||||||
var lastContactCount: Int = 0;
|
|
||||||
var lastFrame: Int = -1;
|
|
||||||
|
|
||||||
public function new(tree: LogicTree) {
|
public function new(tree: LogicTree) {
|
||||||
super(tree);
|
super(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
override function get(from: Int): Dynamic {
|
override function get(from: Int): Dynamic {
|
||||||
var object1: Object = inputs[0].get();
|
var object1: Object = inputs[0].get();
|
||||||
if (object1 == null) return false;
|
|
||||||
|
|
||||||
#if lnx_physics
|
|
||||||
// Enhanced caching: Check both object reference AND RigidBody availability
|
|
||||||
var shouldUpdateCache1 = false;
|
|
||||||
if (object1 != lastObject1) {
|
|
||||||
// Object reference changed - always update cache
|
|
||||||
shouldUpdateCache1 = true;
|
|
||||||
} else if (cachedRb1 == null) {
|
|
||||||
// Same object but no cached RigidBody - check if one was added
|
|
||||||
var currentRb1 = object1.getTrait(RigidBody);
|
|
||||||
if (currentRb1 != null) {
|
|
||||||
shouldUpdateCache1 = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldUpdateCache1) {
|
|
||||||
cachedRb1 = object1.getTrait(RigidBody);
|
|
||||||
lastObject1 = object1;
|
|
||||||
}
|
|
||||||
if (cachedRb1 == null) return false;
|
|
||||||
|
|
||||||
var physics = leenkx.trait.physics.PhysicsWorld.active;
|
|
||||||
var rbs = physics.getContacts(cachedRb1);
|
|
||||||
|
|
||||||
// Early exit if no contacts
|
|
||||||
if (rbs == null || rbs.length == 0) return false;
|
|
||||||
|
|
||||||
// If "any object" mode, any contact is valid - return immediately
|
|
||||||
if (property0) return true;
|
|
||||||
|
|
||||||
// Specific object mode - check if second input exists
|
|
||||||
if (inputs.length <= 1) return false;
|
|
||||||
|
|
||||||
var object2: Object = inputs[1].get();
|
var object2: Object = inputs[1].get();
|
||||||
if (object2 == null) return false;
|
|
||||||
|
|
||||||
// Cache second RigidBody lookup
|
if (object1 == null || object2 == null) return false;
|
||||||
if (object2 != lastObject2) {
|
|
||||||
cachedRb2 = object2.getTrait(RigidBody);
|
#if lnx_physics
|
||||||
lastObject2 = object2;
|
var rb1 = PhysicsCache.getCachedRigidBody(object1);
|
||||||
|
var rb2 = PhysicsCache.getCachedRigidBody(object2);
|
||||||
|
|
||||||
|
if (rb1 != null && rb2 != null) {
|
||||||
|
var rbs = PhysicsCache.getCachedContacts(rb1);
|
||||||
|
return PhysicsCache.hasContactWith(rbs, rb2);
|
||||||
}
|
}
|
||||||
if (cachedRb2 == null) return false;
|
#end
|
||||||
|
|
||||||
// Use indexOf for better performance than manual loop
|
|
||||||
// This is more efficient for small arrays and uses native array methods
|
|
||||||
return rbs.indexOf(cachedRb2) >= 0;
|
|
||||||
#end
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,103 +1,54 @@
|
|||||||
package leenkx.logicnode;
|
package leenkx.logicnode;
|
||||||
|
|
||||||
import iron.object.Object;
|
import iron.object.Object;
|
||||||
|
|
||||||
|
#if lnx_physics
|
||||||
|
import leenkx.trait.physics.PhysicsCache;
|
||||||
import leenkx.trait.physics.RigidBody;
|
import leenkx.trait.physics.RigidBody;
|
||||||
|
#end
|
||||||
|
|
||||||
|
|
||||||
class OnContactNode extends LogicNode {
|
class OnContactNode extends LogicNode {
|
||||||
|
|
||||||
public var property0: String; // Contact type: "begin", "overlap", "end"
|
public var property0: String;
|
||||||
public var property1: Bool; // "On Any Object" checkbox
|
var lastContact = false;
|
||||||
|
|
||||||
// Cache for performance optimization
|
|
||||||
var cachedRb1: RigidBody = null;
|
|
||||||
var cachedRb2: RigidBody = null;
|
|
||||||
var lastObject1: Object = null;
|
|
||||||
var lastObject2: Object = null;
|
|
||||||
var lastObject1TraitCount: Int = 0;
|
|
||||||
var lastObject2TraitCount: Int = 0;
|
|
||||||
var lastContact = false; // Track previous contact state
|
|
||||||
|
|
||||||
public function new(tree: LogicTree) {
|
public function new(tree: LogicTree) {
|
||||||
super(tree);
|
super(tree);
|
||||||
// Subscribe to update events for event-based triggering
|
|
||||||
tree.notifyOnUpdate(update);
|
tree.notifyOnUpdate(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
var object1: Object = inputs[0].get();
|
var object1: Object = inputs[0].get();
|
||||||
if (object1 == null) return;
|
var object2: Object = inputs[1].get();
|
||||||
|
|
||||||
#if lnx_physics
|
if (object1 == null) object1 = tree.object;
|
||||||
// Smart caching: update cache if object changes OR if trait count changes
|
if (object2 == null) object2 = tree.object;
|
||||||
var shouldUpdateCache1 = (object1 != lastObject1) ||
|
|
||||||
(lastObject1 != null && lastObject1.traits.length != lastObject1TraitCount);
|
|
||||||
|
|
||||||
if (shouldUpdateCache1) {
|
|
||||||
cachedRb1 = object1.getTrait(RigidBody);
|
|
||||||
lastObject1 = object1;
|
|
||||||
lastObject1TraitCount = object1.traits.length;
|
|
||||||
}
|
|
||||||
if (cachedRb1 == null) return;
|
|
||||||
|
|
||||||
var rbs = leenkx.trait.physics.PhysicsWorld.active.getContacts(cachedRb1);
|
|
||||||
if (rbs == null || rbs.length == 0) {
|
|
||||||
// No contacts - handle "end" event
|
|
||||||
if (lastContact && property0 == "end") {
|
|
||||||
runOutput(0);
|
|
||||||
}
|
|
||||||
lastContact = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for contact
|
|
||||||
var contact = false;
|
var contact = false;
|
||||||
|
|
||||||
// If "On Any Object" mode, any contact is valid
|
#if lnx_physics
|
||||||
if (property1) {
|
var rb1 = PhysicsCache.getCachedRigidBody(object1);
|
||||||
contact = true;
|
var rb2 = PhysicsCache.getCachedRigidBody(object2);
|
||||||
} else {
|
|
||||||
// Specific object mode - check if second input exists
|
|
||||||
if (inputs.length <= 1) return;
|
|
||||||
|
|
||||||
var object2: Object = inputs[1].get();
|
if (rb1 != null && rb2 != null) {
|
||||||
if (object2 == null) return;
|
var rbs = PhysicsCache.getCachedContacts(rb1);
|
||||||
|
contact = PhysicsCache.hasContactWith(rbs, rb2);
|
||||||
// Smart caching for second object
|
|
||||||
var shouldUpdateCache2 = (object2 != lastObject2) ||
|
|
||||||
(lastObject2 != null && lastObject2.traits.length != lastObject2TraitCount);
|
|
||||||
|
|
||||||
if (shouldUpdateCache2) {
|
|
||||||
cachedRb2 = object2.getTrait(RigidBody);
|
|
||||||
lastObject2 = object2;
|
|
||||||
lastObject2TraitCount = object2.traits.length;
|
|
||||||
}
|
}
|
||||||
if (cachedRb2 == null) return;
|
#end
|
||||||
|
|
||||||
// Check if target object is in contact list
|
var b = false;
|
||||||
contact = rbs.indexOf(cachedRb2) >= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle different contact event types
|
|
||||||
var shouldTrigger = false;
|
|
||||||
switch (property0) {
|
switch (property0) {
|
||||||
case "begin":
|
case "begin":
|
||||||
shouldTrigger = contact && !lastContact;
|
b = contact && !lastContact;
|
||||||
case "overlap":
|
case "overlap":
|
||||||
shouldTrigger = contact;
|
b = contact;
|
||||||
case "end":
|
case "end":
|
||||||
shouldTrigger = !contact && lastContact;
|
b = !contact && lastContact;
|
||||||
}
|
}
|
||||||
|
|
||||||
lastContact = contact;
|
lastContact = contact;
|
||||||
|
|
||||||
if (shouldTrigger) {
|
if (b) runOutput(0);
|
||||||
runOutput(0);
|
|
||||||
}
|
|
||||||
#end
|
|
||||||
}
|
|
||||||
|
|
||||||
// Keep the get method for backward compatibility, but it's not the primary interface
|
|
||||||
override function get(from: Int): Dynamic {
|
|
||||||
return lastContact;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
98
leenkx/Sources/leenkx/trait/physics/PhysicsCache.hx
Normal file
98
leenkx/Sources/leenkx/trait/physics/PhysicsCache.hx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package leenkx.trait.physics;
|
||||||
|
|
||||||
|
import iron.object.Object;
|
||||||
|
|
||||||
|
class PhysicsCache {
|
||||||
|
#if lnx_physics
|
||||||
|
static var rbCache: Map<Int, Dynamic> = new Map();
|
||||||
|
static var contactsCache: Map<Int, Array<Dynamic>> = new Map();
|
||||||
|
static var physicsFrame: Int = 0;
|
||||||
|
static var lastQueryFrame: Int = -1;
|
||||||
|
#end
|
||||||
|
|
||||||
|
public static function getCachedRigidBody(object: Object): Dynamic {
|
||||||
|
#if (!lnx_physics)
|
||||||
|
return null;
|
||||||
|
#else
|
||||||
|
if (object == null) return null;
|
||||||
|
|
||||||
|
var cached = rbCache.get(object.uid);
|
||||||
|
if (cached != null) return cached;
|
||||||
|
|
||||||
|
#if lnx_bullet
|
||||||
|
var rb = object.getTrait(leenkx.trait.physics.bullet.RigidBody);
|
||||||
|
#else
|
||||||
|
var rb = object.getTrait(leenkx.trait.physics.oimo.RigidBody);
|
||||||
|
#end
|
||||||
|
|
||||||
|
if (rb != null) rbCache.set(object.uid, rb);
|
||||||
|
return rb;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getCachedContacts(rb: Dynamic): Array<Dynamic> {
|
||||||
|
#if (!lnx_physics)
|
||||||
|
return null;
|
||||||
|
#else
|
||||||
|
if (rb == null) return null;
|
||||||
|
|
||||||
|
var rbObjectId = (rb.object != null) ? rb.object.uid : -1;
|
||||||
|
|
||||||
|
if (rbObjectId == -1) {
|
||||||
|
#if lnx_bullet
|
||||||
|
if (leenkx.trait.physics.bullet.PhysicsWorld.active == null) return null;
|
||||||
|
return leenkx.trait.physics.bullet.PhysicsWorld.active.getContacts(rb);
|
||||||
|
#else
|
||||||
|
if (leenkx.trait.physics.oimo.PhysicsWorld.active == null) return null;
|
||||||
|
return leenkx.trait.physics.oimo.PhysicsWorld.active.getContacts(rb);
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastQueryFrame == physicsFrame) {
|
||||||
|
var cached = contactsCache.get(rbObjectId);
|
||||||
|
if (cached != null) return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastQueryFrame = physicsFrame;
|
||||||
|
|
||||||
|
var cached = contactsCache.get(rbObjectId);
|
||||||
|
if (cached != null) return cached;
|
||||||
|
|
||||||
|
#if lnx_bullet
|
||||||
|
if (leenkx.trait.physics.bullet.PhysicsWorld.active == null) return null;
|
||||||
|
var contacts = leenkx.trait.physics.bullet.PhysicsWorld.active.getContacts(rb);
|
||||||
|
#else
|
||||||
|
if (leenkx.trait.physics.oimo.PhysicsWorld.active == null) return null;
|
||||||
|
var contacts = leenkx.trait.physics.oimo.PhysicsWorld.active.getContacts(rb);
|
||||||
|
#end
|
||||||
|
|
||||||
|
if (contacts != null) {
|
||||||
|
contactsCache.set(rbObjectId, contacts);
|
||||||
|
}
|
||||||
|
|
||||||
|
return contacts;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static inline function hasContactWith(contacts: Array<Dynamic>, target: Dynamic): Bool {
|
||||||
|
#if (!lnx_physics)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return contacts != null && target != null && contacts.indexOf(target) >= 0;
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function clearCache() {
|
||||||
|
#if lnx_physics
|
||||||
|
rbCache.clear();
|
||||||
|
contactsCache.clear();
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function clearContactsCache() {
|
||||||
|
#if lnx_physics
|
||||||
|
physicsFrame++;
|
||||||
|
contactsCache.clear();
|
||||||
|
#end
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,11 +8,9 @@ class PhysicsWorld extends iron.Trait { public function new() { super(); } }
|
|||||||
#else
|
#else
|
||||||
|
|
||||||
#if lnx_bullet
|
#if lnx_bullet
|
||||||
|
|
||||||
typedef PhysicsWorld = leenkx.trait.physics.bullet.PhysicsWorld;
|
typedef PhysicsWorld = leenkx.trait.physics.bullet.PhysicsWorld;
|
||||||
typedef Hit = leenkx.trait.physics.bullet.PhysicsWorld.Hit;
|
typedef Hit = leenkx.trait.physics.bullet.PhysicsWorld.Hit;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
typedef PhysicsWorld = leenkx.trait.physics.oimo.PhysicsWorld;
|
typedef PhysicsWorld = leenkx.trait.physics.oimo.PhysicsWorld;
|
||||||
typedef Hit = leenkx.trait.physics.oimo.PhysicsWorld.Hit;
|
typedef Hit = leenkx.trait.physics.oimo.PhysicsWorld.Hit;
|
||||||
#end
|
#end
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import iron.system.Time;
|
|||||||
import iron.math.Vec4;
|
import iron.math.Vec4;
|
||||||
import iron.math.Quat;
|
import iron.math.Quat;
|
||||||
import iron.math.RayCaster;
|
import iron.math.RayCaster;
|
||||||
|
import leenkx.trait.physics.PhysicsCache;
|
||||||
|
|
||||||
class Hit {
|
class Hit {
|
||||||
|
|
||||||
@ -145,6 +146,7 @@ class PhysicsWorld extends Trait {
|
|||||||
|
|
||||||
iron.Scene.active.notifyOnRemove(function() {
|
iron.Scene.active.notifyOnRemove(function() {
|
||||||
sceneRemoved = true;
|
sceneRemoved = true;
|
||||||
|
PhysicsCache.clearCache();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,6 +305,8 @@ class PhysicsWorld extends Trait {
|
|||||||
var t = Time.fixedStep * timeScale * Time.scale;
|
var t = Time.fixedStep * timeScale * Time.scale;
|
||||||
if (t == 0.0) return; // Simulation paused
|
if (t == 0.0) return; // Simulation paused
|
||||||
|
|
||||||
|
PhysicsCache.clearContactsCache();
|
||||||
|
|
||||||
#if lnx_debug
|
#if lnx_debug
|
||||||
var startTime = kha.Scheduler.realTime();
|
var startTime = kha.Scheduler.realTime();
|
||||||
#end
|
#end
|
||||||
|
|||||||
25
leenkx/blender/lnx/logicnode/physics/LN_any_contact.py
Normal file
25
leenkx/blender/lnx/logicnode/physics/LN_any_contact.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
from lnx.logicnode.lnx_nodes import *
|
||||||
|
|
||||||
|
class AnyContactNode(LnxLogicTreeNode):
|
||||||
|
"""Activates the output when the rigid body of the connected object makes contact with
|
||||||
|
any other rigid body.
|
||||||
|
"""
|
||||||
|
bl_idname = 'LNAnyContactNode'
|
||||||
|
bl_label = 'Any Contact'
|
||||||
|
lnx_section = 'contact'
|
||||||
|
lnx_version = 1
|
||||||
|
|
||||||
|
property0: HaxeEnumProperty(
|
||||||
|
'property0',
|
||||||
|
items = [('begin', 'Begin', 'Contact with any object begins'),
|
||||||
|
('overlap', 'Overlap', 'Contact with any object is happening'),
|
||||||
|
('end', 'End', 'Contact with any object ends')],
|
||||||
|
name='', default='begin')
|
||||||
|
|
||||||
|
def lnx_init(self, context):
|
||||||
|
self.add_input('LnxNodeSocketObject', 'RB')
|
||||||
|
|
||||||
|
self.add_output('LnxNodeSocketAction', 'Out')
|
||||||
|
|
||||||
|
def draw_buttons(self, context, layout):
|
||||||
|
layout.prop(self, 'property0')
|
||||||
@ -1,16 +1,5 @@
|
|||||||
from lnx.logicnode.lnx_nodes import *
|
from lnx.logicnode.lnx_nodes import *
|
||||||
|
|
||||||
def toggle_second_input(self, context):
|
|
||||||
"""Show/hide the second input socket based on the 'On Any Object' checkbox"""
|
|
||||||
if self.property0: # "On Any Object" is enabled
|
|
||||||
# Hide the second input socket
|
|
||||||
if len(self.inputs) > 1:
|
|
||||||
self.inputs.remove(self.inputs.values()[-1])
|
|
||||||
else: # "On Any Object" is disabled
|
|
||||||
# Show the second input socket if it doesn't exist
|
|
||||||
if len(self.inputs) == 1:
|
|
||||||
self.add_input('LnxNodeSocketObject', 'RB 2')
|
|
||||||
|
|
||||||
class HasContactNode(LnxLogicTreeNode):
|
class HasContactNode(LnxLogicTreeNode):
|
||||||
"""Returns whether the given rigid body has contact with another given rigid body."""
|
"""Returns whether the given rigid body has contact with another given rigid body."""
|
||||||
bl_idname = 'LNHasContactNode'
|
bl_idname = 'LNHasContactNode'
|
||||||
@ -18,18 +7,8 @@ class HasContactNode(LnxLogicTreeNode):
|
|||||||
lnx_section = 'contact'
|
lnx_section = 'contact'
|
||||||
lnx_version = 1
|
lnx_version = 1
|
||||||
|
|
||||||
property0: HaxeBoolProperty(
|
|
||||||
'property0',
|
|
||||||
name='On Any Object',
|
|
||||||
description='If enabled, returns true if the rigid body has contact with any object',
|
|
||||||
default=False,
|
|
||||||
update=toggle_second_input)
|
|
||||||
|
|
||||||
def lnx_init(self, context):
|
def lnx_init(self, context):
|
||||||
self.add_input('LnxNodeSocketObject', 'RB 1')
|
self.add_input('LnxNodeSocketObject', 'RB 1')
|
||||||
self.add_input('LnxNodeSocketObject', 'RB 2')
|
self.add_input('LnxNodeSocketObject', 'RB 2')
|
||||||
|
|
||||||
self.add_output('LnxBoolSocket', 'Has Contact')
|
self.add_output('LnxBoolSocket', 'Has Contact')
|
||||||
|
|
||||||
def draw_buttons(self, context, layout):
|
|
||||||
layout.prop(self, 'property0') # "On Any Object" checkbox
|
|
||||||
|
|||||||
@ -1,16 +1,5 @@
|
|||||||
from lnx.logicnode.lnx_nodes import *
|
from lnx.logicnode.lnx_nodes import *
|
||||||
|
|
||||||
def toggle_second_input(self, context):
|
|
||||||
"""Show/hide the second input socket based on the 'On Any Object' checkbox"""
|
|
||||||
if self.property1: # "On Any Object" is enabled
|
|
||||||
# Hide the second input socket
|
|
||||||
if len(self.inputs) > 1:
|
|
||||||
self.inputs.remove(self.inputs.values()[-1])
|
|
||||||
else: # "On Any Object" is disabled
|
|
||||||
# Show the second input socket if it doesn't exist
|
|
||||||
if len(self.inputs) == 1:
|
|
||||||
self.add_input('LnxNodeSocketObject', 'RB 2')
|
|
||||||
|
|
||||||
class OnContactNode(LnxLogicTreeNode):
|
class OnContactNode(LnxLogicTreeNode):
|
||||||
"""Activates the output when the rigid body make contact with
|
"""Activates the output when the rigid body make contact with
|
||||||
another rigid body.
|
another rigid body.
|
||||||
@ -34,13 +23,6 @@ class OnContactNode(LnxLogicTreeNode):
|
|||||||
('end', 'End', 'The contact between the rigid bodies ends')],
|
('end', 'End', 'The contact between the rigid bodies ends')],
|
||||||
name='', default='begin')
|
name='', default='begin')
|
||||||
|
|
||||||
property1: HaxeBoolProperty(
|
|
||||||
'property1',
|
|
||||||
name='On Any Object',
|
|
||||||
description='If enabled, triggers on contact with any object instead of a specific object',
|
|
||||||
default=False,
|
|
||||||
update=toggle_second_input)
|
|
||||||
|
|
||||||
def lnx_init(self, context):
|
def lnx_init(self, context):
|
||||||
self.add_input('LnxNodeSocketObject', 'RB 1')
|
self.add_input('LnxNodeSocketObject', 'RB 1')
|
||||||
self.add_input('LnxNodeSocketObject', 'RB 2')
|
self.add_input('LnxNodeSocketObject', 'RB 2')
|
||||||
@ -49,4 +31,3 @@ class OnContactNode(LnxLogicTreeNode):
|
|||||||
|
|
||||||
def draw_buttons(self, context, layout):
|
def draw_buttons(self, context, layout):
|
||||||
layout.prop(self, 'property0')
|
layout.prop(self, 'property0')
|
||||||
layout.prop(self, 'property1') # "On Any Object" checkbox
|
|
||||||
|
|||||||
Reference in New Issue
Block a user