Basic fighting system
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bn56p0ytuo060"
|
||||
path="res://.godot/imported/AttackButton.png-ab1949863046f66b014201d64778c962.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/ui/UI/AttackButton.png"
|
||||
dest_files=["res://.godot/imported/AttackButton.png-ab1949863046f66b014201d64778c962.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
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/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bcs0e1bpu8wm1"
|
||||
path="res://.godot/imported/MagicButton.png-f688abbb37e617bc75b48afd1bffb745.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/ui/UI/MagicButton.png"
|
||||
dest_files=["res://.godot/imported/MagicButton.png-f688abbb37e617bc75b48afd1bffb745.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
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/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
@@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://qlfwuakhe57t"
|
||||
path="res://.godot/imported/attack_select_wheel.png-437439dea02962dbfc00f0c03b7b3deb.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://art/ui/UI/attack_select_wheel.png"
|
||||
dest_files=["res://.godot/imported/attack_select_wheel.png-437439dea02962dbfc00f0c03b7b3deb.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
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/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
@@ -0,0 +1,49 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://hk8ahyp6dgl6"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://c76mhhqyk4lgh" path="res://scripts/CSharp/Common/Fight/FightInstance.cs" id="1_ygesl"]
|
||||
[ext_resource type="Script" uid="uid://oe1uypehqvr7" path="res://scripts/CSharp/Common/Fight/FightStateManager.cs" id="2_b0ivm"]
|
||||
|
||||
[node name="FightBaseScene" type="Node2D" node_paths=PackedStringArray("_friendlyFightSpots", "_enemyFightSpots", "camPositionNode", "_fightStateManager", "_fightEndText")]
|
||||
script = ExtResource("1_ygesl")
|
||||
_friendlyFightSpots = [NodePath("FriendlyPositions/FriendPos1"), NodePath("FriendlyPositions/FriendPos2"), NodePath("FriendlyPositions/FriendPos3")]
|
||||
_enemyFightSpots = [NodePath("EnemyPositions/EnemyPos1"), NodePath("EnemyPositions/EnemyPos2"), NodePath("EnemyPositions/EnemyPos3")]
|
||||
camPositionNode = NodePath("CamPositionMarker")
|
||||
_fightStateManager = NodePath("FightStateManager")
|
||||
_fightEndText = NodePath("ResultText")
|
||||
|
||||
[node name="FriendlyPositions" type="Node2D" parent="."]
|
||||
position = Vector2(-625, -6)
|
||||
|
||||
[node name="FriendPos1" type="Node2D" parent="FriendlyPositions"]
|
||||
position = Vector2(0, -395)
|
||||
|
||||
[node name="FriendPos2" type="Node2D" parent="FriendlyPositions"]
|
||||
|
||||
[node name="FriendPos3" type="Node2D" parent="FriendlyPositions"]
|
||||
position = Vector2(0, 424)
|
||||
|
||||
[node name="EnemyPositions" type="Node2D" parent="."]
|
||||
position = Vector2(611, -12)
|
||||
|
||||
[node name="EnemyPos1" type="Node2D" parent="EnemyPositions"]
|
||||
position = Vector2(0, -395)
|
||||
|
||||
[node name="EnemyPos2" type="Node2D" parent="EnemyPositions"]
|
||||
|
||||
[node name="EnemyPos3" type="Node2D" parent="EnemyPositions"]
|
||||
position = Vector2(0, 424)
|
||||
|
||||
[node name="FightStateManager" type="Node" parent="."]
|
||||
script = ExtResource("2_b0ivm")
|
||||
|
||||
[node name="CamPositionMarker" type="Node2D" parent="."]
|
||||
|
||||
[node name="ResultText" type="Label" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_font_sizes/font_size = 141
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
@@ -0,0 +1,8 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://cnjsepvaqdbyq"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://j5ge24rk25wm" path="res://scripts/CSharp/Common/Fight/FightManager.cs" id="1_8p7ev"]
|
||||
[ext_resource type="PackedScene" uid="uid://cpanatqdjjpa3" path="res://prefabs/fight/fighters/vesna_fighter.tscn" id="2_ak1vo"]
|
||||
|
||||
[node name="FightManagerAutoload" type="Node"]
|
||||
script = ExtResource("1_8p7ev")
|
||||
fightingVesnaScene = ExtResource("2_ak1vo")
|
||||
@@ -0,0 +1,89 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://bp64p6y72j71w"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://ccrnmx6bd842k" path="res://art/characters/farm fäulnis blobs.png" id="1_vem8k"]
|
||||
[ext_resource type="Script" uid="uid://by88f32fou7lh" path="res://scripts/CSharp/Common/Fight/Fighter.cs" id="2_4w1ab"]
|
||||
[ext_resource type="Texture2D" uid="uid://qlfwuakhe57t" path="res://art/ui/UI/attack_select_wheel.png" id="3_v4f83"]
|
||||
[ext_resource type="Texture2D" uid="uid://bn56p0ytuo060" path="res://art/ui/UI/AttackButton.png" id="5_vbkts"]
|
||||
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_284vk"]
|
||||
radius = 291.58
|
||||
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_s74nc"]
|
||||
radius = 173.44
|
||||
|
||||
[node name="EnemyBlobFighter" type="Node2D" node_paths=PackedStringArray("_attackButtons", "_targetButtons", "_targetMarker", "_healthText", "_visualSprite")]
|
||||
script = ExtResource("2_4w1ab")
|
||||
name = "Blob"
|
||||
maxHealth = 50
|
||||
attackStrength = 5
|
||||
_attackButtons = NodePath("FightButtons")
|
||||
_targetButtons = NodePath("TargetButtons")
|
||||
_targetMarker = NodePath("TargetButtons/TargetMarker")
|
||||
_healthText = NodePath("HealthShow")
|
||||
_visualSprite = NodePath("Sprite2D")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("1_vem8k")
|
||||
offset = Vector2(-8, -130)
|
||||
region_enabled = true
|
||||
region_rect = Rect2(1735.63, 108.423, 320.374, 333.577)
|
||||
|
||||
[node name="TargetButtons" type="Node2D" parent="."]
|
||||
visible = false
|
||||
|
||||
[node name="TargetMarker" type="Sprite2D" parent="TargetButtons"]
|
||||
visible = false
|
||||
z_index = 200
|
||||
position = Vector2(8, -122)
|
||||
scale = Vector2(4.245, 4.245)
|
||||
texture = ExtResource("3_v4f83")
|
||||
|
||||
[node name="Area2D" type="Area2D" parent="TargetButtons"]
|
||||
position = Vector2(3, -76)
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="TargetButtons/Area2D"]
|
||||
shape = SubResource("CircleShape2D_284vk")
|
||||
|
||||
[node name="FightButtons" type="Node2D" parent="."]
|
||||
visible = false
|
||||
position = Vector2(3, -588)
|
||||
|
||||
[node name="CircleBackground" type="Sprite2D" parent="FightButtons"]
|
||||
z_index = 200
|
||||
scale = Vector2(4.245, 4.245)
|
||||
texture = ExtResource("3_v4f83")
|
||||
|
||||
[node name="AttackButton" type="Node2D" parent="FightButtons"]
|
||||
position = Vector2(0, -536)
|
||||
|
||||
[node name="ButtonBackground" type="Sprite2D" parent="FightButtons/AttackButton"]
|
||||
z_index = 200
|
||||
scale = Vector2(2.48, 2.48)
|
||||
texture = ExtResource("5_vbkts")
|
||||
|
||||
[node name="Area2D" type="Area2D" parent="FightButtons/AttackButton"]
|
||||
collision_layer = 16
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="FightButtons/AttackButton/Area2D"]
|
||||
shape = SubResource("CircleShape2D_s74nc")
|
||||
|
||||
[node name="HealthShow" type="Label" parent="."]
|
||||
z_index = 200
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -197.0
|
||||
offset_top = -451.0
|
||||
offset_right = 207.0
|
||||
offset_bottom = -305.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_font_sizes/font_size = 106
|
||||
text = "100/100"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[connection signal="input_event" from="TargetButtons/Area2D" to="." method="TargetMouseEvent"]
|
||||
[connection signal="mouse_entered" from="TargetButtons/Area2D" to="." method="StartHoverTarget"]
|
||||
[connection signal="mouse_exited" from="TargetButtons/Area2D" to="." method="EndHoverTarget"]
|
||||
[connection signal="input_event" from="FightButtons/AttackButton/Area2D" to="." method="AttackMouseEvent"]
|
||||
@@ -0,0 +1,84 @@
|
||||
[gd_scene load_steps=7 format=3 uid="uid://cpanatqdjjpa3"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://by88f32fou7lh" path="res://scripts/CSharp/Common/Fight/Fighter.cs" id="1_f3j2x"]
|
||||
[ext_resource type="Texture2D" uid="uid://om2axn1vfa5o" path="res://art/animation/Vesna2D/Vesna Anims Sequences/S01-Idle/0001.png" id="2_2ud32"]
|
||||
[ext_resource type="Texture2D" uid="uid://qlfwuakhe57t" path="res://art/ui/UI/attack_select_wheel.png" id="3_80knd"]
|
||||
[ext_resource type="Texture2D" uid="uid://bn56p0ytuo060" path="res://art/ui/UI/AttackButton.png" id="4_0tqnl"]
|
||||
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_0tqnl"]
|
||||
radius = 291.58
|
||||
|
||||
[sub_resource type="CircleShape2D" id="CircleShape2D_4r2vf"]
|
||||
radius = 173.44
|
||||
|
||||
[node name="VesnaFighter" type="Node2D" node_paths=PackedStringArray("_attackButtons", "_targetButtons", "_targetMarker", "_healthText", "_visualSprite")]
|
||||
script = ExtResource("1_f3j2x")
|
||||
name = "Vesna"
|
||||
maxHealth = 100
|
||||
attackStrength = 10
|
||||
_attackButtons = NodePath("FightButtons")
|
||||
_targetButtons = NodePath("TargetButtons")
|
||||
_targetMarker = NodePath("TargetButtons/TargetMarker")
|
||||
_healthText = NodePath("HealthShow")
|
||||
_visualSprite = NodePath("Sprite2D")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("2_2ud32")
|
||||
offset = Vector2(43, -379)
|
||||
|
||||
[node name="TargetButtons" type="Node2D" parent="."]
|
||||
visible = false
|
||||
|
||||
[node name="TargetMarker" type="Sprite2D" parent="TargetButtons"]
|
||||
visible = false
|
||||
z_index = 200
|
||||
position = Vector2(8, -122)
|
||||
scale = Vector2(4.245, 4.245)
|
||||
texture = ExtResource("3_80knd")
|
||||
|
||||
[node name="Area2D" type="Area2D" parent="TargetButtons"]
|
||||
position = Vector2(3, -76)
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="TargetButtons/Area2D"]
|
||||
shape = SubResource("CircleShape2D_0tqnl")
|
||||
|
||||
[node name="FightButtons" type="Node2D" parent="."]
|
||||
visible = false
|
||||
position = Vector2(3, -714)
|
||||
|
||||
[node name="CircleBackground" type="Sprite2D" parent="FightButtons"]
|
||||
z_index = 200
|
||||
scale = Vector2(4.245, 4.245)
|
||||
texture = ExtResource("3_80knd")
|
||||
|
||||
[node name="AttackButton" type="Node2D" parent="FightButtons"]
|
||||
position = Vector2(0, -536)
|
||||
|
||||
[node name="ButtonBackground" type="Sprite2D" parent="FightButtons/AttackButton"]
|
||||
z_index = 200
|
||||
scale = Vector2(2.48, 2.48)
|
||||
texture = ExtResource("4_0tqnl")
|
||||
|
||||
[node name="Area2D" type="Area2D" parent="FightButtons/AttackButton"]
|
||||
collision_layer = 16
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="FightButtons/AttackButton/Area2D"]
|
||||
shape = SubResource("CircleShape2D_4r2vf")
|
||||
|
||||
[node name="HealthShow" type="Label" parent="."]
|
||||
z_index = 200
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = -197.0
|
||||
offset_top = -947.0
|
||||
offset_right = 207.0
|
||||
offset_bottom = -801.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_override_font_sizes/font_size = 106
|
||||
text = "100/100"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[connection signal="input_event" from="FightButtons/AttackButton/Area2D" to="." method="AttackMouseEvent"]
|
||||
+3
-1
@@ -26,8 +26,9 @@ buses/default_bus_layout="uid://b6dwkmkyb0axk"
|
||||
|
||||
Dialogic="*res://addons/dialogic/Core/DialogicGameHandler.gd"
|
||||
InventoryManager="*res://scripts/CSharp/Common/Inventory/InventoryManager.cs"
|
||||
Signal_Debugger="*res://addons/SignalVisualizer/Debugger/SignalDebugger.gd"
|
||||
QuestManager="*res://scripts/CSharp/Common/Quest/QuestManager.cs"
|
||||
FightManagerAutoload="*res://prefabs/fight/fight_manager_autoload.tscn"
|
||||
Signal_Debugger="*res://addons/SignalVisualizer/Debugger/SignalDebugger.gd"
|
||||
|
||||
[dialogic]
|
||||
|
||||
@@ -213,6 +214,7 @@ locale/translations=PackedStringArray("res://dialog/translations/dialogic_charac
|
||||
3d_physics/layer_1="General"
|
||||
2d_physics/layer_2="Background elements"
|
||||
2d_physics/layer_3="player"
|
||||
2d_physics/layer_5="fight ui"
|
||||
3d_physics/layer_5="Player"
|
||||
|
||||
[rendering]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,27 @@
|
||||
using Babushka.scripts.CSharp.Common.Fight;
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Camera;
|
||||
|
||||
public partial class CameraController : Camera2D
|
||||
{
|
||||
[Export] private Node2D _followNode;
|
||||
#region Singleton ( Contains _EnterTree() ) // TODO: use autoload or other solution
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
this.GlobalPosition = _followNode.GlobalPosition;
|
||||
}
|
||||
public static CameraController Instance { get; private set; } = null!;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[Export] private Node2D _followNode;
|
||||
|
||||
public FightInstance? fightToShow;
|
||||
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
this.GlobalPosition = fightToShow?.camPositionNode.GlobalPosition ?? _followNode.GlobalPosition;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Babushka.scripts.CSharp.Common.Camera;
|
||||
using Babushka.scripts.CSharp.Common.Util;
|
||||
using Godot;
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class FightInstance : Node2D //TODO: remake
|
||||
{
|
||||
[Export(PropertyHint.ArrayType)] private Node2D[] _friendlyFightSpots;
|
||||
[Export(PropertyHint.ArrayType)] private Node2D[] _enemyFightSpots;
|
||||
[Export] public Node2D camPositionNode;
|
||||
[Export] private FightStateManager _fightStateManager;
|
||||
[Export] private Label _fightEndText;
|
||||
|
||||
|
||||
[Signal]
|
||||
public delegate void FightStartedEventHandler();
|
||||
|
||||
[Signal]
|
||||
public delegate void FightEndedEventHandler();
|
||||
|
||||
private List<Fighter> _friendlyFighters = new();
|
||||
private List<Fighter> _enemyFighters = new();
|
||||
|
||||
private FightAttack? _stagedAttack = null;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
//_fightStateManager.CurrentFightState = FightStateManager.FightState.FightStartAnim;
|
||||
_fightStateManager.ExitingTransition += from =>
|
||||
{
|
||||
switch (from)
|
||||
{
|
||||
case FightStateManager.FightState.None:
|
||||
CaptureCamera();
|
||||
Show();
|
||||
EmitSignalFightStarted();
|
||||
break;
|
||||
case FightStateManager.FightState.Input:
|
||||
HideAttackButtons();
|
||||
break;
|
||||
case FightStateManager.FightState.InputTargetSelect:
|
||||
HideTargetButtons();
|
||||
break;
|
||||
case FightStateManager.FightState.FriendAttackAnim:
|
||||
_stagedAttack = null;
|
||||
break;
|
||||
case FightStateManager.FightState.PlayerWinAnim:
|
||||
case FightStateManager.FightState.EnemyWinAnim:
|
||||
_fightEndText.Text = "";
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
_fightStateManager.EnteringTransition += to =>
|
||||
{
|
||||
switch (to)
|
||||
{
|
||||
case FightStateManager.FightState.None:
|
||||
EmitSignalFightEnded();
|
||||
CleanUp();
|
||||
Hide();
|
||||
ReleaseCamera();
|
||||
break;
|
||||
case FightStateManager.FightState.Input:
|
||||
if (CheckWin())
|
||||
{
|
||||
break;
|
||||
}
|
||||
ShowAttackButtons();
|
||||
break;
|
||||
case FightStateManager.FightState.InputTargetSelect:
|
||||
ShowTargetButtons();
|
||||
break;
|
||||
case FightStateManager.FightState.FriendAttackAnim:
|
||||
ExecuteAttack();
|
||||
GetTree().CreateTimer(1).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.Enemy;
|
||||
break;
|
||||
case FightStateManager.FightState.Enemy:
|
||||
if (CheckWin())
|
||||
{
|
||||
break;
|
||||
}
|
||||
DecideEnemyAttack();
|
||||
_fightStateManager.CurrentFightState = FightStateManager.FightState.EnemyAttackAnim;
|
||||
break;
|
||||
case FightStateManager.FightState.EnemyAttackAnim:
|
||||
ExecuteAttack();
|
||||
GetTree().CreateTimer(1).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.Input;
|
||||
break;
|
||||
case FightStateManager.FightState.PlayerWinAnim:
|
||||
_fightEndText.Text = "You Win!";
|
||||
GetTree().CreateTimer(3).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.None;
|
||||
break;
|
||||
case FightStateManager.FightState.EnemyWinAnim:
|
||||
_fightEndText.Text = "You Died :(";
|
||||
GetTree().CreateTimer(3).Timeout += () => _fightStateManager.CurrentFightState = FightStateManager.FightState.None;
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
private void CleanUp()
|
||||
{
|
||||
_enemyFighters.ForEach(f => f.QueueFree());
|
||||
_friendlyFighters.ForEach(f => f.QueueFree());
|
||||
_enemyFighters = new();
|
||||
_friendlyFighters = new();
|
||||
}
|
||||
private void DecideEnemyAttack()
|
||||
{
|
||||
var aliveEnemyFighters = _enemyFighters.Where(f => !f.IsDead()).ToList();
|
||||
var aliveFriendlyFighters = _friendlyFighters.Where(f => !f.IsDead()).ToList();
|
||||
|
||||
if (aliveEnemyFighters.Count <= 0)
|
||||
throw new InvalidOperationException("No enemy fighters available for attack.");
|
||||
|
||||
if (aliveFriendlyFighters.Count <= 0)
|
||||
throw new InvalidOperationException("No friendly fighters available to target.");
|
||||
|
||||
var fighter = aliveEnemyFighters.Random();
|
||||
var target = aliveFriendlyFighters.Random();
|
||||
|
||||
_stagedAttack = new FightAttack
|
||||
{
|
||||
attacker = fighter!,
|
||||
needsSelectedTarget = true,
|
||||
damage = fighter!.attackStrength,
|
||||
target = target!
|
||||
};
|
||||
}
|
||||
|
||||
private void ExecuteAttack()
|
||||
{
|
||||
if (_stagedAttack == null)
|
||||
throw new InvalidOperationException("No staged attack to execute.");
|
||||
|
||||
if (!_stagedAttack.needsSelectedTarget)
|
||||
throw new NotImplementedException("Non-targeted attacks are not implemented yet.");
|
||||
|
||||
if (_stagedAttack.needsSelectedTarget && _stagedAttack.target == null)
|
||||
throw new InvalidOperationException("No target selected for the staged attack.");
|
||||
|
||||
_stagedAttack.target!.Health -= _stagedAttack.damage;
|
||||
|
||||
_stagedAttack.attacker.AttackAnimation(_stagedAttack);
|
||||
|
||||
UpdateHealthVisual();
|
||||
}
|
||||
|
||||
private void UpdateHealthVisual()
|
||||
{
|
||||
_friendlyFighters
|
||||
.Concat(_enemyFighters)
|
||||
.ForEach(f => f.UpdateHealthVisual());
|
||||
}
|
||||
|
||||
private void ReleaseCamera()
|
||||
{
|
||||
CameraController.Instance.fightToShow = null;
|
||||
}
|
||||
|
||||
private void CaptureCamera()
|
||||
{
|
||||
CameraController.Instance.fightToShow = this;
|
||||
}
|
||||
|
||||
public void Start(FightParty fightParty, PackedScene?[] enemies)
|
||||
{
|
||||
if (_fightStateManager.IsRunning())
|
||||
{
|
||||
GD.PushWarning("Can not start a running fight");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fightParty.vesna)
|
||||
{
|
||||
InstantiateFighter(_friendlyFightSpots[1], FightManager.Instance.fightingVesnaScene);
|
||||
}
|
||||
|
||||
for (var i = 0; i < Math.Min(_enemyFightSpots.Length, enemies.Length); i++)
|
||||
{
|
||||
var enemy = enemies[i];
|
||||
if (enemy == null)
|
||||
continue;
|
||||
|
||||
InstantiateFighter(_enemyFightSpots[i], enemy, true);
|
||||
}
|
||||
|
||||
_fightStateManager.ToStartAnim();
|
||||
}
|
||||
|
||||
private void InstantiateFighter(Node2D parent, PackedScene fighterScene, bool isEnemy = false)
|
||||
{
|
||||
var fighter = fighterScene.Instantiate<Fighter>();
|
||||
fighter.fightInstance = this;
|
||||
parent.AddChild(fighter);
|
||||
|
||||
if (isEnemy)
|
||||
{
|
||||
_enemyFighters.Add(fighter);
|
||||
}
|
||||
else
|
||||
{
|
||||
_friendlyFighters.Add(fighter);
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectAttack(Fighter fighter)
|
||||
{
|
||||
_stagedAttack = new FightAttack
|
||||
{
|
||||
attacker = fighter,
|
||||
damage = fighter.attackStrength,
|
||||
needsSelectedTarget = true
|
||||
};
|
||||
|
||||
if (_stagedAttack.needsSelectedTarget)
|
||||
{
|
||||
_fightStateManager.CurrentFightState = FightStateManager.FightState.InputTargetSelect;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fightStateManager.CurrentFightState = FightStateManager.FightState.FriendAttackAnim;
|
||||
}
|
||||
}
|
||||
|
||||
private void HideAttackButtons()
|
||||
{
|
||||
_friendlyFighters.ForEach(f => f.HideAttackButton());
|
||||
}
|
||||
|
||||
private void ShowAttackButtons()
|
||||
{
|
||||
_friendlyFighters.ForEach(f => f.ShowAttackButton());
|
||||
}
|
||||
|
||||
private void HideTargetButtons()
|
||||
{
|
||||
_enemyFighters.ForEach(f => f.HideTargetButtons());
|
||||
}
|
||||
|
||||
private void ShowTargetButtons()
|
||||
{
|
||||
_enemyFighters.ForEach(f => f.ShowTargetButtons());
|
||||
}
|
||||
|
||||
public void SelectTargetAndAttack(Fighter fighter)
|
||||
{
|
||||
if (_stagedAttack == null)
|
||||
throw new InvalidOperationException("No staged attack to select target for.");
|
||||
|
||||
_stagedAttack.target = fighter;
|
||||
|
||||
_fightStateManager.CurrentFightState = FightStateManager.FightState.FriendAttackAnim;
|
||||
}
|
||||
|
||||
public bool CheckWin()
|
||||
{
|
||||
if (_enemyFighters.All(f => f.IsDead()))
|
||||
{
|
||||
_fightStateManager.CurrentFightState = FightStateManager.FightState.PlayerWinAnim;
|
||||
return true;
|
||||
}
|
||||
if (_friendlyFighters.All(f => f.IsDead()))
|
||||
{
|
||||
_fightStateManager.CurrentFightState = FightStateManager.FightState.EnemyWinAnim;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public class FightAttack
|
||||
{
|
||||
public int damage;
|
||||
public bool needsSelectedTarget;
|
||||
public Fighter? target;
|
||||
public Fighter attacker;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://c76mhhqyk4lgh
|
||||
@@ -0,0 +1,28 @@
|
||||
using Godot;
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class FightManager : Node
|
||||
{
|
||||
#region AutoLoad ( Contains _EnterTree() )
|
||||
|
||||
public static FightManager Instance { get; private set; } = null!;
|
||||
|
||||
public override void _EnterTree()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[Export]
|
||||
public PackedScene fightingVesnaScene;
|
||||
|
||||
public FightParty fightParty = new();
|
||||
|
||||
public void StartFight(PackedScene[] enemies, FightInstance instance)
|
||||
{
|
||||
GD.Print("Starting Fight");
|
||||
instance.Start(fightParty, enemies);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://j5ge24rk25wm
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public class FightParty
|
||||
{
|
||||
public bool vesna = true;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cvhgnboybc4cm
|
||||
@@ -0,0 +1,19 @@
|
||||
using Godot;
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class FightStarter : Node
|
||||
{
|
||||
[Export(PropertyHint.ArrayType)] private PackedScene[] enemies;
|
||||
[Export] private FightInstance _fightInstance;
|
||||
[Export] private bool _once = true;
|
||||
private bool hasBeenStarted = false;
|
||||
|
||||
public void Start(Node2D _)
|
||||
{
|
||||
if (_once && hasBeenStarted)
|
||||
return;
|
||||
|
||||
hasBeenStarted = true;
|
||||
FightManager.Instance.StartFight(enemies, _fightInstance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://di0xxwfw43m0i
|
||||
@@ -0,0 +1,73 @@
|
||||
using Godot;
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class FightStateManager : Node
|
||||
{
|
||||
[Signal]
|
||||
public delegate void ExitingTransitionEventHandler(FightState exitingState);
|
||||
|
||||
[Signal]
|
||||
public delegate void EnteringTransitionEventHandler(FightState enteringState);
|
||||
|
||||
public enum FightState
|
||||
{
|
||||
None,
|
||||
FightStartAnim,
|
||||
Input,
|
||||
InputTargetSelect,
|
||||
FriendAttackAnim,
|
||||
Enemy,
|
||||
EnemyAttackAnim,
|
||||
PlayerWinAnim,
|
||||
EnemyWinAnim
|
||||
}
|
||||
|
||||
private FightState _fightStateBacking = FightState.None;
|
||||
|
||||
public FightState CurrentFightState
|
||||
{
|
||||
set => Transition(_fightStateBacking, value);
|
||||
get => _fightStateBacking;
|
||||
}
|
||||
|
||||
private void Transition(FightState from, FightState to)
|
||||
{
|
||||
if(from == to)
|
||||
return;
|
||||
|
||||
GD.Print($"Transitioning from {from} to {to}");
|
||||
ExitTransition(from);
|
||||
_fightStateBacking = to;
|
||||
EnterTransition(to);
|
||||
}
|
||||
|
||||
private void ExitTransition(FightState from)
|
||||
{
|
||||
EmitSignalExitingTransition(from);
|
||||
}
|
||||
|
||||
private void EnterTransition(FightState to)
|
||||
{
|
||||
EmitSignalEnteringTransition(to);
|
||||
switch (to)
|
||||
{
|
||||
case FightState.FightStartAnim:
|
||||
EnterFightStartAnim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void EnterFightStartAnim()
|
||||
{
|
||||
GetTree().CreateTimer(1).Timeout += () => CurrentFightState = FightState.Input;
|
||||
}
|
||||
|
||||
public void ToStartAnim()
|
||||
{
|
||||
CurrentFightState = FightState.FightStartAnim;
|
||||
}
|
||||
|
||||
public bool IsRunning()
|
||||
{
|
||||
return CurrentFightState != FightState.None;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://oe1uypehqvr7
|
||||
@@ -0,0 +1,131 @@
|
||||
using Godot;
|
||||
namespace Babushka.scripts.CSharp.Common.Fight;
|
||||
|
||||
public partial class Fighter : Node2D
|
||||
{
|
||||
[Export] public string name;
|
||||
[Export] public int maxHealth;
|
||||
[Export] public int attackStrength;
|
||||
|
||||
[ExportCategory("References")]
|
||||
[Export] private Node2D _attackButtons;
|
||||
[Export] private Node2D _targetButtons;
|
||||
[Export] private Node2D _targetMarker;
|
||||
[Export] private Label _healthText;
|
||||
[Export] private Node2D _visualSprite;
|
||||
|
||||
|
||||
private int _health;
|
||||
|
||||
|
||||
public FightInstance fightInstance;
|
||||
public int Health
|
||||
{
|
||||
get => _health;
|
||||
set
|
||||
{
|
||||
_health = value;
|
||||
if (_health <= 0)
|
||||
{
|
||||
_health = 0;
|
||||
Die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Die()
|
||||
{
|
||||
_visualSprite.Scale = new Vector2(1, 0.3f);
|
||||
}
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
Health = maxHealth;
|
||||
UpdateHealthVisual();
|
||||
}
|
||||
|
||||
public void Attack()
|
||||
{
|
||||
fightInstance.SelectAttack(this);
|
||||
}
|
||||
|
||||
public void HideAttackButton()
|
||||
{
|
||||
_attackButtons.Hide();
|
||||
}
|
||||
|
||||
public void ShowAttackButton()
|
||||
{
|
||||
_attackButtons.Show();
|
||||
}
|
||||
|
||||
public void HideTargetButtons()
|
||||
{
|
||||
_targetButtons.Hide();
|
||||
}
|
||||
|
||||
public void ShowTargetButtons()
|
||||
{
|
||||
_targetButtons.Show();
|
||||
}
|
||||
|
||||
public void TargetMouseEvent(Node viewport, InputEvent inputEvent, int shapeIdx)
|
||||
{
|
||||
if (inputEvent.IsPressed())
|
||||
ClickedTarget();
|
||||
}
|
||||
|
||||
public void AttackMouseEvent(Node viewport, InputEvent inputEvent, int shapeIdx)
|
||||
{
|
||||
if (inputEvent.IsPressed())
|
||||
ClickedAttack();
|
||||
}
|
||||
|
||||
private void ClickedAttack()
|
||||
{
|
||||
fightInstance.SelectAttack(this);
|
||||
}
|
||||
|
||||
private void ClickedTarget()
|
||||
{
|
||||
fightInstance.SelectTargetAndAttack(this);
|
||||
}
|
||||
|
||||
public void StartHoverTarget()
|
||||
{
|
||||
_targetMarker.Visible = true;
|
||||
}
|
||||
|
||||
public void EndHoverTarget()
|
||||
{
|
||||
_targetMarker.Visible = false;
|
||||
}
|
||||
|
||||
public void UpdateHealthVisual()
|
||||
{
|
||||
_healthText.Text = $"{Health}/{maxHealth}";
|
||||
}
|
||||
|
||||
public void AttackAnimation(FightAttack attack)
|
||||
{
|
||||
var tween = GetTree().CreateTween();
|
||||
tween.TweenProperty(this, "global_position", attack.target.GlobalPosition, 0.15);
|
||||
tween.TweenCallback(Callable.From(() => attack.target?.HitAnimation(attack)));
|
||||
tween.TweenProperty(this, "position", new Vector2(0, 0), 0.7)
|
||||
.SetTrans(Tween.TransitionType.Cubic).SetEase(Tween.EaseType.Out);
|
||||
|
||||
}
|
||||
|
||||
private void HitAnimation(FightAttack attack)
|
||||
{
|
||||
var tween = GetTree().CreateTween();
|
||||
tween.TweenProperty(this, "scale", new Vector2(1.4f, 0.6f), 0.15);
|
||||
tween.TweenProperty(this, "scale", new Vector2(1,1), 0.4)
|
||||
.SetTrans(Tween.TransitionType.Cubic).SetEase(Tween.EaseType.Out);
|
||||
}
|
||||
|
||||
public bool IsDead()
|
||||
{
|
||||
return Health <= 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://by88f32fou7lh
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SqlTypes;
|
||||
using System.Linq;
|
||||
using System.Xml.Schema;
|
||||
namespace Babushka.scripts.CSharp.Common.Util;
|
||||
|
||||
public static class LinqExtras
|
||||
{
|
||||
public static void ForEach<T>(this IEnumerable<T> self, Action<T> action)
|
||||
{
|
||||
foreach (var t in self)
|
||||
{
|
||||
action.Invoke(t);
|
||||
}
|
||||
}
|
||||
|
||||
public static T? Random<T>(this IEnumerable<T> self)
|
||||
{
|
||||
var selfList = self.ToList();
|
||||
if (selfList.Count == 0) return default;
|
||||
if (selfList.Count == 1) return selfList[0];
|
||||
var randomIndex = new Random().Next(0, selfList.Count);
|
||||
return selfList[randomIndex];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user