made default resolution adaptive sensiticity because makes more sense, removed other things since no difference and dunno

This commit is contained in:
2025-07-03 05:27:24 +02:00
parent 5824bd91aa
commit 444a215e63
2 changed files with 68 additions and 146 deletions

View File

@ -7,44 +7,24 @@ import kha.System;
import kha.FastFloat; import kha.FastFloat;
class MouseLookNode extends LogicNode { class MouseLookNode extends LogicNode {
// Note: This implementation works in degrees internally and converts to radians only when applying rotations public var property0: String;
// Sub-pixel interpolation is always enabled for optimal precision public var property1: Bool;
// Features: Resolution-adaptive scaling and precise low-sensitivity support public var property2: Bool;
public var property3: Bool;
public var property0: String; // Front axis public var property4: Bool;
public var property1: Bool; // Center Mouse public var property5: Bool;
public var property2: Bool; // Invert X public var property7: Bool;
public var property3: Bool; // Invert Y
public var property4: Bool; // Cap Left/Right
public var property5: Bool; // Cap Up/Down
// New strategy toggles
public var property6: Bool; // Resolution-Adaptive Scaling
// Smoothing variables
var smoothX: FastFloat = 0.0;
var smoothY: FastFloat = 0.0;
// Capping limits (in degrees)
var maxHorizontal: FastFloat = 180.0; // 180 degrees
var maxVertical: FastFloat = 90.0; // 90 degrees
// Current accumulated rotations for capping
var currentHorizontal: FastFloat = 0.0;
var currentVertical: FastFloat = 0.0;
// Sub-pixel interpolation accumulators
var accumulatedHorizontalRotation: FastFloat = 0.0;
var accumulatedVerticalRotation: FastFloat = 0.0;
var minimumRotationThreshold: FastFloat = 0.01; // degrees (was 0.0001 radians)
// Frame rate independence removed - not applicable to mouse input
// Resolution adaptive scaling
var baseResolutionWidth: FastFloat = 1920.0;
var baseResolutionHeight: FastFloat = 1080.0;
var smoothX: Float = 0.0;
var smoothY: Float = 0.0;
var maxHorizontal: Float = Math.PI;
var maxVertical: Float = Math.PI / 2;
var currentHorizontal: Float = 0.0;
var currentVertical: Float = 0.0;
var baseResolutionWidth: Float = 1920.0;
static inline var BASE_SCALE: Float = 1500.0;
static var RADIAN_SCALING_FACTOR: Float = Math.PI * 50.0 / 180.0;
public function new(tree: LogicTree) { public function new(tree: LogicTree) {
super(tree); super(tree);
@ -63,114 +43,64 @@ class MouseLookNode extends LogicNode {
var mouse = Input.getMouse(); var mouse = Input.getMouse();
// Handle mouse centering/locking
if (property1) { if (property1) {
if (mouse.started() && !mouse.locked) { if (mouse.started() && !mouse.locked) {
mouse.lock(); mouse.lock();
} }
} }
// Only process if mouse is active
if (!mouse.locked && !mouse.down()) { if (!mouse.locked && !mouse.down()) {
runOutput(0); runOutput(0);
return; return;
} }
// Get mouse movement deltas var deltaX: Float = mouse.movementX;
var deltaX: FastFloat = mouse.movementX; var deltaY: Float = mouse.movementY;
var deltaY: FastFloat = mouse.movementY;
// Note: Sensitivity will be applied later to preserve precision for small movements
// Apply inversion
if (property2) deltaX = -deltaX; if (property2) deltaX = -deltaX;
if (property3) deltaY = -deltaY; if (property3) deltaY = -deltaY;
// Strategy 1: Resolution-Adaptive Scaling // Always apply resolution-adaptive scaling
var resolutionMultiplier: FastFloat = 1.0; var resolutionMultiplier: Float = System.windowWidth() / baseResolutionWidth;
if (property6) {
var currentWidth = System.windowWidth();
var currentHeight = System.windowHeight();
resolutionMultiplier = (currentWidth / baseResolutionWidth) * (currentHeight / baseResolutionHeight);
resolutionMultiplier = Math.sqrt(resolutionMultiplier); // Take square root to avoid over-scaling
}
// Frame Rate Independence disabled for mouse input - mouse deltas are inherently frame-rate independent
// Apply smoothing
if (smoothing > 0.0) { if (smoothing > 0.0) {
var smoothFactor = 1.0 - Math.min(smoothing, 0.99); // Prevent complete smoothing var smoothingFactor: Float = Math.min(smoothing, 0.99);
smoothX = smoothX * smoothing + deltaX * smoothFactor; smoothX = smoothX * smoothingFactor + deltaX * (1.0 - smoothingFactor);
smoothY = smoothY * smoothing + deltaY * smoothFactor; smoothY = smoothY * smoothingFactor + deltaY * (1.0 - smoothingFactor);
deltaX = smoothX; deltaX = smoothX;
deltaY = smoothY; deltaY = smoothY;
} }
// Determine rotation axes based on front axis setting
var horizontalAxis = new Vec4(); var horizontalAxis = new Vec4();
var verticalAxis = new Vec4(); var verticalAxis = new Vec4();
switch (property0) { switch (property0) {
case "X": // X is front case "X":
horizontalAxis.set(0, 0, 1); // Z axis for horizontal (yaw) horizontalAxis.set(0, 0, 1);
verticalAxis.set(0, 1, 0); // Y axis for vertical (pitch) verticalAxis.set(0, 1, 0);
case "Y": // Y is front (default) case "Y":
#if lnx_yaxisup #if lnx_yaxisup
horizontalAxis.set(0, 0, 1); // Z axis for horizontal (yaw) horizontalAxis.set(0, 0, 1);
verticalAxis.set(1, 0, 0); // X axis for vertical (pitch) verticalAxis.set(1, 0, 0);
#else #else
horizontalAxis.set(0, 0, 1); // Z axis for horizontal (yaw) horizontalAxis.set(0, 0, 1);
verticalAxis.set(1, 0, 0); // X axis for vertical (pitch) verticalAxis.set(1, 0, 0);
#end #end
case "Z": // Z is front case "Z":
horizontalAxis.set(0, 1, 0); // Y axis for horizontal (yaw) horizontalAxis.set(0, 1, 0);
verticalAxis.set(1, 0, 0); // X axis for vertical (pitch) verticalAxis.set(1, 0, 0);
} }
// Base scaling // Always apply resolution-adaptive scaling
var baseScale: FastFloat = 1500.0; var finalScale: Float = BASE_SCALE * resolutionMultiplier;
var finalScale = baseScale;
// Apply resolution scaling
if (property6) {
finalScale *= resolutionMultiplier;
}
// Apply sensitivity scaling after all enhancement strategies to preserve precision
deltaX *= sensitivity; deltaX *= sensitivity;
deltaY *= sensitivity; deltaY *= sensitivity;
// Calculate rotation amounts (in degrees) var horizontalRotation: Float = (-deltaX / finalScale) * RADIAN_SCALING_FACTOR;
var horizontalRotation: FastFloat = (-deltaX / finalScale) * 180.0 / Math.PI; var verticalRotation: Float = (-deltaY / finalScale) * RADIAN_SCALING_FACTOR;
var verticalRotation: FastFloat = (-deltaY / finalScale) * 180.0 / Math.PI;
// Note: Frame rate independence removed for mouse input as mouse deltas if (property4) {
// are already frame-rate independent by nature. Mouse input represents
// instantaneous user intent, not time-based movement.
// Strategy 2: Sub-Pixel Interpolation (always enabled)
accumulatedHorizontalRotation += horizontalRotation;
accumulatedVerticalRotation += verticalRotation;
// Only apply rotation if accumulated amount exceeds threshold
if (Math.abs(accumulatedHorizontalRotation) >= minimumRotationThreshold) {
horizontalRotation = accumulatedHorizontalRotation;
accumulatedHorizontalRotation = 0.0;
} else {
horizontalRotation = 0.0;
}
if (Math.abs(accumulatedVerticalRotation) >= minimumRotationThreshold) {
verticalRotation = accumulatedVerticalRotation;
accumulatedVerticalRotation = 0.0;
} else {
verticalRotation = 0.0;
}
// Apply capping constraints
if (property4) { // Cap Left/Right
currentHorizontal += horizontalRotation; currentHorizontal += horizontalRotation;
if (currentHorizontal > maxHorizontal) { if (currentHorizontal > maxHorizontal) {
horizontalRotation -= (currentHorizontal - maxHorizontal); horizontalRotation -= (currentHorizontal - maxHorizontal);
@ -181,7 +111,7 @@ class MouseLookNode extends LogicNode {
} }
} }
if (property5) { // Cap Up/Down if (property5) {
currentVertical += verticalRotation; currentVertical += verticalRotation;
if (currentVertical > maxVertical) { if (currentVertical > maxVertical) {
verticalRotation -= (currentVertical - maxVertical); verticalRotation -= (currentVertical - maxVertical);
@ -192,40 +122,37 @@ class MouseLookNode extends LogicNode {
} }
} }
// Apply horizontal rotation to body (yaw) if (horizontalRotation != 0.0) {
if (Math.abs(horizontalRotation) > 0.01) { // 0.01 degrees threshold bodyObject.transform.rotate(horizontalAxis, horizontalRotation);
bodyObject.transform.rotate(horizontalAxis, horizontalRotation * Math.PI / 180.0); // Convert degrees to radians
// Sync physics if needed
#if lnx_physics #if lnx_physics
var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody); var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody);
if (rigidBody != null) rigidBody.syncTransform(); if (rigidBody != null) rigidBody.syncTransform();
#end #end
} }
// Apply vertical rotation to head (pitch) if head object is provided if (headObject != null && verticalRotation != 0.0) {
if (headObject != null && Math.abs(verticalRotation) > 0.01) { // 0.01 degrees threshold if (property7) {
// For head rotation, use the head's local coordinate system // Local space rotation (recommended for FPS)
headObject.transform.rotate(verticalAxis, verticalRotation);
} else {
// World space rotation
var headVerticalAxis = headObject.transform.world.right(); var headVerticalAxis = headObject.transform.world.right();
headObject.transform.rotate(headVerticalAxis, verticalRotation * Math.PI / 180.0); // Convert degrees to radians headObject.transform.rotate(headVerticalAxis, verticalRotation);
}
// Sync physics if needed
#if lnx_physics #if lnx_physics
var headRigidBody = headObject.getTrait(leenkx.trait.physics.RigidBody); var headRigidBody = headObject.getTrait(leenkx.trait.physics.RigidBody);
if (headRigidBody != null) headRigidBody.syncTransform(); if (headRigidBody != null) headRigidBody.syncTransform();
#end #end
} else if (headObject == null) { } else if (headObject == null && verticalRotation != 0.0) {
// If no head object, apply vertical rotation to body as well bodyObject.transform.rotate(verticalAxis, verticalRotation);
if (Math.abs(verticalRotation) > 0.01) { // 0.01 degrees threshold
bodyObject.transform.rotate(verticalAxis, verticalRotation * Math.PI / 180.0); // Convert degrees to radians
// Sync physics if needed
#if lnx_physics #if lnx_physics
var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody); var rigidBody = bodyObject.getTrait(leenkx.trait.physics.RigidBody);
if (rigidBody != null) rigidBody.syncTransform(); if (rigidBody != null) rigidBody.syncTransform();
#end #end
} }
}
runOutput(0); runOutput(0);
} }

