diff --git a/CoroutineManager.tscn b/CoroutineManager.tscn index 662f965..2a1a7fb 100644 --- a/CoroutineManager.tscn +++ b/CoroutineManager.tscn @@ -1,10 +1,10 @@ -[gd_scene load_steps=3 format=2] +[gd_scene load_steps=3 format=3 uid="uid://3thn65kd8af7"] -[ext_resource path="res://HCoroutines/src/CoroutineManager.cs" type="Script" id=1] -[ext_resource path="res://HCoroutines/src/Util/TimeScheduler.cs" type="Script" id=2] +[ext_resource type="Script" path="res://HCoroutines/src/CoroutineManager.cs" id="1"] +[ext_resource type="Script" path="res://HCoroutines/src/Util/TimeScheduler.cs" id="2"] [node name="CoroutineManager" type="Node"] -script = ExtResource( 1 ) +script = ExtResource("1") [node name="TimeScheduler" type="Node" parent="."] -script = ExtResource( 2 ) +script = ExtResource("2") diff --git a/README.md b/README.md index a8f15b3..4e672b1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # HCoroutines -![Godot 3.5](https://img.shields.io/badge/Godot-3.5-blue?logo=godot-engine&logoColor=white&style=for-the-badge) ![](https://img.shields.io/github/license/Inspiaaa/HCoroutines?style=for-the-badge) ![](https://img.shields.io/github/v/release/Inspiaaa/HCoroutines?style=for-the-badge) ![](https://img.shields.io/badge/Godot-C%23-green?logo=csharp&style=for-the-badge) +![Godot 4.1.3](https://img.shields.io/badge/Godot-4.1.3-blue?logo=godot-engine&logoColor=white&style=for-the-badge) ![](https://img.shields.io/github/license/Inspiaaa/HCoroutines?style=for-the-badge) ![](https://img.shields.io/github/v/release/Inspiaaa/HCoroutines?style=for-the-badge) ![](https://img.shields.io/badge/Godot-C%23-green?logo=csharp&style=for-the-badge) HCoroutines is a library that helps you write game logic in an **intuitive** way by bringing the concept of **hierarchical coroutines** to Godot (C#). Its built-in coroutine types are specifically designed for Godot, **reducing boilerplate** code and increasing **readability**. At the same time, **async methods** can also be seamlessly integrated with coroutines. @@ -29,7 +29,7 @@ using System.Threading.Tasks; // Import the library. using HCoroutines; -public class Demo : Node2D { +public partial class Demo : Node2D { public override void _Ready() { // Spawn a new coroutine that is managed by // the default CoroutineManager. @@ -60,7 +60,7 @@ public class Demo : Node2D { yield return Co.Await(Task.Delay(100)); // Await and use the result of an async task - var fetch = Co.Await(FetchNumber()); + var fetch = Co.Await(FetchNumber()); yield return fetch; int number = fetch.Task.Result; @@ -77,18 +77,17 @@ public class Demo : Node2D { } private IEnumerator GoTo(Vector2 target, float duration) { - Vector2 start = Position; float speed = Position.DistanceTo(target) / duration; while (Position.DistanceTo(target) > 0.01f) { // delta time can be accessed via Co.DeltaTime. - Position = Position.MoveToward(target, duration * Co.DeltaTime); + Position = Position.MoveToward(target, speed * Co.DeltaTime); yield return null; } } private IEnumerator Turn(float duration) { - float fullRotation = (float)(2 * Math.PI); + float fullRotation = 2 * Mathf.Pi; float angularSpeed = fullRotation / duration; float angle = 0; @@ -99,7 +98,7 @@ public class Demo : Node2D { } } - private async Task FetchNumber() { + private static async Task FetchNumber() { await Task.Delay(100); return 0; } @@ -151,6 +150,10 @@ To access the delta time from within a coroutine: ```csharp float deltaTime = Co.DeltaTime; ``` +or +```csharp +double deltaTime = Co.DeltaTimeDouble; +``` All coroutines inherit from the `CoroutineBase` class. To define a coroutine in the intuitive / standard way with `IEnumerators`, you can use the `Coroutine` class which wraps the `IEnumerator` (Either via `Co.Coroutine(...)` or `new Coroutine(...)`). diff --git a/demo/AnimatedIcon.tscn b/demo/AnimatedIcon.tscn index 086b165..5b3f6dd 100644 --- a/demo/AnimatedIcon.tscn +++ b/demo/AnimatedIcon.tscn @@ -1,9 +1,9 @@ -[gd_scene load_steps=3 format=2] +[gd_scene load_steps=3 format=3 uid="uid://cb2pyqnqkjpuc"] -[ext_resource path="res://HCoroutines/demo/Icon.png" type="Texture" id=1] -[ext_resource path="res://HCoroutines/demo/IconAnimation.cs" type="Script" id=2] +[ext_resource type="Texture2D" uid="uid://bu2485fdkbfkv" path="res://HCoroutines/demo/Icon.png" id="1"] +[ext_resource type="Script" path="res://HCoroutines/demo/IconAnimation.cs" id="2"] -[node name="Icon" type="Sprite"] -position = Vector2( 499, 297 ) -texture = ExtResource( 1 ) -script = ExtResource( 2 ) +[node name="Icon" type="Sprite2D"] +position = Vector2(499, 297) +texture = ExtResource("1") +script = ExtResource("2") diff --git a/demo/Demo.tscn b/demo/Demo.tscn index 75ca2b5..2d25e42 100644 --- a/demo/Demo.tscn +++ b/demo/Demo.tscn @@ -1,27 +1,22 @@ -[gd_scene load_steps=3 format=2] +[gd_scene load_steps=3 format=3 uid="uid://chu3ymn2s6v1s"] -[ext_resource path="res://HCoroutines/demo/AnimatedIcon.tscn" type="PackedScene" id=1] -[ext_resource path="res://HCoroutines/demo/IconSpawner.cs" type="Script" id=2] +[ext_resource type="PackedScene" uid="uid://cb2pyqnqkjpuc" path="res://HCoroutines/demo/AnimatedIcon.tscn" id="1"] +[ext_resource type="Script" path="res://HCoroutines/demo/IconSpawner.cs" id="2"] [node name="Node2D" type="Node2D"] -script = ExtResource( 2 ) -icon = ExtResource( 1 ) +script = ExtResource("2") +icon = ExtResource("1") -[node name="Icon" parent="." instance=ExtResource( 1 )] +[node name="Icon" parent="." instance=ExtResource("1")] [node name="Camera2D" type="Camera2D" parent="."] -current = true [node name="UI" type="CanvasLayer" parent="."] [node name="MarginContainer" type="MarginContainer" parent="UI"] +anchors_preset = 10 anchor_right = 1.0 -margin_bottom = 14.0 -custom_constants/margin_top = 20 [node name="Label" type="Label" parent="UI/MarginContainer"] -margin_top = 20.0 -margin_right = 1024.0 -margin_bottom = 34.0 +layout_mode = 2 text = "Click to create a new animated icon" -align = 1 diff --git a/demo/Icon.png.import b/demo/Icon.png.import index 26958f7..7a9ccee 100644 --- a/demo/Icon.png.import +++ b/demo/Icon.png.import @@ -1,8 +1,9 @@ [remap] importer="texture" -type="StreamTexture" -path="res://.import/Icon.png-68b487edcbe40feab18e741224dda706.stex" +type="CompressedTexture2D" +uid="uid://bu2485fdkbfkv" +path="res://.godot/imported/Icon.png-68b487edcbe40feab18e741224dda706.ctex" metadata={ "vram_texture": false } @@ -10,26 +11,24 @@ metadata={ [deps] source_file="res://HCoroutines/demo/Icon.png" -dest_files=[ "res://.import/Icon.png-68b487edcbe40feab18e741224dda706.stex" ] +dest_files=["res://.godot/imported/Icon.png-68b487edcbe40feab18e741224dda706.ctex"] [params] compress/mode=0 +compress/high_quality=false compress/lossy_quality=0.7 -compress/hdr_mode=0 -compress/bptc_ldr=0 +compress/hdr_compression=1 compress/normal_map=0 -flags/repeat=0 -flags/filter=true -flags/mipmaps=false -flags/anisotropic=false -flags/srgb=2 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" 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 +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/demo/IconAnimation.cs b/demo/IconAnimation.cs index a715254..0130a51 100644 --- a/demo/IconAnimation.cs +++ b/demo/IconAnimation.cs @@ -1,10 +1,9 @@ using Godot; -using System; using System.Collections; using HCoroutines; using System.Threading.Tasks; -public class IconAnimation : Node2D +public partial class IconAnimation : Node2D { public override void _Ready() { @@ -59,7 +58,7 @@ private IEnumerator ChangeColor(Color targetColor, float duration) { // Another way to do a tween - SceneTreeTween tween = CreateTween(); + Tween tween = CreateTween(); tween .TweenProperty(this, "modulate", targetColor, duration) .SetTrans(Tween.TransitionType.Expo); diff --git a/demo/IconSpawner.cs b/demo/IconSpawner.cs index 9d2c355..0b32eb4 100644 --- a/demo/IconSpawner.cs +++ b/demo/IconSpawner.cs @@ -1,7 +1,6 @@ using Godot; -using System; -public class IconSpawner : Node2D +public partial class IconSpawner : Node2D { [Export] private PackedScene icon; @@ -9,9 +8,9 @@ public override void _Input(InputEvent e) { if (e is InputEventMouseButton mouseEvent) { - if (mouseEvent.ButtonIndex == (int)ButtonList.Left && mouseEvent.Pressed) + if (mouseEvent.ButtonIndex == MouseButton.Left && mouseEvent.Pressed) { - Node2D node = icon.Instance(); + Node2D node = icon.Instantiate(); node.Position = GetLocalMousePosition(); AddChild(node); } diff --git a/docs/.gdignore b/docs/.gdignore new file mode 100644 index 0000000..e69de29 diff --git a/src/Co.cs b/src/Co.cs index 48bef93..fc3e82c 100644 --- a/src/Co.cs +++ b/src/Co.cs @@ -27,6 +27,8 @@ private static Coroutine[] GetCoroutines(IEnumerator[] enumerators) public static float DeltaTime => CoroutineManager.Instance.DeltaTime; + public static double DeltaTimeDouble => CoroutineManager.Instance.DeltaTimeDouble; + public static void Run(CoroutineBase coroutine) => CoroutineManager.Instance.StartCoroutine(coroutine); @@ -82,7 +84,7 @@ public static WaitUntilCoroutine WaitUntil(Func condition) => new WaitUntilCoroutine(condition); - public static WaitForSignalCoroutine WaitForSignal(Godot.Object obj, string signal) + public static WaitForSignalCoroutine WaitForSignal(GodotObject obj, string signal) => new WaitForSignalCoroutine(obj, signal); @@ -113,7 +115,7 @@ public static RepeatCoroutine RepeatInfinitely(Func creator) => new RepeatCoroutine(-1, coroutine => new Coroutine(creator())); - public static TweenCoroutine Tween(Action setupTween) + public static TweenCoroutine Tween(Action setupTween) => new TweenCoroutine(setupTween); diff --git a/src/CoroutineManager.cs b/src/CoroutineManager.cs index c6fabb4..fac83ab 100644 --- a/src/CoroutineManager.cs +++ b/src/CoroutineManager.cs @@ -4,10 +4,11 @@ namespace HCoroutines { - public class CoroutineManager : Node + public partial class CoroutineManager : Node { public static CoroutineManager Instance { get; private set; } public float DeltaTime { get; set; } + public double DeltaTimeDouble { get; set; } private bool isIteratingActiveCoroutines = false; private HashSet activeCoroutines = new HashSet(); @@ -51,9 +52,10 @@ public override void _EnterTree() Instance = this; } - public override void _Process(float delta) + public override void _Process(double delta) { - DeltaTime = delta; + DeltaTimeDouble = delta; + DeltaTime = (float)delta; isIteratingActiveCoroutines = true; diff --git a/src/Coroutines/AwaitCoroutine.cs b/src/Coroutines/AwaitCoroutine.cs index d34a302..bfa74a0 100644 --- a/src/Coroutines/AwaitCoroutine.cs +++ b/src/Coroutines/AwaitCoroutine.cs @@ -1,5 +1,3 @@ -using System; -using System.Collections; using System.Threading.Tasks; namespace HCoroutines diff --git a/src/Coroutines/Coroutine.cs b/src/Coroutines/Coroutine.cs index 8833131..d5a0a36 100644 --- a/src/Coroutines/Coroutine.cs +++ b/src/Coroutines/Coroutine.cs @@ -1,6 +1,5 @@ using System; using System.Collections; -using System.ComponentModel; namespace HCoroutines { diff --git a/src/Coroutines/TweenCoroutine.cs b/src/Coroutines/TweenCoroutine.cs index 75a2e91..ad6eedb 100644 --- a/src/Coroutines/TweenCoroutine.cs +++ b/src/Coroutines/TweenCoroutine.cs @@ -11,11 +11,11 @@ namespace HCoroutines /// public class TweenCoroutine : CoroutineBase { - private Action setupTween; - private SceneTreeTween tween; + private Action setupTween; + private Tween tween; private int schedulerId; - public TweenCoroutine(Action setupTween) + public TweenCoroutine(Action setupTween) { this.setupTween = setupTween; } diff --git a/src/Coroutines/WaitForSignalCoroutine.cs b/src/Coroutines/WaitForSignalCoroutine.cs index 1062c01..285b5c3 100644 --- a/src/Coroutines/WaitForSignalCoroutine.cs +++ b/src/Coroutines/WaitForSignalCoroutine.cs @@ -1,3 +1,4 @@ +using Godot; using HCoroutines.Util; namespace HCoroutines @@ -7,11 +8,11 @@ namespace HCoroutines /// public class WaitForSignalCoroutine : CoroutineBase { - private Godot.Object targetObject; + private GodotObject targetObject; private string targetSignal; private int schedulerId; - public WaitForSignalCoroutine(Godot.Object obj, string signal) + public WaitForSignalCoroutine(GodotObject obj, string signal) { this.targetObject = obj; this.targetSignal = signal; diff --git a/src/Util/TimeScheduler.cs b/src/Util/TimeScheduler.cs index 4dafc93..afb5917 100644 --- a/src/Util/TimeScheduler.cs +++ b/src/Util/TimeScheduler.cs @@ -4,11 +4,11 @@ namespace HCoroutines.Util { - public class TimeScheduler : Node + public partial class TimeScheduler : Node { public static TimeScheduler Instance { get; private set; } - private Dictionary actionsById = new Dictionary(); + private Dictionary actionsById = new(); private int idCounter = 0; public override void _EnterTree() @@ -26,21 +26,19 @@ private int GetNextScheduleId() public int Schedule(Action action, float delay) { - SceneTreeTimer timer = GetTree().CreateTimer(delay, pauseModeProcess: false); + SceneTreeTimer timer = GetTree().CreateTimer(delay, processAlways: false); return ScheduleOnSignal(action, timer, "timeout"); } - public int ScheduleOnSignal(Action action, Godot.Object obj, string signal) + public int ScheduleOnSignal(Action action, GodotObject obj, string signal) { int id = GetNextScheduleId(); actionsById[id] = action; obj.Connect( signal, - this, - nameof(CallCallback), - new Godot.Collections.Array(id), - (int)ConnectFlags.Oneshot + Callable.From(() => CallCallback(id)), + (int)ConnectFlags.OneShot ); return id;