feat: initial import
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
using Godot;
|
||||
using GodotHostTest.GodotDI;
|
||||
using GodotHostTest.Interfaces;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace GodotHostTest.Game;
|
||||
|
||||
public partial class GameRootScope : RootScope
|
||||
{
|
||||
[Export] private TargetSpawner _targetSpawner = null!;
|
||||
|
||||
protected override void Configure(IServiceCollection serviceCollection)
|
||||
{
|
||||
serviceCollection
|
||||
.AddSingleton<ITargetCollector>(_targetSpawner)
|
||||
.AddSingleton<ITargetSpawner>(_targetSpawner);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dk578xnlxjwrr
|
||||
@@ -0,0 +1,21 @@
|
||||
using Godot;
|
||||
using GodotHostTest.GodotDI;
|
||||
using GodotHostTest.Helpers;
|
||||
using GodotHostTest.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using R3;
|
||||
|
||||
namespace GodotHostTest.Game;
|
||||
|
||||
public partial class Projectile : Node2D
|
||||
{
|
||||
[Inject] private readonly ILogger<Projectile> _logger = null!;
|
||||
[Inject] private readonly ITargetSpawner _targetSpawner = null!;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
_targetSpawner.TargetSpawned
|
||||
.Subscribe(_ => _logger.LogInformation("Projectile got informed of target spawning")).AddTo(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dc5mvle8lc40j
|
||||
@@ -0,0 +1,37 @@
|
||||
using R3;
|
||||
using Godot;
|
||||
using GodotHostTest.GodotDI;
|
||||
using GodotHostTest.Helpers;
|
||||
using GodotHostTest.Interfaces;
|
||||
|
||||
namespace GodotHostTest.Game;
|
||||
|
||||
public partial class Score : Control
|
||||
{
|
||||
[Export] private AnimationPlayer _animationPlayer = null!;
|
||||
[Export] private Label _label = null!;
|
||||
[Inject] private readonly ITargetSpawner _targetSpawner = null!;
|
||||
|
||||
private int _score;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_targetSpawner.TargetSpawned.Subscribe(OnTargetSpawned).AddTo(this);
|
||||
base._Ready();
|
||||
}
|
||||
|
||||
private void OnTargetSpawned(ITarget target)
|
||||
{
|
||||
_animationPlayer.Play("wiggle");
|
||||
target.Hit.Select(_ => 20).Merge(target.TimedOut.Select(_ => -5)).SubscribeOnce(delta =>
|
||||
{
|
||||
_score += delta;
|
||||
UpdateScore();
|
||||
}).AddTo(this);
|
||||
}
|
||||
|
||||
private void UpdateScore()
|
||||
{
|
||||
_label.Text = $"Score: {_score}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bgrjeadxhgmvi
|
||||
@@ -0,0 +1,61 @@
|
||||
using Godot;
|
||||
using GodotHostTest.GodotDI;
|
||||
using GodotHostTest.Interfaces;
|
||||
using R3;
|
||||
|
||||
namespace GodotHostTest.Game;
|
||||
|
||||
public partial class Target : Node2D, ITarget
|
||||
{
|
||||
[Export] public double TimeOutDurationInSeconds;
|
||||
[Export] public required Timer TimeOutTimer;
|
||||
[Export] public required Sprite2D Image;
|
||||
[Export] public required Area2D CollisionArea;
|
||||
|
||||
private readonly Subject<Unit> _timedOut = new();
|
||||
private readonly Subject<Unit> _hit = new();
|
||||
|
||||
[Inject] private readonly ITargetCollector _targetCollector = null!;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_targetCollector.NewTarget(this);
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
_timedOut.Dispose();
|
||||
_hit.Dispose();
|
||||
}
|
||||
|
||||
public Observable<Unit> TimedOut => _timedOut.AsObservable();
|
||||
|
||||
public Observable<Unit> Hit => _hit.AsObservable();
|
||||
|
||||
// todo: hook to collision
|
||||
private void OnHit()
|
||||
{
|
||||
Disable();
|
||||
TimeOutTimer.Stop();
|
||||
_hit.OnNext(Unit.Default);
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
{
|
||||
Image.Visible = true;
|
||||
CollisionArea.Monitoring = true;
|
||||
TimeOutTimer.Start(TimeOutDurationInSeconds);
|
||||
}
|
||||
|
||||
private void Disable()
|
||||
{
|
||||
Image.Visible = false;
|
||||
CollisionArea.Monitoring = false;
|
||||
}
|
||||
|
||||
private void OnTimeout()
|
||||
{
|
||||
Disable();
|
||||
_timedOut.OnNext(Unit.Default);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bv2hat41dyxiv
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using GodotHostTest.Helpers;
|
||||
using GodotHostTest.Interfaces;
|
||||
using R3;
|
||||
|
||||
namespace GodotHostTest.Game;
|
||||
|
||||
public partial class TargetSpawner : Node2D, ITargetCollector, ITargetSpawner
|
||||
{
|
||||
[Export] public double TimeBetweenSpawns;
|
||||
|
||||
[Export] public required Timer Timer;
|
||||
|
||||
private readonly List<ITarget> _availableTargets = [];
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Spawn();
|
||||
Timer.Start(TimeBetweenSpawns);
|
||||
}
|
||||
|
||||
private void MakeTargetAvailable(ITarget target)
|
||||
{
|
||||
_availableTargets.Add(target);
|
||||
}
|
||||
|
||||
private void OnTimer()
|
||||
{
|
||||
Spawn();
|
||||
}
|
||||
|
||||
private void Spawn()
|
||||
{
|
||||
// pick a random target
|
||||
var randomIndex = GD.RandRange(0, _availableTargets.Count - 1);
|
||||
var target = _availableTargets[randomIndex];
|
||||
_availableTargets.RemoveAt(randomIndex);
|
||||
|
||||
// enable it
|
||||
target.Enable();
|
||||
|
||||
// notify that a target has been spawned
|
||||
_targetSpawned.OnNext(target);
|
||||
}
|
||||
|
||||
public void NewTarget(ITarget target)
|
||||
{
|
||||
_availableTargets.Add(target);
|
||||
target.Hit.Merge(target.TimedOut).Select(_ => target).Subscribe(MakeTargetAvailable).AddTo(this);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
_targetSpawned.Dispose();
|
||||
}
|
||||
|
||||
private readonly Subject<ITarget> _targetSpawned = new();
|
||||
public Observable<ITarget> TargetSpawned => _targetSpawned.AsObservable();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cxfrtglku2gfa
|
||||
@@ -0,0 +1,15 @@
|
||||
using Godot;
|
||||
using GodotHostTest.GodotDI;
|
||||
|
||||
namespace GodotHostTest.Game;
|
||||
|
||||
public partial class Turret : Sprite2D
|
||||
{
|
||||
[Inject] private readonly ISceneInstantiator _sceneInstantiator = null!;
|
||||
[Export] private PackedScene _projectilePackedScene = null!;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
GetTree().CreateTimer(1).Timeout += () => AddChild(_sceneInstantiator.Instantiate(_projectilePackedScene));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://ce7gnp1lcrrdv
|
||||
@@ -0,0 +1,18 @@
|
||||
[gd_scene format=3 uid="uid://brbufibn7hi3o"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://dc5mvle8lc40j" path="res://Game/Projectile.cs" id="1_80yud"]
|
||||
[ext_resource type="Script" uid="uid://qjonl8stia46" path="res://GodotDI/Scope.cs" id="2_3kmdq"]
|
||||
[ext_resource type="Texture2D" uid="uid://y1ros3y7hag2" path="res://icon.svg" id="3_1i54g"]
|
||||
|
||||
[node name="Projectile" type="Node2D" unique_id=1686616504]
|
||||
script = ExtResource("1_80yud")
|
||||
|
||||
[node name="Scope" type="Node" parent="." unique_id=513224818 node_paths=PackedStringArray("InjectedNodes")]
|
||||
script = ExtResource("2_3kmdq")
|
||||
InjectedNodes = [NodePath("..")]
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=1021740171]
|
||||
modulate = Color(1, 1, 0, 1)
|
||||
rotation = 0.7853982
|
||||
scale = Vector2(0.3, 0.3)
|
||||
texture = ExtResource("3_1i54g")
|
||||
@@ -0,0 +1,31 @@
|
||||
[gd_scene format=3 uid="uid://3v8kq1rfwhmr"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://y1ros3y7hag2" path="res://icon.svg" id="1_032qf"]
|
||||
[ext_resource type="Script" uid="uid://bv2hat41dyxiv" path="res://Game/Target.cs" id="1_c0a8e"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_u8d0v"]
|
||||
size = Vector2(128, 128)
|
||||
|
||||
[node name="Target" type="Node2D" unique_id=2101558052 node_paths=PackedStringArray("TimeOutTimer", "Image", "CollisionArea")]
|
||||
script = ExtResource("1_c0a8e")
|
||||
TimeOutDurationInSeconds = 7.0
|
||||
TimeOutTimer = NodePath("TimeOutTimer")
|
||||
Image = NodePath("Sprite2D")
|
||||
CollisionArea = NodePath("CollisionArea")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="." unique_id=31059524]
|
||||
visible = false
|
||||
modulate = Color(1, 0.20392157, 0.015686275, 1)
|
||||
texture = ExtResource("1_032qf")
|
||||
|
||||
[node name="CollisionArea" type="Area2D" parent="." unique_id=116681968]
|
||||
monitoring = false
|
||||
monitorable = false
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="CollisionArea" unique_id=1558252366]
|
||||
shape = SubResource("RectangleShape2D_u8d0v")
|
||||
|
||||
[node name="TimeOutTimer" type="Timer" parent="." unique_id=1079777109]
|
||||
one_shot = true
|
||||
|
||||
[connection signal="timeout" from="TimeOutTimer" to="." method="OnTimeout"]
|
||||
Reference in New Issue
Block a user