diff --git a/SpringDamper.gd b/SpringDamper.gd new file mode 100644 index 0000000..9362c22 --- /dev/null +++ b/SpringDamper.gd @@ -0,0 +1,28 @@ +# Based on: allenchou.net/2015/04/game-math-precise-control-over-numeric-springing/ + +extends Object + +class_name SpringDamper + +var omega +var zeta + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + +func _init(osc_freq:float = 1.0, osc_red:float = 0.1, osc_red_h:float = 1.0): + assert (osc_red > 0.001 and osc_red < 0.999) + omega = osc_freq * 2 * PI + zeta = log(1.0 - osc_red) / (-omega * osc_red_h) + print ("omega: ", omega, " zeta: ", zeta) + +func calc(x, v, xt, h:float): + var f = 1.0 + 2.0 * h * zeta * omega + var oo = omega * omega + var hoo = oo * h + var hhoo = hoo * h + var det_inv = 1.0 / (f + hhoo) + var det_x = f * x + h * v + hhoo * xt + var det_v = v + hoo * (xt - x) + return [det_x * det_inv, det_v * det_inv] diff --git a/project.godot b/project.godot index d28fad5..257eb97 100644 --- a/project.godot +++ b/project.godot @@ -8,8 +8,14 @@ config_version=4 -_global_script_classes=[ ] +_global_script_classes=[ { +"base": "Object", +"class": "SpringDamper", +"language": "GDScript", +"path": "res://SpringDamper.gd" +} ] _global_script_class_icons={ +"SpringDamper": "" } [application] diff --git a/scenes/Game.tscn b/scenes/Game.tscn index 1ee3b1f..1a584ef 100644 --- a/scenes/Game.tscn +++ b/scenes/Game.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=15 format=2] +[gd_scene load_steps=14 format=2] [ext_resource path="res://scenes/World.gd" type="Script" id=1] [ext_resource path="res://scenes/Grid.gd" type="Script" id=2] @@ -9,7 +9,6 @@ [ext_resource path="res://scenes/Editor.gd" type="Script" id=7] [ext_resource path="res://scenes/GridHighlight.gd" type="Script" id=8] [ext_resource path="res://assets/boat.svg" type="Texture" id=9] -[ext_resource path="res://scenes/IslandMapRenderer.gd" type="Script" id=10] [sub_resource type="DynamicFont" id=1] size = 27 @@ -291,6 +290,10 @@ current = true scale = Vector2( 0.455, 0.455 ) texture = ExtResource( 9 ) +[node name="Birdy" type="Node2D" parent="World"] + +[node name="Timer" type="Timer" parent="World/Birdy"] + [node name="IslandMapRenderer" type="Viewport" parent="."] size = Vector2( 300, 300 ) own_world = true @@ -298,7 +301,6 @@ world = SubResource( 4 ) render_target_v_flip = true render_target_clear_mode = 2 render_target_update_mode = 1 -script = ExtResource( 10 ) [node name="Camera2D" type="Camera2D" parent="IslandMapRenderer"] @@ -309,3 +311,4 @@ script = ExtResource( 10 ) [connection signal="toggled" from="World/UI/TopContainer/EditIslandButton" to="Editor" method="_on_EditIslandButton_toggled"] [connection signal="pressed" from="World/UI/TopContainer/Button" to="World" method="_on_generate_button_pressed"] [connection signal="pressed" from="World/UI/VBoxContainer/MapButton" to="World" method="_on_MapButton_pressed"] +[connection signal="pressed" from="World/UI/VBoxContainer/BirdyButton" to="World" method="_on_BirdyButton_pressed"] diff --git a/scenes/World.gd b/scenes/World.gd index aa3a2b5..a82343d 100644 --- a/scenes/World.gd +++ b/scenes/World.gd @@ -20,7 +20,10 @@ onready var FPSValueLabel = get_node("UI/TopContainer/FPSValue") onready var IslandMap = get_node("UI/IslandMap") onready var IslandMapRenderer = get_node("../IslandMapRenderer") +onready var BirdyTimer = get_node("Birdy/Timer") + var Island = preload("Island.gd") +var SpringDamper = preload("res://SpringDamper.gd") var hex_grid_bbox = [[0,0], [10,10]] @@ -39,6 +42,12 @@ var hex_line_path = [] var treasure_island = null var treasure_map_rendered = false +var birdy_spring = null +var birdy_spring_x = Vector2.ONE +var birdy_spring_v = Vector2.ZERO +var birdy_spring_xt = Vector2.ONE +var birdy_duration = 4.0 + # # Godot Functions # @@ -46,13 +55,15 @@ func _ready(): Grid.view_camera = WorldCamera GridHighlight.view_camera = WorldCamera + birdy_spring = SpringDamper.new(2, 0.99, 0.5) + generate() # Set player starting position PlayerChar.position = Globals.HexGrid.get_hex_center(Vector2(0,0)) -func _process(_delta): +func _process(delta): if Editor == null or not Editor.is_active(): WorldCamera.offset = PlayerChar.position @@ -70,6 +81,14 @@ func _process(_delta): PlayerBoat.transform.origin = Globals.HexToWorld(anchor_tile) else: PlayerBoat.transform.origin = PlayerChar.transform.origin + + var res = birdy_spring.calc(birdy_spring_x, birdy_spring_v, birdy_spring_xt, delta) + birdy_spring_x = res[0] + birdy_spring_v = res[1] + WorldCamera.zoom = birdy_spring_x + + if BirdyTimer.time_left == 0: + birdy_spring_xt = Vector2.ONE func draw_hex_path (path: Array, color: Color): @@ -447,3 +466,11 @@ func _unhandled_input(event): func _on_MapButton_pressed(): IslandMap.visible = !IslandMap.visible + + +func _on_BirdyButton_pressed(): + if birdy_spring_xt == Vector2.ONE: + birdy_spring_xt = Vector2.ONE * 4 + BirdyTimer.one_shot = true + BirdyTimer.start(birdy_duration) +