Rewrote the game in C#

Added sounds and music
This commit is contained in:
2024-03-21 11:53:40 +01:00
parent abf8bf23ba
commit afab78db12
53 changed files with 1117 additions and 741 deletions

44
src/Game/Arrow.cs Normal file
View File

@@ -0,0 +1,44 @@
using Godot;
using System;
namespace Hellswipers.Game;
public partial class Arrow : Polygon2D {
public enum Dirs { Right, Down, Left, Up }
private static readonly Color NormalColor = Colors.White;
private static readonly Color DoneColor = Colors.Khaki;
private static readonly Color ErrorColor = Color.Color8(217, 70, 72);
private Polygon2D _inner;
private bool _done = false;
public Dirs CurrentDir { private set; get; }
public override void _Ready() {
_inner = GetNode<Polygon2D>("Inner");
}
public void SetDir(Dirs dir) {
CurrentDir = dir;
Rotation = dir switch {
Dirs.Right => 0,
Dirs.Down => (float)(Math.PI / 2),
Dirs.Left => (float)Math.PI,
Dirs.Up => (float)(Math.PI * 3 / 2),
_ => Rotation
};
}
public void Done() {
_done = true;
_inner.Color = DoneColor;
}
public void Error() {
var tween = CreateTween();
tween.TweenProperty(_inner, "color", ErrorColor, 0.15);
tween.TweenInterval(0.15);
tween.TweenProperty(_inner, "color", NormalColor, 0.2);
_done = false;
}
}

16
src/Game/Audio.cs Normal file
View File

@@ -0,0 +1,16 @@
using Godot;
namespace Hellswipers.Game;
public partial class Audio : Node {
private AudioStreamPlayer _okPlayer;
private AudioStreamPlayer _errPlayer;
public void Ok() => _okPlayer.Play();
public void Err() => _errPlayer.Play();
public override void _Ready() {
_okPlayer = GetNode<AudioStreamPlayer>("OkSound");
_errPlayer = GetNode<AudioStreamPlayer>("ErrorSound");
}
}

149
src/Game/Game.cs Normal file
View File

