Advertisement
Guest User

Untitled

a guest
Mar 15th, 2025
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.87 KB | None | 0 0
  1. extends CharacterBody2D
  2. class_name Player
  3. #
  4. # MOVEMENT & ANIMATION SETTINGS
  5. #
  6. @export var speed: float = 600
  7. @export var gravity: float = 1000
  8.  
  9. # Ground movement
  10. @export var ground_acceleration: float = 1000.0
  11. @export var ground_deceleration: float = 2300.0
  12.  
  13. # Air movement
  14. @export var air_acceleration: float = 400.0
  15. @export var air_turnaround_deceleration: float = 800.0
  16. @export var air_no_input_deceleration: float = 50.0
  17.  
  18. # Jump
  19. @export var jump_force: float = 400
  20. @export var jump_cut_off: float = 0.5
  21.  
  22. # Triple jump
  23. @export var triple_jump_timeout: float = 0.3
  24. @export var second_jump_multiplier: float = 1.6
  25. @export var third_jump_multiplier: float = 2.0
  26. @export var third_jump_rotation: float = 360.0
  27. @export var third_jump_rotation_duration: float = 0.5
  28.  
  29. # Jump Dust Effect
  30. @export var jump_dust_scene: PackedScene
  31.  
  32. # Jump Queue
  33. var jump_queued: bool = false
  34. var jump_queue_timer: float = 0.0
  35. @export var jump_queue_duration: float = 1.0
  36.  
  37. #Sound effect volumes
  38. @export var JumpLandVolumeDB: float = -14.5
  39. #
  40. # INTERNAL STATE
  41. #
  42. var jump_chain_count: int = 0
  43. var elapsed_time: float = 0.0
  44. var last_land_time: float = 0.0
  45. var was_on_floor: bool = false
  46. var jump_land_timer: float = 0.0
  47. var jump_land_duration: float = 0.2
  48. var is_chopping: bool = false
  49. var current_woodpile: Node = null # Reference to the current woodpile being interacted with
  50. var chop_count: int = 0 # Number of chops performed on the current woodpile
  51. var input_enabled: bool = true
  52. var force_idle_time: float = 0.0
  53. var original_jump_chain_count: int = 0 # Variable to store the original jump chain count
  54. var stored_velocity: Vector2 = Vector2.ZERO
  55. var frozen: bool = false
  56.  
  57. # Array to hold chop sound effects
  58. var chop_sounds: Array = []
  59. # Jump sound effects directory
  60.  
  61. var jump_up_sfx = [
  62. preload("res://Assets/Sound Effects/JumpUpSFX/JumpUp1.mp3"),
  63. preload("res://Assets/Sound Effects/JumpUpSFX/JumpUp2.mp3"),
  64. preload("res://Assets/Sound Effects/JumpUpSFX/JumpUp3.mp3")
  65. ]
  66.  
  67.  
  68. # Signal to notify woodpile destruction
  69. signal woodpile_destroyed
  70.  
  71. var active_respawn_box: RespawnBox = null
  72.  
  73. func set_active_respawn_box(box: RespawnBox) -> void:
  74. active_respawn_box = box
  75.  
  76. func freeze() -> void:
  77. is_respawning = true
  78. # Example: disable movement/input here if needed.
  79. # velocity = Vector2.ZERO
  80.  
  81. func unfreeze() -> void:
  82. is_respawning = false
  83. # Re-enable movement/input here.
  84.  
  85. func play_internal_animation_Mute() -> void:
  86. var LandSFX = $JumpLandSound
  87. var timer : Timer = Timer.new()
  88. add_child(timer)
  89. timer.wait_time = 5.0
  90. LandSFX.set_volume_db(-80)
  91. timer.timeout.connect(_Land_Sound_Unmute)
  92. timer.start()
  93.  
  94. func _Land_Sound_Unmute() -> void:
  95. var LandSFX = $JumpLandSound
  96. LandSFX.set_volume_db(JumpLandVolumeDB)
  97.  
  98. func _ready():
  99. # Set the initial spawn position
  100. spawn_position = position
  101. add_to_group("player")
  102.  
  103. # Ensure the steam effect is hidden initially
  104. if steam_effect:
  105. steam_effect.visible = false
  106.  
  107. # Connect necessary signals and initialize sound effects
  108. randomize()
  109. $ChopArea.connect("area_entered", Callable(self, "_on_chop_area_body_entered"))
  110. $ChopArea.connect("area_exited", Callable(self, "_on_chop_area_body_exited"))
  111. $AnimatedSprite2D.connect("frame_changed", Callable(self, "_on_frame_changed"))
  112.  
  113. # Preload chop sound effects into an array
  114. chop_sounds = [
  115. preload("res://Assets/Sound Effects/ChopSFX/ChopSound1.mp3"),
  116. preload("res://Assets/Sound Effects/ChopSFX/ChopSound2.mp3"),
  117. preload("res://Assets/Sound Effects/ChopSFX/ChopSound3.mp3"),
  118. preload("res://Assets/Sound Effects/ChopSFX/ChopSound4.mp3"),
  119. preload("res://Assets/Sound Effects/ChopSFX/ChopSound5.mp3"),
  120. preload("res://Assets/Sound Effects/ChopSFX/ChopSound6.mp3"),
  121. preload("res://Assets/Sound Effects/ChopSFX/ChopSound7.mp3"),
  122. preload("res://Assets/Sound Effects/ChopSFX/ChopSound8.mp3"),
  123. ]
  124.  
  125.  
  126. var jump_count: int = 0
  127. var last_jump_time: float = 0.0
  128.  
  129. func force_third_jump(launch_factor: float = 2.0) -> void:
  130. jump_count = 2
  131. last_jump_time = Time.get_ticks_msec() / 1000.0
  132.  
  133. # Apply the jump using our custom launch_factor
  134. velocity.y = -(jump_force * launch_factor)
  135.  
  136. $AnimatedSprite2D.stop()
  137. $AnimatedSprite2D.play("Jump Up")
  138.  
  139. var original_scale = scale
  140. var stretched_scale = Vector2(original_scale.x * 0.8, original_scale.y * 1.4)
  141.  
  142. var tween = create_tween()
  143.  
  144. # 1) Stretch over 0.05s
  145. tween.tween_property(self, "scale", stretched_scale, 0.1)
  146.  
  147. # 2) After 0.05s, shrink back over 0.05s
  148. tween.tween_property(self, "scale", original_scale, 0.05).set_delay(0.05)
  149.  
  150.  
  151. func set_input_enabled(enabled: bool) -> void:
  152. input_enabled = enabled
  153.  
  154. func play_idle_animation() -> void:
  155. $AnimatedSprite2D.play("Idle")
  156.  
  157. func force_idle() -> void:
  158. velocity = Vector2.ZERO
  159. $AnimatedSprite2D.stop()
  160. $AnimatedSprite2D.play("Idle")
  161. # Force the Idle animation for 0.5 seconds, overriding falling logic.
  162. force_idle_time = 0.2
  163.  
  164. func _physics_process(delta):
  165. if frozen:
  166. # When frozen, simply update the physics without applying gravity.
  167. move_and_slide()
  168. return
  169.  
  170. if is_respawning:
  171. # Ignore input or forcibly set velocity to zero here
  172. velocity = Vector2.ZERO
  173. $AnimatedSprite2D.play("Respawning")
  174. $RunningSound.stop()
  175. return
  176.  
  177. if not input_enabled:
  178. # Process physics if necessary, but ignore input.
  179. velocity.y += gravity * delta
  180. move_and_slide()
  181. return
  182. # If chopping, skip all movement logic
  183. if is_chopping:
  184. move_and_slide() # Allow for gravity application while chopping
  185. return
  186.  
  187. # Update timers
  188. elapsed_time += delta
  189.  
  190. # Apply gravity
  191. velocity.y += gravity * delta
  192.  
  193. # Handle Jump Input
  194. if Input.is_action_just_pressed("ui_up"):
  195. if is_on_floor():
  196. _perform_jump()
  197. elif is_near_ground(): # Allow jump queue when near ground
  198. jump_queued = true
  199. jump_queue_timer = jump_queue_duration
  200.  
  201. # Handle Queued Jump
  202. if jump_queued:
  203. jump_queue_timer -= delta
  204. if jump_queue_timer <= 0:
  205. jump_queued = false # Expire the jump queue
  206. elif is_on_floor():
  207. jump_queued = false
  208. _perform_jump() # Properly trigger the jump, respecting the chain
  209.  
  210. # Ground vs. Air Movement
  211. if is_on_floor():
  212. _handle_ground_movement(delta)
  213. else:
  214. _handle_air_movement(delta)
  215.  
  216. # Short hop logic
  217. #if Input.is_action_just_released("ui_up") and velocity.y < 0:
  218. #velocity.y *= jump_cut_off
  219.  
  220. # Move the character
  221. move_and_slide()
  222.  
  223. # Landing Detection
  224. if is_on_floor() and not was_on_floor:
  225. last_land_time = elapsed_time
  226.  
  227. if flip_tween and flip_tween.is_valid():
  228. flip_tween.kill()
  229. flip_tween = null
  230.  
  231. rotation_degrees = 0
  232. # Reset jump chain count after landing
  233. if jump_chain_count == 3:
  234. jump_chain_count = 0 # Reset after completing the third jump
  235.  
  236. self.rotation_degrees = 0
  237. $AnimatedSprite2D.stop()
  238. $AnimatedSprite2D.play("Jump Land")
  239. jump_land_timer = jump_land_duration
  240.  
  241. $JumpLandSound.pitch_scale = randf_range(1, 1.45)
  242. $JumpLandSound.play()
  243.  
  244. # Reset jump chain if speed < 250 or timeout exceeded
  245. if is_on_floor():
  246. if abs(velocity.x) < 250 or (elapsed_time - last_land_time > triple_jump_timeout):
  247. jump_chain_count = 0
  248.  
  249. was_on_floor = is_on_floor()
  250.  
  251. # Update animations
  252. _update_animation(delta)
  253.  
  254. # Handle Chopping
  255. if Input.is_action_just_pressed("mouse_button_1"):
  256. _start_chop()
  257.  
  258. #
  259. # HELPER FUNCTIONS
  260. #
  261.  
  262. func is_near_ground() -> bool:
  263. return $RayCast2D.is_colliding()
  264.  
  265. func _handle_ground_movement(delta):
  266. var input_dir = 0
  267. if Input.is_action_pressed("ui_left"):
  268. input_dir -= 1
  269. $AnimationPlayer.play("Left_Flip")
  270. $ChopArea.position = Vector2(-30, 0) # Move ChopArea to the left
  271. if Input.is_action_pressed("ui_right"):
  272. input_dir += 1
  273. $AnimationPlayer.play("Right_Flip")
  274. $ChopArea.position = Vector2(30, 0) # Move ChopArea to the right
  275.  
  276. var target_speed = input_dir * speed
  277. if input_dir != 0:
  278. velocity.x = move_toward(velocity.x, target_speed, ground_acceleration * delta)
  279. else:
  280. velocity.x = move_toward(velocity.x, 0, ground_deceleration * delta)
  281.  
  282. func _handle_air_movement(delta):
  283. var input_dir = 0
  284. if Input.is_action_pressed("ui_left"):
  285. input_dir -= 1
  286. if Input.is_action_pressed("ui_right"):
  287. input_dir += 1
  288.  
  289. if input_dir == 0:
  290. velocity.x = move_toward(velocity.x, 0, air_no_input_deceleration * delta)
  291. else:
  292. var target_speed = input_dir * speed
  293. if sign(velocity.x) != sign(target_speed) and abs(velocity.x) > 0.1:
  294. velocity.x = move_toward(velocity.x, 0, air_turnaround_deceleration * delta)
  295. else:
  296. velocity.x = move_toward(velocity.x, target_speed, air_acceleration * delta)
  297.  
  298. # Track whether the third jump flip has been triggered
  299. var in_third_jump_flip: bool = false
  300.  
  301. func _perform_jump():
  302. # Reset the jump chain if the timeout has expired
  303. if elapsed_time - last_land_time > triple_jump_timeout:
  304. jump_chain_count = 1
  305. else:
  306. jump_chain_count += 1
  307.  
  308. # Clamp jump chain count to 3
  309. if jump_chain_count > 3:
  310. jump_chain_count = 3
  311.  
  312. # Determine the jump force and animation
  313. var this_jump_force = jump_force
  314. var animation_name = "1st Jump"
  315.  
  316. if jump_chain_count == 2:
  317. this_jump_force *= second_jump_multiplier
  318. animation_name = "2nd Jump"
  319. elif jump_chain_count == 3:
  320. this_jump_force *= third_jump_multiplier
  321. animation_name = "3rd Jump"
  322.  
  323. # Trigger the third jump flip
  324. _trigger_third_jump_flip()
  325.  
  326. # Play the JumpWoosh sound effect
  327. if $JumpWoosh:
  328. $JumpWoosh.pitch_scale = randf_range(1.2, 2.0)
  329. $JumpWoosh.play()
  330.  
  331. # Apply the jump force
  332. velocity.y = -this_jump_force
  333. _spawn_jump_dust(animation_name)
  334.  
  335. # Play the jump animation and sound
  336. $AnimatedSprite2D.stop()
  337. $AnimatedSprite2D.play("Jump Up")
  338.  
  339. if $JumpAudio:
  340. $JumpAudio.stream = jump_up_sfx[randi() % jump_up_sfx.size()]
  341. $JumpAudio.pitch_scale = randf_range(0.9, 1.2)
  342. $JumpAudio.play()
  343.  
  344. var flip_tween: Tween = null
  345.  
  346. func _trigger_third_jump_flip():
  347. if flip_tween and flip_tween.is_valid():
  348. flip_tween.kill()
  349.  
  350. var flip_direction = sign(velocity.x)
  351. if flip_direction == 0:
  352. flip_direction = 1
  353.  
  354. flip_tween = create_tween()
  355. flip_tween.set_ease(Tween.EASE_OUT)
  356. flip_tween.set_trans(Tween.TRANS_CIRC)
  357.  
  358. var first_overshoot_rotation = flip_direction * (third_jump_rotation + 25)
  359. var second_overshoot_rotation = flip_direction * (third_jump_rotation - 10)
  360.  
  361. flip_tween.tween_property(self, "rotation_degrees", first_overshoot_rotation, third_jump_rotation_duration * 0.6)
  362. flip_tween.tween_property(self, "rotation_degrees", second_overshoot_rotation, third_jump_rotation_duration * 0.3)
  363. flip_tween.set_trans(Tween.TRANS_ELASTIC)
  364. flip_tween.tween_property(self, "rotation_degrees", flip_direction * third_jump_rotation, third_jump_rotation_duration * 3)
  365.  
  366. flip_tween.connect("finished", Callable(self, "_on_flip_tween_finished"))
  367.  
  368. func _on_flip_tween_finished():
  369. flip_tween = null
  370.  
  371. func _spawn_jump_dust(animation_name: String):
  372. if jump_dust_scene:
  373. var dust_instance = jump_dust_scene.instantiate()
  374. dust_instance.global_position = global_position
  375.  
  376. # Adjust the vertical position for each animation
  377. var offset_y = 0
  378. match animation_name:
  379. "1st Jump":
  380. offset_y = 21
  381. "2nd Jump":
  382. offset_y = 0
  383. "3rd Jump":
  384. offset_y = -8
  385.  
  386. dust_instance.position.y += offset_y
  387. get_parent().add_child(dust_instance)
  388. dust_instance.play(animation_name)
  389.  
  390. func _update_animation(delta):
  391. # If we're forcing idle, decrement the timer and force the Idle animation.
  392. if force_idle_time > 0:
  393. force_idle_time -= delta
  394. $AnimatedSprite2D.play("Idle")
  395. return
  396. if $AnimatedSprite2D.animation == "Jump Land" and jump_land_timer > 0:
  397. jump_land_timer -= delta
  398. return
  399.  
  400. # If airborne and falling, play the first frame of Jump Land
  401. if not is_on_floor() and velocity.y > 0: # Falling
  402. if $AnimatedSprite2D.animation != "Jump Land" or $AnimatedSprite2D.frame != 0:
  403. $AnimatedSprite2D.stop()
  404. $AnimatedSprite2D.play("Jump Land")
  405. $AnimatedSprite2D.frame = 0 # Display the first frame of Jump Land
  406. $AnimatedSprite2D.stop() # Pause the animation at the first frame
  407. $RunningSound.stop() # Stop the running sound when airborne
  408. return
  409.  
  410. # Ground animations (Idle, Walking, Running)
  411. if is_on_floor():
  412. var spd = abs(velocity.x)
  413. if spd < 17: # any less than 17 makes running into walls look buggy.
  414. $AnimatedSprite2D.play("Idle")
  415. $RunningSound.stop()
  416. elif spd < 350:
  417. $AnimatedSprite2D.play("Walking")
  418. $RunningSound.stop()
  419. else:
  420. $AnimatedSprite2D.play("Running")
  421. if not $RunningSound.playing:
  422. $RunningSound.play()
  423. else:
  424. # Stop the running sound when not on the floor
  425. $RunningSound.stop()
  426.  
  427. # Steam Effect Variables
  428. @onready var steam_effect = $AnimatedSprite2D/SteamEffect
  429.  
  430. func _shake_woodpile(woodpile):
  431. var sprite = woodpile.get_parent().get_node("Sprite2D")
  432. # Check that the sprite is still valid.
  433. if not is_instance_valid(sprite):
  434. return
  435. var original_position = sprite.position
  436. # Defer the tween creation so that if the woodpile is freed soon after,
  437. # the tween won’t be started.
  438. call_deferred("_start_shake_tween", sprite, original_position)
  439.  
  440. func _start_shake_tween(sprite, original_position):
  441. # Check again that the sprite is still valid.
  442. if not is_instance_valid(sprite):
  443. return
  444. var tween = create_tween()
  445. tween.set_trans(Tween.TRANS_SINE)
  446. tween.set_ease(Tween.EASE_OUT)
  447. tween.tween_property(sprite, "position", original_position + Vector2(-5, 0), 0.05)
  448. tween.tween_property(sprite, "position", original_position + Vector2(5, 0), 0.05)
  449. tween.tween_property(sprite, "position", original_position, 0.05)
  450.  
  451.  
  452. # Modify _on_frame_changed to trigger the steam effect
  453. func _on_frame_changed():
  454. if $AnimatedSprite2D.animation == "Chop" and $AnimatedSprite2D.frame == 4:
  455. # Check if the player is hitting a woodpile
  456. if current_woodpile:
  457. # Play a random chop sound with random pitch
  458. if chop_sounds.size() > 0:
  459. $ChopSounds.stream = chop_sounds[randi() % chop_sounds.size()]
  460. $ChopSounds.pitch_scale = randf_range(0.9, 1.2) # Random pitch variation
  461. $ChopSounds.play()
  462.  
  463. # Only shake the woodpile on the first two chops
  464. if chop_count < 2:
  465. _shake_woodpile(current_woodpile)
  466.  
  467. # Emit particles: emit extra particles on the third hit
  468. if chop_count == 2:
  469. _emit_particles(current_woodpile, 1000) # Emit more particles for the last chop
  470. else:
  471. _emit_particles(current_woodpile) # Emit default 500 particles
  472.  
  473. chop_count += 1
  474.  
  475. # Play steam effect
  476. _play_steam_effect()
  477.  
  478. # Handle woodpile destruction on the third chop
  479. if chop_count >= 3:
  480. var woodpile_sprite = current_woodpile.get_parent().get_node("Sprite2D")
  481. if woodpile_sprite:
  482. woodpile_sprite.queue_free()
  483. current_woodpile.queue_free()
  484. current_woodpile = null
  485. chop_count = 0
  486. emit_signal("woodpile_destroyed")
  487.  
  488. # Add a function to play and stop the steam effect
  489. var is_steam_playing: bool = false # Add this variable to track if the steam effect is already playing
  490.  
  491. func _emit_particles(woodpile, amount: int = 500):
  492. var particles = woodpile.get_parent().get_node("CPUParticles2D")
  493. if particles:
  494. particles.amount = amount
  495. particles.emitting = true
  496. await get_tree().create_timer(0.05).timeout
  497. particles.emitting = false
  498.  
  499. func _play_steam_effect():
  500. if steam_effect and not is_steam_playing:
  501. is_steam_playing = true # Set the flag to true when the animation starts
  502. steam_effect.visible = true
  503. steam_effect.play("default") # Replace "default" with the name of your steam animation
  504. $SteamSound.pitch_scale = randf_range(0.5, 1.2)
  505. $SteamSound.play()
  506.  
  507. # Connect the animation_finished signal
  508. steam_effect.animation_finished.connect(_stop_steam_effect)
  509.  
  510. func _stop_steam_effect():
  511. if steam_effect:
  512. steam_effect.visible = false
  513. steam_effect.stop()
  514. steam_effect.animation_finished.disconnect(_stop_steam_effect)
  515. is_steam_playing = false # Reset the flag when the animation finishes
  516.  
  517. func _start_chop():
  518. if velocity.x == 0 and is_on_floor(): # Only chop when stationary and on the ground
  519. is_chopping = true
  520. $AnimatedSprite2D.stop()
  521. $AnimatedSprite2D.play("Chop")
  522. $AnimatedSprite2D.connect("animation_finished", Callable(self, "_on_chop_animation_finished"))
  523. $Swing.pitch_scale = randf_range(1, 0.5)
  524. $Swing.play()
  525.  
  526. func _on_chop_animation_finished():
  527. if $AnimatedSprite2D.animation == "Chop":
  528. is_chopping = false
  529. $AnimatedSprite2D.disconnect("animation_finished", Callable(self, "_on_chop_animation_finished"))
  530.  
  531. func _on_chop_area_body_entered(area):
  532. if area.name == "WoodPileArea2D":
  533. current_woodpile = area
  534. chop_count = 0
  535.  
  536. func _on_chop_area_body_exited(area):
  537. if area.name == "WoodPileArea2D" and current_woodpile == area:
  538. current_woodpile = null
  539.  
  540. # Add to your variables section
  541. var spawn_position: Vector2
  542. var is_respawning: bool = false
  543.  
  544. func respawn() -> void:
  545. is_respawning = true
  546. velocity = Vector2.ZERO
  547.  
  548. # Fade out over 0.5 seconds (adjust as desired).
  549. var tween = create_tween()
  550. var fade_out = tween.tween_property(self, "modulate", Color(1, 1, 1, 0), 0.5)
  551. await fade_out.finished
  552.  
  553. # Teleport to spawn_position.
  554. global_position = spawn_position
  555. rotation_degrees = 0
  556. velocity = Vector2.ZERO
  557.  
  558. # Fade in over 0.5 seconds.
  559. tween = create_tween()
  560. var fade_in = tween.tween_property(self, "modulate", Color(1, 1, 1, 1), 0.5)
  561. await fade_in.finished
  562.  
  563. is_respawning = false
  564.  
  565. func freeze_movement() -> void:
  566. # Store current velocity so you can restore it later.
  567. stored_velocity = velocity
  568. # Zero out the velocity.
  569. velocity = Vector2.ZERO
  570. # Set the frozen flag so gravity isn’t applied.
  571. frozen = true
  572. # Stop the animation so the sprite stays on its current frame.
  573. $AnimatedSprite2D.pause()
  574. # Disable input.
  575. set_input_enabled(false)
  576. $RunningSound.stop()
  577.  
  578. func unfreeze_movement() -> void:
  579. # Restore the stored velocity.
  580. velocity = stored_velocity
  581. stored_velocity = Vector2.ZERO
  582. # Clear the frozen flag so gravity resumes.
  583. frozen = false
  584. # Re-enable input.
  585. set_input_enabled(true)
  586. # Resume an appropriate animation (for example, Idle).
  587. $AnimatedSprite2D.play()
  588.  
  589. func _flip_left():
  590. $AnimationPlayer.play("Left_Flip")
  591.  
  592. func _flip_right():
  593. $AnimationPlayer.play("Right_Flip")
  594.  
  595. func _force_walk_anim():
  596. $AnimatedSprite2D.play("Walking")
  597.  
  598. @onready var scene_transition_pos_marker: Marker2D = $"../NextScenePrompt/SceneTransitionAnim/SceneTransitionPosMarker"
  599.  
  600. func scene_transition_player_postition_change():
  601. self.global_position = scene_transition_pos_marker.global_position
  602.  
  603. func transition_player_movement():
  604. # Get the player's current position
  605. var original_position = self.position
  606. # Define the offset (for example, 100 pixels right and 50 pixels down)
  607. var offset_position = original_position + Vector2(500, 0)
  608.  
  609. # Create and configure the tween
  610. var tween = create_tween()
  611. tween.set_trans(Tween.TRANS_LINEAR)
  612. tween.set_process_mode(Tween.TWEEN_PROCESS_IDLE)
  613.  
  614. # Tween the player's position to the offset position over 0.5 seconds
  615. tween.tween_property(self, "position", offset_position, 3.5)
  616.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement