├── .gitignore ├── .zed └── settings.json ├── LICENSE ├── README.md ├── godot-csharp ├── EntityComponent │ ├── Components │ │ ├── PowerReceiver.cs │ │ └── PowerSource.cs │ ├── Entities │ │ ├── BatteryEntity.cs │ │ ├── BatteryEntity.tscn │ │ ├── GeneratorEntity.cs │ │ └── GeneratorEntity.tscn │ ├── Game.cs │ ├── Game.tscn │ ├── PowerSystem.cs │ └── Shared │ │ ├── battery_indicator.png │ │ ├── battery_indicator.png.import │ │ ├── tileset.svg │ │ ├── tileset.svg.import │ │ └── tileset.tres ├── Godot Design Pattern csharp demo.csproj ├── Godot Design Pattern csharp demo.csproj.old ├── Godot Design Pattern csharp demo.sln ├── Godot Design Pattern csharp demo.sln.old ├── Properties │ └── AssemblyInfo.cs ├── Shared │ ├── background.png │ ├── background.png.import │ ├── monserrate_bold.tres │ ├── montserrat_extrabold.otf │ ├── player.png │ ├── player.png.import │ ├── tileset_platformer.png │ ├── tileset_platformer.png.import │ └── tileset_platformer.tres ├── StateMachine │ ├── Player │ │ ├── Air.cs │ │ ├── Idle.cs │ │ ├── Player.cs │ │ ├── Player.tscn │ │ ├── PlayerState.cs │ │ ├── Run.cs │ │ └── StateMachine.cs │ ├── State.cs │ └── StateMachineDemoCSharp.tscn ├── default_env.tres ├── icon.png ├── icon.png.import └── project.godot ├── godot ├── common │ ├── background.png │ ├── background.png.import │ ├── monserrate_bold.tres │ ├── montserrat_extrabold.otf │ ├── montserrat_extrabold.otf.import │ ├── player.png │ ├── player.png.import │ ├── tileset_platformer.png │ ├── tileset_platformer.png.import │ └── tileset_platformer.tres ├── default_env.tres ├── entity_component │ ├── common │ │ ├── battery_indicator.png │ │ ├── battery_indicator.png.import │ │ ├── tileset.svg │ │ ├── tileset.svg.import │ │ └── tileset.tres │ ├── components │ │ ├── power_receiver.gd │ │ └── power_source.gd │ ├── entities │ │ ├── battery_entity.gd │ │ ├── battery_entity.tscn │ │ ├── generator_entity.gd │ │ └── generator_entity.tscn │ ├── game.gd │ ├── game.tscn │ └── power_system.gd ├── finite_state_machine │ ├── demo_state_machine.tscn │ ├── node_version │ │ ├── player.gd │ │ ├── player.tscn │ │ ├── state.gd │ │ ├── state_machine.gd │ │ └── states │ │ │ ├── falling.gd │ │ │ ├── gliding.gd │ │ │ ├── idle.gd │ │ │ ├── jumping.gd │ │ │ ├── player_state.gd │ │ │ └── running.gd │ ├── simple_version │ │ ├── player_single_script.gd │ │ └── player_single_script.tscn │ └── without_states │ │ └── player_without_states.gd ├── icon.png ├── icon.png.import └── project.godot └── images └── design-patterns-banner.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Godot-specific ignores 3 | .import/ 4 | .godot/ 5 | 6 | # Mono-specific ignores 7 | .mono/ 8 | data_*/ 9 | -------------------------------------------------------------------------------- /.zed/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "hard_tabs": true 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 GDQuest 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Godot Design Patterns 2 | 3 | ![Godot design patterns banner](images/design-patterns-banner.png) 4 | 5 | This repository is a collection of programming patterns implemented in Godot. 6 | 7 | On our website, you will also find some free companion guides. 8 | 9 | Here are the ones we released already: 10 | 11 | - [Finite state machine in Godot 4](https://www.gdquest.com/tutorial/godot/design-patterns/finite-state-machine/) 12 | - [Entity Component pattern in Godot 3](https://www.gdquest.com/tutorial/godot/design-patterns/entity-component-pattern/) 13 | 14 | If you want to learn Godot and support our work, check out our [Godot courses](https://school.gdquest.com/). -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Components/PowerReceiver.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class PowerReceiver : Node 5 | { 6 | [Signal] 7 | public delegate void PowerReceived(float power, float delta); 8 | 9 | [Export] 10 | public float PowerRequired = 50.0f; 11 | 12 | public float Efficiency = 0.0f; 13 | } 14 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Components/PowerSource.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class PowerSource : Node 5 | { 6 | [Signal] 7 | public delegate void PowerDrawn(float power, float delta); 8 | 9 | [Export] 10 | public float PowerAmount = 50.0f; 11 | 12 | public float Efficiency = 0.0f; 13 | } 14 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Entities/BatteryEntity.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using System.Threading.Tasks; 4 | 5 | public class BatteryEntity : Node2D 6 | { 7 | /// 8 | /// Total amount of power the battery is able to hold 9 | /// 10 | [Export] 11 | public float MaxStorage = 1000.0f; 12 | 13 | /// 14 | /// Actual amount of power currently in the battery 15 | /// 16 | private float _storedPower = 0.0f; 17 | public float StoredPower 18 | { 19 | get { return _storedPower; } 20 | set { SetStoredPower(value); } 21 | } 22 | 23 | private PowerReceiver receiver; 24 | private PowerSource source; 25 | private Sprite indicator; 26 | 27 | public override void _Ready() 28 | { 29 | // onready equivalent doesn't exist in C# 30 | receiver = GetNode("PowerReceiver"); 31 | source = GetNode("PowerSource"); 32 | indicator = GetNode("Indicator"); 33 | } 34 | 35 | private void SetStoredPower(float value) 36 | { 37 | _storedPower = value; 38 | 39 | // Make sure all nodes are ready 40 | if (!this.IsInsideTree()) 41 | { 42 | Task.Run(async () => await ToSignal(this, "ready")); 43 | } 44 | 45 | // Set receiver efficiency to 0 if already full, otherwise set it to a percentage 46 | // of power that it can still receive from its input capacity. 47 | receiver.Efficiency = _storedPower >= MaxStorage ? 48 | 0.0f : 49 | Math.Min((MaxStorage - _storedPower) / receiver.PowerRequired, 1.0f); 50 | 51 | source.Efficiency = _storedPower <= 0 ? 52 | 0.0f : 53 | Math.Min(_storedPower / source.PowerAmount, 1.0f); 54 | 55 | // Update shader with power amount so the indicator is up to date with amount 56 | var shader = (ShaderMaterial)indicator.Material; 57 | shader.SetShaderParam("amount", _storedPower / MaxStorage); 58 | indicator.Material = shader; 59 | } 60 | 61 | /// 62 | /// Reduce the amount of power in the battery by the power value per second 63 | /// 64 | /// 65 | /// 66 | private void OnPowerSourcePowerDrawn(float power, float delta) 67 | { 68 | StoredPower = Math.Max(0, _storedPower - Math.Min(power, source.PowerAmount * source.Efficiency) * delta); 69 | } 70 | 71 | /// 72 | /// Increase the amount of power in the battery by the power value per second 73 | /// 74 | /// 75 | /// 76 | private void OnPowerReceiverPowerReceived(float power, float delta) 77 | { 78 | StoredPower = Math.Min(MaxStorage, _storedPower + power * delta); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Entities/BatteryEntity.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=8 format=2] 2 | 3 | [ext_resource path="res://EntityComponent/Shared/tileset.svg" type="Texture" id=1] 4 | [ext_resource path="res://EntityComponent/Shared/battery_indicator.png" type="Texture" id=2] 5 | [ext_resource path="res://EntityComponent/Components/PowerSource.cs" type="Script" id=3] 6 | [ext_resource path="res://EntityComponent/Entities/BatteryEntity.cs" type="Script" id=4] 7 | [ext_resource path="res://EntityComponent/Components/PowerReceiver.cs" type="Script" id=5] 8 | 9 | [sub_resource type="Shader" id=1] 10 | code = "shader_type canvas_item; 11 | 12 | //A percentage from 0 to 1 for how full the battery is 13 | uniform float amount : hint_range(0, 1) = 0.0; 14 | 15 | void fragment() { 16 | //Load the texture as a mask for our flat color indicator 17 | vec4 mask = texture(TEXTURE, UV); 18 | //We only need the red part of it. The rest, black or transparent, is of 19 | //no interest. 20 | float masking_area = mask.r; 21 | 22 | //Set the percentage of the UV sampling along the X axis to either 0 or 1, 23 | // based on how full the battery is. So if amount is 0.5, the percentage will 24 | // be 0 if UV.x is greater than that. 25 | float uv_percentage = step(UV.x, amount); 26 | 27 | //Set the sprite to the sprite's modulate color, and the alpha to the UV 28 | //percentage calculated above so only the red parts show up. 29 | COLOR = vec4(mask.rgb, uv_percentage * masking_area); 30 | }" 31 | 32 | [sub_resource type="ShaderMaterial" id=2] 33 | resource_local_to_scene = true 34 | shader = SubResource( 1 ) 35 | shader_param/amount = 0.0 36 | 37 | [node name="BatteryEntity" type="Node2D" groups=[ 38 | "power_receivers", 39 | "power_sources", 40 | ]] 41 | script = ExtResource( 4 ) 42 | 43 | [node name="PowerSource" type="Node" parent="."] 44 | script = ExtResource( 3 ) 45 | PowerAmount = 200.0 46 | 47 | [node name="PowerReceiver" type="Node" parent="."] 48 | script = ExtResource( 5 ) 49 | PowerRequired = 200.0 50 | 51 | [node name="Sprite" type="Sprite" parent="."] 52 | position = Vector2( 0, -14.8726 ) 53 | texture = ExtResource( 1 ) 54 | region_enabled = true 55 | region_rect = Rect2( 119, 4, 102, 82 ) 56 | 57 | [node name="Indicator" type="Sprite" parent="."] 58 | modulate = Color( 1, 0, 0, 1 ) 59 | material = SubResource( 2 ) 60 | position = Vector2( -23.2885, -17.3956 ) 61 | scale = Vector2( 0.6, 0.6 ) 62 | texture = ExtResource( 2 ) 63 | [connection signal="PowerDrawn" from="PowerSource" to="." method="OnPowerSourcePowerDrawn"] 64 | [connection signal="PowerReceived" from="PowerReceiver" to="." method="OnPowerReceiverPowerReceived"] 65 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Entities/GeneratorEntity.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class GeneratorEntity : Node2D 5 | { 6 | private AnimationPlayer _animationPlayer; 7 | private PowerSource _powerSource; 8 | 9 | public override void _Ready() 10 | { 11 | _animationPlayer = GetNode("AnimationPlayer"); 12 | _animationPlayer.Play("Work"); 13 | 14 | _powerSource = GetNode("PowerSource"); 15 | _powerSource.Efficiency = 1.0f; 16 | } 17 | 18 | private void OnPowerSourcePowerDrawn(float power, float delta) 19 | { 20 | var proportion = power / _powerSource.PowerAmount; 21 | _animationPlayer.PlaybackSpeed = proportion; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Entities/GeneratorEntity.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=2] 2 | 3 | [ext_resource path="res://EntityComponent/Components/PowerSource.cs" type="Script" id=1] 4 | [ext_resource path="res://EntityComponent/Shared/tileset.svg" type="Texture" id=2] 5 | [ext_resource path="res://EntityComponent/Entities/GeneratorEntity.cs" type="Script" id=3] 6 | 7 | [sub_resource type="Animation" id=1] 8 | resource_name = "Work" 9 | length = 0.6 10 | loop = true 11 | tracks/0/type = "value" 12 | tracks/0/path = NodePath("PistonBack:position") 13 | tracks/0/interp = 1 14 | tracks/0/loop_wrap = true 15 | tracks/0/imported = false 16 | tracks/0/enabled = true 17 | tracks/0/keys = { 18 | "times": PoolRealArray( 0, 0.3, 0.6 ), 19 | "transitions": PoolRealArray( 1, 1, 1 ), 20 | "update": 0, 21 | "values": [ Vector2( 0, -33 ), Vector2( 0, -60.7809 ), Vector2( 0, -33 ) ] 22 | } 23 | tracks/1/type = "value" 24 | tracks/1/path = NodePath("PistonFront:position") 25 | tracks/1/interp = 1 26 | tracks/1/loop_wrap = true 27 | tracks/1/imported = false 28 | tracks/1/enabled = true 29 | tracks/1/keys = { 30 | "times": PoolRealArray( 0, 0.3, 0.6 ), 31 | "transitions": PoolRealArray( 1, 1, 1 ), 32 | "update": 0, 33 | "values": [ Vector2( 0, -3.42728 ), Vector2( 0, -31.2082 ), Vector2( 0, -3.42728 ) ] 34 | } 35 | 36 | [node name="GeneratorEntity" type="Node2D" groups=[ 37 | "power_sources", 38 | ]] 39 | script = ExtResource( 3 ) 40 | 41 | [node name="PowerSource" type="Node" parent="."] 42 | script = ExtResource( 1 ) 43 | PowerAmount = 200.0 44 | 45 | [node name="Base" type="Sprite" parent="."] 46 | position = Vector2( 0, -5.42728 ) 47 | texture = ExtResource( 2 ) 48 | region_enabled = true 49 | region_rect = Rect2( 229, 34, 102, 62 ) 50 | 51 | [node name="PistonBack" type="Sprite" parent="."] 52 | position = Vector2( 0, -33 ) 53 | texture = ExtResource( 2 ) 54 | region_enabled = true 55 | region_rect = Rect2( 560, 24, 100, 27 ) 56 | 57 | [node name="PistonShaft" type="Sprite" parent="."] 58 | modulate = Color( 0.301961, 0.933333, 0.14902, 1 ) 59 | position = Vector2( 0, -31.4285 ) 60 | texture = ExtResource( 2 ) 61 | region_enabled = true 62 | region_rect = Rect2( 364, 4, 52, 70 ) 63 | 64 | [node name="PistonFront" type="Sprite" parent="."] 65 | position = Vector2( 0, -3.42728 ) 66 | texture = ExtResource( 2 ) 67 | region_enabled = true 68 | region_rect = Rect2( 449, 49, 102, 37 ) 69 | 70 | [node name="AnimationPlayer" type="AnimationPlayer" parent="."] 71 | anims/Work = SubResource( 1 ) 72 | [connection signal="PowerDrawn" from="PowerSource" to="." method="OnPowerSourcePowerDrawn"] 73 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Game.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System.Collections.Generic; 3 | 4 | public class Game : Node 5 | { 6 | private PowerSystem powerSystem = new PowerSystem(); 7 | 8 | public override void _Ready() 9 | { 10 | var sources = GetTree().GetNodesInGroup("power_sources"); 11 | var sourceList = ToList(sources); 12 | var receivers = GetTree().GetNodesInGroup("power_receivers"); 13 | var receiverList = ToList(receivers); 14 | var tileMap = GetNode("TileMap"); 15 | powerSystem.Setup(sourceList, receiverList, tileMap); 16 | } 17 | 18 | public override void _PhysicsProcess(float delta) 19 | { 20 | powerSystem.Update(delta); 21 | } 22 | 23 | private List ToList(Godot.Collections.Array array) where T : Node 24 | { 25 | var results = new List(); 26 | 27 | foreach (var element in array) 28 | { 29 | results.Add((T)element); 30 | } 31 | 32 | return results; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Game.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=2] 2 | 3 | [ext_resource path="res://EntityComponent/Game.cs" type="Script" id=1] 4 | [ext_resource path="res://EntityComponent/Shared/tileset.tres" type="TileSet" id=2] 5 | [ext_resource path="res://EntityComponent/Entities/GeneratorEntity.tscn" type="PackedScene" id=3] 6 | [ext_resource path="res://EntityComponent/Entities/BatteryEntity.tscn" type="PackedScene" id=4] 7 | 8 | [node name="Game" type="Node"] 9 | script = ExtResource( 1 ) 10 | 11 | [node name="TileMap" type="TileMap" parent="."] 12 | mode = 1 13 | tile_set = ExtResource( 2 ) 14 | cell_size = Vector2( 100, 50 ) 15 | cell_y_sort = true 16 | format = 1 17 | tile_data = PoolIntArray( -589807, 0, 0, -589806, 0, 0, -524272, 0, 0, -524271, 0, 0, -524270, 0, 0, -524269, 0, 0, -458737, 0, 0, -458736, 0, 0, -458735, 0, 0, -458734, 0, 0, -458733, 0, 0, -458732, 0, 0, -393202, 0, 0, -393201, 0, 0, -393200, 0, 0, -393199, 0, 0, -393198, 0, 0, -393197, 0, 0, -393196, 0, 0, -393195, 0, 0, -327667, 0, 0, -327666, 0, 0, -327665, 0, 0, -327664, 0, 0, -327663, 0, 0, -327662, 0, 0, -327661, 0, 0, -327660, 0, 0, -327659, 0, 0, -327658, 0, 0, -262132, 0, 0, -262131, 0, 0, -262130, 0, 0, -262129, 0, 0, -262128, 0, 0, -262127, 0, 0, -262126, 0, 0, -262125, 0, 0, -262124, 0, 0, -262123, 0, 0, -262122, 0, 0, -262121, 0, 0, -196597, 0, 0, -196596, 0, 0, -196595, 0, 0, -196594, 0, 0, -196593, 0, 0, -196592, 0, 0, -196591, 0, 0, -196590, 0, 0, -196589, 0, 0, -196588, 0, 0, -196587, 0, 0, -196586, 0, 0, -196585, 0, 0, -196584, 0, 0, -131062, 0, 0, -131061, 0, 0, -131060, 0, 0, -131059, 0, 0, -131058, 0, 0, -131057, 0, 0, -131056, 0, 0, -131055, 0, 0, -131054, 0, 0, -131053, 0, 0, -131052, 0, 0, -131051, 0, 0, -131050, 0, 0, -131049, 0, 0, -131048, 0, 0, -131047, 0, 0, -65526, 0, 0, -65525, 0, 0, -65524, 0, 0, -65523, 0, 0, -65522, 0, 0, -65521, 0, 0, -65520, 0, 0, -65519, 0, 0, -65518, 0, 0, -65517, 0, 0, -65516, 0, 0, -65515, 0, 0, -65514, 0, 0, -65513, 0, 0, -65512, 0, 0, -65511, 0, 0, -65510, 0, 0, 11, 0, 0, 12, 0, 0, 13, 0, 0, 14, 0, 0, 15, 0, 0, 16, 0, 0, 17, 0, 0, 18, 0, 0, 19, 0, 0, 20, 0, 0, 21, 0, 0, 22, 0, 0, 23, 0, 0, 24, 0, 0, 25, 0, 0, 65548, 0, 0, 65549, 0, 0, 65550, 0, 0, 65551, 0, 0, 65552, 0, 0, 65553, 0, 0, 65554, 0, 0, 65555, 0, 0, 65556, 0, 0, 65557, 0, 0, 65558, 0, 0, 65559, 0, 0, 65560, 0, 0, 131085, 0, 0, 131086, 0, 0, 131087, 0, 0, 131088, 0, 0, 131089, 0, 0, 131090, 0, 0, 131091, 0, 0, 131092, 0, 0, 131093, 0, 0, 131094, 0, 0, 131095, 0, 0, 196622, 0, 0, 196623, 0, 0, 196624, 0, 0, 196625, 0, 0, 196626, 0, 0, 196627, 0, 0, 196628, 0, 0, 196629, 0, 0, 196630, 0, 0, 262159, 0, 0, 262160, 0, 0, 262161, 0, 0, 262162, 0, 0, 262163, 0, 0, 262164, 0, 0, 262165, 0, 0, 327696, 0, 0, 327697, 0, 0, 327698, 0, 0, 327699, 0, 0, 327700, 0, 0, 393233, 0, 0, 393234, 0, 0, 393235, 0, 0, 458770, 0, 0 ) 18 | 19 | [node name="GeneratorEntity" parent="TileMap" instance=ExtResource( 3 )] 20 | position = Vector2( 850.646, 400.105 ) 21 | 22 | [node name="BatteryEntity" parent="TileMap" instance=ExtResource( 4 )] 23 | position = Vector2( 901.627, 425.519 ) 24 | 25 | [node name="BatteryEntity2" parent="TileMap" instance=ExtResource( 4 )] 26 | position = Vector2( 952.473, 451.134 ) 27 | 28 | [node name="BatteryEntity3" parent="TileMap" instance=ExtResource( 4 )] 29 | position = Vector2( 1002.48, 476.533 ) 30 | 31 | [node name="BatteryEntity4" parent="TileMap" instance=ExtResource( 4 )] 32 | position = Vector2( 1052.48, 501.931 ) 33 | 34 | [node name="Camera2D" type="Camera2D" parent="."] 35 | position = Vector2( 953.234, 439.71 ) 36 | current = true 37 | zoom = Vector2( 0.379, 0.379 ) 38 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/PowerSystem.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using System.Collections.Generic; 4 | public class PowerSystem : Reference 5 | { 6 | private Dictionary sources = new Dictionary(); 7 | private Dictionary receivers = new Dictionary(); 8 | 9 | private List> paths = new List>(); 10 | 11 | private Dictionary receiverAlreadyProvided = new Dictionary(); 12 | 13 | public void Setup(List powerSources, 14 | List powerReceivers, 15 | TileMap tileMap) 16 | { 17 | foreach (var source in powerSources) 18 | { 19 | var location = tileMap.WorldToMap(source.GlobalPosition); 20 | sources.Add(location, FindChildOfType(source)); 21 | paths.Add(new List { location }); 22 | } 23 | 24 | foreach (var receiver in powerReceivers) 25 | { 26 | var location = tileMap.WorldToMap(receiver.GlobalPosition); 27 | receivers.Add(location, FindChildOfType(receiver)); 28 | } 29 | 30 | foreach (var path in paths) 31 | { 32 | foreach (var receiver in receivers) 33 | { 34 | if (receiver.Key.x == path[0].x + 1) 35 | { 36 | path.Add(receiver.Key); 37 | } 38 | } 39 | } 40 | } 41 | 42 | public void Update(float delta) 43 | { 44 | receiverAlreadyProvided.Clear(); 45 | 46 | foreach (var path in paths) 47 | { 48 | var source = sources[path[0]]; 49 | 50 | var avilablePower = source.PowerAmount * source.Efficiency; 51 | 52 | var powerDraw = 0.0f; 53 | 54 | foreach (var cell in path.GetRange(1, path.Count - 1)) 55 | { 56 | if (!receivers.ContainsKey(cell)) 57 | { 58 | continue; 59 | } 60 | 61 | var receiver = receivers[cell]; 62 | var powerRequired = receiver.PowerRequired * receiver.Efficiency; 63 | 64 | if (receiverAlreadyProvided.ContainsKey(cell)) 65 | { 66 | var receiverTotal = receiverAlreadyProvided[cell]; 67 | if (receiverTotal >= powerRequired) 68 | { 69 | continue; 70 | } 71 | else 72 | { 73 | powerRequired -= receiverTotal; 74 | } 75 | } 76 | 77 | receiver.EmitSignal("PowerReceived", Math.Min(avilablePower, powerRequired), delta); 78 | powerDraw += powerRequired; 79 | 80 | if (!receiverAlreadyProvided.ContainsKey(cell)) 81 | { 82 | receiverAlreadyProvided[cell] = Math.Min(avilablePower, powerRequired); 83 | } 84 | else 85 | { 86 | receiverAlreadyProvided[cell] += Math.Min(avilablePower, powerRequired); 87 | } 88 | 89 | avilablePower -= powerRequired; 90 | } 91 | 92 | source.EmitSignal("PowerDrawn", powerDraw, delta); 93 | } 94 | } 95 | 96 | private T FindChildOfType(Node parent) where T : Node 97 | { 98 | foreach (var child in parent.GetChildren()) 99 | { 100 | if (child is T specifiedType) 101 | { 102 | return specifiedType; 103 | } 104 | } 105 | 106 | return null; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Shared/battery_indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdquest-demos/godot-design-patterns/34c16b71db6d97decb46f0253984aa4cd9259a5d/godot-csharp/EntityComponent/Shared/battery_indicator.png -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Shared/battery_indicator.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/battery_indicator.png-d2ad5601d9bd0d85c4f08309c7fc43a0.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://EntityComponent/Shared/battery_indicator.png" 13 | dest_files=[ "res://.import/battery_indicator.png-d2ad5601d9bd0d85c4f08309c7fc43a0.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Shared/tileset.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 51 | 61 | 62 | 64 | 65 | 67 | image/svg+xml 68 | 70 | 71 | 72 | 73 | 74 | 79 | 83 | 87 | 91 | 95 | 99 | 103 | 107 | 111 | 115 | 119 | 122 | 127 | 132 | 139 | 140 | 144 | 148 | 151 | 156 | 161 | 168 | 169 | 173 | 177 | 181 | 185 | 190 | 195 | 199 | 203 | 208 | 212 | 216 | 221 | 225 | 229 | 233 | 237 | 241 | 245 | 249 | 253 | 257 | 261 | 265 | 269 | 273 | 277 | 281 | 285 | 290 | 291 | 292 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Shared/tileset.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/tileset.svg-5e64a4ffd02ef8c7e1f4b5122a94507b.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://EntityComponent/Shared/tileset.svg" 13 | dest_files=[ "res://.import/tileset.svg-5e64a4ffd02ef8c7e1f4b5122a94507b.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | process/normal_map_invert_y=false 32 | stream=false 33 | size_limit=0 34 | detect_3d=true 35 | svg/scale=1.0 36 | -------------------------------------------------------------------------------- /godot-csharp/EntityComponent/Shared/tileset.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="TileSet" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://EntityComponent/Shared/tileset.svg" type="Texture" id=1] 4 | 5 | [resource] 6 | 0/name = "tileset.svg 0" 7 | 0/texture = ExtResource( 1 ) 8 | 0/tex_offset = Vector2( 0, 0 ) 9 | 0/modulate = Color( 1, 1, 1, 1 ) 10 | 0/region = Rect2( 10, 10, 100, 100 ) 11 | 0/tile_mode = 0 12 | 0/occluder_offset = Vector2( 0, 0 ) 13 | 0/navigation_offset = Vector2( 0, 0 ) 14 | 0/shape_offset = Vector2( 0, 0 ) 15 | 0/shape_transform = Transform2D( 1, 0, 0, 1, 0, 0 ) 16 | 0/shape_one_way = false 17 | 0/shape_one_way_margin = 0.0 18 | 0/shapes = [ ] 19 | 0/z_index = 0 20 | -------------------------------------------------------------------------------- /godot-csharp/Godot Design Pattern csharp demo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Tools 4 | {BF2F76E5-AC42-4490-A763-E95D8BC76269} 5 | Library 6 | GodotDesignPatterncsharpdemo 7 | Godot Design Pattern csharp demo 8 | 1.0.7333.3918 9 | net472 10 | 12 | false 13 | false 14 | false 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /godot-csharp/Godot Design Pattern csharp demo.csproj.old: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Tools 5 | AnyCPU 6 | {BF2F76E5-AC42-4490-A763-E95D8BC76269} 7 | Library 8 | .mono\temp\bin\$(Configuration) 9 | GodotDesignPatterncsharpdemo 10 | Godot Design Pattern csharp demo 11 | v4.7 12 | 1.0.7333.3918 13 | .mono\temp\obj 14 | $(BaseIntermediateOutputPath)\$(Configuration) 15 | Debug 16 | Release 17 | 18 | 19 | true 20 | portable 21 | false 22 | $(GodotDefineConstants);GODOT;DEBUG; 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | portable 29 | true 30 | $(GodotDefineConstants);GODOT; 31 | prompt 32 | 4 33 | false 34 | 35 | 36 | true 37 | portable 38 | false 39 | $(GodotDefineConstants);GODOT;DEBUG;TOOLS; 40 | prompt 41 | 4 42 | false 43 | 44 | 45 | 46 | False 47 | $(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/GodotSharp.dll 48 | 49 | 50 | False 51 | $(ProjectDir)/.mono/assemblies/$(ApiConfiguration)/GodotSharpEditor.dll 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /godot-csharp/Godot Design Pattern csharp demo.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 2012 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot Design Pattern csharp demo", "Godot Design Pattern csharp demo.csproj", "{BF2F76E5-AC42-4490-A763-E95D8BC76269}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | ExportDebug|Any CPU = ExportDebug|Any CPU 9 | ExportRelease|Any CPU = ExportRelease|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU 15 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU 16 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU 17 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /godot-csharp/Godot Design Pattern csharp demo.sln.old: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio 2012 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Godot Design Pattern csharp demo", "Godot Design Pattern csharp demo.csproj", "{BF2F76E5-AC42-4490-A763-E95D8BC76269}" 4 | EndProject 5 | Global 6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 7 | Debug|Any CPU = Debug|Any CPU 8 | Release|Any CPU = Release|Any CPU 9 | Tools|Any CPU = Tools|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.Release|Any CPU.Build.0 = Release|Any CPU 16 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.Tools|Any CPU.ActiveCfg = Tools|Any CPU 17 | {BF2F76E5-AC42-4490-A763-E95D8BC76269}.Tools|Any CPU.Build.0 = Tools|Any CPU 18 | EndGlobalSection 19 | EndGlobal 20 | -------------------------------------------------------------------------------- /godot-csharp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | // Information about this assembly is defined by the following attributes. 4 | // Change them to the values specific to your project. 5 | 6 | [assembly: AssemblyTitle("Godot Design Pattern csharp demo")] 7 | [assembly: AssemblyDescription("")] 8 | [assembly: AssemblyConfiguration("")] 9 | [assembly: AssemblyCompany("")] 10 | [assembly: AssemblyProduct("")] 11 | [assembly: AssemblyCopyright("")] 12 | [assembly: AssemblyTrademark("")] 13 | [assembly: AssemblyCulture("")] 14 | 15 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". 16 | // The form "{Major}.{Minor}.*" will automatically update the build and revision, 17 | // and "{Major}.{Minor}.{Build}.*" will update just the revision. 18 | 19 | [assembly: AssemblyVersion("1.0.*")] 20 | 21 | // The following attributes are used to specify the signing key for the assembly, 22 | // if desired. See the Mono documentation for more information about signing. 23 | 24 | //[assembly: AssemblyDelaySign(false)] 25 | //[assembly: AssemblyKeyFile("")] 26 | -------------------------------------------------------------------------------- /godot-csharp/Shared/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdquest-demos/godot-design-patterns/34c16b71db6d97decb46f0253984aa4cd9259a5d/godot-csharp/Shared/background.png -------------------------------------------------------------------------------- /godot-csharp/Shared/background.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/background.png-d8b19effa74161a3ece6b68995ea2cc7.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://Shared/background.png" 13 | dest_files=[ "res://.import/background.png-d8b19effa74161a3ece6b68995ea2cc7.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /godot-csharp/Shared/monserrate_bold.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="DynamicFont" load_steps=2 format=2] 2 | 3 | [ext_resource path="res://Shared/montserrat_extrabold.otf" type="DynamicFontData" id=1] 4 | 5 | [resource] 6 | size = 22 7 | font_data = ExtResource( 1 ) 8 | -------------------------------------------------------------------------------- /godot-csharp/Shared/montserrat_extrabold.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdquest-demos/godot-design-patterns/34c16b71db6d97decb46f0253984aa4cd9259a5d/godot-csharp/Shared/montserrat_extrabold.otf -------------------------------------------------------------------------------- /godot-csharp/Shared/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdquest-demos/godot-design-patterns/34c16b71db6d97decb46f0253984aa4cd9259a5d/godot-csharp/Shared/player.png -------------------------------------------------------------------------------- /godot-csharp/Shared/player.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/player.png-0e3f197cea916321015378cec296c5b4.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://Shared/player.png" 13 | dest_files=[ "res://.import/player.png-0e3f197cea916321015378cec296c5b4.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /godot-csharp/Shared/tileset_platformer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gdquest-demos/godot-design-patterns/34c16b71db6d97decb46f0253984aa4cd9259a5d/godot-csharp/Shared/tileset_platformer.png -------------------------------------------------------------------------------- /godot-csharp/Shared/tileset_platformer.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="StreamTexture" 5 | path="res://.import/tileset_platformer.png-a00bea6b34edff2d6015c50f9a248ee5.stex" 6 | metadata={ 7 | "vram_texture": false 8 | } 9 | 10 | [deps] 11 | 12 | source_file="res://Shared/tileset_platformer.png" 13 | dest_files=[ "res://.import/tileset_platformer.png-a00bea6b34edff2d6015c50f9a248ee5.stex" ] 14 | 15 | [params] 16 | 17 | compress/mode=0 18 | compress/lossy_quality=0.7 19 | compress/hdr_mode=0 20 | compress/bptc_ldr=0 21 | compress/normal_map=0 22 | flags/repeat=0 23 | flags/filter=true 24 | flags/mipmaps=false 25 | flags/anisotropic=false 26 | flags/srgb=2 27 | process/fix_alpha_border=true 28 | process/premult_alpha=false 29 | process/HDR_as_SRGB=false 30 | process/invert_color=false 31 | stream=false 32 | size_limit=0 33 | detect_3d=true 34 | svg/scale=1.0 35 | -------------------------------------------------------------------------------- /godot-csharp/Shared/tileset_platformer.tres: -------------------------------------------------------------------------------- 1 | [gd_resource type="TileSet" load_steps=8 format=2] 2 | 3 | [ext_resource path="res://Shared/tileset_platformer.png" type="Texture" id=1] 4 | 5 | [sub_resource type="OccluderPolygon2D" id=1] 6 | polygon = PoolVector2Array( 0, 0, 80, 0, 80, 80, 0, 80 ) 7 | 8 | [sub_resource type="ConvexPolygonShape2D" id=2] 9 | points = PoolVector2Array( 0, 0, 80, 0, 80, 80, 0, 80 ) 10 | 11 | [sub_resource type="OccluderPolygon2D" id=3] 12 | polygon = PoolVector2Array( 0, 0, 80, 0, 80, 80, 0, 80 ) 13 | 14 | [sub_resource type="ConvexPolygonShape2D" id=4] 15 | points = PoolVector2Array( 0, 0, 80, 0, 80, 80, 0, 80 ) 16 | 17 | [sub_resource type="ConvexPolygonShape2D" id=5] 18 | points = PoolVector2Array( 0, 80, 80, 0, 80, 80 ) 19 | 20 | [sub_resource type="ConvexPolygonShape2D" id=6] 21 | points = PoolVector2Array( 0, 80, 160, 0, 160, 80 ) 22 | 23 | [resource] 24 | 0/name = "tileset.png 0" 25 | 0/texture = ExtResource( 1 ) 26 | 0/tex_offset = Vector2( 0, 0 ) 27 | 0/modulate = Color( 1, 1, 1, 1 ) 28 | 0/region = Rect2( 0, 0, 80, 80 ) 29 | 0/tile_mode = 0 30 | 0/occluder_offset = Vector2( 0, 0 ) 31 | 0/occluder = SubResource( 1 ) 32 | 0/navigation_offset = Vector2( 0, 0 ) 33 | 0/shapes = [ { 34 | "autotile_coord": Vector2( 0, 0 ), 35 | "one_way": false, 36 | "one_way_margin": 1.0, 37 | "shape": SubResource( 2 ), 38 | "shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 ) 39 | } ] 40 | 0/z_index = 0 41 | 1/name = "tileset.png 1" 42 | 1/texture = ExtResource( 1 ) 43 | 1/tex_offset = Vector2( 0, 0 ) 44 | 1/modulate = Color( 1, 1, 1, 1 ) 45 | 1/region = Rect2( 80, 0, 80, 80 ) 46 | 1/tile_mode = 0 47 | 1/occluder_offset = Vector2( 0, 0 ) 48 | 1/occluder = SubResource( 3 ) 49 | 1/navigation_offset = Vector2( 0, 0 ) 50 | 1/shapes = [ { 51 | "autotile_coord": Vector2( 0, 0 ), 52 | "one_way": true, 53 | "one_way_margin": 1.0, 54 | "shape": SubResource( 4 ), 55 | "shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 ) 56 | } ] 57 | 1/z_index = 0 58 | 2/name = "tileset.png 2" 59 | 2/texture = ExtResource( 1 ) 60 | 2/tex_offset = Vector2( 0, 0 ) 61 | 2/modulate = Color( 1, 1, 1, 1 ) 62 | 2/region = Rect2( 0, 80, 80, 80 ) 63 | 2/tile_mode = 0 64 | 2/occluder_offset = Vector2( 0, 0 ) 65 | 2/navigation_offset = Vector2( 0, 0 ) 66 | 2/shapes = [ { 67 | "autotile_coord": Vector2( 0, 0 ), 68 | "one_way": false, 69 | "one_way_margin": 1.0, 70 | "shape": SubResource( 5 ), 71 | "shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 ) 72 | } ] 73 | 2/z_index = 0 74 | 3/name = "tileset.png 3" 75 | 3/texture = ExtResource( 1 ) 76 | 3/tex_offset = Vector2( 0, 0 ) 77 | 3/modulate = Color( 1, 1, 1, 1 ) 78 | 3/region = Rect2( 0, 160, 160, 80 ) 79 | 3/tile_mode = 0 80 | 3/occluder_offset = Vector2( 0, 0 ) 81 | 3/navigation_offset = Vector2( 0, 0 ) 82 | 3/shapes = [ { 83 | "autotile_coord": Vector2( 0, 0 ), 84 | "one_way": false, 85 | "one_way_margin": 1.0, 86 | "shape": SubResource( 6 ), 87 | "shape_transform": Transform2D( 1, 0, 0, 1, 0, 0 ) 88 | } ] 89 | 3/z_index = 0 90 | -------------------------------------------------------------------------------- /godot-csharp/StateMachine/Player/Air.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | // The GD tutorial has this class named "Jump.gd". However, in C#, 6 | // the name of a class is also its type, and should always be the node's 7 | // name to avoid problems down the line. 8 | public class Air : PlayerState 9 | { 10 | /// 11 | /// If we get a message asking us to jump, we jump. 12 | /// 13 | /// 14 | public override void Enter(Dictionary message = null) 15 | { 16 | if (message != null && 17 | message.ContainsKey("doJump") && 18 | message["doJump"] == true) 19 | { 20 | _player.Velocity.y = -_player.JumpImpulse; 21 | } 22 | } 23 | 24 | public override void PhysicsUpdate(float delta) 25 | { 26 | // Horizontal movement 27 | var inputDirectionX = Input.GetActionStrength("move_right") - Input.GetActionStrength("move_left"); 28 | 29 | // Vertical Movement 30 | _player.Velocity.x = _player.Speed * inputDirectionX; 31 | _player.Velocity.y += _player.Gravity * delta; 32 | _player.Velocity = _player.MoveAndSlide(_player.Velocity, Vector2.Up); 33 | 34 | // Landing 35 | if (_player.IsOnFloor()) 36 | { 37 | if (Godot.Mathf.IsEqualApprox(_player.Velocity.x, 0.0f)) 38 | { 39 | _stateMachine.TransitionTo("Idle"); 40 | } 41 | else 42 | { 43 | _stateMachine.TransitionTo("Run"); 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /godot-csharp/StateMachine/Player/Idle.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | public class Idle : PlayerState 6 | { 7 | /// 8 | /// Upon entering the state, we set the Player node's velocity to zero. 9 | /// 10 | /// 11 | public override void Enter(Dictionary message = null) 12 | { 13 | // We must declare all the properties we access through `owner` in the `Player.cs` script. 14 | _player.Velocity = Vector2.Zero; 15 | } 16 | 17 | public override void PhysicsUpdate(float delta) 18 | { 19 | // If you have platforms that break when standing on them, you need that check for the character to fall. 20 | if (!_player.IsOnFloor()) 21 | { 22 | _stateMachine.TransitionTo("Air"); 23 | return; 24 | } 25 | 26 | if (Input.IsActionJustPressed("move_up")) 27 | { 28 | // As we'll only have one air state for both jump and fall, we use the `msg` dictionary 29 | // to tell the next state that we want to jump. 30 | var message = new Dictionary() 31 | { 32 | { "doJump", true } 33 | }; 34 | _stateMachine.TransitionTo("Air", message); 35 | } 36 | else if (Input.IsActionPressed("move_left") || Input.IsActionPressed("move_right")) 37 | { 38 | _stateMachine.TransitionTo("Run"); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /godot-csharp/StateMachine/Player/Player.cs: -------------------------------------------------------------------------------- 1 | using Godot; 2 | using System; 3 | 4 | public class Player : KinematicBody2D 5 | { 6 | public int Speed = 500; 7 | public int JumpImpulse = 1200; 8 | public int Gravity = 3500; 9 | 10 | public Vector2 Velocity = new Vector2(); 11 | 12 | public Label label; 13 | public StateMachine _stateMachine; 14 | 15 | public override void _Ready() 16 | { 17 | label = GetNode