@@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Godot;
namespace Hellswipers.Game;
public partial class Game : Control {
private const int TotalWidth = 1920;
private const int SpaceBetweenArrows = 8;
private const long ErrorLengthMs = 400;
private PackedScene _arrowScene;
private AnimationPlayer _player;
private Node2D _arrowsNode;
private Label _nameLabel;
private Icons _icons;
private readonly Gem[] _gems = Gem.LoadGems();
private readonly Random _rand = new();
private readonly Stopwatch _errorWatch = new();
private readonly Queue<Gem> _nextGems = new();
private readonly List<Arrow> _arrows = new();
private Gem _current;
private bool _disabled = false;
private int _pos = -1;
public delegate void VoidEventHandler();
public event VoidEventHandler SwipeOk;
public event VoidEventHandler SwipeErr;
public event VoidEventHandler Solved;
private Gem RandomGem() => _gems[_rand.Next(_gems.Length)];
private async void StartNewRound() {
var gem = RandomGem();
_icons.Update(gem);
_nextGems.Enqueue(gem);
_current = _nextGems.Dequeue();
_disabled = true;
var tween = CreateTween();
tween.SetParallel();
if (_pos != -1) {
_arrows.ForEach(v => {
var newPos = v.CurrentDir switch {
Arrow.Dirs.Right => new Vector2(100, 0),
Arrow.Dirs.Down => new Vector2(0, 100),
Arrow.Dirs.Left => new Vector2(-100, 0),
Arrow.Dirs.Up => new Vector2(0, -100),
_ => new Vector2(0, 0)
};
tween.TweenProperty(v, "position", v.Position + newPos, 0.2);
});
_player.Play("round-end");
await ToSignal(_player, AnimationMixer.SignalName.AnimationFinished);
_arrows.ForEach(v => {
_arrowsNode.RemoveChild(v);
v.QueueFree();
});
_arrows.Clear();
tween = CreateTween();
tween.SetParallel();
}
_pos = 0;
_nameLabel.Text = _current.Name;
var arrowCount = _current.Dirs.Length;
var totalArrowWidth = 64 * arrowCount + SpaceBetweenArrows * (arrowCount - 1);
var xPos = (TotalWidth - totalArrowWidth) / 2;
foreach (var dir in _current.Dirs) {
var arrow = _arrowScene.Instantiate<Arrow>();
var startPos = dir switch {
Arrow.Dirs.Right => new Vector2(-100, 0),
Arrow.Dirs.Down => new Vector2(0, -100),
Arrow.Dirs.Left => new Vector2(100, 0),
Arrow.Dirs.Up => new Vector2(0, 100),
_ => new Vector2(0, 0)
};
startPos.X += xPos;
arrow.Position = startPos;
tween.TweenProperty(arrow, "position", new Vector2(xPos, 0), 0.2);
arrow.SetDir(dir);
_arrows.Add(arrow);
_arrowsNode.AddChild(arrow);
xPos += 64 + SpaceBetweenArrows;
}
_player.Play("round-start");
await ToSignal(_player, AnimationMixer.SignalName.AnimationFinished);
_disabled = false;
}
private void HandleInput(Arrow.Dirs dir) {
if (_disabled) {
if (_errorWatch.IsRunning && _errorWatch.ElapsedMilliseconds >= ErrorLengthMs) {
_disabled = false;
_errorWatch.Stop();
} else return;
}
if (_pos >= _current.Dirs.Length) return;
if (dir == _current.Dirs[_pos]) {
_arrows[_pos].Done();
_pos++;
SwipeOk!.Invoke();
if (_pos == _current.Dirs.Length) {
Solved!.Invoke();
StartNewRound();
}
} else {
_disabled = true;
SwipeErr!.Invoke();
_errorWatch.Start();
_arrows.ForEach(v => v.Error());
_pos = 0;
}
}
public override void _Ready() {
_player = GetNode<AnimationPlayer>("AnimationPlayer");
_arrowsNode = GetNode<Node2D>("Arrows");
_nameLabel = GetNode<Label>("Name");
_icons = GetNode<Icons>("Icons");
var stats = GetNode<Stats>("StatContainer");
SwipeOk += () => stats.Combo++;
SwipeErr += () => stats.Combo = 0;
Solved += () => stats.Solved++;
var audio = GetNode<Audio>("Audio");
SwipeOk += audio.Ok;
SwipeErr += audio.Err;
_arrowScene = ResourceLoader.Load<PackedScene>("res://game/arrow.tscn");
for (int i = 0; i < 7; ++i)
_nextGems.Enqueue(RandomGem());
_icons.Init(_nextGems.ToArray());
StartNewRound();
}
}

88
src/Game/GemData.cs Normal file
View File