View File

@ -5,8 +5,7 @@ class MouseLookNode(LnxLogicTreeNode):
"""Controls object rotation based on mouse movement for FPS-style camera control. """Controls object rotation based on mouse movement for FPS-style camera control.
Features: Features:
- Sub-pixel interpolation (always enabled) for optimal precision and smooth low-sensitivity movement - Built-in resolution-adaptive scaling for consistent feel across different screen resolutions
- Resolution-adaptive scaling for consistent feel across different screen resolutions
""" """
bl_idname = 'LNMouseLookNode' bl_idname = 'LNMouseLookNode'
bl_label = 'Mouse Look' bl_label = 'Mouse Look'
@ -56,11 +55,11 @@ class MouseLookNode(LnxLogicTreeNode):
description='Limit vertical rotation', description='Limit vertical rotation',
default=True) default=True)
# Strategy toggles # Head rotation space toggle
property6: HaxeBoolProperty( property7: HaxeBoolProperty(
'property6', 'property7',
name='Resolution Adaptive', name='Head Local Space',
description='Scale sensitivity based on screen resolution', description='Enable it if the Head is child of the Body to avoid weird rotation',
default=False) default=False)
@ -72,7 +71,7 @@ class MouseLookNode(LnxLogicTreeNode):
self.add_input('LnxNodeSocketObject', 'Body') self.add_input('LnxNodeSocketObject', 'Body')
self.add_input('LnxNodeSocketObject', 'Head') self.add_input('LnxNodeSocketObject', 'Head')
self.add_input('LnxFloatSocket', 'Sensitivity', default_value=0.5) self.add_input('LnxFloatSocket', 'Sensitivity', default_value=0.5)
self.add_input('LnxFloatSocket', 'Smoothing', default_value=0.0) self.add_input('LnxFactorSocket', 'Smoothing', default_value=0.0)
self.add_output('LnxNodeSocketAction', 'Out') self.add_output('LnxNodeSocketAction', 'Out')
@ -92,10 +91,6 @@ class MouseLookNode(LnxLogicTreeNode):
col.prop(self, 'property4', text='Cap Left / Right') col.prop(self, 'property4', text='Cap Left / Right')
col.prop(self, 'property5', text='Cap Up / Down') col.prop(self, 'property5', text='Cap Up / Down')
# Separator # Head behavior section
layout.separator()
# Enhancement strategies section
col = layout.column(align=True) col = layout.column(align=True)
col.label(text="Enhancement Strategies:") col.prop(self, 'property7', text='Head Local Space')
col.prop(self, 'property6', text='Resolution Adaptive')