Allows players to reload projectiles on their weapons.

允许玩家对武器装填抛射体了。
This commit is contained in:
Cold-Mint 2024-10-05 09:13:14 +08:00
parent 8a7a9bcf5d
commit 839d60b62a
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
11 changed files with 155 additions and 29 deletions

View File

@ -113,4 +113,4 @@ log_enter_the_screen,进入屏幕。,Enter screen,画面に移動。
log_exit_the_screen,退出屏幕。,Exit screen,画面を終了します。
log_failed_to_create_room_preview,创建{0}的房间预览图失败。,Failed to create a room preview of the {0}.,{0}の部屋のプレビューを作成できませんでした。
log_generated_item_is_empty,生成的物品{0}是空的吗{1}。,Generated item {0} is empty {1}.,生成したアイテム{0}は空ですか{1}。
log_magics_is_null,法术列表是空的。,The spell list is empty.,スペルリストは空です
log_projectile_generate_magic_is_null,没有装填可提供抛射体的法术。,There is no reload spell that provides projectiles.,射出体を提供するスペルを装填していません
1 id zh en ja
113 log_exit_the_screen 退出屏幕。 Exit screen 画面を終了します。
114 log_failed_to_create_room_preview 创建{0}的房间预览图失败。 Failed to create a room preview of the {0}. {0}の部屋のプレビューを作成できませんでした。
115 log_generated_item_is_empty 生成的物品{0}是空的吗{1}。 Generated item {0} is empty {1}. 生成したアイテム{0}は空ですか{1}。
116 log_magics_is_null log_projectile_generate_magic_is_null 法术列表是空的。 没有装填可提供抛射体的法术。 The spell list is empty. There is no reload spell that provides projectiles. スペルリストは空です。 射出体を提供するスペルを装填していません。

View File

@ -1,6 +1,6 @@
[gd_scene load_steps=6 format=3 uid="uid://crthy8a50a4t"]
[ext_resource type="Script" path="res://scripts/pickable/MagicPickAble.cs" id="1_5mane"]
[ext_resource type="Script" path="res://scripts/spell/SpellPickAble.cs" id="1_v0grp"]
[ext_resource type="AudioStream" uid="uid://cak6chjjsu7wo" path="res://sounds/fire.wav" id="4_ffr2k"]
[ext_resource type="Texture2D" uid="uid://bbcjkyrsx88av" path="res://sprites/projectile/curseOfTheUndead.png" id="4_y6nkf"]
@ -14,8 +14,8 @@ size = Vector2(20, 20.75)
collision_layer = 8
collision_mask = 34
angular_damp = -1.0
script = ExtResource("1_5mane")
UniqueIcon = ExtResource("4_y6nkf")
script = ExtResource("1_v0grp")
_projectilePath = "res://prefab/projectile/curseOfTheUndead.tscn"
[node name="DamageArea2D" type="Area2D" parent="."]
collision_layer = 8

View File

@ -16,7 +16,7 @@ collision_layer = 8
collision_mask = 34
angular_damp = -1.0
script = ExtResource("1_w8hhv")
NumberSlots = 5
_numberSlots = 5
FiringIntervalAsMillisecond = 300
_recoilStrength = 5
UniqueIcon = ExtResource("3_31iau")

View File

@ -118,7 +118,7 @@ visible = false
[node name="WeaponContainer" type="Node2D" parent="."]
[node name="MagicContainer" type="Node2D" parent="."]
[node name="SpellContainer" type="Node2D" parent="."]
[node name="PlayerContainer" type="Node2D" parent="."]

View File

@ -227,14 +227,14 @@ public static class Config
public const int ProjectileWeapon = 3;
/// <summary>
/// <para>Magic</para>
/// <para>Spell</para>
/// <para>法术</para>
/// </summary>
/// <remarks>
///<para>Type of special item used in Projectile weapons</para>
///<para>用于远程武器内的特殊物品类型</para>
/// </remarks>
public const int Magic = 4;
public const int Spell = 4;
}
/// <summary>

View File

@ -50,10 +50,10 @@ public static class GameSceneDepend
public static Node2D? ProjectileContainer { get; set; }
/// <summary>
/// <para>MagicContainer</para>
/// <para>SpellContainer</para>
/// <para>法术容器</para>
/// </summary>
public static Node2D? MagicContainer { get; set; }
public static Node2D? SpellContainer { get; set; }
/// <summary>
/// <para>WeaponContainer</para>

