parent
5eb8fc781f
commit
20f9f8a5f4
37
Sources/armory/logicnode/SelectNode.hx
Normal file
37
Sources/armory/logicnode/SelectNode.hx
Normal file
|
@ -0,0 +1,37 @@
|
|||
package armory.logicnode;
|
||||
|
||||
class SelectNode extends LogicNode {
|
||||
|
||||
/** Execution mode. **/
|
||||
public var property0: String;
|
||||
|
||||
var value: Dynamic = null;
|
||||
|
||||
public function new(tree: LogicTree) {
|
||||
super(tree);
|
||||
}
|
||||
|
||||
override function run(from: Int) {
|
||||
// Get value according to the activated input (run() can only be called
|
||||
// if the execution mode is from_input).
|
||||
value = inputs[from + Std.int(inputs.length / 2)].get();
|
||||
|
||||
runOutput(0);
|
||||
}
|
||||
|
||||
override function get(from: Int): Dynamic {
|
||||
if (property0 == "from_index") {
|
||||
var index = inputs[0].get() + 2;
|
||||
|
||||
// Return default value for invalid index
|
||||
if (index < 2 || index >= inputs.length) {
|
||||
return inputs[1].get();
|
||||
}
|
||||
|
||||
return inputs[index].get();
|
||||
}
|
||||
|
||||
// from_input
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -270,6 +270,30 @@ class ArmNodeRemoveInputOutputButton(bpy.types.Operator):
|
|||
return{'FINISHED'}
|
||||
|
||||
|
||||
class ArmNodeCallFuncButton(bpy.types.Operator):
|
||||
"""Operator that calls a function on a specified
|
||||
node (used for dynamic callbacks)."""
|
||||
bl_idname = 'arm.node_call_func'
|
||||
bl_label = 'Execute'
|
||||
bl_options = {'UNDO', 'INTERNAL'}
|
||||
|
||||
node_index: StringProperty(name='Node Index', default='')
|
||||
callback_name: StringProperty(name='Callback Name', default='')
|
||||
|
||||
def execute(self, context):
|
||||
node = array_nodes[self.node_index]
|
||||
if hasattr(node, self.callback_name):
|
||||
getattr(node, self.callback_name)()
|
||||
else:
|
||||
return {'CANCELLED'}
|
||||
|
||||
# Reset to default again for subsequent calls of this operator
|
||||
self.node_index = ''
|
||||
self.callback_name = ''
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class ArmNodeSearch(bpy.types.Operator):
|
||||
bl_idname = "arm.node_search"
|
||||
bl_label = "Search..."
|
||||
|
@ -460,12 +484,16 @@ def reset_globals():
|
|||
category_items = OrderedDict()
|
||||
|
||||
|
||||
bpy.utils.register_class(ArmNodeSearch)
|
||||
bpy.utils.register_class(ArmNodeAddInputButton)
|
||||
bpy.utils.register_class(ArmNodeAddInputValueButton)
|
||||
bpy.utils.register_class(ArmNodeRemoveInputButton)
|
||||
bpy.utils.register_class(ArmNodeRemoveInputValueButton)
|
||||
bpy.utils.register_class(ArmNodeAddOutputButton)
|
||||
bpy.utils.register_class(ArmNodeRemoveOutputButton)
|
||||
bpy.utils.register_class(ArmNodeAddInputOutputButton)
|
||||
bpy.utils.register_class(ArmNodeRemoveInputOutputButton)
|
||||
REG_CLASSES = (
|
||||
ArmNodeSearch,
|
||||
ArmNodeAddInputButton,
|
||||
ArmNodeAddInputValueButton,
|
||||
ArmNodeRemoveInputButton,
|
||||
ArmNodeRemoveInputValueButton,
|
||||
ArmNodeAddOutputButton,
|
||||
ArmNodeRemoveOutputButton,
|
||||
ArmNodeAddInputOutputButton,
|
||||
ArmNodeRemoveInputOutputButton,
|
||||
ArmNodeCallFuncButton
|
||||
)
|
||||
register, unregister = bpy.utils.register_classes_factory(REG_CLASSES)
|
||||
|
|
122
blender/arm/logicnode/logic/LN_select.py
Normal file
122
blender/arm/logicnode/logic/LN_select.py
Normal file
|
@ -0,0 +1,122 @@
|
|||
from bpy.types import NodeSocketInterfaceInt
|
||||
|
||||
from arm.logicnode.arm_nodes import *
|
||||
|
||||
|
||||
class SelectNode(ArmLogicTreeNode):
|
||||
"""Selects one of multiple values (of arbitrary types) based on some
|
||||
input state. The exact behaviour of this node is specified by the
|
||||
`Execution Mode` option (see below).
|
||||
|
||||
@output Out: [*Available if Execution Mode is set to From Input*]
|
||||
Activated after the node was executed.
|
||||
|
||||
@output Value: The last selected value. This value is not reset
|
||||
until the next execution of this node.
|
||||
|
||||
@option Execution Mode: Specifies the condition that determines
|
||||
what value to choose.
|
||||
|
||||
- `From Index`: Select the value at the given index. If there is
|
||||
no value at that index, the value plugged in to the
|
||||
`Default` input is used instead (`null` if unconnected).
|
||||
|
||||
- `From Input`: This mode uses input pairs of one action socket
|
||||
and one value socket. Depending on which action socket is
|
||||
activated, the associated value socket (the value with the
|
||||
same index as the activated action input) is forwarded to
|
||||
the `Value` output.
|
||||
|
||||
@option New: Add a new value to the list of values.
|
||||
@option X Button: Remove the value with the highest index."""
|
||||
bl_idname = 'LNSelectNode'
|
||||
bl_label = 'Select'
|
||||
arm_version = 1
|
||||
min_inputs = 2
|
||||
|
||||
def update_exec_mode(self, context):
|
||||
self.set_mode()
|
||||
|
||||
property0: EnumProperty(
|
||||
name='Execution Mode',
|
||||
description="The node's behaviour.",
|
||||
items=[
|
||||
('from_index', 'From Index', 'Choose the value from the given index'),
|
||||
('from_input', 'From Input', 'Choose the value with the same position as the active input')],
|
||||
default='from_index',
|
||||
update=update_exec_mode,
|
||||
)
|
||||
|
||||
# The number of choices, NOT of individual inputs. This needs to be
|
||||
# a property in order to be saved with each individual node
|
||||
num_choices: IntProperty(default=1, min=0)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
array_nodes[str(id(self))] = self
|
||||
|
||||
def init(self, context):
|
||||
super().init(context)
|
||||
|
||||
self.set_mode()
|
||||
|
||||
def set_mode(self):
|
||||
self.inputs.clear()
|
||||
self.outputs.clear()
|
||||
|
||||
if self.property0 == 'from_index':
|
||||
self.add_input('NodeSocketInt', 'Index')
|
||||
self.add_input('NodeSocketShader', 'Default')
|
||||
self.num_choices = 0
|
||||
|
||||
# from_input
|
||||
else:
|
||||
# We could also start with index 1 here, but we need to use
|
||||
# 0 for the "from_index" mode and it makes the code simpler
|
||||
# if we stick to the same convention for both exec modes
|
||||
self.add_input('ArmNodeSocketAction', 'Input 0')
|
||||
self.add_input('NodeSocketShader', 'Value 0')
|
||||
self.num_choices = 1
|
||||
|
||||
self.add_output('ArmNodeSocketAction', 'Out')
|
||||
|
||||
self.add_output('NodeSocketShader', 'Value')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0', text='')
|
||||
|
||||
row = layout.row(align=True)
|
||||
|
||||
op = row.operator('arm.node_call_func', text='New', icon='PLUS', emboss=True)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'add_input_func'
|
||||
|
||||
op = row.operator('arm.node_call_func', text='', icon='X', emboss=True)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'remove_input_func'
|
||||
|
||||
def add_input_func(self):
|
||||
if self.property0 == 'from_input':
|
||||
self.add_input('ArmNodeSocketAction', f'Input {self.num_choices}')
|
||||
|
||||
# Move new action input up to the end of all other action inputs
|
||||
self.inputs.move(from_index=len(self.inputs) - 1, to_index=self.num_choices)
|
||||
|
||||
self.add_input('NodeSocketShader', f'Value {self.num_choices}')
|
||||
|
||||
self.num_choices += 1
|
||||
|
||||
def remove_input_func(self):
|
||||
if self.property0 == 'from_input':
|
||||
if len(self.inputs) > self.min_inputs:
|
||||
self.inputs.remove(self.inputs[self.num_choices - 1])
|
||||
|
||||
if len(self.inputs) > self.min_inputs:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
self.num_choices -= 1
|
||||
|
||||
def draw_label(self) -> str:
|
||||
if self.num_choices == 0:
|
||||
return self.bl_label
|
||||
|
||||
return f'{self.bl_label}: [{self.num_choices}]'
|
|
@ -363,6 +363,7 @@ class ReplaceNodesOperator(bpy.types.Operator):
|
|||
|
||||
|
||||
def register():
|
||||
arm.logicnode.arm_nodes.register()
|
||||
arm.logicnode.arm_sockets.register()
|
||||
|
||||
bpy.utils.register_class(ArmLogicTree)
|
||||
|
@ -403,3 +404,4 @@ def unregister():
|
|||
bpy.utils.register_class(ARM_MT_NodeAddOverride.overridden_menu)
|
||||
|
||||
arm.logicnode.arm_sockets.unregister()
|
||||
arm.logicnode.arm_nodes.unregister()
|
||||
|
|
Loading…
Reference in a new issue