Compare commits

...

7 Commits

6 changed files with 126 additions and 38 deletions

View File

@@ -29,12 +29,24 @@ Supports combos like Ctrl+Shift+Alt+Cmd. For people with more keybinds than fing
![Modifier Keys](https://github.com/user-attachments/assets/6d492134-f929-4e3e-a6c6-a89cf16cd62f) ![Modifier Keys](https://github.com/user-attachments/assets/6d492134-f929-4e3e-a6c6-a89cf16cd62f)
### ↗️ Middle Mouse Button Panning ### ↗️ Editor Middle Mouse Button Panning
Hold MMB in the editor to pan around the scene, it'll reset when you go back to live. Hold MMB in the editor to pan around the scene, it'll reset when you go back to live.
![Panning](https://github.com/user-attachments/assets/b8687b69-fc84-43c9-950b-70395ae54820) ![Panning](https://github.com/user-attachments/assets/b8687b69-fc84-43c9-950b-70395ae54820)
### ↗️ View Mode MMB Shake
Hold MMB in view mode to shake your character, Show off them physics!
![viewmodeshake](https://github.com/user-attachments/assets/536dc4ae-0562-494f-8cd0-2d2ef115f085)
🎞️ Delta Time Physics
Physics are now framerate-independent. Low FPS wont make your character move in slow motion anymore.
Just smooth, consistent jank if thats your thing. Great for stop-motion vibes.
### 🎤 Microphone Fixes ### 🎤 Microphone Fixes

View File

@@ -4,7 +4,8 @@ extends Node2D
@onready var editButton = $Edit/Button @onready var editButton = $Edit/Button
func _process(delta): func _process(delta):
var uiAnimSpeed = Global.main.physicsTimeMultiplier * 20.0 if Global.main else 120.0
if Rect2(editButton.get_parent().position-Vector2(24,24),editButton.size).has_point(get_local_mouse_position()): if Rect2(editButton.get_parent().position-Vector2(24,24),editButton.size).has_point(get_local_mouse_position()):
editSprite.scale = lerp(editSprite.scale,Vector2(1.2,1.2),0.2) editSprite.scale = lerp(editSprite.scale, Vector2(1.2,1.2), delta * uiAnimSpeed)
else: else:
editSprite.scale = lerp(editSprite.scale,Vector2(1.0,1.0),0.2) editSprite.scale = lerp(editSprite.scale, Vector2(1.0,1.0), delta * uiAnimSpeed)

View File

@@ -30,7 +30,8 @@ func _process(delta):
if buttons[b] == null: if buttons[b] == null:
continue continue
if Rect2(buttons[b].get_parent().position-Vector2(24,24),buttons[b].size).has_point(get_local_mouse_position()): if Rect2(buttons[b].get_parent().position-Vector2(24,24),buttons[b].size).has_point(get_local_mouse_position()):
sprites[s].scale = lerp(sprites[s].scale,Vector2(1.2,1.2),0.2) var uiAnimSpeed = Global.main.physicsTimeMultiplier * 20.0 if Global.main else 120.0
sprites[s].scale = lerp(sprites[s].scale, Vector2(1.2,1.2), delta * uiAnimSpeed)
if Input.is_action_pressed("mouse_left"): if Input.is_action_pressed("mouse_left"):
sprites[s].scale = Vector2(0.6,0.6) sprites[s].scale = Vector2(0.6,0.6)
match b: match b:
@@ -50,7 +51,8 @@ func _process(delta):
Global.mouse.text = "Duplicate sprite" Global.mouse.text = "Duplicate sprite"
else: else:
sprites[s].scale = lerp(sprites[s].scale,Vector2(1.0,1.0),0.2) var uiAnimSpeed = Global.main.physicsTimeMultiplier * 20.0 if Global.main else 120.0
sprites[s].scale = lerp(sprites[s].scale, Vector2(1.0,1.0), delta * uiAnimSpeed)
s += 1 s += 1
var newColor = Color.DARK_SLATE_GRAY if Global.heldSprite == null else Color.WHITE var newColor = Color.DARK_SLATE_GRAY if Global.heldSprite == null else Color.WHITE

View File

@@ -36,6 +36,10 @@ var yVel = 0
var bounceSlider = 250 var bounceSlider = 250
var bounceGravity = 1000 var bounceGravity = 1000
# Physics timing multiplier - adjust this to fine-tune physics speed
# 1.0 = very slow, 10.0 = reasonable, 60.0 = old frame-based speed
var physicsTimeMultiplier = 6.0
#Costumes #Costumes
var costume = 1 var costume = 1
var bounceOnCostumeChange = false var bounceOnCostumeChange = false
@@ -49,6 +53,12 @@ var initialPanPosition = Vector2.ZERO
var initialCameraOffset = Vector2.ZERO var initialCameraOffset = Vector2.ZERO
var cameraOffset = Vector2.ZERO var cameraOffset = Vector2.ZERO
#View Mode Panning
var viewModePanning = false
var initialViewPanPosition = Vector2.ZERO
var viewPanOffset = Vector2.ZERO
var viewPanLerpSpeed = 3.0
var bounceChange = 0.0 var bounceChange = 0.0
#IMPORTANT #IMPORTANT
@@ -141,18 +151,28 @@ func _ready():
func _process(delta): func _process(delta):
var hold = origin.get_parent().position.y var hold = origin.get_parent().position.y
origin.get_parent().position.y += yVel * 0.0166 origin.get_parent().position.y += yVel * delta * physicsTimeMultiplier
if origin.get_parent().position.y > 0: if origin.get_parent().position.y > 0:
origin.get_parent().position.y = 0 origin.get_parent().position.y = 0
bounceChange = hold - origin.get_parent().position.y bounceChange = hold - origin.get_parent().position.y
yVel += bounceGravity*0.0166 yVel += bounceGravity * delta * physicsTimeMultiplier
# Handle view mode panning lerp back to center
if !editMode:
if !viewModePanning:
# Lerp back to center when not actively panning
viewPanOffset = viewPanOffset.lerp(Vector2.ZERO, viewPanLerpSpeed * delta)
# Apply view pan offset to the root character (affects physics)
origin.position = (get_viewport().get_visible_rect().size * 0.5) + viewPanOffset
updateCameraPosition()
if Input.is_action_just_pressed("openFolder"): if Input.is_action_just_pressed("openFolder"):
OS.shell_open(ProjectSettings.globalize_path("user://")) OS.shell_open(ProjectSettings.globalize_path("user://"))
moveSpriteMenu(delta) moveSpriteMenu(delta)
zoomScene() zoomScene(delta)
fileSystemOpen = isFileSystemOpen() fileSystemOpen = isFileSystemOpen()
@@ -173,15 +193,24 @@ func _input(event):
isPanning = false isPanning = false
else: else:
if event.pressed: if event.pressed:
# Reset camera in view mode # Start view mode panning
resetCameraPosition() viewModePanning = true
initialViewPanPosition = event.global_position
else:
# Stop view mode panning
viewModePanning = false
# Handle mouse movement during panning # Handle mouse movement during edit mode panning
elif editMode and event is InputEventMouseMotion and isPanning: elif editMode and event is InputEventMouseMotion and isPanning:
var totalDelta = event.global_position - initialPanPosition var totalDelta = event.global_position - initialPanPosition
# Calculate new camera offset from initial position plus total movement # Scale pan distance based on zoom level for more intuitive panning
cameraOffset = initialCameraOffset - totalDelta # Higher zoom (closer) = less movement, lower zoom (farther) = more movement
var zoomScale = 1.0 / camera.zoom.x
var scaledDelta = totalDelta * zoomScale
# Calculate new camera offset from initial position plus scaled movement
cameraOffset = initialCameraOffset - scaledDelta
# Update camera position immediately # Update camera position immediately
var s = get_viewport().get_visible_rect().size var s = get_viewport().get_visible_rect().size
@@ -194,6 +223,15 @@ func _input(event):
viewerArrows.position = editControls.position viewerArrows.position = editControls.position
pushUpdates.position.y = controlPanel.position.y pushUpdates.position.y = controlPanel.position.y
pushUpdates.position.x = editControls.position.x pushUpdates.position.x = editControls.position.x
# Handle mouse movement during view mode panning
elif !editMode and event is InputEventMouseMotion and viewModePanning:
var totalDelta = event.global_position - initialViewPanPosition
# Scale pan distance for view mode (less sensitive than edit mode)
# Invert the movement so dragging right moves character right (not left)
var panSensitivity = 0.5
viewPanOffset = -totalDelta * panSensitivity
func followShadow(): func followShadow():
# Shadow disabled for selected sprites # Shadow disabled for selected sprites
@@ -235,7 +273,7 @@ func onWindowSizeChange():
updateCameraPosition() updateCameraPosition()
spriteList.position.x = s.x - 233 spriteList.position.x = s.x - 233
func zoomScene(): func zoomScene(delta):
#Handles Zooming #Handles Zooming
if Input.is_action_pressed("control"): if Input.is_action_pressed("control"):
if Input.is_action_just_pressed("scrollUp"): if Input.is_action_just_pressed("scrollUp"):
@@ -249,7 +287,7 @@ func zoomScene():
scaleOverall -= 10 scaleOverall -= 10
changeZoom() changeZoom()
$ControlPanel/ZoomLabel.modulate.a = lerp($ControlPanel/ZoomLabel.modulate.a,0.0,0.02) $ControlPanel/ZoomLabel.modulate.a = lerp($ControlPanel/ZoomLabel.modulate.a, 0.0, delta * (physicsTimeMultiplier * 1.2))
func changeZoom(): func changeZoom():
var newZoom = Vector2(1.0,1.0) / camera.zoom var newZoom = Vector2(1.0,1.0) / camera.zoom
@@ -296,6 +334,8 @@ func updateCameraPosition():
func resetCameraPosition(): func resetCameraPosition():
cameraOffset = Vector2.ZERO cameraOffset = Vector2.ZERO
isPanning = false isPanning = false
viewPanOffset = Vector2.ZERO
viewModePanning = false
updateCameraPosition() updateCameraPosition()
Global.pushUpdate("Camera reset to center.") Global.pushUpdate("Camera reset to center.")
@@ -315,6 +355,10 @@ func swapMode():
# Reset camera when entering view mode # Reset camera when entering view mode
if !editMode: if !editMode:
resetCameraPosition() resetCameraPosition()
else:
# Reset view mode panning when entering edit mode
viewPanOffset = Vector2.ZERO
viewModePanning = false
get_viewport().transparent_bg = !editMode get_viewport().transparent_bg = !editMode
if Global.backgroundColor.a != 0.0: if Global.backgroundColor.a != 0.0:
@@ -660,9 +704,9 @@ func moveSpriteMenu(delta):
if $EditControls/MoveMenuUp.overlaps_area(Global.mouse.area): if $EditControls/MoveMenuUp.overlaps_area(Global.mouse.area):
Global.spriteEdit.position.y += (delta*432.0) Global.spriteEdit.position.y += (delta * 432.0 * physicsTimeMultiplier)
elif $EditControls/MoveMenuDown.overlaps_area(Global.mouse.area): elif $EditControls/MoveMenuDown.overlaps_area(Global.mouse.area):
Global.spriteEdit.position.y -= (delta*432.0) Global.spriteEdit.position.y -= (delta * 432.0 * physicsTimeMultiplier)
if Global.spriteEdit.position.y > 66: if Global.spriteEdit.position.y > 66:
Global.spriteEdit.position.y = 66 Global.spriteEdit.position.y = 66

View File

@@ -14358,6 +14358,7 @@ text = "Zoom : 100%"
horizontal_alignment = 2 horizontal_alignment = 2
[node name="VersionLabels" type="Node2D" parent="ControlPanel"] [node name="VersionLabels" type="Node2D" parent="ControlPanel"]
position = Vector2(-284, 59)
[node name="Label" type="Label" parent="ControlPanel/VersionLabels"] [node name="Label" type="Label" parent="ControlPanel/VersionLabels"]
offset_left = -713.0 offset_left = -713.0
@@ -14377,13 +14378,21 @@ label_settings = SubResource("LabelSettings_qg0do")
[node name="versionNo" type="Label" parent="ControlPanel/VersionLabels/Label2"] [node name="versionNo" type="Label" parent="ControlPanel/VersionLabels/Label2"]
layout_mode = 0 layout_mode = 0
offset_left = 144.0 offset_left = 104.0
offset_top = 40.0 offset_top = 11.0
offset_right = 282.0 offset_right = 242.0
offset_bottom = 74.0 offset_bottom = 54.0
text = "v1.4.5" text = "v1.4.5"
label_settings = SubResource("LabelSettings_xvf50") label_settings = SubResource("LabelSettings_xvf50")
[node name="Label3" type="Label" parent="ControlPanel/VersionLabels"]
offset_left = -566.0
offset_top = -93.0
offset_right = -428.0
offset_bottom = -59.0
text = "Litruv Edition"
label_settings = SubResource("LabelSettings_qg0do")
[node name="EditControls" type="Node2D" parent="."] [node name="EditControls" type="Node2D" parent="."]
z_index = 4090 z_index = 4090
script = ExtResource("17_bf1ic") script = ExtResource("17_bf1ic")

View File

@@ -79,12 +79,13 @@ var ignoreBounce = false
#Animation #Animation
var frames = 1 var frames = 1
var animSpeed = 0 var animSpeed = 0
var animTime = 0.0 # Time accumulator for animations
var remadePolygon = false var remadePolygon = false
var clipped = false var clipped = false
var tick = 0 var time = 0.0 # Time accumulator for physics calculations
#Opacity #Opacity
var spriteOpacity = 1.0 var spriteOpacity = 1.0
@@ -224,7 +225,7 @@ func replaceSprite(pathNew):
remakePolygon() remakePolygon()
func _process(delta): func _process(delta):
tick += 1 time += delta
if Global.heldSprite == self: if Global.heldSprite == self:
grabArea.visible = true grabArea.visible = true
@@ -251,13 +252,17 @@ func _process(delta):
talkBlink() talkBlink()
animation() animation(delta)
func animation(): func animation(delta):
var speed = max(float(animSpeed),Engine.max_fps*6.0)
if animSpeed > 0 and frames > 1: if animSpeed > 0 and frames > 1:
if Global.animationTick % int((speed)/float(animSpeed)) == 0: animTime += delta
# Convert animSpeed to frames per second - no additional scaling needed since this controls frame rate
var frameRate = animSpeed / 60.0 # Normalize from old frame-based system
var frameInterval = 1.0 / frameRate
if animTime >= frameInterval:
animTime -= frameInterval
if sprite.frame == frames - 1: if sprite.frame == frames - 1:
sprite.frame = 0 sprite.frame = 0
else: else:
@@ -348,31 +353,46 @@ func drag(delta):
if dragSpeed == 0: if dragSpeed == 0:
dragger.global_position = wob.global_position dragger.global_position = wob.global_position
else: else:
dragger.global_position = lerp(dragger.global_position,wob.global_position,1/dragSpeed) # Convert dragSpeed to a proper delta-time lerp factor
# Higher dragSpeed = slower movement, so we invert it
# Use Global.main.physicsTimeMultiplier for consistent physics timing
var physicsMultiplier = Global.main.physicsTimeMultiplier if Global.main else 10.0
var lerpFactor = clamp(delta * (physicsMultiplier * 10.0 / max(dragSpeed, 0.1)), 0.0, 1.0)
dragger.global_position = lerp(dragger.global_position, wob.global_position, lerpFactor)
dragOrigin.global_position = dragger.global_position dragOrigin.global_position = dragger.global_position
func wobble(): func wobble():
wob.position.x = sin(tick*xFrq)*xAmp # Use Global.main.physicsTimeMultiplier for consistent physics timing
wob.position.y = sin(tick*yFrq)*yAmp var physicsMultiplier = Global.main.physicsTimeMultiplier if Global.main else 10.0
var scaledTime = time * physicsMultiplier
wob.position.x = sin(scaledTime * xFrq) * xAmp
wob.position.y = sin(scaledTime * yFrq) * yAmp
func rotationalDrag(length,delta): func rotationalDrag(length, delta):
var yvel = (length * rdragStr) var yvel = (length * rdragStr)
#Calculate Max angle #Calculate Max angle
yvel = clamp(yvel,rLimitMin,rLimitMax) yvel = clamp(yvel, rLimitMin, rLimitMax)
# Add rotation wobble as percentage of rotational limits range # Add rotation wobble as percentage of rotational limits range
var rotationRange = rLimitMax - rLimitMin var rotationRange = rLimitMax - rLimitMin
var rotationWobble = sin(tick*rFrq) * (rotationRange * rAmp * 0.01) var physicsMultiplier = Global.main.physicsTimeMultiplier if Global.main else 10.0
var scaledTime = time * physicsMultiplier
var rotationWobble = sin(scaledTime * rFrq) * (rotationRange * rAmp * 0.01)
var totalRotation = yvel + rotationWobble var totalRotation = yvel + rotationWobble
sprite.rotation = lerp_angle(sprite.rotation,deg_to_rad(totalRotation),0.25) # Use delta-based lerp for smooth rotation with slower speed
var lerpFactor = clamp(delta * (physicsMultiplier * 1.0), 0.0, 1.0) # Reduced from 15.0 to 4.0
sprite.rotation = lerp_angle(sprite.rotation, deg_to_rad(totalRotation), lerpFactor)
func stretch(length,delta): func stretch(length, delta):
var yvel = (length * stretchAmount * 0.01) var yvel = (length * stretchAmount * 0.01)
var target = Vector2(1.0-yvel,1.0+yvel) var target = Vector2(1.0 - yvel, 1.0 + yvel)
sprite.scale = lerp(sprite.scale,target,0.5) # Use delta-based lerp for smooth stretching
var physicsMultiplier = Global.main.physicsTimeMultiplier if Global.main else 10.0
var lerpFactor = clamp(delta * (physicsMultiplier * 30.0), 0.0, 1.0)
sprite.scale = lerp(sprite.scale, target, lerpFactor)
func changeCollision(enable): func changeCollision(enable):
grabArea.monitorable = enable grabArea.monitorable = enable