@@ -0,0 +1,88 @@
using System.Linq;
using Godot;
namespace Hellswipers.Game;
public record struct Gem {
public readonly Texture2D Texture;
public readonly string Name;
public readonly Arrow.Dirs[] Dirs;
public Gem(string Name, string textureName, Arrow.Dirs[] Dirs) {
this.Name = Name;
this.Dirs = Dirs;
Texture = ResourceLoader.Load<Texture2D>(textureName);
}
public Variant this[int i] {
get {
switch (i) {
case 0:
return Name;
case 1:
return Texture;
case 2:
return Dirs.Select(v => (int)v).ToArray();
}
return 0;
}
}
public static Gem[] LoadGems() => new Gem[] {
new ("LIFT-850 Jump Pack", "res://game/gems/LIFT-850icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Up}),
new ("B-1 Supply Pack", "res://game/gems/B-1icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Down}),
new ("AX/LAS-5 \"Guard Dog\" Rover", "res://game/gems/AX-LAS-5icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Right}),
new ("SH-20 Ballistic Shield Backpack", "res://game/gems/SH-20icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left}),
new ("SH-32 Shield Generator Pack", "res://game/gems/SH-32icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Left,Arrow.Dirs.Right}),
new ("AX/AR-23 \"Guard Dog\"", "res://game/gems/AX-AR-23icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down}),
new ("MG-43 Machine Gun", "res://game/gems/MG-43icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("APW-1 Anti-Materiel Rifle", "res://game/gems/APW-1icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Down}),
new ("M-105 Stalwart", "res://game/gems/M-105icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Left}),
new ("EAT-17 Expendable Anti-tank", "res://game/gems/EAT-17icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("GR-8 Recoilless Rifle", "res://game/gems/GR-8icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Left}),
new ("FLAM-40 Flamethrower", "res://game/gems/FLAM-40icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Up}),
new ("AC-8 Autocannon", "res://game/gems/AC-8icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("RS-422 Railgun", "res://game/gems/RS-422icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Right}),
new ("FAF-14 SPEAR Launcher", "res://game/gems/FAF-14icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Down}),
new ("GL-21 Grenade Launcher", "res://game/gems/GL-21icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Down}),
new ("LAS-98 Laser Cannon", "res://game/gems/LAS-98icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left}),
new ("ARC-3 Arc Thrower", "res://game/gems/ARC-3icon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Left}),
new ("Reinforce", "res://game/gems/Reinforceicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Left,Arrow.Dirs.Up}),
new ("SOS Beacon", "res://game/gems/SOSicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Up}),
new ("Resupply", "res://game/gems/ResupplyIcon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("NUX-223 Hellbomb", "res://game/gems/Strat_NUX-223_Hellbomb_mk1.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up}),
new ("SSSD Delivery", "res://game/gems/DeliverSSSDicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up}),
new ("Seismic Probe", "res://game/gems/Seismic_probe_icon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Down}),
new ("Upload Data", "res://game/gems/DeliverSSSDicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Up}),
new ("Eagle Rearm", "res://game/gems/HD2_Eagle_Rearm_Icon.jpg", new [] {Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("E/MG-101 HMG Emplacement", "res://game/gems/HMGTurreticon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Left}),
new ("FX-12 Shield Generator Relay", "res://game/gems/Shieldrelayicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Left,Arrow.Dirs.Right}),
new ("A/ARC-3 Tesla Tower", "res://game/gems/Teslaicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Right}),
new ("MD-6 Anti-Personnel Minefield", "res://game/gems/Minefieldicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Right}),
new ("MD-I4 Incendiary Mines", "res://game/gems/Fireminefieldicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Left,Arrow.Dirs.Down}),
new ("A/MG-43 Machine Gun Sentry", "res://game/gems/MGsentryicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Up}),
new ("A/G-16 Gatling Sentry", "res://game/gems/Gatlingsentryicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Left}),
new ("A/M-12 Mortar Sentry", "res://game/gems/Mortarsentryicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Down}),
new ("A/AC-8 Autocannon Sentry", "res://game/gems/Autocannoasentryicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Up}),
new ("A/MLS-4X Rocket Sentry", "res://game/gems/Missilesentryicon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Left}),
new ("A/M-23 EMS Mortar Sentry", "res://game/gems/EMSmortaricon.png", new [] {Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Right}),
new ("Orbital Gatling Barrage", "res://game/gems/OrbitalGatlingicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Up,Arrow.Dirs.Up}),
new ("Orbital Airburst Strike", "res://game/gems/OrbitalAirbursticon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Right}),
new ("Orbital 120MM HE Barrage", "res://game/gems/Orbital120icon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Left,Arrow.Dirs.Right,Arrow.Dirs.Down}),
new ("Orbital 380MM HE Barrage", "res://game/gems/Orbital380icon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Up,Arrow.Dirs.Left,Arrow.Dirs.Down,Arrow.Dirs.Down}),
new ("Orbital Walking Barrage", "res://game/gems/OrbitalWalkingicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Right,Arrow.Dirs.Down}),
new ("Orbital Laser", "res://game/gems/OrbitalLasericon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down}),
new ("Orbital Railcannon Strike", "res://game/gems/OrbitalRailcannonicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Right}),
new ("Orbital Precision Strike", "res://game/gems/OrbitalPrecisionicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Up}),
new ("Orbital Gas Strike", "res://game/gems/OrbitalGasicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Right}),
new ("Orbital EMS Strike", "res://game/gems/OrbitalEMSicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Left,Arrow.Dirs.Down}),
new ("Orbital Smoke Strike", "res://game/gems/OrbitalSmokeicon.png", new [] {Arrow.Dirs.Right,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up}),
new ("Eagle Strafing Run", "res://game/gems/EagleStrafingicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Right}),
new ("Eagle Airstrike", "res://game/gems/EagleAirstrikeicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Right}),
new ("Eagle Cluster Bomb", "res://game/gems/EagleClusterbombicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Right}),
new ("Eagle Napalm Airstrike", "res://game/gems/EagleNapalmicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Up}),
new ("Eagle Smoke Strike", "res://game/gems/EagleSmokeicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Down}),
new ("Eagle 110MM Rocket Pods", "res://game/gems/EagleRocketpodicon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Up,Arrow.Dirs.Left}),
new ("Eagle 500kg Bomb", "res://game/gems/Eagle500icon.png", new [] {Arrow.Dirs.Up,Arrow.Dirs.Right,Arrow.Dirs.Down,Arrow.Dirs.Down,Arrow.Dirs.Down})
};
}

56
src/Game/Icons.cs Normal file
View File

@@ -0,0 +1,56 @@
using System.Collections.Generic;
using Godot;
namespace Hellswipers.Game;
public partial class Icons : Node2D {
private const int IconSize = 144;
private const int SpaceBetween = 48;
private const int TotalIconSize = IconSize + SpaceBetween;
private const double AnimationLength = 0.4;
private static readonly Vector2 IconScale = new(3, 3);
private readonly Queue<Sprite2D> _icons = new();
private Sprite2D CreateIcon(Texture2D tex) {
var icon = new Sprite2D();
icon.Texture = tex;
icon.Scale = IconScale;
AddChild(icon);
_icons.Enqueue(icon);
return icon;
}
public void Init(Gem[] nextGems) {
CreateIcon(null);
var pos = TotalIconSize;
foreach (var gem in nextGems) {
CreateIcon(gem.Texture).Position = new(pos, 0);
pos += TotalIconSize;
}
}
public void Update(Gem gem) {
var tween = CreateTween();
tween.SetParallel();
tween.SetTrans(Tween.TransitionType.Cubic);
tween.SetEase(Tween.EaseType.InOut);
var oldIcon = _icons.Dequeue();
tween.TweenProperty(oldIcon, "position:x", -Position.X - IconSize, AnimationLength);
tween.TweenProperty(oldIcon, "self_modulate", new Color(1, 1, 1, 0), AnimationLength);
var newIcon = CreateIcon(gem.Texture);
newIcon.Position = new(_icons.Count * TotalIconSize, 0);
newIcon.SelfModulate = new(1, 1, 1, 0);
tween.TweenProperty(newIcon, "self_modulate", new Color(1, 1, 1, 1), AnimationLength);
foreach (var icon in _icons)
tween.TweenProperty(icon, "position:x", icon.Position.X - TotalIconSize, AnimationLength);
tween.Finished += () => {
RemoveChild(oldIcon);
oldIcon.QueueFree();
};
}
}

46
src/Game/Input.cs Normal file
View File

@@ -0,0 +1,46 @@
using System;
using Godot;
namespace Hellswipers.Game;
public partial class Game {
private Vector2? _swipeStart;
private void CalcSwipe(Vector2 end) {
if (!_swipeStart.HasValue)
return;
var delta = end - _swipeStart.Value;
_swipeStart = null;
var deltaAbs = delta.Abs();
var biggest = Math.Max(deltaAbs.X, deltaAbs.Y);
if (biggest < 50)
return;
HandleInput(deltaAbs.X > deltaAbs.Y
? (delta.X > 0 ? Arrow.Dirs.Right : Arrow.Dirs.Left)
: (delta.Y > 0 ? Arrow.Dirs.Down : Arrow.Dirs.Up)
);
}
public override void _UnhandledInput(InputEvent ev) {
if (ev is InputEventMouseButton evm) {
if (ev.IsPressed())
_swipeStart = evm.Position;
else
CalcSwipe(evm.Position);
} else {
if (ev.IsActionPressed("key_up"))
HandleInput(Arrow.Dirs.Up);
else if (ev.IsActionPressed("key_down"))
HandleInput(Arrow.Dirs.Down);
else if (ev.IsActionPressed("key_left"))
HandleInput(Arrow.Dirs.Left);
else if (ev.IsActionPressed("key_right"))
HandleInput(Arrow.Dirs.Right);
else if (ev.IsActionPressed("escape"))
GetTree().ChangeSceneToPacked(ResourceLoader.Load<PackedScene>("res://main_menu/main_menu.tscn"));
}
}
}

33
src/Game/Stats.cs Normal file
View File

@@ -0,0 +1,33 @@
using Godot;
namespace Hellswipers.Game;
public partial class Stats : Node {
private Label _comboLabel;
private Label _solvedLabel;
private int _combo = 0;
private int _solved = 0;
public int Combo {
get => _combo;
set {
_combo = value;
_comboLabel.Text = _combo.ToString();
}
}
public int Solved {
get => _solved;
set {
_solved = value;
_solvedLabel.Text = _solved.ToString();
}
}
public override void _Ready() {
_comboLabel = GetNode<Label>("Combo");
_solvedLabel = GetNode<Label>("Solved");
}
}

26
src/MainMenu.cs Normal file
View File

@@ -0,0 +1,26 @@
using Godot;
namespace Hellswipers;
public partial class MainMenu : Control {
public override void _Ready() {
Settings.Init();
var sb = GetNode<TextureToggleButton>("Settings/SoundToggle");
sb.State = Settings.SoundMute;
sb.StateChanged = v => Settings.SoundMute = v;
var mb = GetNode<TextureToggleButton>("Settings/MusicToggle");
mb.State = Settings.MusicMute;
mb.StateChanged = v => Settings.MusicMute = v;
GetNode<Button>("StartButton").Pressed +=
() => GetTree().ChangeSceneToPacked(ResourceLoader.Load<PackedScene>("res://game/game.tscn"));
GetNode<Button>("ExitButton").Pressed += () => {
var tree = GetTree();
tree.Root.PropagateNotification((int)NotificationWMCloseRequest);
tree.Quit();
};
}
}

26
src/Settings.cs Normal file
View File

@@ -0,0 +1,26 @@
using Godot;
namespace Hellswipers;
public static class Settings {
private static bool _initDone;
private static int _soundBus, _musicBus;
public static bool SoundMute {
get => AudioServer.IsBusMute(_soundBus);
set => AudioServer.SetBusMute(_soundBus, value);
}
public static bool MusicMute {
get => AudioServer.IsBusMute(_musicBus);
set => AudioServer.SetBusMute(_musicBus, value);
}
public static void Init() {
if (_initDone) return;
_initDone = true;
_soundBus = AudioServer.GetBusIndex("Sound");
_musicBus = AudioServer.GetBusIndex("Music");
}
}

View File

@@ -0,0 +1,54 @@
using System;
using Godot;
namespace Hellswipers;
[Tool]
[GlobalClass]
public partial class TextureToggleButton : BaseButton {
public Action<bool> StateChanged = null;
[Export] public Texture2D FalseTexture;
[Export] public Texture2D TrueTexture;
[Export]
public bool State {
get => _state;
set {
_state = value;
StateChanged?.Invoke(value);
QueueRedraw();
}
}
private bool _state;
private Color _baseColor;
private Color _hoverColor;
private Color _pressColor;
public override Vector2 _GetMinimumSize() => new(
Math.Max(FalseTexture?.GetWidth() ?? 0, TrueTexture?.GetWidth() ?? 0),
Math.Max(FalseTexture?.GetHeight() ?? 0, TrueTexture?.GetHeight() ?? 0)
);
public override void _Pressed() => State = !State;
public override void _Draw() {
SelfModulate = GetDrawMode() switch {
DrawMode.Normal => _baseColor,
DrawMode.Disabled => _baseColor,
DrawMode.Hover => _hoverColor,
DrawMode.Pressed => _pressColor,
DrawMode.HoverPressed => _pressColor,
_ => SelfModulate
};
if (TrueTexture != null && FalseTexture != null)
DrawTexture(State ? TrueTexture : FalseTexture, Vector2.Zero);
}
public override void _Ready() {
_baseColor = GetThemeColor("font_color", "Button");
_hoverColor = GetThemeColor("font_hover_color", "Button");
_pressColor = GetThemeColor("font_pressed_color", "Button");
}
}