View File

@ -47,8 +47,8 @@ public partial class GameSceneLoader : SceneLoaderTemplate
GameSceneDepend.ProjectileContainer = projectileContainer;
//Load magic container
//加载魔术容器
var magicContainer = GetNode<Node2D>("MagicContainer");
GameSceneDepend.MagicContainer = magicContainer;
var magicContainer = GetNode<Node2D>("SpellContainer");
GameSceneDepend.SpellContainer = magicContainer;
//Load Packsack container
//加载背包容器
var packsackContainer = GetNode<Node2D>("PacksackContainer");

View File

@ -4,14 +4,14 @@ using Godot;
namespace ColdMint.scripts.projectile;
/// <summary>
/// <para>Magic</para>
/// <para>Spell</para>
/// <para>法术</para>
/// </summary>
/// <remarks>
///<para>For projectile weapons</para>
///<para>用于抛射体武器</para>
/// </remarks>
public interface IMagic
public interface ISpell
{
/// <summary>
/// <para>GetProjectile</para>

View File

@ -1,8 +1,9 @@
using ColdMint.scripts.pickable;
using ColdMint.scripts.projectile;
using ColdMint.scripts.weapon;
using Godot;
namespace ColdMint.scripts.pickable;
namespace ColdMint.scripts.spell;
/// <summary>
/// <para>magic</para>
@ -12,8 +13,9 @@ namespace ColdMint.scripts.pickable;
///<para>For projectile weapons</para>
///<para>用于抛射体武器</para>
/// </remarks>
public partial class MagicPickAble : PickAbleTemplate, IMagic
public partial class SpellPickAble : PickAbleTemplate, ISpell
{
[Export]
private string? _projectilePath;
private PackedScene? _projectileScene;
@ -28,7 +30,7 @@ public partial class MagicPickAble : PickAbleTemplate, IMagic
public override int ItemType
{
get => Config.ItemType.Magic;
get => Config.ItemType.Spell;
}
public PackedScene? GetProjectile()

View File

@ -235,9 +235,9 @@ public static class NodeUtils
return GameSceneDepend.ProjectileContainer;
}
if (GameSceneDepend.MagicContainer != null && childNode is IMagic)
if (GameSceneDepend.SpellContainer != null && childNode is ISpell)
{
return GameSceneDepend.MagicContainer;
return GameSceneDepend.SpellContainer;
}
if (GameSceneDepend.WeaponContainer != null && childNode is WeaponTemplate)

View File

@ -3,6 +3,7 @@ using ColdMint.scripts.debug;
using ColdMint.scripts.inventory;
using ColdMint.scripts.map.events;
using ColdMint.scripts.projectile;
using ColdMint.scripts.utils;
using Godot;
namespace ColdMint.scripts.weapon;
@ -27,9 +28,81 @@ public partial class ProjectileWeapon : WeaponTemplate
/// <para>Number of slots for ranged weapons</para>
/// <para>远程武器的槽位数量</para>
/// </summary>
[Export] public int NumberSlots { get; set; }
[Export]
private int _numberSlots;
private readonly List<IMagic> _magics = new();
/// <summary>
/// <para>How many projectiles are generated per fire</para>
/// <para>每次开火生成多少个抛射体</para>
/// </summary>
public int NumberOfProjectiles { get; set; } = 1;
private readonly List<ISpell> _spells = new();
/// <summary>
/// <para>Saves the position of a spell with projectile generation</para>
/// <para>保存具有抛射体生成能力的法术位置</para>
/// </summary>
private readonly List<int> _spellProjectileIndexes = new();
/// <summary>
/// <para>Whether to fire spells in sequence</para>
/// <para>是否按顺序发射法术</para>
/// </summary>
[Export]
private bool _fireSequentially;
/// <summary>
/// <para>The index used the last time a spell was cast</para>
/// <para>上次发射法术时采用的索引</para>
/// </summary>
private int _lastUsedProjectileMagicIndex;
/// <summary>
/// <para>Get next index</para>
/// <para>获取下次索引</para>
/// </summary>
/// <returns></returns>
private int GetNextProjectileMagicIndex()
{
if (_fireSequentially)
{
_lastUsedProjectileMagicIndex++;
if (_lastUsedProjectileMagicIndex >= _spellProjectileIndexes.Count)
{
return 0;
}
return _lastUsedProjectileMagicIndex;
}
else
{
return RandomUtils.Instance.Next(0, _spellProjectileIndexes.Count);
}
}
/// <summary>
/// <para>Gets the loading range of the spell</para>
/// <para>获取法术的加载范围</para>
/// </summary>
/// <returns></returns>
private int[] GetSpellScope()
{
var index = GetNextProjectileMagicIndex();
var endIndex = _spellProjectileIndexes[index];
if (index > 0)
{
//And the previous index can set the starting position.(The starting position is increased by 1 to avoid using spells with projectile generation as starting points.)
//还有前面的索引可设定起始位置。(这里起始位置加1是为了避免 具有抛射体生成能力的法术 作为起点。)
var startIndex = _spellProjectileIndexes[index - 1] + 1;
return [startIndex, endIndex];
}
else
{
return
[
0, endIndex
];
}
}
public override int ItemType
{
@ -40,9 +113,8 @@ public partial class ProjectileWeapon : WeaponTemplate
{
base._Ready();
_marker2D = GetNode<Marker2D>("Marker2D");
SelfItemContainer = new UniversalItemContainer(NumberSlots);
SelfItemContainer.AllowAddingItemByType(Config.ItemType.Magic);
SelfItemContainer.ItemDataChangeEvent += OnItemDataChangeEvent;
SelfItemContainer = new UniversalItemContainer(_numberSlots);
SelfItemContainer.AllowAddingItemByType(Config.ItemType.Spell);
}
private void OnItemDataChangeEvent(ItemDataChangeEvent itemDataChangeEvent)
@ -51,7 +123,8 @@ public partial class ProjectileWeapon : WeaponTemplate
{
return;
}
_magics.Clear();
_spells.Clear();
_spellProjectileIndexes.Clear();
var totalCapacity = SelfItemContainer.GetTotalCapacity();
for (var i = 0; i < totalCapacity; i++)
{
@ -60,11 +133,27 @@ public partial class ProjectileWeapon : WeaponTemplate
{
continue;
}
if (item is not IMagic magic)
if (item is not ISpell spell)
{
continue;
}
_magics.Add(magic);
_spells.Add(spell);
var packedScene = spell.GetProjectile();
if (packedScene != null)
{
//Has the ability to generate projectiles.
//拥有抛射体生成能力。
_spellProjectileIndexes.Add(i);
}
}
}
public override void _EnterTree()
{
base._EnterTree();
if (SelfItemContainer != null)
{
SelfItemContainer.ItemDataChangeEvent += OnItemDataChangeEvent;
}
}
@ -96,10 +185,45 @@ public partial class ProjectileWeapon : WeaponTemplate
LogCat.LogError("projectile_container_is_null");
return;
}
if (_magics.Count == 0)
if (_spellProjectileIndexes.Count == 0)
{
LogCat.LogError("magics_is_null");
LogCat.LogError("projectile_generate_magic_is_null");
return;
}
var spellScope = GetSpellScope();
//The final spell is a projectile generator.
//最后的法术是拥有抛射体生成能力的。
var spellProjectile = _spells[spellScope[1]];
var packedScene = spellProjectile.GetProjectile();
if (packedScene == null)
{
return;
}
for (var i = spellScope[0]; i <= spellScope[1]; i++)
{
var spell = _spells[i];
spell.ModifyWeapon(this);
}
for (var i = 0; i < NumberOfProjectiles; i++)
{
var projectile = NodeUtils.InstantiatePackedScene<Projectile>(packedScene);
if (projectile == null) return;
for (var s = spellScope[0]; s <= spellScope[1]; s++)
{
var spell = _spells[s];
spell.ModifyProjectile(projectile);
}
NodeUtils.CallDeferredAddChild(GameSceneDepend.ProjectileContainer, projectile);
projectile.Owner = owner;
projectile.TargetNode = GameSceneDepend.TemporaryTargetNode;
projectile.Velocity =
_marker2D.GlobalPosition.DirectionTo(enemyGlobalPosition) * projectile.Speed;
projectile.Position = _marker2D.GlobalPosition;
}
for (var i = spellScope[0]; i <= spellScope[1]; i++)
{
var spell = _spells[i];
spell.RestoreWeapon(this);
}
}
}