From 3525ef2ecd306b6ea0c6a3307d5f414eb8a868b3 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Fri, 19 Aug 2022 18:48:54 +0200 Subject: [PATCH] Simple player entity --- Assets/pirate.svg | 203 ++++++++++++++++++++++ Assets/pirate.svg.import | 35 ++++ Components/ClickableComponent.gd | 16 +- Components/ClickableComponent.tscn | 17 ++ Components/MovableComponent.gd | 11 +- Entities/PlayerEntity.gd | 44 +++++ Entities/PlayerEntity.tscn | 25 +++ PlayerNode.gd => Entities/SimpleEntity.gd | 9 +- Entities/SimpleEntity.tscn | 19 +- Entities/WanderingEntity.tscn | 17 +- Game.gd | 15 +- Game.tscn | 10 +- Utils/SpringDamper.gd | 28 +++ project.godot | 6 + 14 files changed, 406 insertions(+), 49 deletions(-) create mode 100644 Assets/pirate.svg create mode 100644 Assets/pirate.svg.import create mode 100644 Components/ClickableComponent.tscn create mode 100644 Entities/PlayerEntity.gd create mode 100644 Entities/PlayerEntity.tscn rename PlayerNode.gd => Entities/SimpleEntity.gd (81%) create mode 100644 Utils/SpringDamper.gd diff --git a/Assets/pirate.svg b/Assets/pirate.svg new file mode 100644 index 0000000..800a0bb --- /dev/null +++ b/Assets/pirate.svg @@ -0,0 +1,203 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Assets/pirate.svg.import b/Assets/pirate.svg.import new file mode 100644 index 0000000..39a60b1 --- /dev/null +++ b/Assets/pirate.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/pirate.svg-3b2dea93c8f9ecaa3dd364c5dc991522.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/pirate.svg" +dest_files=[ "res://.import/pirate.svg-3b2dea93c8f9ecaa3dd364c5dc991522.stex" ] + +[params] + +compress/mode=0 +compress/lossy_quality=0.7 +compress/hdr_mode=0 +compress/bptc_ldr=0 +compress/normal_map=0 +flags/repeat=0 +flags/filter=true +flags/mipmaps=false +flags/anisotropic=false +flags/srgb=2 +process/fix_alpha_border=true +process/premult_alpha=false +process/HDR_as_SRGB=false +process/invert_color=false +process/normal_map_invert_y=false +stream=false +size_limit=0 +detect_3d=true +svg/scale=1.0 diff --git a/Components/ClickableComponent.gd b/Components/ClickableComponent.gd index c6f5af6..16460ba 100644 --- a/Components/ClickableComponent.gd +++ b/Components/ClickableComponent.gd @@ -7,10 +7,22 @@ export var collision_size = Vector2(1, 1) onready var collision_shape = $Area2D +var is_mouseover = false + # Called when the node enters the scene tree for the first time. func _ready(): collision_shape.scale = collision_size -func _on_Area2D_input_event(viewport, event, shape_idx): - if event is InputEventMouseButton and event.pressed: + +func _input(event): + if event is InputEventMouseButton and event.pressed and is_mouseover: emit_signal ("clicked") + get_tree().get_root().set_input_as_handled() + + +func _on_Area2D_mouse_entered(): + is_mouseover = true + + +func _on_Area2D_mouse_exited(): + is_mouseover = false diff --git a/Components/ClickableComponent.tscn b/Components/ClickableComponent.tscn new file mode 100644 index 0000000..48b6235 --- /dev/null +++ b/Components/ClickableComponent.tscn @@ -0,0 +1,17 @@ +[gd_scene load_steps=3 format=2] + +[ext_resource path="res://Components/ClickableComponent.gd" type="Script" id=1] + +[sub_resource type="CircleShape2D" id=1] +radius = 31.4006 + +[node name="Clickable" type="Node2D"] +script = ExtResource( 1 ) + +[node name="Area2D" type="Area2D" parent="."] + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] +shape = SubResource( 1 ) + +[connection signal="mouse_entered" from="Area2D" to="." method="_on_Area2D_mouse_entered"] +[connection signal="mouse_exited" from="Area2D" to="." method="_on_Area2D_mouse_exited"] diff --git a/Components/MovableComponent.gd b/Components/MovableComponent.gd index eb96003..bf5b9ea 100644 --- a/Components/MovableComponent.gd +++ b/Components/MovableComponent.gd @@ -1,12 +1,16 @@ extends Node2D +var SpringDamper = preload("res://Utils/SpringDamper.gd") export var target = Vector2 (0, 0) export var pos = Vector2 (0, 0) +export var vel = Vector2 (0, 0) export var max_speed = 50 export var spring_k = 10 export var spring_b = 0.5 +onready var spring_damper = SpringDamper.new(4, .99, 0.5) + var velocity = Vector2(0, 0) const pos_error_eps = 0.01 @@ -20,8 +24,9 @@ func _ready(): # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): if (target - pos).length_squared() > pos_error_eps * pos_error_eps: - var acceleration = spring_k * (target - pos) - spring_b * velocity - velocity = velocity + acceleration * delta - pos = pos + velocity * delta + var spring_res = spring_damper.calc(pos, vel, target, delta) + + pos = spring_res[0] + vel = spring_res[1] emit_signal("position_updated", pos) diff --git a/Entities/PlayerEntity.gd b/Entities/PlayerEntity.gd new file mode 100644 index 0000000..ba8b09a --- /dev/null +++ b/Entities/PlayerEntity.gd @@ -0,0 +1,44 @@ +extends Node2D + +onready var color_component = $Components/Color +onready var tinted_sprite_component = $Components/TintedSprite +onready var clickable_component = $Components/Clickable +onready var movable_component = $Components/Movable + +onready var is_active = false + +# Called when the node enters the scene tree for the first time. +func _ready(): + if color_component and tinted_sprite_component: + print ("Connecting signals") + color_component.connect("color_changed", tinted_sprite_component, "set_color_tint") + + if clickable_component: + clickable_component.connect("clicked", self, "_on_entity_clicked") + + if movable_component: + movable_component.connect("position_updated", self, "_on_position_updated") + movable_component.target = self.transform.origin + movable_component.pos = self.transform.origin + +func _process(delta): + if is_active and color_component: + var color = Color( + (sin(float(OS.get_system_time_msecs()) / 1000.0) + 1.0) / 2.0, + (sin(float(OS.get_system_time_msecs()) / 300.0) + 1.0) / 2.0, + (sin(float(OS.get_system_time_msecs()) / 100.0) + 1.0) / 2.0 + ) + color_component.set_color(color) + pass + +func _on_entity_clicked(): + is_active = not is_active + +func _on_position_updated(new_position): + transform.origin = new_position + update() + +func on_world_location_clicked(position): + assert(movable_component) + + movable_component.target = position diff --git a/Entities/PlayerEntity.tscn b/Entities/PlayerEntity.tscn new file mode 100644 index 0000000..d6a7fa3 --- /dev/null +++ b/Entities/PlayerEntity.tscn @@ -0,0 +1,25 @@ +[gd_scene load_steps=7 format=2] + +[ext_resource path="res://Entities/PlayerEntity.gd" type="Script" id=1] +[ext_resource path="res://Components/TintedSpriteComponent.gd" type="Script" id=2] +[ext_resource path="res://Components/ColorComponent.gd" type="Script" id=3] +[ext_resource path="res://Components/ClickableComponent.tscn" type="PackedScene" id=4] +[ext_resource path="res://Components/MovableComponent.gd" type="Script" id=5] +[ext_resource path="res://Assets/pirate.svg" type="Texture" id=6] + +[node name="PlayerEntity" type="Node2D"] +script = ExtResource( 1 ) + +[node name="Components" type="Node2D" parent="."] + +[node name="Movable" type="Node2D" parent="Components"] +script = ExtResource( 5 ) + +[node name="Clickable" parent="Components" instance=ExtResource( 4 )] + +[node name="TintedSprite" type="Sprite" parent="Components"] +texture = ExtResource( 6 ) +script = ExtResource( 2 ) + +[node name="Color" type="Node" parent="Components"] +script = ExtResource( 3 ) diff --git a/PlayerNode.gd b/Entities/SimpleEntity.gd similarity index 81% rename from PlayerNode.gd rename to Entities/SimpleEntity.gd index ea51c3e..1ecc3c0 100644 --- a/PlayerNode.gd +++ b/Entities/SimpleEntity.gd @@ -1,9 +1,9 @@ -extends Node +extends Node2D onready var color_component = $Components/Color onready var tinted_sprite_component = $Components/TintedSprite onready var clickable_component = $Components/Clickable -onready var undef_component = $ebvlerb +onready var movable_component = $Components/Movable onready var is_active = false @@ -12,15 +12,12 @@ func _ready(): if color_component and tinted_sprite_component: print ("Connecting signals") color_component.connect("color_changed", tinted_sprite_component, "set_color_tint") - tinted_sprite_component.set_color_tint(color_component.color) if clickable_component: clickable_component.connect("clicked", self, "_on_entity_clicked") + func _process(delta): - if Engine.editor_hint: - tinted_sprite_component.tint_color = color_component.color - if is_active and color_component: var color = Color( (sin(float(OS.get_system_time_msecs()) / 1000.0) + 1.0) / 2.0, diff --git a/Entities/SimpleEntity.tscn b/Entities/SimpleEntity.tscn index 92c115c..3c66c88 100644 --- a/Entities/SimpleEntity.tscn +++ b/Entities/SimpleEntity.tscn @@ -1,26 +1,17 @@ -[gd_scene load_steps=7 format=2] +[gd_scene load_steps=6 format=2] [ext_resource path="res://Components/TintedSpriteComponent.gd" type="Script" id=1] -[ext_resource path="res://PlayerNode.gd" type="Script" id=2] +[ext_resource path="res://Entities/SimpleEntity.gd" type="Script" id=2] [ext_resource path="res://Components/ColorComponent.gd" type="Script" id=3] -[ext_resource path="res://Components/ClickableComponent.gd" type="Script" id=4] +[ext_resource path="res://Components/ClickableComponent.tscn" type="PackedScene" id=4] [ext_resource path="res://icon.png" type="Texture" id=5] -[sub_resource type="CircleShape2D" id=1] -radius = 31.4006 - [node name="SimpleEntity" type="Node2D"] script = ExtResource( 2 ) [node name="Components" type="Node2D" parent="."] -[node name="Clickable" type="Node2D" parent="Components"] -script = ExtResource( 4 ) - -[node name="Area2D" type="Area2D" parent="Components/Clickable"] - -[node name="CollisionShape2D" type="CollisionShape2D" parent="Components/Clickable/Area2D"] -shape = SubResource( 1 ) +[node name="Clickable" parent="Components" instance=ExtResource( 4 )] [node name="TintedSprite" type="Sprite" parent="Components"] texture = ExtResource( 5 ) @@ -29,5 +20,3 @@ script = ExtResource( 1 ) [node name="Color" type="Node" parent="Components"] script = ExtResource( 3 ) color = Color( 1, 1, 1, 1 ) - -[connection signal="input_event" from="Components/Clickable/Area2D" to="Components/Clickable" method="_on_Area2D_input_event"] diff --git a/Entities/WanderingEntity.tscn b/Entities/WanderingEntity.tscn index 5a0b61a..30aa63e 100644 --- a/Entities/WanderingEntity.tscn +++ b/Entities/WanderingEntity.tscn @@ -1,15 +1,12 @@ -[gd_scene load_steps=8 format=2] +[gd_scene load_steps=7 format=2] [ext_resource path="res://Components/TintedSpriteComponent.gd" type="Script" id=1] [ext_resource path="res://Entities/WanderingEntity.gd" type="Script" id=2] [ext_resource path="res://Components/ColorComponent.gd" type="Script" id=3] -[ext_resource path="res://Components/ClickableComponent.gd" type="Script" id=4] +[ext_resource path="res://Components/ClickableComponent.tscn" type="PackedScene" id=4] [ext_resource path="res://icon.png" type="Texture" id=5] [ext_resource path="res://Components/MovableComponent.gd" type="Script" id=6] -[sub_resource type="CircleShape2D" id=1] -radius = 31.4006 - [node name="WanderingEntity" type="Node2D"] script = ExtResource( 2 ) @@ -18,13 +15,7 @@ script = ExtResource( 2 ) [node name="Movable" type="Node2D" parent="Components"] script = ExtResource( 6 ) -[node name="Clickable" type="Node2D" parent="Components"] -script = ExtResource( 4 ) - -[node name="Area2D" type="Area2D" parent="Components/Clickable"] - -[node name="CollisionShape2D" type="CollisionShape2D" parent="Components/Clickable/Area2D"] -shape = SubResource( 1 ) +[node name="Clickable" parent="Components" instance=ExtResource( 4 )] [node name="TintedSprite" type="Sprite" parent="Components"] texture = ExtResource( 5 ) @@ -32,5 +23,3 @@ script = ExtResource( 1 ) [node name="Color" type="Node" parent="Components"] script = ExtResource( 3 ) - -[connection signal="input_event" from="Components/Clickable/Area2D" to="Components/Clickable" method="_on_Area2D_input_event"] diff --git a/Game.gd b/Game.gd index 122c334..92970ae 100644 --- a/Game.gd +++ b/Game.gd @@ -3,17 +3,14 @@ extends Node2D onready var SimpleEntity = preload("res://Entities/SimpleEntity.tscn") onready var WanderingEntity = preload("res://Entities/WanderingEntity.tscn") +onready var player = $PlayerEntity onready var entities = $Entities +signal world_location_clicked # Called when the node enters the scene tree for the first time. func _ready(): - pass # Replace with function body. - - -# Called every frame. 'delta' is the elapsed time since the previous frame. -#func _process(delta): -# pass + self.connect("world_location_clicked", player, "on_world_location_clicked") func _on_AddEntityButton_pressed(): var entity_instance = SimpleEntity.instance() @@ -27,3 +24,9 @@ func _on_AddWanderingEntity_pressed(): entity_instance.transform.origin = Vector2(randf() * viewport_rect.size[0], randf() * viewport_rect.size[1]) entities.add_child(entity_instance) entity_instance.set_target(Vector2(randf() * viewport_rect.size[0], randf() * viewport_rect.size[1])) + +func _unhandled_input(event): + if event is InputEventMouseButton and event.pressed: + #get_tree().get_root().set_input_as_handled() + emit_signal("world_location_clicked", event.position) + pass diff --git a/Game.tscn b/Game.tscn index 9fdfd10..37f30a7 100644 --- a/Game.tscn +++ b/Game.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=3 format=2] +[gd_scene load_steps=4 format=2] [ext_resource path="res://Entities/SimpleEntity.tscn" type="PackedScene" id=1] +[ext_resource path="res://Entities/PlayerEntity.tscn" type="PackedScene" id=2] [ext_resource path="res://Game.gd" type="Script" id=6] [node name="Game" type="Node2D"] @@ -34,15 +35,18 @@ __meta__ = { [node name="SimpleEntity" parent="Entities" instance=ExtResource( 1 )] position = Vector2( 360, 118 ) -[node name="Color" parent="Entities/SimpleEntity/Components" index="3"] +[node name="Color" parent="Entities/SimpleEntity/Components" index="2"] color = Color( 0.298039, 0.745098, 0.368627, 1 ) [node name="SimpleEntity2" parent="Entities" instance=ExtResource( 1 )] position = Vector2( 157, 306 ) -[node name="Color" parent="Entities/SimpleEntity2/Components" index="3"] +[node name="Color" parent="Entities/SimpleEntity2/Components" index="2"] color = Color( 0, 0.0156863, 1, 1 ) +[node name="PlayerEntity" parent="." instance=ExtResource( 2 )] +position = Vector2( 263, 225 ) + [connection signal="pressed" from="Control/AddEntityButton" to="." method="_on_AddEntityButton_pressed"] [connection signal="pressed" from="Control/AddWanderingEntity" to="." method="_on_AddWanderingEntity_pressed"] diff --git a/Utils/SpringDamper.gd b/Utils/SpringDamper.gd new file mode 100644 index 0000000..9362c22 --- /dev/null +++ b/Utils/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 5f3b141..22d0dc3 100644 --- a/project.godot +++ b/project.godot @@ -19,6 +19,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://Components/ColorComponent.gd" }, { +"base": "Object", +"class": "SpringDamper", +"language": "GDScript", +"path": "res://Utils/SpringDamper.gd" +}, { "base": "Sprite", "class": "TintedSpriteComponent", "language": "GDScript", @@ -27,6 +32,7 @@ _global_script_classes=[ { _global_script_class_icons={ "ClickableComponent": "", "ColorComponent": "", +"SpringDamper": "", "TintedSpriteComponent": "" }