Added minigame
This commit is contained in:
@@ -0,0 +1 @@
|
||||
uid://dlik4vktiu7dg
|
||||
@@ -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<T>
|
||||
{
|
||||
internal class Region
|
||||
{
|
||||
public required T value;
|
||||
public float proportion = 1f;
|
||||
}
|
||||
|
||||
public enum DoubleHitHandling
|
||||
{
|
||||
Allow,
|
||||
Disallow,
|
||||
Remove,
|
||||
}
|
||||
|
||||
internal List<Region> regions = new();
|
||||
internal DoubleHitHandling doubleHitHandling = DoubleHitHandling.Allow;
|
||||
internal int maxHitCount = 3;
|
||||
|
||||
// add region
|
||||
public Builder<T> AddRegion(T value)
|
||||
{
|
||||
regions.Add(new Region { value = value });
|
||||
return this;
|
||||
}
|
||||
|
||||
// region settings
|
||||
public Builder<T> 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<T> WithDoubleHitHandling(DoubleHitHandling handling)
|
||||
{
|
||||
if (handling != DoubleHitHandling.Allow)
|
||||
throw new NotImplementedException();
|
||||
|
||||
doubleHitHandling = handling;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> WithHitCount(int hitCount)
|
||||
{
|
||||
this.maxHitCount = hitCount;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private TaskCompletionSource? _minigameComplete;
|
||||
private List<int>? _hits;
|
||||
private float _armPosition = 0f;
|
||||
private float _armSpeed = 1f;
|
||||
private List<float>? _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<List<T>> Run<T>(Builder<T> 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<T>(Builder<T> builder)
|
||||
{
|
||||
_minigameComplete = new();
|
||||
_hits = [];
|
||||
_armPosition = 0f;
|
||||
_armSpeed = 1f;
|
||||
_regions = [];
|
||||
|
||||
SetupRegions(builder);
|
||||
|
||||
_maxHitCount = builder.maxHitCount;
|
||||
}
|
||||
|
||||
private void SetupRegions<T>(Builder<T> 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<RegionVisual>();
|
||||
_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());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://ct7l4er2kljnc
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cdpsa4qrlai31
|
||||
@@ -0,0 +1,10 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public partial class SpinnyArmVisual : Node2D
|
||||
{
|
||||
public void SetAngle(float normalAngle)
|
||||
{
|
||||
Rotation = normalAngle * float.Pi * 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://djkyrp24ljff0
|
||||
@@ -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<int>()
|
||||
.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<int> result)
|
||||
{
|
||||
GD.Print(string.Join(" ,", result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://iv0dbf32bfw1
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dq7gahfp0lk7v
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user