mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 07:45:33 +00:00
2D Character and weapons
This commit is contained in:
parent
072f6d0ce6
commit
cc9c4e5aa1
37 changed files with 1115 additions and 91 deletions
|
|
@ -1,10 +1,11 @@
|
|||
[gd_scene load_steps=56 format=3 uid="uid://ec4m3geediis"]
|
||||
[gd_scene load_steps=57 format=3 uid="uid://ec4m3geediis"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://cvisn0b641od4" path="res://addons/cyclops_level_builder/nodes/cyclops_block.gd" id="1_18fbr"]
|
||||
[ext_resource type="Script" uid="uid://ba0tf7ihw4hpp" path="res://Scripts/Misc/CameraController3D.cs" id="1_g4gcm"]
|
||||
[ext_resource type="Script" uid="uid://b8g8mflgsr5dc" path="res://Scripts/GameController.cs" id="1_joeuf"]
|
||||
[ext_resource type="PackedScene" uid="uid://dkwi1hu1bixoe" path="res://Scenes/HUD/HUD.tscn" id="2_itd0i"]
|
||||
[ext_resource type="Script" uid="uid://djeq3sxhsep3c" path="res://addons/cyclops_level_builder/resources/data_vector_byte.gd" id="2_kler0"]
|
||||
[ext_resource type="Script" uid="uid://c5nxsq3tyxcx6" path="res://Scripts/InventoryManager.cs" id="3_itd0i"]
|
||||
[ext_resource type="Script" uid="uid://civ3w78ahacnu" path="res://addons/cyclops_level_builder/resources/data_vector_int.gd" id="3_k6bah"]
|
||||
[ext_resource type="Script" uid="uid://db41w3h28c2la" path="res://addons/cyclops_level_builder/resources/data_vector_float.gd" id="4_01bfr"]
|
||||
[ext_resource type="Script" uid="uid://c43o57os2lmc3" path="res://addons/cyclops_level_builder/resources/mesh_vector_data.gd" id="5_hmj6t"]
|
||||
|
|
@ -417,6 +418,9 @@ script = ExtResource("1_joeuf")
|
|||
|
||||
[node name="HUD" parent="GameController" instance=ExtResource("2_itd0i")]
|
||||
|
||||
[node name="InventoryManager" type="Node" parent="GameController"]
|
||||
script = ExtResource("3_itd0i")
|
||||
|
||||
[node name="block0" type="Node3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0)
|
||||
script = ExtResource("1_18fbr")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=19 format=3 uid="uid://rimplblbptcd"]
|
||||
[gd_scene load_steps=22 format=3 uid="uid://rimplblbptcd"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://88smibkin17p" path="res://Scripts/Components/FSM/3DPlayer/IsoPlayerFSMProxy.cs" id="1_cc7e7"]
|
||||
[ext_resource type="Texture2D" uid="uid://ddwhrlrgj6i00" path="res://Sprites/Actors/Cirno.png" id="1_vex34"]
|
||||
|
|
@ -8,11 +8,14 @@
|
|||
[ext_resource type="Script" uid="uid://c5brx3ail1tlh" path="res://Scripts/Components/FSM/3DPlayer/IsoMovementModule.cs" id="5_fg04g"]
|
||||
[ext_resource type="Script" uid="uid://eop2ue3otxcs" path="res://Scripts/Components/FSM/3DPlayer/IsoPlayerStorageModule.cs" id="6_habpy"]
|
||||
[ext_resource type="Script" uid="uid://dq338w2lw5phl" path="res://Scripts/Components/Actors/KeyboardInputProvider.cs" id="7_4cdxq"]
|
||||
[ext_resource type="Script" uid="uid://1fryvj4omkin" path="res://Scripts/Components/Actors/MouseAimProvider3D.cs" id="9_2ffwi"]
|
||||
[ext_resource type="Script" uid="uid://c8ar11sg0su2h" path="res://Scripts/Components/FSM/3DPlayer/ShadowModule.cs" id="9_fg04g"]
|
||||
[ext_resource type="Script" uid="uid://bm73kgly8gv2i" path="res://Scripts/Components/FSM/3DPlayer/IsoInteractionController.cs" id="10_habpy"]
|
||||
[ext_resource type="Script" uid="uid://d1ixvdcii6uy7" path="res://Scripts/Components/FSM/3DPlayer/SelectorController.cs" id="11_4cdxq"]
|
||||
[ext_resource type="Script" uid="uid://vne180ohyucn" path="res://Scripts/Components/FSM/3DPlayer/IsoActivationProvider.cs" id="11_4exx2"]
|
||||
[ext_resource type="AudioStream" uid="uid://myr6n2c1u503" path="res://SFX/581602__samsterbirdies__beep-error.mp3" id="13_2ffwi"]
|
||||
[ext_resource type="Script" uid="uid://d2psafx4f3f58" path="res://Scripts/Components/FSM/3DPlayer/PlayerWeaponModule3D.cs" id="15_el8as"]
|
||||
[ext_resource type="Script" uid="uid://by0x0qmbmkoak" path="res://Scripts/Components/FSM/3DPlayer/PlayerWeaponProvider3D.cs" id="16_olwak"]
|
||||
|
||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_fg04g"]
|
||||
radius = 0.349554
|
||||
|
|
@ -47,7 +50,7 @@ script = ExtResource("2_3oyrx")
|
|||
|
||||
[node name="Active" type="Node" parent="StateMachine" node_paths=PackedStringArray("_moduleNodes")]
|
||||
script = ExtResource("3_cc7e7")
|
||||
_moduleNodes = [NodePath("../../InputProvider"), NodePath("../../MovementModule"), NodePath("../../ShadowModule"), NodePath("../../InteractionController"), NodePath("../../ActivationProvider")]
|
||||
_moduleNodes = [NodePath("../../InputProvider"), NodePath("../../MovementModule"), NodePath("../../ShadowModule"), NodePath("../../InteractionController"), NodePath("../../ActivationProvider"), NodePath("../../WeaponModule")]
|
||||
|
||||
[node name="Sprite" type="Sprite3D" parent="."]
|
||||
transform = Transform3D(0.707107, -0.5, 0.5, 0, 0.707107, 0.707107, -0.707107, -0.5, 0.5, 0, 0, 0)
|
||||
|
|
@ -80,6 +83,9 @@ Root = NodePath("..")
|
|||
[node name="InputProvider" type="Node" parent="."]
|
||||
script = ExtResource("7_4cdxq")
|
||||
|
||||
[node name="MouseAimProvider" type="Node3D" parent="InputProvider"]
|
||||
script = ExtResource("9_2ffwi")
|
||||
|
||||
[node name="Shadow" type="MeshInstance3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, -0.29, 0)
|
||||
mesh = SubResource("QuadMesh_fg04g")
|
||||
|
|
@ -120,3 +126,13 @@ bus = &"Effects"
|
|||
|
||||
[node name="AudioListener3D" type="AudioListener3D" parent="."]
|
||||
current = true
|
||||
|
||||
[node name="WeaponModule" type="Node" parent="." node_paths=PackedStringArray("WeaponProvider", "InputProvider", "Storage")]
|
||||
script = ExtResource("15_el8as")
|
||||
WeaponProvider = NodePath("WeaponProvider")
|
||||
InputProvider = NodePath("../InputProvider")
|
||||
Storage = NodePath("../Storage")
|
||||
|
||||
[node name="WeaponProvider" type="Node" parent="WeaponModule" node_paths=PackedStringArray("StorageModule")]
|
||||
script = ExtResource("16_olwak")
|
||||
StorageModule = NodePath("../../Storage")
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=91 format=3 uid="uid://c4pr2707hbeph"]
|
||||
[gd_scene load_steps=92 format=3 uid="uid://c4pr2707hbeph"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://d2ubk5gucny6s" path="res://Scripts/Components/FSM/PlayerFSMProxy.cs" id="1_g3wua"]
|
||||
[ext_resource type="Script" uid="uid://bw2hakslndaxm" path="res://Scripts/Components/FSM/PlayerStateMachine.cs" id="1_mpmil"]
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
[ext_resource type="Script" uid="uid://cqwvssstkrdmw" path="res://Scripts/Components/Actors/ActorResourceProvider.cs" id="15_5qlss"]
|
||||
[ext_resource type="Texture2D" uid="uid://cf2855sd3hqty" path="res://Sprites/Actors/Aiming_Reticule_Small.png" id="19_fnw0c"]
|
||||
[ext_resource type="Texture2D" uid="uid://bc4tp44e00g0d" path="res://Sprites/Actors/Focus_Square.png" id="20_3ho10"]
|
||||
[ext_resource type="Script" uid="uid://bfmnmk0rfwa1i" path="res://Scripts/Components/Actors/MouseAimProvider2D.cs" id="20_3rkrn"]
|
||||
[ext_resource type="Script" uid="uid://dv205x8msohpv" path="res://Scripts/Components/Actors/ActivationProvider.cs" id="22_12cwd"]
|
||||
[ext_resource type="PackedScene" uid="uid://chkpk7erlqajg" path="res://Scenes/Selector.tscn" id="23_5tmtw"]
|
||||
[ext_resource type="AudioStream" uid="uid://myr6n2c1u503" path="res://SFX/581602__samsterbirdies__beep-error.mp3" id="24_5tmtw"]
|
||||
|
|
@ -383,7 +384,7 @@ _animationProvider = NodePath("../../AnimationProvider")
|
|||
[node name="Dead" type="Node2D" parent="StateMachine" node_paths=PackedStringArray("_animationProvider", "_inputProvider", "_healthProvider", "_motivationProvider")]
|
||||
script = ExtResource("4_0pqs8")
|
||||
_animationProvider = NodePath("../../AnimationProvider")
|
||||
_inputProvider = NodePath("../../InputProvider")
|
||||
_inputProvider = NodePath("")
|
||||
_healthProvider = NodePath("../../DamageReceiver/HealthProvider")
|
||||
_motivationProvider = NodePath("../../DamageReceiver/MotivationProvider")
|
||||
|
||||
|
|
@ -444,9 +445,12 @@ script = ExtResource("7_pmkfo")
|
|||
_animatedSprite = NodePath("../Legs")
|
||||
BlinkMaterial = ExtResource("4_5qlss")
|
||||
|
||||
[node name="InputProvider" type="Node2D" parent="."]
|
||||
[node name="InputProvider" type="Node" parent="."]
|
||||
script = ExtResource("8_i6wc8")
|
||||
|
||||
[node name="MouseAimProvider" type="Node2D" parent="InputProvider"]
|
||||
script = ExtResource("20_3rkrn")
|
||||
|
||||
[node name="CrosshairProvider" type="Node2D" parent="." node_paths=PackedStringArray("StorageModule", "AnimatedSprite")]
|
||||
script = ExtResource("9_s0ir4")
|
||||
StorageModule = NodePath("../Storage")
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ public partial class Barrel : Area2D, IDestructible
|
|||
if (ExplosionData == null) return;
|
||||
|
||||
|
||||
var explosion = PoolingManager.Instance.SpawnBullet(ExplosionData);
|
||||
var explosion = PoolingManager.Instance.SpawnBullet<Bullet>(ExplosionData);
|
||||
explosion.GlobalPosition = this.GlobalPosition;
|
||||
|
||||
//var explosion = this.CreateSibling<Bullet>(ExplosionData.BulletScene);
|
||||
|
|
|
|||
|
|
@ -1313,7 +1313,7 @@ position = Vector2(-2000, -736)
|
|||
[node name="ControlPad8" parent="Parallax2D/Factory Tilemaps/LevelProps" node_paths=PackedStringArray("Targets") instance=ExtResource("12_hfkf1")]
|
||||
position = Vector2(-2027, -735)
|
||||
Targets = [NodePath("../HorizontalForceField")]
|
||||
Requirements = Array[ExtResource("36_pt47r")]([ExtResource("84_ma1ta")])
|
||||
Requirements = [ExtResource("84_ma1ta")]
|
||||
|
||||
[node name="Ammo6" parent="Parallax2D/Factory Tilemaps/LevelProps" instance=ExtResource("34_17pjh")]
|
||||
position = Vector2(-872, -220)
|
||||
|
|
|
|||
|
|
@ -7,10 +7,11 @@ using Cirno.Scripts;
|
|||
using Cirno.Scripts.Components;
|
||||
using Cirno.Scripts.Controllers;
|
||||
using Cirno.Scripts.Resources;
|
||||
using Cirno.Scripts.Weapons;
|
||||
|
||||
public partial class Bullet : Area2D
|
||||
public partial class Bullet : Area2D, IBullet
|
||||
{
|
||||
[Export] public float Speed = 1900f;
|
||||
[Export] public float Speed { get; set; } = 1900f;
|
||||
|
||||
public BulletOwner BulletOwner => _bulletInfo?.Owner ?? BulletOwner.None;
|
||||
|
||||
|
|
@ -336,21 +337,4 @@ public partial class Bullet : Area2D
|
|||
//QueueFree();
|
||||
PoolingManager.Instance.DisableBullet(this);
|
||||
}
|
||||
}
|
||||
|
||||
public enum BulletOwner
|
||||
{
|
||||
None,
|
||||
Player,
|
||||
Enemy
|
||||
}
|
||||
|
||||
public enum DamageType
|
||||
{
|
||||
Neutral,
|
||||
Ballistic,
|
||||
Fire,
|
||||
Ice,
|
||||
Explosive,
|
||||
Acid
|
||||
}
|
||||
6
Scripts/BulletOwner.cs
Normal file
6
Scripts/BulletOwner.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
public enum BulletOwner
|
||||
{
|
||||
None,
|
||||
Player,
|
||||
Enemy
|
||||
}
|
||||
1
Scripts/BulletOwner.cs.uid
Normal file
1
Scripts/BulletOwner.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c6d6jblnwc5uy
|
||||
9
Scripts/Components/Actors/IMouseAimProvider.cs
Normal file
9
Scripts/Components/Actors/IMouseAimProvider.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Components.Actors;
|
||||
|
||||
public interface IMouseAimProvider
|
||||
{
|
||||
public Vector2 GetMouseAimInput();
|
||||
}
|
||||
1
Scripts/Components/Actors/IMouseAimProvider.cs.uid
Normal file
1
Scripts/Components/Actors/IMouseAimProvider.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://mr42tbagcs8t
|
||||
|
|
@ -6,28 +6,19 @@ namespace Cirno.Scripts.Components.Actors;
|
|||
|
||||
public partial class KeyboardInputProvider : InputProvider
|
||||
{
|
||||
[ExportCategory("Movement")]
|
||||
[Export]
|
||||
public StringName LeftAxisName { get; private set; } = "left";
|
||||
[Export]
|
||||
public StringName RightAxisName { get; private set; } = "right";
|
||||
[Export]
|
||||
public StringName UpAxisName { get; private set; } = "up";
|
||||
[Export]
|
||||
public StringName DownAxisName { get; private set; } = "down";
|
||||
[ExportCategory("Movement")] [Export] public StringName LeftAxisName { get; private set; } = "left";
|
||||
[Export] public StringName RightAxisName { get; private set; } = "right";
|
||||
[Export] public StringName UpAxisName { get; private set; } = "up";
|
||||
[Export] public StringName DownAxisName { get; private set; } = "down";
|
||||
|
||||
[ExportCategory("Aiming")]
|
||||
[Export]
|
||||
public StringName LeftAimName { get; private set; } = "aim_left";
|
||||
[Export]
|
||||
public StringName RightAimName { get; private set; } = "aim_right";
|
||||
[Export]
|
||||
public StringName UpAimName { get; private set; } = "aim_up";
|
||||
[Export]
|
||||
public StringName DownAimName { get; private set; } = "aim_down";
|
||||
[ExportCategory("Aiming")] [Export] public StringName LeftAimName { get; private set; } = "aim_left";
|
||||
[Export] public StringName RightAimName { get; private set; } = "aim_right";
|
||||
[Export] public StringName UpAimName { get; private set; } = "aim_up";
|
||||
[Export] public StringName DownAimName { get; private set; } = "aim_down";
|
||||
|
||||
[ExportCategory("Action Names")] [Export]
|
||||
private StringName _shootActionName = "shoot";
|
||||
|
||||
[ExportCategory("Action Names")]
|
||||
[Export] private StringName _shootActionName = "shoot";
|
||||
[Export] private StringName _useActionName = "Use";
|
||||
[Export] private StringName _scanActionName = "scan";
|
||||
[Export] private StringName _strafeActionName = "strafe";
|
||||
|
|
@ -38,7 +29,14 @@ public partial class KeyboardInputProvider : InputProvider
|
|||
[Export] private StringName _freezeActionName = "Freeze";
|
||||
[Export] private StringName _reloadActionName = "Reload";
|
||||
|
||||
private enum AimInputMethod { RightStick, Mouse }
|
||||
private IMouseAimProvider _mouseAImProvider;
|
||||
|
||||
private enum AimInputMethod
|
||||
{
|
||||
RightStick,
|
||||
Mouse
|
||||
}
|
||||
|
||||
private AimInputMethod _lastUsedInput = AimInputMethod.RightStick;
|
||||
|
||||
public override void _Ready()
|
||||
|
|
@ -49,11 +47,19 @@ public partial class KeyboardInputProvider : InputProvider
|
|||
|
||||
private void DelayedRegisterGameManager()
|
||||
{
|
||||
_mouseAImProvider = GetNodeOrNull<IMouseAimProvider>("MouseAimProvider");
|
||||
|
||||
if (_mouseAImProvider is null)
|
||||
{
|
||||
GD.Print("Mouse aim provider is null");
|
||||
}
|
||||
|
||||
if (GameManager.Instance is null)
|
||||
{
|
||||
GD.Print("No GameManager found for keyboard inputprovider");
|
||||
return;
|
||||
}
|
||||
|
||||
GameManager.Instance.GameStateChange += InstanceOnGameStateChange;
|
||||
_enabled = true;
|
||||
}
|
||||
|
|
@ -63,7 +69,7 @@ public partial class KeyboardInputProvider : InputProvider
|
|||
private void InstanceOnGameStateChange(GameState state)
|
||||
{
|
||||
if (state is not GameState.Playing) return;
|
||||
|
||||
|
||||
_enabled = false;
|
||||
|
||||
_ = DelayResume();
|
||||
|
|
@ -75,7 +81,7 @@ public partial class KeyboardInputProvider : InputProvider
|
|||
await Task.Delay(200);
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
|
||||
public override Vector2 GetMovementInput()
|
||||
{
|
||||
return Input.GetVector(LeftAxisName, RightAxisName, UpAxisName, DownAxisName);
|
||||
|
|
@ -98,26 +104,27 @@ public partial class KeyboardInputProvider : InputProvider
|
|||
|
||||
return _lastUsedInput == AimInputMethod.RightStick ? rightStickInput : mouseInput;
|
||||
}
|
||||
|
||||
|
||||
private Vector2 GetRightStickInput()
|
||||
{
|
||||
return new Vector2(
|
||||
Input.GetAxis(LeftAimName,RightAimName),
|
||||
Input.GetAxis(LeftAimName, RightAimName),
|
||||
Input.GetAxis(UpAimName, DownAimName)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private Vector2 GetMouseAimInput()
|
||||
{
|
||||
//Camera2D camera = GetViewport().GetCamera2D();
|
||||
//if (camera == null) return Vector2.Zero; // Ensure there's a valid camera
|
||||
|
||||
//Vector2 mouseScreenPos = GetViewport().get_local_mouse_position();
|
||||
if (GameManager.Instance is null) return Vector2.Zero;
|
||||
|
||||
Vector2 mouseWorldPos = DisplayServer.MouseGetPosition();// GameManager.Instance.GetGlobalMousePosition();
|
||||
|
||||
return mouseWorldPos - GameManager.Instance.PlayerPosition.Value; // Get direction vector
|
||||
return _mouseAImProvider?.GetMouseAimInput() ?? Vector2.Zero;
|
||||
// //Camera2D camera = GetViewport().GetCamera2D();
|
||||
// //if (camera == null) return Vector2.Zero; // Ensure there's a valid camera
|
||||
//
|
||||
// //Vector2 mouseScreenPos = GetViewport().get_local_mouse_position();
|
||||
// if (GameManager.Instance is null) return Vector2.Zero;
|
||||
//
|
||||
// Vector2 mouseWorldPos = DisplayServer.MouseGetPosition();// GameManager.Instance.GetGlobalMousePosition();
|
||||
//
|
||||
// return mouseWorldPos - GameManager.Instance.PlayerPosition.Value; // Get direction vector
|
||||
}
|
||||
|
||||
public override bool GetActionJustPressed(string action)
|
||||
|
|
@ -134,12 +141,12 @@ public partial class KeyboardInputProvider : InputProvider
|
|||
{
|
||||
return GetActionJustPressed(_inventoryActionName);
|
||||
}
|
||||
|
||||
|
||||
public override bool GetShootPressed()
|
||||
{
|
||||
return _enabled && GetActionPressed(_shootActionName);
|
||||
}
|
||||
|
||||
|
||||
public override bool GetShootJustPressed()
|
||||
{
|
||||
return GetActionJustPressed(_shootActionName);
|
||||
|
|
@ -149,6 +156,7 @@ public partial class KeyboardInputProvider : InputProvider
|
|||
{
|
||||
return GetActionJustPressed(_useActionName);
|
||||
}
|
||||
|
||||
public override bool GetScanJustPressed()
|
||||
{
|
||||
return GetActionJustPressed(_scanActionName);
|
||||
|
|
@ -173,25 +181,24 @@ public partial class KeyboardInputProvider : InputProvider
|
|||
{
|
||||
return GetActionJustPressed(_pauseActionName);
|
||||
}
|
||||
|
||||
|
||||
public override bool GetFreezeJustPressed()
|
||||
{
|
||||
return GetActionJustPressed(_freezeActionName);
|
||||
}
|
||||
|
||||
|
||||
public override bool GetFreezePressed()
|
||||
{
|
||||
return GetActionPressed(_freezeActionName);
|
||||
}
|
||||
|
||||
|
||||
public override bool GetReloadJustPressed()
|
||||
{
|
||||
return GetActionJustPressed(_reloadActionName);
|
||||
}
|
||||
|
||||
|
||||
public override bool GetReloadPressed()
|
||||
{
|
||||
return GetActionPressed(_reloadActionName);
|
||||
}
|
||||
|
||||
}
|
||||
13
Scripts/Components/Actors/MouseAimProvider2D.cs
Normal file
13
Scripts/Components/Actors/MouseAimProvider2D.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Components.Actors;
|
||||
|
||||
public partial class MouseAimProvider2D : Node2D, IMouseAimProvider
|
||||
{
|
||||
public Vector2 GetMouseAimInput()
|
||||
{
|
||||
var mouseWorldPos = this.GetGlobalMousePosition();
|
||||
|
||||
return mouseWorldPos - this.GlobalPosition;
|
||||
}
|
||||
}
|
||||
1
Scripts/Components/Actors/MouseAimProvider2D.cs.uid
Normal file
1
Scripts/Components/Actors/MouseAimProvider2D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bfmnmk0rfwa1i
|
||||
16
Scripts/Components/Actors/MouseAimProvider3D.cs
Normal file
16
Scripts/Components/Actors/MouseAimProvider3D.cs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
using Cirno.Scripts.Misc;
|
||||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Components.Actors;
|
||||
|
||||
public partial class MouseAimProvider3D : Node3D, IMouseAimProvider
|
||||
{
|
||||
public Vector2 GetMouseAimInput()
|
||||
{
|
||||
Vector2 mouseWorldPos = DisplayServer.MouseGetPosition();
|
||||
|
||||
var screenPosition = CameraController3D.Instance.UnprojectPosition(this.GlobalPosition);
|
||||
|
||||
return mouseWorldPos - screenPosition;
|
||||
}
|
||||
}
|
||||
1
Scripts/Components/Actors/MouseAimProvider3D.cs.uid
Normal file
1
Scripts/Components/Actors/MouseAimProvider3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://1fryvj4omkin
|
||||
|
|
@ -24,7 +24,7 @@ public partial class BulletSpawner : Node2D
|
|||
for (int i = 0; i < bulletInfo.BulletCount; i++)
|
||||
{
|
||||
// bullet = this.CreateChildOf<Bullet>(_gameManager.BulletsContainer, bulletScene, bulletInfo.Position);
|
||||
bullet = PoolingManager.Instance.SpawnBullet(bulletInfo.OriginalBulletResource);
|
||||
bullet = PoolingManager.Instance.SpawnBullet<Bullet>(bulletInfo.OriginalBulletResource);
|
||||
bullet.GlobalPosition = bulletInfo.Position;
|
||||
|
||||
// var bullet = this.CreateChildOf<Bullet>(_gameManager.BulletsContainer, bulletInfo.BulletScene ?? BulletScene, bulletInfo.Position);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ public partial class IsoMovementModule : ModuleBase<PlayerState, CharacterBody3D
|
|||
public int MovementSpeed => _isStrafing ? StrafeSpeed : Speed;
|
||||
|
||||
private IStateMachine<PlayerState, CharacterBody3D> _stateMachine;
|
||||
|
||||
private CharacterBody3D MainObject => _stateMachine.MainObject;
|
||||
|
||||
public override void EnterState(PlayerState state)
|
||||
|
|
|
|||
70
Scripts/Components/FSM/3DPlayer/PlayerWeaponModule3D.cs
Normal file
70
Scripts/Components/FSM/3DPlayer/PlayerWeaponModule3D.cs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
using Cirno.Scripts.Components.Actors;
|
||||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
||||
|
||||
public partial class PlayerWeaponModule3D : ModuleBase<PlayerState, CharacterBody3D>
|
||||
{
|
||||
[Export] public PlayerWeaponProvider3D WeaponProvider { get; private set; }
|
||||
|
||||
[Export] public InputProvider InputProvider { get; private set; }
|
||||
[Export] public IsoPlayerStorageModule Storage { get; private set; }
|
||||
|
||||
private IStateMachine<PlayerState, CharacterBody3D> _stateMachine;
|
||||
private CharacterBody3D MainObject => _stateMachine.MainObject;
|
||||
|
||||
public override void EnterState(PlayerState state)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void ExitState(PlayerState state)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void Init(IStateMachine<PlayerState, CharacterBody3D> machine)
|
||||
{
|
||||
_stateMachine = machine;
|
||||
|
||||
WeaponProvider.Init(MainObject);
|
||||
}
|
||||
|
||||
public override void Process(double delta)
|
||||
{
|
||||
WeaponProvider.Update(delta);
|
||||
|
||||
HandleShoot();
|
||||
|
||||
HandleWeaponSwitch();
|
||||
}
|
||||
|
||||
public override void PhysicsProcess(double delta)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void HandleShoot()
|
||||
{
|
||||
if (InputProvider.GetReloadJustPressed())
|
||||
{
|
||||
WeaponProvider.Reload();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!InputProvider.GetShootPressed()) return;
|
||||
WeaponProvider.Shoot(Storage.AimingDirection);
|
||||
}
|
||||
|
||||
private void HandleWeaponSwitch()
|
||||
{
|
||||
if (InputProvider.GetWeaponNextJustPressed())
|
||||
{
|
||||
WeaponProvider.NextWeapon();
|
||||
}
|
||||
else if (InputProvider.GetWeaponPreviousJustPressed())
|
||||
{
|
||||
WeaponProvider.PreviousWeapon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://d2psafx4f3f58
|
||||
286
Scripts/Components/FSM/3DPlayer/PlayerWeaponProvider3D.cs
Normal file
286
Scripts/Components/FSM/3DPlayer/PlayerWeaponProvider3D.cs
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Cirno.Scripts.Resources;
|
||||
using Cirno.Scripts.Weapons;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Cirno.Scripts.Components.FSM._3DPlayer;
|
||||
|
||||
public partial class PlayerWeaponProvider3D : Node
|
||||
{
|
||||
[Export] public IsoPlayerStorageModule StorageModule { get; set; }
|
||||
[Export] public PackedScene WeaponTemplate { get; private set; }
|
||||
|
||||
[Export] public double WeaponSwitchCooldown { get; private set; } = 0.5d;
|
||||
|
||||
[Export] public Marker3D WeaponRightOffset { get; private set; } // local offset when facing right
|
||||
[Export] public Marker3D WeaponLeftOffset { get; private set; } // local offset when facing left
|
||||
|
||||
public Array<Weapon3D> EquippedWeapons { get; set; } = [];
|
||||
|
||||
private int _currentWeaponIndex = 0;
|
||||
|
||||
private double _switchCooldown = 0d;
|
||||
private bool _switching = false;
|
||||
|
||||
private int CurrentWeaponIndex
|
||||
{
|
||||
get => Math.Clamp(_currentWeaponIndex, 0, EquippedWeapons.Count -1);
|
||||
|
||||
set
|
||||
{
|
||||
if (value > EquippedWeapons.Count - 1)
|
||||
{
|
||||
_currentWeaponIndex = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (value < 0)
|
||||
{
|
||||
_currentWeaponIndex = EquippedWeapons.Count - 1;
|
||||
return;
|
||||
}
|
||||
|
||||
_currentWeaponIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Weapon3D EquippedWeapon { get; set; }
|
||||
|
||||
private CharacterBody3D _parent;
|
||||
|
||||
public void Init(CharacterBody3D parent)
|
||||
{
|
||||
_parent = parent;
|
||||
|
||||
InventoryManager.Instance.WeaponEquip += this.OnInventoryWeaponEquipped;
|
||||
|
||||
InventoryManager.Instance.ItemAdded += OnInventoryWeaponAdded;
|
||||
|
||||
EquipStartupWeapon();
|
||||
}
|
||||
|
||||
public void Update(double delta)
|
||||
{
|
||||
RotateWeapon();
|
||||
|
||||
if (!_switching) return;
|
||||
_switchCooldown += delta;
|
||||
if (_switchCooldown >= WeaponSwitchCooldown)
|
||||
{
|
||||
_switching = false;
|
||||
_switchCooldown = 0d;
|
||||
}
|
||||
}
|
||||
|
||||
private void RotateWeapon()
|
||||
{
|
||||
if (EquippedWeapon is null) return;
|
||||
|
||||
//EquippedWeapon.RotateWeapon(StorageModule.FacingDirection, WeaponLeftOffset.Position, WeaponRightOffset.Position);
|
||||
|
||||
|
||||
|
||||
// EquippedWeapon.SetRotation(angle + Mathf.Pi / 2.0f);
|
||||
//
|
||||
//
|
||||
//
|
||||
// EquippedWeapon.FlipH = facingLeft;
|
||||
//
|
||||
// // 3. Position on correct side (assuming EquippedWeapon is a child of the Player node)
|
||||
// EquippedWeapon.Position = facingLeft ? WeaponLeftOffset : WeaponRightOffset;
|
||||
}
|
||||
|
||||
private void OnInventoryWeaponEquipped(string itemKey)
|
||||
{
|
||||
Equip(itemKey, true);
|
||||
}
|
||||
|
||||
private void OnInventoryWeaponAdded(LootItem item, int amount)
|
||||
{
|
||||
if (item.Item is not ItemTypes.Weapon) return;
|
||||
Equip(item, false);
|
||||
}
|
||||
|
||||
private void EquipStartupWeapon()
|
||||
{
|
||||
if (EquippedWeapon is not null) return;
|
||||
if (!string.IsNullOrWhiteSpace(GlobalState.Session.EquippedWeaponId))
|
||||
{
|
||||
// equip it
|
||||
Equip(GlobalState.Session.EquippedWeaponId, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to equip whatever is first
|
||||
var weaponData = InventoryManager.Instance.Items.FirstOrDefault(x => x.Item.Item is ItemTypes.Weapon);
|
||||
if (weaponData is null) return;
|
||||
|
||||
Equip(weaponData.Item.ItemKey, false);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// This is a soft equip
|
||||
public void AddWeapon(Weapon3D weapon)
|
||||
{
|
||||
EquippedWeapons.Add(weapon);
|
||||
}
|
||||
|
||||
// Triggered by event in inventorymanager
|
||||
private void EquipWeapon(Weapon3D weapon)
|
||||
{
|
||||
if (EquippedWeapon == weapon)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to start cooldown
|
||||
EquippedWeapon?.Hide();
|
||||
|
||||
EquippedWeapon = weapon;
|
||||
CurrentWeaponIndex = EquippedWeapons.IndexOf(weapon);
|
||||
GlobalState.Session.EquippedWeaponId = weapon.WeaponData.ItemKey;
|
||||
|
||||
EquippedWeapon.Show();
|
||||
|
||||
_switching = true;
|
||||
_switchCooldown = 0d;
|
||||
|
||||
InventoryManager.Instance.UpdateEquippedWeapon(weapon.WeaponData.ItemKey);
|
||||
}
|
||||
|
||||
public void NextWeapon()
|
||||
{
|
||||
CurrentWeaponIndex += 1;
|
||||
|
||||
Equip(EquippedWeapons[CurrentWeaponIndex], true);
|
||||
}
|
||||
|
||||
public void PreviousWeapon()
|
||||
{
|
||||
CurrentWeaponIndex -= 1;
|
||||
|
||||
Equip(EquippedWeapons[CurrentWeaponIndex], true);
|
||||
}
|
||||
|
||||
public void Shoot(Vector2 direction)
|
||||
{
|
||||
if (EquippedWeapon == null) return;
|
||||
if (_switching) return;
|
||||
|
||||
EquippedWeapon.ShootDirection = direction;
|
||||
EquippedWeapon.Shoot();
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
if (EquippedWeapon == null) return;
|
||||
if (_switching) return;
|
||||
|
||||
EquippedWeapon.Reload();
|
||||
}
|
||||
|
||||
// Remastered method
|
||||
private LootItem GetItemFromInventory(string itemKey)
|
||||
{
|
||||
return InventoryManager.Instance.Items.FirstOrDefault(x => x.Item.ItemKey == itemKey)?.Item;
|
||||
}
|
||||
|
||||
private Weapon3D GetWeaponFromLocal(string itemKey)
|
||||
{
|
||||
return EquippedWeapons.FirstOrDefault(x => x.WeaponData.ItemKey == itemKey);
|
||||
}
|
||||
|
||||
// Remastered method
|
||||
private Weapon3D SpawnWeapon(string itemKey)
|
||||
{
|
||||
return SpawnWeapon(GetItemFromInventory(itemKey));
|
||||
}
|
||||
|
||||
// Remastered method
|
||||
private Weapon3D SpawnWeapon(LootItem startingItem)
|
||||
{
|
||||
if (startingItem is null)
|
||||
{
|
||||
GD.Print($"Could not spawn weapon was not in the inventory.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (WeaponTemplate == null)
|
||||
{
|
||||
GD.Print("Could not spawn weapon because template is null");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if it's not spawned already
|
||||
var maybeExistingWeapon = GetWeaponFromLocal(startingItem.ItemKey);
|
||||
if (maybeExistingWeapon is not null) return maybeExistingWeapon;
|
||||
|
||||
var weapon = WeaponTemplate.Instantiate<Weapon3D>();
|
||||
this.AddChild(weapon);
|
||||
//this.CreateSibling<Weapon>(WeaponTemplate);
|
||||
weapon.WeaponData = startingItem.WeaponData;
|
||||
|
||||
weapon.Sprite.Texture = startingItem.InventorySprite;
|
||||
|
||||
this.AddWeapon(weapon);
|
||||
return weapon;
|
||||
}
|
||||
|
||||
public Weapon3D Equip(LootItem item, bool force)
|
||||
{
|
||||
var maybeExistingWeapon = GetWeaponFromLocal(item.ItemKey);
|
||||
if (maybeExistingWeapon is not null) return Equip(maybeExistingWeapon, force);
|
||||
|
||||
// Spawn if not present
|
||||
var spawnedWeapon = SpawnWeapon(item);
|
||||
return Equip(spawnedWeapon, force);
|
||||
}
|
||||
|
||||
public Weapon3D Equip(string itemKey, bool force)
|
||||
{
|
||||
// Check in local inventory first
|
||||
var maybeExistingWeapon = GetWeaponFromLocal(itemKey);
|
||||
if (maybeExistingWeapon is not null) return Equip(maybeExistingWeapon, force);
|
||||
|
||||
// Spawn if not present
|
||||
var spawnedWeapon = SpawnWeapon(itemKey);
|
||||
if (spawnedWeapon is null)
|
||||
{
|
||||
GD.Print($"Tried to spawn weapon {itemKey} but failed because it was null.");
|
||||
return null;
|
||||
};
|
||||
return Equip(spawnedWeapon, force);
|
||||
}
|
||||
|
||||
public Weapon3D Equip(Weapon3D weapon, bool force)
|
||||
{
|
||||
// When we get here we already have a spawned weapon and it's in the list
|
||||
|
||||
if (weapon is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Always equip it if there's nothing equipped
|
||||
if (this.EquippedWeapon is null)
|
||||
{
|
||||
this.EquipWeapon(weapon);
|
||||
return weapon;
|
||||
}
|
||||
|
||||
// If it's a soft equip check for priority
|
||||
if (!force && this.EquippedWeapon.WeaponData.Priority < weapon.WeaponData.Priority)
|
||||
{
|
||||
this.EquipWeapon(weapon);
|
||||
return weapon;
|
||||
}
|
||||
|
||||
EquipWeapon(weapon);
|
||||
return weapon;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
uid://by0x0qmbmkoak
|
||||
|
|
@ -75,6 +75,7 @@ public partial class FreezeModule : ModuleBase<PlayerState, CharacterBody2D>
|
|||
private List<Bullet> GetNearbyBullets()
|
||||
{
|
||||
return (from child in PoolingManager.Instance.GetAllActiveBullets()
|
||||
.Cast<Bullet>()
|
||||
where child is not null
|
||||
where child.Enabled // Could be redundant but better check in case of errors
|
||||
where child.BulletOwner is not BulletOwner.Player
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Cirno.Scripts.Resources;
|
||||
using Cirno.Scripts.Weapons;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Cirno.Scripts.Controllers;
|
||||
|
||||
public partial class PoolingManager : Node2D
|
||||
public partial class PoolingManager : Node
|
||||
{
|
||||
public static PoolingManager Instance { get; private set; }
|
||||
|
||||
|
|
@ -15,10 +16,10 @@ public partial class PoolingManager : Node2D
|
|||
|
||||
[Export] public bool DebugView { get; private set; } = false;
|
||||
|
||||
private readonly System.Collections.Generic.Dictionary<BulletResource, System.Collections.Generic.List<Bullet>>
|
||||
private readonly System.Collections.Generic.Dictionary<BulletResource, System.Collections.Generic.List<IBullet>>
|
||||
_activeBullets = new();
|
||||
|
||||
private readonly System.Collections.Generic.Dictionary<BulletResource, System.Collections.Generic.List<Bullet>>
|
||||
private readonly System.Collections.Generic.Dictionary<BulletResource, System.Collections.Generic.List<IBullet>>
|
||||
_inactiveBullets = new();
|
||||
|
||||
public override void _Ready()
|
||||
|
|
@ -26,7 +27,7 @@ public partial class PoolingManager : Node2D
|
|||
Instance = this;
|
||||
}
|
||||
|
||||
public Bullet SpawnBullet(BulletResource bulletResource, bool active = true)
|
||||
public IBullet SpawnBullet(BulletResource bulletResource, bool active = true)
|
||||
{
|
||||
// Look for bullet among the inactive ones
|
||||
// If present move it to active, set it as active and return it
|
||||
|
|
@ -53,27 +54,32 @@ public partial class PoolingManager : Node2D
|
|||
return bullet;
|
||||
}
|
||||
|
||||
public IEnumerable<Bullet> GetAllActiveBullets()
|
||||
public T SpawnBullet<T>(BulletResource bulletResource, bool active = true) where T : IBullet
|
||||
{
|
||||
return (T)SpawnBullet(bulletResource, active);
|
||||
}
|
||||
|
||||
public IEnumerable<IBullet> GetAllActiveBullets()
|
||||
{
|
||||
return _activeBullets.Values.SelectMany(list => list);
|
||||
}
|
||||
|
||||
public IEnumerable<Bullet> GetAllInActiveBullets()
|
||||
public IEnumerable<IBullet> GetAllInActiveBullets()
|
||||
{
|
||||
return _activeBullets.Values.SelectMany(list => list);
|
||||
}
|
||||
|
||||
public List<Bullet> GetActiveBulletsList(BulletResource resource)
|
||||
public List<IBullet> GetActiveBulletsList(BulletResource resource)
|
||||
{
|
||||
return GetOrCreateList(_activeBullets, resource);
|
||||
}
|
||||
|
||||
private List<Bullet> GetInactiveBulletsList(BulletResource resource)
|
||||
private List<IBullet> GetInactiveBulletsList(BulletResource resource)
|
||||
{
|
||||
return GetOrCreateList(_inactiveBullets, resource);
|
||||
}
|
||||
|
||||
public void DisableBullet(Bullet bullet)
|
||||
public void DisableBullet(IBullet bullet)
|
||||
{
|
||||
var activeBulletsList = GetActiveBulletsList(bullet.BulletInfo.OriginalBulletResource);
|
||||
|
||||
|
|
@ -106,7 +112,7 @@ public partial class PoolingManager : Node2D
|
|||
|
||||
}
|
||||
|
||||
private List<Bullet> GetOrCreateList(System.Collections.Generic.Dictionary<BulletResource, List<Bullet>> dict, BulletResource resource)
|
||||
private List<IBullet> GetOrCreateList(System.Collections.Generic.Dictionary<BulletResource, List<IBullet>> dict, BulletResource resource)
|
||||
{
|
||||
if (dict.TryGetValue(resource, out var list)) return list;
|
||||
list = [];
|
||||
|
|
@ -116,9 +122,11 @@ public partial class PoolingManager : Node2D
|
|||
|
||||
|
||||
|
||||
private Bullet InstantiateBullet(BulletResource bulletData)
|
||||
private IBullet InstantiateBullet(BulletResource bulletData)
|
||||
{
|
||||
var bullet = this.CreateChild<Bullet>(bulletData.BulletScene);
|
||||
var bullet = bulletData.BulletScene.Instantiate<Bullet>();
|
||||
this.AddChild(bullet);
|
||||
//this.CreateChild<Bullet>(bulletData.BulletScene);
|
||||
return bullet;
|
||||
}
|
||||
|
||||
|
|
|
|||
9
Scripts/DamageType.cs
Normal file
9
Scripts/DamageType.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
public enum DamageType
|
||||
{
|
||||
Neutral,
|
||||
Ballistic,
|
||||
Fire,
|
||||
Ice,
|
||||
Explosive,
|
||||
Acid
|
||||
}
|
||||
1
Scripts/DamageType.cs.uid
Normal file
1
Scripts/DamageType.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bwmkakrqrb8w1
|
||||
|
|
@ -5,13 +5,11 @@ using System.Linq;
|
|||
using Cirno.Scripts;
|
||||
using Cirno.Scripts.Resources;
|
||||
|
||||
public partial class InventoryManager : Node2D
|
||||
public partial class InventoryManager : Node
|
||||
{
|
||||
public static InventoryManager Instance { get; private set; }
|
||||
|
||||
public ItemsDatabase ItemsDatabase { get; set; }
|
||||
|
||||
public bool RedKeycard { get; set; }
|
||||
|
||||
private Dictionary<string, ItemContainer> _itemsDict = new();
|
||||
|
||||
|
|
|
|||
|
|
@ -232,7 +232,7 @@ public partial class PlayerMovement : CharacterBody2D, IDestructible
|
|||
// emit projectile
|
||||
var bulletData = item.WeaponData.MakeBullet(this.GlobalPosition);
|
||||
|
||||
var bullet = PoolingManager.Instance.SpawnBullet(bulletData.OriginalBulletResource);
|
||||
var bullet = PoolingManager.Instance.SpawnBullet<Bullet>(bulletData.OriginalBulletResource);
|
||||
|
||||
bullet.GlobalPosition = this.GlobalPosition;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public partial class SpiderbombEffectResource : ItemEffectResource
|
|||
public IITemEffectMachine Execute()
|
||||
{
|
||||
|
||||
var bullet = PoolingManager.Instance.SpawnBullet(item.WeaponData.BulletData);
|
||||
var bullet = PoolingManager.Instance.SpawnBullet<Bullet>(item.WeaponData.BulletData);
|
||||
bullet.GlobalPosition = parent.Machine.MainObject.GlobalPosition;
|
||||
|
||||
//var bullet = parent.CreateChildOf<Bullet>(GameManager.Instance.BulletsContainer, item.WeaponData.BulletData.BulletScene, parent.GlobalPosition);
|
||||
|
|
|
|||
11
Scripts/Utils/VectorExtensions.cs
Normal file
11
Scripts/Utils/VectorExtensions.cs
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Utils;
|
||||
|
||||
public static class VectorExtensions
|
||||
{
|
||||
public static Vector2 ToVector2(this Vector3 original)
|
||||
{
|
||||
return new Vector2(original.X, original.Z);
|
||||
}
|
||||
}
|
||||
1
Scripts/Utils/VectorExtensions.cs.uid
Normal file
1
Scripts/Utils/VectorExtensions.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b2r4bucv0o1ui
|
||||
|
|
@ -165,7 +165,7 @@ public partial class Weapon : Node2D
|
|||
// Rotate the ShootDirection by the spread angle
|
||||
Vector2 spreadDirection = ShootDirection.Rotated(Mathf.DegToRad(spreadOffset));
|
||||
|
||||
var bullet = PoolingManager.Instance.SpawnBullet(WeaponData.BulletData);
|
||||
var bullet = PoolingManager.Instance.SpawnBullet<Bullet>(WeaponData.BulletData);
|
||||
bullet.GlobalPosition = _muzzle.GlobalPosition;
|
||||
|
||||
//var bullet = this.CreateChildOf<Bullet>(_gameManager.BulletsContainer, WeaponData.BulletData.BulletScene, _muzzle.GlobalPosition);
|
||||
|
|
|
|||
310
Scripts/Weapons/Bullet3D.cs
Normal file
310
Scripts/Weapons/Bullet3D.cs
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Cirno.Scripts.Components;
|
||||
using Cirno.Scripts.Controllers;
|
||||
using Cirno.Scripts.Resources;
|
||||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Weapons;
|
||||
|
||||
public partial class Bullet3D : Area3D, IBullet
|
||||
{
|
||||
[Export] public float Speed { get; set; } = 1900f;
|
||||
|
||||
public BulletOwner BulletOwner => _bulletInfo?.Owner ?? BulletOwner.None;
|
||||
|
||||
public float Damage => _bulletInfo?.Damage ?? 1;
|
||||
|
||||
public DamageType DamageType => _bulletInfo?.DamageType ?? DamageType.Neutral;
|
||||
|
||||
protected Vector2 _direction = Vector2.Right;
|
||||
|
||||
private double _elapsedTime = 0f;
|
||||
private BulletInfo _bulletInfo;
|
||||
|
||||
public BulletInfo BulletInfo => _bulletInfo;
|
||||
|
||||
private List<ModifierWrapper> _modifiers = new();
|
||||
|
||||
private GameManager _gameManager;
|
||||
|
||||
public bool IsGrazed { get; set; } = false;
|
||||
|
||||
public bool IsFrozen { get; private set; } = false;
|
||||
public bool Enabled { get; private set; } = false;
|
||||
|
||||
[Signal]
|
||||
public delegate void OnDestroyEventHandler();
|
||||
|
||||
private AudioStreamPlayer2D _grazeSound;
|
||||
private GpuParticles2D _grazeParticles;
|
||||
|
||||
private CollisionShape2D _collisionShape2D;
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_grazeSound = GetNodeOrNull<AudioStreamPlayer2D>("AudioStreamPlayer2D");
|
||||
_grazeParticles = GetNodeOrNull<GpuParticles2D>("GrazeParticles");
|
||||
|
||||
_collisionShape2D = GetNode<CollisionShape2D>("CollisionShape2D");
|
||||
}
|
||||
|
||||
public void Initialize(BulletInfo bulletInfo, GameManager gameManager)
|
||||
{
|
||||
_bulletInfo = bulletInfo;
|
||||
|
||||
_gameManager = gameManager;
|
||||
|
||||
_elapsedTime = 0f;
|
||||
|
||||
this.Speed = bulletInfo.Speed;
|
||||
|
||||
// Need to clone them here
|
||||
// _modifiers = _bulletInfo.TimeModifiers.Select(x => x.MakeClone()).ToList();
|
||||
|
||||
|
||||
// var clonedModifiers = _bulletInfo.TimeModifiers.Select(x => x.MakeClone());
|
||||
// _modifiers = clonedModifiers.ToList();
|
||||
|
||||
// Ugly hack to make instances unique
|
||||
_modifiers = _bulletInfo.TimeModifiers.Select(x => x.Wrap()).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enables the bullet, shows the sprite and activates collisions
|
||||
/// </summary>
|
||||
public void Enable()
|
||||
{
|
||||
Enabled = true;
|
||||
Show();
|
||||
if (this._collisionShape2D is null)
|
||||
{
|
||||
_collisionShape2D = GetNode<CollisionShape2D>("CollisionShape2D");
|
||||
}
|
||||
|
||||
_collisionShape2D.SetDeferred(CollisionShape2D.PropertyName.Disabled, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables the bullet, hides the sprite and disables collisions
|
||||
/// </summary>
|
||||
public void Disable(bool hideSprite = true)
|
||||
{
|
||||
Enabled = false;
|
||||
if (hideSprite && !BulletInfo.Attributes.HasFlag(BulletFlags.PersistSprite))
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
|
||||
if (this._collisionShape2D is null)
|
||||
{
|
||||
_collisionShape2D = GetNode<CollisionShape2D>("CollisionShape2D");
|
||||
}
|
||||
|
||||
_collisionShape2D.SetDeferred(CollisionShape2D.PropertyName.Disabled, true);
|
||||
}
|
||||
|
||||
public void Graze()
|
||||
{
|
||||
if (!Enabled) return;
|
||||
_grazeSound?.Play();
|
||||
if (_grazeParticles is not null)
|
||||
{
|
||||
_grazeParticles.Emitting = true;
|
||||
}
|
||||
|
||||
IsGrazed = true;
|
||||
}
|
||||
|
||||
private void ApplyTimeModifiers(double delta)
|
||||
{
|
||||
return;
|
||||
// foreach (var modifier in _modifiers)
|
||||
// {
|
||||
// if (_elapsedTime >= modifier.TimeModifier.TimeInSeconds)
|
||||
// {
|
||||
// if (!modifier.Applied)
|
||||
// {
|
||||
// modifier.Applied = true;
|
||||
// modifier.TimeModifier.Start(this);
|
||||
// modifier.Elapsed = 0;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// modifier.Elapsed += delta;
|
||||
// }
|
||||
//
|
||||
// modifier.TimeModifier.Update(this, delta, modifier.Elapsed);
|
||||
//
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
public virtual void RotateBullet(float degrees)
|
||||
{
|
||||
float radians = Mathf.DegToRad(degrees);
|
||||
_direction = _direction.Rotated(radians).Normalized(); // Rotate direction
|
||||
|
||||
if (!BulletInfo.Attributes.HasFlag(BulletFlags.Rotateable)) return;
|
||||
//SetRotation(Rotation + radians);
|
||||
}
|
||||
|
||||
public virtual void RotateSpriteDegrees(float degrees)
|
||||
{
|
||||
if (!BulletInfo.Attributes.HasFlag(BulletFlags.Rotateable)) return;
|
||||
//SetRotationDegrees(RotationDegrees + degrees);
|
||||
}
|
||||
|
||||
public virtual void RotateSprite(float radians)
|
||||
{
|
||||
if (!BulletInfo.Attributes.HasFlag(BulletFlags.Rotateable)) return;
|
||||
//SetRotation(Rotation + radians);
|
||||
}
|
||||
|
||||
public void FacePlayer()
|
||||
{
|
||||
if (_gameManager.Player != null)
|
||||
{
|
||||
//_direction = (_gameManager.PlayerPosition.Value - this.GlobalPosition).Normalized();
|
||||
RotateBullet(0); // quick hack to rotate lasers
|
||||
//LookAt(player.GlobalPosition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void SetDirection(Vector2 direction)
|
||||
{
|
||||
var normalized = direction.Normalized();
|
||||
|
||||
_direction = normalized;
|
||||
|
||||
if (!BulletInfo.Attributes.HasFlag(BulletFlags.Rotateable)) return;
|
||||
//SetRotation(Mathf.Atan2(normalized.Y, normalized.X) + Mathf.Pi / 2);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
_elapsedTime += delta;
|
||||
|
||||
if (_elapsedTime >= _bulletInfo.LifeTime)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public override void _PhysicsProcess(double delta)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
if (_bulletInfo != null)
|
||||
{
|
||||
ApplyTimeModifiers(delta);
|
||||
}
|
||||
|
||||
if (BulletInfo.Attributes.HasFlag(BulletFlags.Controllable))
|
||||
{
|
||||
ControlBullet(delta);
|
||||
}
|
||||
|
||||
//this.Position += ((float)(Speed * delta) * _direction);
|
||||
}
|
||||
|
||||
private void ControlBullet(double delta)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
var axis = Input.GetAxis("left", "right");
|
||||
|
||||
if (axis != 0)
|
||||
{
|
||||
float rotationSpeed = 180f; // Degrees per second
|
||||
RotateBullet(axis * rotationSpeed * (float)delta);
|
||||
}
|
||||
}
|
||||
|
||||
private void _on_visible_on_screen_notifier_2d_screen_exited()
|
||||
{
|
||||
if (!Enabled) return;
|
||||
if (!BulletInfo.Attributes.HasFlag(BulletFlags.DieOutOfScreen)) return;
|
||||
//Debug.WriteLine("Destroy bullet out of screen");
|
||||
Destroy();
|
||||
}
|
||||
|
||||
private void _on_body_entered(Node2D body)
|
||||
{
|
||||
if (body.IsInGroup("Solid"))
|
||||
{
|
||||
//Debug.WriteLine("Collision");
|
||||
RequestCollisionDestruction();
|
||||
}
|
||||
//// Do not Collide with body for purpose of destroying bullets
|
||||
// else if (body.IsInGroup("Destroyable"))
|
||||
// {
|
||||
// Debug.WriteLine("Collision with destroyable object body");
|
||||
// QueueFree();
|
||||
// }
|
||||
}
|
||||
|
||||
private void _on_area_entered(Area2D area)
|
||||
{
|
||||
if (area.IsInGroup("Solid"))
|
||||
{
|
||||
RequestCollisionDestruction();
|
||||
return;
|
||||
}
|
||||
|
||||
if (area.IsInGroup("Destroyable") && area is IDestructible destructible &&
|
||||
CanHit(BulletOwner, destructible.BulletGroup))
|
||||
{
|
||||
// hit
|
||||
destructible.Hit(Damage, DamageType);
|
||||
|
||||
RequestCollisionDestruction();
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanHit(BulletOwner bulletOwner, BulletOwner targetGroup)
|
||||
{
|
||||
// If either is None, it always hits
|
||||
if (bulletOwner == BulletOwner.None || targetGroup == BulletOwner.None)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, it hits only if they are different groups
|
||||
return bulletOwner != targetGroup;
|
||||
}
|
||||
|
||||
public void RequestCollisionDestruction()
|
||||
{
|
||||
if (!Enabled) return;
|
||||
if (_bulletInfo.DestroyOnCollision)
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
private void Destroy()
|
||||
{
|
||||
if (_bulletInfo?.DestructionParticlesScene != null)
|
||||
{
|
||||
//this.CreateSibling<Node2D>(_bulletInfo.DestructionParticlesScene);
|
||||
|
||||
//particle.Init();
|
||||
}
|
||||
|
||||
EmitSignal(Bullet.SignalName.OnDestroy);
|
||||
//QueueFree();
|
||||
PoolingManager.Instance.DisableBullet(this);
|
||||
}
|
||||
|
||||
public void Freeze()
|
||||
{
|
||||
IsFrozen = true;
|
||||
EmitSignal(Bullet.SignalName.OnDestroy);
|
||||
//QueueFree();
|
||||
PoolingManager.Instance.DisableBullet(this);
|
||||
}
|
||||
}
|
||||
1
Scripts/Weapons/Bullet3D.cs.uid
Normal file
1
Scripts/Weapons/Bullet3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cg6y36s7buapp
|
||||
34
Scripts/Weapons/IBullet.cs
Normal file
34
Scripts/Weapons/IBullet.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using Cirno.Scripts.Components;
|
||||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Weapons;
|
||||
|
||||
public interface IBullet
|
||||
{
|
||||
public float Speed { get; set; }
|
||||
public BulletOwner BulletOwner { get; }
|
||||
public float Damage { get; }
|
||||
public DamageType DamageType { get; }
|
||||
public BulletInfo BulletInfo { get; }
|
||||
|
||||
public bool IsGrazed { get; }
|
||||
|
||||
public bool IsFrozen { get; }
|
||||
public bool Enabled { get; }
|
||||
|
||||
public delegate void OnDestroyEventHandler();
|
||||
|
||||
public void Initialize(BulletInfo bulletInfo, GameManager gameManager);
|
||||
|
||||
public void Enable();
|
||||
public void Disable(bool hideSprite = true);
|
||||
public void Graze();
|
||||
public void RotateBullet(float degrees);
|
||||
public void RotateSpriteDegrees(float degrees);
|
||||
public void RotateSprite(float radians);
|
||||
public void FacePlayer();
|
||||
public void SetDirection(Vector2 direction);
|
||||
public bool CanHit(BulletOwner bulletOwner, BulletOwner targetGroup);
|
||||
public void RequestCollisionDestruction();
|
||||
public void Freeze();
|
||||
}
|
||||
1
Scripts/Weapons/IBullet.cs.uid
Normal file
1
Scripts/Weapons/IBullet.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://58w1nidcpf2j
|
||||
228
Scripts/Weapons/Weapon3D.cs
Normal file
228
Scripts/Weapons/Weapon3D.cs
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
using Cirno.Scripts.Controllers;
|
||||
using Cirno.Scripts.Resources;
|
||||
using Cirno.Scripts.Utils;
|
||||
using Godot;
|
||||
|
||||
namespace Cirno.Scripts.Weapons;
|
||||
|
||||
public partial class Weapon3D : Node
|
||||
{
|
||||
[Export]
|
||||
public WeaponResource WeaponData { get; set; }
|
||||
|
||||
[Export]
|
||||
public PackedScene BulletScene { get; set; }
|
||||
|
||||
[Export]
|
||||
public Marker3D Muzzle { get; set; }
|
||||
|
||||
[Export]
|
||||
public Marker3D Pivot { get; set; }
|
||||
|
||||
[Export]
|
||||
public Sprite3D Sprite { get; private set; }
|
||||
|
||||
[Export] public StringName PowerKey { get; set; } = "POWER";
|
||||
|
||||
[Signal]
|
||||
public delegate void ShootingEventHandler();
|
||||
|
||||
[Signal]
|
||||
public delegate void ReloadingEventHandler();
|
||||
|
||||
[Signal] public delegate void EmptyEventHandler();
|
||||
|
||||
public int Ammo { get; set; } = 0;
|
||||
|
||||
private int _loadedAmmo;
|
||||
public int LoadedAmmo
|
||||
{
|
||||
get => _loadedAmmo;
|
||||
private set
|
||||
{
|
||||
_loadedAmmo = value;
|
||||
_inventoryManager?.NotifyLoadedAmmoChange(WeaponData?.ItemKey, _loadedAmmo);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2 ShootDirection { get; set; } = Vector2.Zero;
|
||||
|
||||
private Timer _cooldownTimer;
|
||||
|
||||
private GameManager _gameManager;
|
||||
|
||||
private InventoryManager _inventoryManager;
|
||||
|
||||
private readonly StringName _shieldAmmoType = "SHIELD";
|
||||
private bool UsesBattery => WeaponData.AmmoKey == _shieldAmmoType;
|
||||
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
_cooldownTimer = GetNode<Timer>("./ShootTimer");
|
||||
|
||||
// Start full
|
||||
if (WeaponData != null)
|
||||
{
|
||||
LoadedAmmo = WeaponData.BulletCapacity;
|
||||
}
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
EmitSignalReloading();
|
||||
|
||||
_cooldownTimer.Start(WeaponData.ReloadTime);
|
||||
|
||||
if (WeaponData.InfiniteAmmo || string.IsNullOrWhiteSpace(WeaponData.AmmoKey))
|
||||
{
|
||||
LoadedAmmo = WeaponData.BulletCapacity;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ammoToLoad = _inventoryManager.RemoveItem(WeaponData.AmmoKey, WeaponData.BulletCapacity - LoadedAmmo);
|
||||
|
||||
if (ammoToLoad > 0)
|
||||
{
|
||||
LoadedAmmo = ammoToLoad;
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitSignalEmpty();
|
||||
//GD.Print("Out of ammo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Shoot(BulletOwner? ownerOverride = null)
|
||||
{
|
||||
// Waiting on reload or Rate of Fire cooldown?
|
||||
if (!_cooldownTimer.IsStopped())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for battery if it's used
|
||||
if (UsesBattery)
|
||||
{
|
||||
if (GameManager.Instance.Player.Shield.CurrentResource >= WeaponData.AmmoPerShot)
|
||||
{
|
||||
GameManager.Instance.Player.Shield.CurrentResource -= WeaponData.AmmoPerShot;
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitSignalEmpty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Out of ammo?
|
||||
if (LoadedAmmo < WeaponData.AmmoPerShot)
|
||||
{
|
||||
if (WeaponData.AutoReload)
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
EmitSignalEmpty();
|
||||
return;
|
||||
}
|
||||
|
||||
EmitSignalShooting();
|
||||
|
||||
// TODO: Shoot at muzzle position, need to provide a way to turn it, on a radius?
|
||||
|
||||
float halfSpread = WeaponData.SpreadAngle / 2f;
|
||||
float spreadStep = WeaponData.BulletsPerShot > 1 ? WeaponData.SpreadAngle / (WeaponData.BulletsPerShot - 1) : 0;
|
||||
|
||||
for (int i = 0; i < WeaponData.BulletsPerShot; i++)
|
||||
{
|
||||
// Calculate angle offset for this bullet
|
||||
float spreadOffset = -halfSpread + (spreadStep * i);
|
||||
|
||||
// Add random spread
|
||||
if (WeaponData.RandomSpread > 0)
|
||||
{
|
||||
// Gaussian with mean = 0, stddev = WeaponData.RandomSpread
|
||||
spreadOffset += RandomStuff.GaussianClamped(
|
||||
mean: 0f,
|
||||
stdDev: WeaponData.RandomSpread, // tuning knob
|
||||
min: -halfSpread,
|
||||
max: halfSpread
|
||||
);
|
||||
}
|
||||
|
||||
// Rotate the ShootDirection by the spread angle
|
||||
Vector2 spreadDirection = ShootDirection.Rotated(Mathf.DegToRad(spreadOffset));
|
||||
|
||||
// Restore pooling
|
||||
var bullet = PoolingManager.Instance.SpawnBullet<Bullet3D>(WeaponData.BulletData);
|
||||
|
||||
//var bullet = WeaponData.BulletData.BulletScene.Instantiate<Bullet3D>()
|
||||
|
||||
bullet.GlobalPosition = Muzzle.GlobalPosition;
|
||||
|
||||
//var bullet = this.CreateChildOf<Bullet>(_gameManager.BulletsContainer, WeaponData.BulletData.BulletScene, _muzzle.GlobalPosition);
|
||||
|
||||
if (bullet == null)
|
||||
{
|
||||
GD.PrintErr("Bullet is null, not shooting");
|
||||
return;
|
||||
};
|
||||
|
||||
var bulletData = WeaponData.MakeBullet(Muzzle.GlobalPosition.ToVector2()); // TODO: Fix for 3D
|
||||
if (ownerOverride.HasValue)
|
||||
{
|
||||
bulletData.Owner = ownerOverride.Value;
|
||||
}
|
||||
|
||||
if (bulletData.Owner is BulletOwner.Player || ownerOverride is BulletOwner.Player)
|
||||
{
|
||||
// Apply the P multiplier
|
||||
bulletData.Damage *=
|
||||
GetBulletStrengthMultiplier(bulletData.Damage, bulletData.OriginalBulletResource.MaxDamage, 20);
|
||||
}
|
||||
|
||||
bullet.Initialize(bulletData, _gameManager);
|
||||
|
||||
//bullet.SetDirection(ShootDirection);
|
||||
bullet.SetDirection(spreadDirection);
|
||||
bullet.Speed = WeaponData.BulletData.BulletSpeed;
|
||||
}
|
||||
|
||||
if (!UsesBattery)
|
||||
{
|
||||
LoadedAmmo -= WeaponData.AmmoPerShot;
|
||||
}
|
||||
|
||||
//_inventoryManager.NotifyLoadedAmmoChange(WeaponData.ItemKey, LoadedAmmo);
|
||||
// if (!string.IsNullOrWhiteSpace(WeaponData?.AmmoKey))
|
||||
// {
|
||||
// // Notify hud to decrease weapon
|
||||
//
|
||||
// }
|
||||
|
||||
_cooldownTimer.Start(WeaponData?.RateOfFire ?? 0);
|
||||
}
|
||||
|
||||
private float GetBulletStrengthMultiplier(float baseDamage, float maxDamage, float maxPower)
|
||||
{
|
||||
var p = InventoryManager.Instance.GetItemCount(PowerKey);
|
||||
|
||||
float minMultiplier = 1.0f;
|
||||
float maxMultiplier = maxDamage / baseDamage;
|
||||
|
||||
float normalizedPower = Mathf.Clamp((float)p / maxPower, 0f, 1f);
|
||||
return Mathf.Lerp(minMultiplier, maxMultiplier, normalizedPower);
|
||||
}
|
||||
|
||||
public void Hide()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void Show()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
1
Scripts/Weapons/Weapon3D.cs.uid
Normal file
1
Scripts/Weapons/Weapon3D.cs.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dutroqc0grqyv
|
||||
Loading…
Add table
Add a link
Reference in a new issue