armory/blender/arm/logicnode/physics/LN_add_physics_constraint.py
2020-12-05 01:12:59 +01:00

177 lines
7.9 KiB
Python

from arm.logicnode.arm_nodes import *
class AddPhysicsConstraintNode(ArmLogicTreeNode):
"""
Add a physics constraint to constrain two rigid bodies if not already present.
@option Fixed: No fredom of movement. Relative positions and rotations of rigid bodies are fixed
@option Point: Both rigid bodies are constrained at the pivot object.
@option Hinge: Constrained objects can move only along angular Z axis of the pivot object.
@option Slider: Constrained objects can move only along linear X axis of the pivot object.
@option Piston: Constrained objects can move only and rotate along X axis of the pivot object.
@option GenericSpring: Fully custimizable generic 6 degree of freedom constraint with optional springs. All liner and angular axes can be constrained
along with spring options. Use `Physics Constraint Node` to set a combination of constraints and springs.
@seeNode Physics Constraint
@input Pivot object: The object to which the physics constraint traint is applied. This object will not be affected by the constraint
but is necessary to specify the constraint axes and location. Hence, the pivot object need not be a rigid body. Typically an `Empty`
object may be used. Each pivot object can have only one constraint trait applied. Moving/rotating/parenting the pivot object after the constraint
is applied has no effect. However, removig the pivot object removes the constraint and `RB 1` and `RB 2` are no longer constrained.
@input RB 1: The first rigid body to be constrained. Must be a rigid body. This object can be constrained by more than one constraint.
@input RB 2: The second rigid body to be constrained. Must be a rigid body. This object can be constrained by more than one constraint.
@input Disable Collisions: Disable collisions between `RB 1` and `RB 2`
@input Breakable: Constraint can break if stress on the constraint is more than the set threshold. Disable this option to disable breaking.
@input Breaking threshold: Stress on the constraint above which the constraint breaks. Depends on the mass, velocity of rigid bodies and type of constraint.
@input Limit Lower: Lower limit of the consraint in that particular axis
@input Limit Upper: Upper limit of the constraint in that particular axis. (`lower limit` = `upper limit`) --> Fully constrained. (`lower limit` < `upper limit`) --> Partially constrained
(`lower limit` > `upper limit`) --> Full freedom.
@input Angular limits: Limits to constarin rotation. Specified in degrees. Range (-360 to +360)
@input Add Constarint: Option to add custom constraint to `Generic Spring` type.
"""
bl_idname = 'LNAddPhysicsConstraintNode'
bl_label = 'Add Physics Constraint'
arm_sction = 'add'
arm_version = 1
@staticmethod
def get_enum_id_value(obj, prop_name, value):
return obj.bl_rna.properties[prop_name].enum_items[value].identifier
@staticmethod
def get_count_in(type_name):
return {
'Fixed': 0,
'Point': 1,
'Hinge': 2,
'Slider': 3,
'Piston': 4,
'Generic Spring': 5
}.get(type_name, 0)
def get_enum(self):
return self.get('property0', 0)
def set_enum(self, value):
# Checking the selection of another type
select_current = self.get_enum_id_value(self, 'property0', value)
select_prev = self.property0
#Check if a different type is selected
if select_prev != select_current:
print('New value selected')
# Arguements for type Fixed
if (self.get_count_in(select_current) == 0):
while (len(self.inputs) > 7):
self.inputs.remove(self.inputs.values()[-1])
# Arguements for type Point
if (self.get_count_in(select_current) == 1):
while (len(self.inputs) > 7):
self.inputs.remove(self.inputs.values()[-1])
#Arguements for type Hinge
if (self.get_count_in(select_current) == 2):
while (len(self.inputs) > 7):
self.inputs.remove(self.inputs.values()[-1])
#Z ang limits
self.add_input('NodeSocketBool', 'Z angle')
self.add_input('NodeSocketFloat', 'Z ang lower', -45.0)
self.add_input('NodeSocketFloat', 'Z ang upper', 45.0)
#Arguements for type Slider
if (self.get_count_in(select_current) == 3):
while (len(self.inputs) > 7):
self.inputs.remove(self.inputs.values()[-1])
#X lin limits
self.add_input('NodeSocketBool', 'X linear')
self.add_input('NodeSocketFloat', 'X lin lower')
self.add_input('NodeSocketFloat', 'X lin upper')
#Arguements for type Piston
if (self.get_count_in(select_current) == 4):
while (len(self.inputs) > 7):
self.inputs.remove(self.inputs.values()[-1])
#X lin limits
self.add_input('NodeSocketBool', 'X linear')
self.add_input('NodeSocketFloat', 'X lin lower')
self.add_input('NodeSocketFloat', 'X lin upper')
#X ang limits
self.add_input('NodeSocketBool', 'X angle')
self.add_input('NodeSocketFloat', 'X ang lower', -45.0)
self.add_input('NodeSocketFloat', 'X ang upper', 45.0)
#Arguements for type GenericSpring
if (self.get_count_in(select_current) == 5):
while (len(self.inputs) > 7):
self.inputs.remove(self.inputs.values()[-1])
self['property0'] = value
property0: EnumProperty(
items = [('Fixed', 'Fixed', 'Fixed'),
('Point', 'Point', 'Point'),
('Hinge', 'Hinge', 'Hinge'),
('Slider', 'Slider', 'Slider'),
('Piston', 'Piston', 'Piston'),
('Generic Spring', 'Generic Spring', 'Generic Spring')],
name='Type', default='Fixed', set=set_enum, get=get_enum)
def __init__(self):
array_nodes[str(id(self))] = self
def init(self, context):
super(AddPhysicsConstraintNode, self).init(context)
self.add_input('ArmNodeSocketAction', 'In')
self.add_input('ArmNodeSocketObject', 'Pivot Object')
self.add_input('ArmNodeSocketObject', 'RB 1')
self.add_input('ArmNodeSocketObject', 'RB 2')
self.add_input('NodeSocketBool', 'Disable Collissions')
self.add_input('NodeSocketBool', 'Breakable')
self.add_input('NodeSocketFloat', 'Breaking Threshold')
self.add_output('ArmNodeSocketAction', 'Out')
def draw_buttons(self, context, layout):
layout.prop(self, 'property0')
#GenericSpring:
if (self.get_count_in(self.property0) == 5):
grid0 = layout.grid_flow(row_major=True, columns=1, align=True)
grid0.label(text="Possible Constraints:")
grid0.label(text="Linear [X, Y, Z]")
grid0.label(text="Angular [X, Y, Z]")
grid0.label(text="Spring Linear [X, Y, Z]")
grid0.label(text="Spring Angular [X, Y, Z]")
row = layout.row(align=True)
column = row.column(align=True)
op = column.operator('arm.node_add_input', text='Add Constraint', icon='PLUS', emboss=True)
op.node_index = str(id(self))
op.socket_type = 'NodeSocketShader'
op.name_format = 'Constraint {0}'.format(len(self.inputs) - 6)
column1 = row.column(align=True)
op = column1.operator('arm.node_remove_input', text='', icon='X', emboss=True)
op.node_index = str(id(self))
#Static inputs
if len(self.inputs) < 8:
column1.enabled = False
#Max Possible inputs
if len(self.inputs) > 18:
column.enabled = False