From 8624e2aea8d314859baf59adfd5f9e6d908057d6 Mon Sep 17 00:00:00 2001 From: jonathan Date: Thu, 2 Oct 2025 01:32:52 +0200 Subject: [PATCH] Added minigame --- prefabs/minigame/minigame.tscn | 38 ++++ prefabs/minigame/region_visual.tscn | 25 +++ project.godot | 4 +- scenes/Babushka_scene_fight_happening.tscn | 2 +- .../testing/Babushka_scene_minigame_test.tscn | 12 ++ .../Fight/Actions/BlobAttackAction.cs.uid | 1 + .../Common/Minigame/MinigameController.cs | 180 ++++++++++++++++++ .../Common/Minigame/MinigameController.cs.uid | 1 + .../CSharp/Common/Minigame/RegionVisual.cs | 19 ++ .../Common/Minigame/RegionVisual.cs.uid | 1 + .../CSharp/Common/Minigame/SpinnyArmVisual.cs | 10 + .../Common/Minigame/SpinnyArmVisual.cs.uid | 1 + .../Common/TestScripts/MinigameTestStarter.cs | 30 +++ .../TestScripts/MinigameTestStarter.cs.uid | 1 + scripts/CSharp/Common/Util/ClickDetect.cs | 16 ++ scripts/CSharp/Common/Util/ClickDetect.cs.uid | 1 + scripts/CSharp/Common/Util/LinqExtras.cs | 9 + shader/minigame_pie_section.gdshader | 72 +++++++ shader/minigame_pie_section.gdshader.uid | 1 + 19 files changed, 421 insertions(+), 3 deletions(-) create mode 100644 prefabs/minigame/minigame.tscn create mode 100644 prefabs/minigame/region_visual.tscn create mode 100644 scenes/testing/Babushka_scene_minigame_test.tscn create mode 100644 scripts/CSharp/Common/Fight/Actions/BlobAttackAction.cs.uid create mode 100644 scripts/CSharp/Common/Minigame/MinigameController.cs create mode 100644 scripts/CSharp/Common/Minigame/MinigameController.cs.uid create mode 100644 scripts/CSharp/Common/Minigame/RegionVisual.cs create mode 100644 scripts/CSharp/Common/Minigame/RegionVisual.cs.uid create mode 100644 scripts/CSharp/Common/Minigame/SpinnyArmVisual.cs create mode 100644 scripts/CSharp/Common/Minigame/SpinnyArmVisual.cs.uid create mode 100644 scripts/CSharp/Common/TestScripts/MinigameTestStarter.cs create mode 100644 scripts/CSharp/Common/TestScripts/MinigameTestStarter.cs.uid create mode 100644 scripts/CSharp/Common/Util/ClickDetect.cs create mode 100644 scripts/CSharp/Common/Util/ClickDetect.cs.uid create mode 100644 shader/minigame_pie_section.gdshader create mode 100644 shader/minigame_pie_section.gdshader.uid diff --git a/prefabs/minigame/minigame.tscn b/prefabs/minigame/minigame.tscn new file mode 100644 index 0000000..5541b09 --- /dev/null +++ b/prefabs/minigame/minigame.tscn @@ -0,0 +1,38 @@ +[gd_scene load_steps=7 format=3 uid="uid://bydwj3pbvqrhb"] + +[ext_resource type="Script" uid="uid://ct7l4er2kljnc" path="res://scripts/CSharp/Common/Minigame/MinigameController.cs" id="1_17v35"] +[ext_resource type="PackedScene" uid="uid://dhfda4o386byp" path="res://prefabs/minigame/region_visual.tscn" id="2_rrvb1"] +[ext_resource type="Script" uid="uid://djkyrp24ljff0" path="res://scripts/CSharp/Common/Minigame/SpinnyArmVisual.cs" id="3_86pvs"] +[ext_resource type="Texture2D" uid="uid://bgn2ci6nu85t5" path="res://addons/dialogic/Example Assets/next-indicator/next-indicator-dialogic-1.png" id="3_pe4tw"] +[ext_resource type="Script" uid="uid://dq7gahfp0lk7v" path="res://scripts/CSharp/Common/Util/ClickDetect.cs" id="5_86pvs"] + +[sub_resource type="CircleShape2D" id="CircleShape2D_pe4tw"] +radius = 554.923 + +[node name="Minigame" type="Node2D" node_paths=PackedStringArray("_regionsParent")] +script = ExtResource("1_17v35") +_regionVisualPrefab = ExtResource("2_rrvb1") +_regionsParent = NodePath("RegionsParent") +_baseRegionColor = Color(0.176888, 0.482224, 0.338857, 1) + +[node name="RegionsParent" type="Node2D" parent="."] + +[node name="SpinnyArm" type="Node2D" parent="."] +script = ExtResource("3_86pvs") + +[node name="ArmVisual" type="Node2D" parent="SpinnyArm"] + +[node name="Sprite" type="Sprite2D" parent="SpinnyArm/ArmVisual"] +position = Vector2(0, -40) +rotation = -3.14159 +scale = Vector2(1, 2.08) +texture = ExtResource("3_pe4tw") + +[node name="Area2D" type="Area2D" parent="."] +script = ExtResource("5_86pvs") + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] +shape = SubResource("CircleShape2D_pe4tw") + +[connection signal="ArmMoved" from="." to="SpinnyArm" method="SetAngle"] +[connection signal="Click" from="Area2D" to="." method="Hit"] diff --git a/prefabs/minigame/region_visual.tscn b/prefabs/minigame/region_visual.tscn new file mode 100644 index 0000000..01a1aa1 --- /dev/null +++ b/prefabs/minigame/region_visual.tscn @@ -0,0 +1,25 @@ +[gd_scene load_steps=5 format=3 uid="uid://dhfda4o386byp"] + +[ext_resource type="Script" uid="uid://cdpsa4qrlai31" path="res://scripts/CSharp/Common/Minigame/RegionVisual.cs" id="1_4ymj8"] +[ext_resource type="Shader" uid="uid://d0dayn7dc885j" path="res://shader/minigame_pie_section.gdshader" id="1_8p2xn"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_86pvs"] +resource_local_to_scene = true +shader = ExtResource("1_8p2xn") +shader_parameter/textureSize = 400.0 +shader_parameter/fillColor = Color(0.285466, 0.685481, 0.880632, 1) +shader_parameter/borderColor = Color(1, 1, 1, 1) +shader_parameter/borderWidth = 0.025 +shader_parameter/angles = Vector2(0.01, 0.18) +shader_parameter/smoothWidth = 0.0052 + +[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_0navw"] +size = Vector2(400, 400) + +[node name="RegionVisual" type="Node2D" node_paths=PackedStringArray("_sliceSprite")] +script = ExtResource("1_4ymj8") +_sliceSprite = NodePath("Sprite2D") + +[node name="Sprite2D" type="Sprite2D" parent="."] +material = SubResource("ShaderMaterial_86pvs") +texture = SubResource("PlaceholderTexture2D_0navw") diff --git a/project.godot b/project.godot index c4309b8..1e6f86e 100644 --- a/project.godot +++ b/project.godot @@ -11,8 +11,8 @@ config_version=5 [application] config/name="Babushka" -run/main_scene="uid://bopv10dqm1knc" -config/features=PackedStringArray("4.5", "C#", "Forward Plus") +run/main_scene="uid://c1dsbe7ryaije" +config/features=PackedStringArray("4.4", "C#", "Forward Plus") run/max_fps=120 boot_splash/fullsize=false boot_splash/image="uid://utam4axkvutc" diff --git a/scenes/Babushka_scene_fight_happening.tscn b/scenes/Babushka_scene_fight_happening.tscn index f7d0bed..84b09f8 100644 --- a/scenes/Babushka_scene_fight_happening.tscn +++ b/scenes/Babushka_scene_fight_happening.tscn @@ -187,10 +187,10 @@ offset_right = 794.0 offset_bottom = -472.0 text = "Hello world" +[connection signal="SignalTransitionState" from="FightHappening" to="ActionAnimationController/StateReactionActionAnimation" method="FightHappeningStateTransitioned"] [connection signal="SignalTransitionState" from="FightHappening" to="FightVisuals" method="FightHappeningStateChange"] [connection signal="SignalTransitionState" from="FightHappening" to="ActionSelect/StateReactionInputActionSelect" method="FightHappeningStateTransitioned"] [connection signal="SignalTransitionState" from="FightHappening" to="StateMachineDebugger" method="StateChange"] -[connection signal="SignalTransitionState" from="FightHappening" to="ActionAnimationController/StateReactionActionAnimation" method="FightHappeningStateTransitioned"] [connection signal="OnStateEntered" from="ActionAnimationController/StateReactionActionAnimation" to="ActionAnimationController" method="StateEnter"] [connection signal="OnStateExited" from="ActionAnimationController/StateReactionActionAnimation" to="ActionAnimationController" method="StateExit"] [connection signal="pressed" from="ActionSelect/BottomPanel/VBoxContainer/MarginContainer/HBoxContainer/MarginContainer/AttackButton" to="ActionSelect" method="SelectAction" binds= [1]] diff --git a/scenes/testing/Babushka_scene_minigame_test.tscn b/scenes/testing/Babushka_scene_minigame_test.tscn new file mode 100644 index 0000000..a53c4d9 --- /dev/null +++ b/scenes/testing/Babushka_scene_minigame_test.tscn @@ -0,0 +1,12 @@ +[gd_scene load_steps=3 format=3 uid="uid://c1dsbe7ryaije"] + +[ext_resource type="Script" uid="uid://iv0dbf32bfw1" path="res://scripts/CSharp/Common/TestScripts/MinigameTestStarter.cs" id="1_fwf73"] +[ext_resource type="PackedScene" uid="uid://bydwj3pbvqrhb" path="res://prefabs/minigame/minigame.tscn" id="1_wh3re"] + +[node name="BabushkaSceneMinigameTest" type="Node2D" node_paths=PackedStringArray("_minigameController")] +script = ExtResource("1_fwf73") +_minigameController = NodePath("Minigame") + +[node name="Minigame" parent="." instance=ExtResource("1_wh3re")] + +[node name="Camera2D" type="Camera2D" parent="."] diff --git a/scripts/CSharp/Common/Fight/Actions/BlobAttackAction.cs.uid b/scripts/CSharp/Common/Fight/Actions/BlobAttackAction.cs.uid new file mode 100644 index 0000000..872ca20 --- /dev/null +++ b/scripts/CSharp/Common/Fight/Actions/BlobAttackAction.cs.uid @@ -0,0 +1 @@ +uid://dlik4vktiu7dg diff --git a/scripts/CSharp/Common/Minigame/MinigameController.cs b/scripts/CSharp/Common/Minigame/MinigameController.cs new file mode 100644 index 0000000..11ce926 --- /dev/null +++ b/scripts/CSharp/Common/Minigame/MinigameController.cs @@ -0,0 +1,180 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Babushka.scripts.CSharp.Common.Util; +using Godot; + +namespace Babushka.scripts.CSharp.Common.Minigame; + +public partial class MinigameController : Node2D +{ + public class Builder + { + internal class Region + { + public required T value; + public float proportion = 1f; + } + + public enum DoubleHitHandling + { + Allow, + Disallow, + Remove, + } + + internal List regions = new(); + internal DoubleHitHandling doubleHitHandling = DoubleHitHandling.Allow; + internal int maxHitCount = 3; + + // add region + public Builder AddRegion(T value) + { + regions.Add(new Region { value = value }); + return this; + } + + // region settings + public Builder RegionWithProportion(float proportion) + { + if (regions.Count == 0) + throw new InvalidOperationException("No region to set proportion for"); + + regions.Last().proportion = proportion; + return this; + } + + // general settings + public Builder WithDoubleHitHandling(DoubleHitHandling handling) + { + if (handling != DoubleHitHandling.Allow) + throw new NotImplementedException(); + + doubleHitHandling = handling; + return this; + } + + public Builder WithHitCount(int hitCount) + { + this.maxHitCount = hitCount; + return this; + } + } + + private TaskCompletionSource? _minigameComplete; + private List? _hits; + private float _armPosition = 0f; + private float _armSpeed = 1f; + private List? _regions; + private int _maxHitCount; + + [Export] private PackedScene _regionVisualPrefab = null!; + [Export] private Node2D _regionsParent = null!; + [Export] private Color _baseRegionColor = Colors.Red; + + [Signal] public delegate void ArmMovedEventHandler(float newPos); + + public override void _EnterTree() + { + HideMinigame(); + } + + public override void _Process(double delta) + { + _armPosition += _armSpeed * (float)delta; + _armPosition = Mathf.PosMod(_armPosition, 1); + EmitSignalArmMoved(_armPosition); + } + + public async Task> Run(Builder builder) + { + ShowMinigame(); + Setup(builder); + await _minigameComplete!.Task; + var returnValue = _hits!.Select(h => builder.regions[h].value).ToList(); + Reset(); + HideMinigame(); + return returnValue; + } + + public void Hit() + { + if (_hits == null) return; + + int i; + for (i = 0; i < _regions!.Count - 1; i++) + { + if (_armPosition < _regions[i]) + { + break; + } + } + + _hits.Add(i); + + _armSpeed = -_armSpeed; + + if (_hits.Count >= _maxHitCount) + { + _minigameComplete!.SetResult(); + } + } + + private void Setup(Builder builder) + { + _minigameComplete = new(); + _hits = []; + _armPosition = 0f; + _armSpeed = 1f; + _regions = []; + + SetupRegions(builder); + + _maxHitCount = builder.maxHitCount; + } + + private void SetupRegions(Builder builder) + { + // common calculations + var totalRegionProportion = builder.regions.Sum(r => r.proportion); + + // spawn regions + var regionSum = 0f; + foreach (var region in builder.regions) + { + var regionVisual = _regionVisualPrefab.Instantiate(); + _regionsParent.AddChild(regionVisual); + + var normalisedAngleStart = regionSum / totalRegionProportion; + var normalisedAngleEnd = (regionSum + region.proportion) / totalRegionProportion; + var normalAngles = new Vector2(normalisedAngleStart, normalisedAngleEnd); + + regionVisual.Setup(normalAngles, _baseRegionColor.RandomHue()); + + regionSum += region.proportion; + + _regions!.Add(normalisedAngleEnd); + } + } + + private void ShowMinigame() + { + Show(); + ProcessMode = ProcessModeEnum.Inherit; + } + + private void HideMinigame() + { + Hide(); + ProcessMode = ProcessModeEnum.Disabled; + } + + private void Reset() + { + _minigameComplete = null; + _hits = null; + _regionsParent.GetChildren().ForEach(c => c.QueueFree()); + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Minigame/MinigameController.cs.uid b/scripts/CSharp/Common/Minigame/MinigameController.cs.uid new file mode 100644 index 0000000..248e5e6 --- /dev/null +++ b/scripts/CSharp/Common/Minigame/MinigameController.cs.uid @@ -0,0 +1 @@ +uid://ct7l4er2kljnc diff --git a/scripts/CSharp/Common/Minigame/RegionVisual.cs b/scripts/CSharp/Common/Minigame/RegionVisual.cs new file mode 100644 index 0000000..a715092 --- /dev/null +++ b/scripts/CSharp/Common/Minigame/RegionVisual.cs @@ -0,0 +1,19 @@ +using Godot; +using System; + +public partial class RegionVisual : Node +{ + [Export] private Sprite2D _sliceSprite; + + public override void _EnterTree() + { + //_sliceSprite.Material = new Material() + } + + public void Setup(Vector2 normalAngles, Color color) + { + var mat = (_sliceSprite.Material as ShaderMaterial)!; + mat.SetShaderParameter("angles", normalAngles); + mat.SetShaderParameter("fillColor", color); + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Minigame/RegionVisual.cs.uid b/scripts/CSharp/Common/Minigame/RegionVisual.cs.uid new file mode 100644 index 0000000..72e65b1 --- /dev/null +++ b/scripts/CSharp/Common/Minigame/RegionVisual.cs.uid @@ -0,0 +1 @@ +uid://cdpsa4qrlai31 diff --git a/scripts/CSharp/Common/Minigame/SpinnyArmVisual.cs b/scripts/CSharp/Common/Minigame/SpinnyArmVisual.cs new file mode 100644 index 0000000..772cdef --- /dev/null +++ b/scripts/CSharp/Common/Minigame/SpinnyArmVisual.cs @@ -0,0 +1,10 @@ +using Godot; +using System; + +public partial class SpinnyArmVisual : Node2D +{ + public void SetAngle(float normalAngle) + { + Rotation = normalAngle * float.Pi * 2; + } +} diff --git a/scripts/CSharp/Common/Minigame/SpinnyArmVisual.cs.uid b/scripts/CSharp/Common/Minigame/SpinnyArmVisual.cs.uid new file mode 100644 index 0000000..663cb3c --- /dev/null +++ b/scripts/CSharp/Common/Minigame/SpinnyArmVisual.cs.uid @@ -0,0 +1 @@ +uid://djkyrp24ljff0 diff --git a/scripts/CSharp/Common/TestScripts/MinigameTestStarter.cs b/scripts/CSharp/Common/TestScripts/MinigameTestStarter.cs new file mode 100644 index 0000000..63af215 --- /dev/null +++ b/scripts/CSharp/Common/TestScripts/MinigameTestStarter.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Linq; +using Babushka.scripts.CSharp.Common.Minigame; +using Godot; + +namespace Babushka.scripts.CSharp.Common.TestScripts; + +public partial class MinigameTestStarter : Node +{ + [Export] private MinigameController _minigameController = null!; + + public override void _Ready() + { + _minigameController.Run( + new MinigameController.Builder() + .WithHitCount(5) + .AddRegion(1) + .AddRegion(2).RegionWithProportion(2) + .AddRegion(3) + .AddRegion(4).RegionWithProportion(2) + .AddRegion(5) + .AddRegion(6).RegionWithProportion(2) + ).ContinueWith(task => OnEnd(task.Result)); + } + + private void OnEnd(List result) + { + GD.Print(string.Join(" ,", result)); + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/TestScripts/MinigameTestStarter.cs.uid b/scripts/CSharp/Common/TestScripts/MinigameTestStarter.cs.uid new file mode 100644 index 0000000..6e25630 --- /dev/null +++ b/scripts/CSharp/Common/TestScripts/MinigameTestStarter.cs.uid @@ -0,0 +1 @@ +uid://iv0dbf32bfw1 diff --git a/scripts/CSharp/Common/Util/ClickDetect.cs b/scripts/CSharp/Common/Util/ClickDetect.cs new file mode 100644 index 0000000..894ce33 --- /dev/null +++ b/scripts/CSharp/Common/Util/ClickDetect.cs @@ -0,0 +1,16 @@ +using Godot; + +namespace Babushka.scripts.CSharp.Common.Util; + +public partial class ClickDetect : Area2D +{ + [Signal] public delegate void ClickEventHandler(); + + public override void _Input(InputEvent evt) + { + if (evt is InputEventMouseButton { ButtonIndex: MouseButton.Left, Pressed: true }) + { + EmitSignalClick(); + } + } +} \ No newline at end of file diff --git a/scripts/CSharp/Common/Util/ClickDetect.cs.uid b/scripts/CSharp/Common/Util/ClickDetect.cs.uid new file mode 100644 index 0000000..b4b1fee --- /dev/null +++ b/scripts/CSharp/Common/Util/ClickDetect.cs.uid @@ -0,0 +1 @@ +uid://dq7gahfp0lk7v diff --git a/scripts/CSharp/Common/Util/LinqExtras.cs b/scripts/CSharp/Common/Util/LinqExtras.cs index fc84aa8..edb8aee 100644 --- a/scripts/CSharp/Common/Util/LinqExtras.cs +++ b/scripts/CSharp/Common/Util/LinqExtras.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using System.Data.SqlTypes; using System.Linq; using System.Xml.Schema; +using Godot; + namespace Babushka.scripts.CSharp.Common.Util; public static class LinqExtras @@ -46,4 +48,11 @@ public static class LinqExtras } return selfList; } + + public static Color RandomHue(this Color color) + { + color.ToHsv(out _, out float saturation, out var value ); + var rng = new RandomNumberGenerator(); + return Color.FromHsv(rng.Randf(), saturation, value); + } } diff --git a/shader/minigame_pie_section.gdshader b/shader/minigame_pie_section.gdshader new file mode 100644 index 0000000..f7a3fe5 --- /dev/null +++ b/shader/minigame_pie_section.gdshader @@ -0,0 +1,72 @@ +shader_type canvas_item; + +uniform float textureSize = 400.0; +uniform vec3 fillColor:source_color = vec3(1.0,0.0,0.0); +uniform vec3 borderColor:source_color = vec3(1.0,1.0,1.0); +uniform float borderWidth = 0.1; +uniform vec2 angles = vec2(0.2,0.4); +uniform float smoothWidth:hint_range(0.0001, 0.1, 0.0001) = 0.01; + +void vertex() { + +} + +//vec2 polar_coordinates(vec2 uv, vec2 center, vec2 tps) { +// vec2 dir = uv - center*textureSize*tps.x; +// dir = vec2(dir.y,-dir.x); +// float radius = length(dir) * 2.0; +// float angle = atan(dir.y, dir.x) * 1.0/(3.1416 * 2.0); +// return vec2(radius/(textureSize*tps.x), angle + 0.5); +//} + +float sd_circle(vec2 norm_uv,float radius){ + float d = distance(norm_uv,vec2(0.0)); + return d - radius; +} + +float sd_line(vec2 norm_uv){ + return norm_uv.x; +} + +vec2 rotate_uv(vec2 norm_uv, float angle_normal){ + float angle_rad = angle_normal * 2.0 * PI; + mat2 rotation = mat2(vec2( cos(angle_rad), sin(angle_rad)), + vec2(-sin(angle_rad), cos(angle_rad))); + return norm_uv * rotation; +} + +vec2 normalize_uv(vec2 uv,vec2 tps){ + vec2 zeroToOne = uv / (textureSize*tps); + return zeroToOne*2.0-1.0; +} + +void fragment() { + //vec2 pc = polar_coordinates(UV,vec2(0.5,0.5),TEXTURE_PIXEL_SIZE); + //bool isIn = pc.x<1.0 && pc.y > 0.2 && pc.y < 0.9; + ////bool isIn = TEXTURE_PIXEL_SIZE.x < 1.0/3.99; + ////COLOR = vec4(pc.x,pc.y,0,1); + //COLOR.a = isIn?1.0f:0.0f; + //COLOR.rgb = (pc.x > 1.0-borderWidth)?borderColor:fillColor; + vec2 normal_uv = normalize_uv(UV,TEXTURE_PIXEL_SIZE); + //vec2 normal_uv = VERTEX; + bool isBigAngle = angles.y - angles.x >0.5; + float line1 = sd_line(rotate_uv(normal_uv,angles.x)); + float line2 = sd_line(rotate_uv(normal_uv,angles.y)); + float linesCombined = isBigAngle ? min(-line1,line2):max(-line1,line2); + float circle = sd_circle(normal_uv,0.95); + float final_distance = max(linesCombined,circle); + //float final_distance = sd_line(normal_uv); + COLOR.a = 1.0-smoothstep(0.0,1.0, final_distance/smoothWidth); + //COLOR.r = 0.0; + //COLOR.g = 0.0; + //COLOR.b = 0.0; + //COLOR.rg = VERTEX*SCREEN_PIXEL_SIZE; + //COLOR.rg = UV*TEXTURE_PIXEL_SIZE; + //COLOR.rg = center; + COLOR.rgb = fillColor; +} + +//void light() { +// // Called for every pixel for every light affecting the CanvasItem. +// // Uncomment to replace the default light processing function with this one. +//} diff --git a/shader/minigame_pie_section.gdshader.uid b/shader/minigame_pie_section.gdshader.uid new file mode 100644 index 0000000..050a7d5 --- /dev/null +++ b/shader/minigame_pie_section.gdshader.uid @@ -0,0 +1 @@ +uid://d0dayn7dc885j