from lnx.logicnode.lnx_nodes import * class MouseLookNode(LnxLogicTreeNode): """MouseLookNode - Blender UI interface for FPS-style mouse look camera controller This class defines the Blender node interface for the MouseLookNode logic node. It creates the visual node that appears in Blender's logic tree editor and defines all the properties that configure the mouse look behavior. The node provides controls for: - Axis orientation configuration - Mouse cursor behavior - Movement inversion options - Rotation limiting/capping - Head rotation space behavior Features: - Built-in resolution-adaptive scaling for consistent feel across different screen resolutions - Automatic physics synchronization for rigid bodies - Support for both single-object and dual-object (body/head) setups """ # Blender node identification bl_idname = 'LNMouseLookNode' # Unique identifier for Blender's node system bl_label = 'Mouse Look' # Display name in node menu and header lnx_section = 'mouse' # Category section in node add menu lnx_version = 1 # Node version for compatibility tracking # Property 0: Front Axis Configuration # Determines which 3D axis represents the "forward" direction of the character/camera # This affects how horizontal and vertical rotations are applied to the objects property0: HaxeEnumProperty( 'property0', items=[('X', 'X Axis', 'X Axis as front'), # X-forward (side-scrolling, specific orientations) ('Y', 'Y Axis', 'Y Axis as front'), # Y-forward (most common for 3D games) ('Z', 'Z Axis', 'Z Axis as front')], # Z-forward (top-down, specific orientations) name='Front', default='Y') # Y-axis is default as it's most common in 3D game development # Property 1: Automatic Mouse Cursor Management # When enabled, automatically centers and locks the mouse cursor when mouse input starts # This is essential for FPS games to prevent cursor from leaving game window property1: HaxeBoolProperty( 'property1', name='Hide Locked', description='Automatically center and lock the mouse cursor when mouse input begins', default=True) # Enabled by default for typical FPS behavior # Property 2: Horizontal Movement Inversion # Allows users to invert horizontal mouse movement (left becomes right, right becomes left) # Some players prefer inverted controls for consistency with flight simulators property2: HaxeBoolProperty( 'property2', name='Invert X', description='Invert horizontal mouse movement - moving mouse right turns character left', default=False) # Most players expect non-inverted horizontal movement # Property 3: Vertical Movement Inversion # Allows users to invert vertical mouse movement (up becomes down, down becomes up) # More commonly used than horizontal inversion, especially by flight sim players property3: HaxeBoolProperty( 'property3', name='Invert Y', description='Invert vertical mouse movement - moving mouse up looks down', default=False) # Most players expect non-inverted vertical movement # Property 4: Horizontal Rotation Limiting # Prevents the character from rotating beyond specified horizontal limits # Useful for fixed-perspective games or when character shouldn't turn completely around property4: HaxeBoolProperty( 'property4', name='Cap Left / Right', description='Limit horizontal rotation to prevent full 360-degree turns', default=False) # Disabled by default - most FPS games allow full horizontal rotation # Property 5: Vertical Rotation Limiting # Prevents looking too far up or down, simulating human neck movement limitations # Essential for realistic FPS games to prevent disorienting over-rotation property5: HaxeBoolProperty( 'property5', name='Cap Up / Down', description='Limit vertical rotation to simulate natural neck movement (±90 degrees)', default=True) # Enabled by default for realistic FPS behavior # Property 6: Head Rotation Space Mode # Controls whether head rotation uses local or world space coordinates # Critical for preventing rotation issues when head object is child of body object property6: HaxeBoolProperty( 'property6', name='Head Local Space', description='Use local space for head rotation - enable when Head is child of Body to avoid gimbal lock', default=False) # Disabled by default, enable when using parent-child object relationships def lnx_init(self, context): """Initialize the node's input and output sockets This method is called when the node is first created in Blender. It defines all the connection points (sockets) that other nodes can connect to. Input Sockets: - Action In: Execution flow input (when this node should run) - Body: The main character/player object that rotates horizontally - Head: Optional camera/head object that rotates vertically (can be child of Body) - Sensitivity: Mouse sensitivity multiplier (0.5 = half sensitivity, 2.0 = double sensitivity) - Smoothing: Movement smoothing factor (0.0 = no smoothing, higher = more smoothing) Output Sockets: - Action Out: Execution flow output (continues to next node after processing) """ # Execution flow input - connects from previous logic node self.add_input('LnxNodeSocketAction', 'In') # Object inputs - require 3D objects from the scene self.add_input('LnxNodeSocketObject', 'Body') # Main character object (required) self.add_input('LnxNodeSocketObject', 'Head') # Camera/head object (optional) # Numeric inputs with sensible defaults self.add_input('LnxFloatSocket', 'Sensitivity', default_value=0.5) # Medium sensitivity self.add_input('LnxFloatSocket', 'Smoothing', default_value=0.0) # No smoothing by default # Execution flow output - connects to next logic node self.add_output('LnxNodeSocketAction', 'Out') def draw_buttons(self, context, layout): """Draw the node's user interface in Blender's logic tree editor This method creates the visual controls that appear on the node in Blender. It organizes properties into logical groups for better usability. Args: context: Blender context (current scene, selected objects, etc.) layout: UI layout object for arranging interface elements """ # Basic configuration section layout.prop(self, 'property0', text='Front') # Front axis dropdown layout.prop(self, 'property1', text='Hide Locked') # Mouse locking checkbox # Movement inversion controls section # Group X and Y inversion together for logical organization col = layout.column(align=True) # Create aligned column col.label(text="Invert XY:") # Section header row = col.row(align=True) # Create horizontal row within column row.prop(self, 'property2', text='X', toggle=True) # X inversion toggle button row.prop(self, 'property3', text='Y', toggle=True) # Y inversion toggle button # Rotation limiting controls section # Group rotation caps together since they're related functionality col = layout.column(align=True) # Create new aligned column col.prop(self, 'property4', text='Cap Left / Right') # Horizontal capping checkbox col.prop(self, 'property5', text='Cap Up / Down') # Vertical capping checkbox # Advanced head behavior section # Separate advanced option that affects technical behavior col = layout.column(align=True) # Create new aligned column col.prop(self, 'property6', text='Head Local Space') # Head rotation space checkbox