Add item types. Item containers now support limiting added item types. Added spell classes for projectile weapons.
加入物品类型,物品容器支持限制添加的物品类型了。加入适用于抛射体武器的法术类。
This commit is contained in:
parent
bb0f582fed
commit
2d7985010d
|
@ -4,7 +4,6 @@ log_missing_parameters,缺少参数。,Missing parameters.,パラメータが不
|
|||
log_room_root_node_must_be_node2d,房间根节点必须是 Node2D。,Room root node must be an instance of Node2D.,ルートノードはNode2Dでなければなりません。
|
||||
log_width_or_height_of_room_slot_must_be_1,房间槽的宽度或高度必须为1。,The width or height of the room slot must be 1.,部屋の溝の幅または高さは1でなければなりません。
|
||||
log_connected_room_timeout,连接房间超时。,Timeout when connecting rooms.,接続部屋はタイムアウトです。
|
||||
log_projectiles_is_empty,未设置抛射体。,The projectile is not set.,射出体は設置されていません。
|
||||
log_map_generator_missing_parameters,地图生成器缺少参数。,Map generator missing parameters.,マップジェネレータが不足しています。
|
||||
log_map_generator_attempts_to_parse_empty_layout_diagrams,地图生成器尝试解析空的布局图。,Map generator attempts to parse empty layout diagrams.,マップジェネレータは空のレイアウト図を解析しようとしています。
|
||||
log_map_generator_has_no_starting_room_data,地图生成器没有起点房间数据。,Map generator has no starting room data.,マップ生成器に起点部屋データはありません。
|
||||
|
|
|
|
@ -1,8 +1,7 @@
|
|||
[gd_scene load_steps=8 format=3 uid="uid://dnnn2xyayiehk"]
|
||||
[gd_scene load_steps=7 format=3 uid="uid://dnnn2xyayiehk"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://wt50kx6bup51" path="res://sprites/weapon/StaffNecromancy.png" id="1_ms3us"]
|
||||
[ext_resource type="Script" path="res://scripts/weapon/ProjectileWeapon.cs" id="1_w8hhv"]
|
||||
[ext_resource type="PackedScene" uid="uid://c01av43yk1q71" path="res://prefab/projectile/curseOfTheUndead.tscn" id="2_mwli5"]
|
||||
[ext_resource type="Texture2D" uid="uid://dg5vwprt66w4j" path="res://sprites/weapon/StaffNecromancy_Icon.png" id="3_31iau"]
|
||||
[ext_resource type="AudioStream" uid="uid://cak6chjjsu7wo" path="res://sounds/fire.wav" id="4_ffr2k"]
|
||||
|
||||
|
@ -17,9 +16,7 @@ collision_layer = 8
|
|||
collision_mask = 34
|
||||
angular_damp = -1.0
|
||||
script = ExtResource("1_w8hhv")
|
||||
OffsetAngle = 0.087
|
||||
ProjectileScenes = [ExtResource("2_mwli5")]
|
||||
Sequentially = true
|
||||
NumberSlots = 5
|
||||
FiringIntervalAsMillisecond = 300
|
||||
_recoilStrength = 5
|
||||
UniqueIcon = ExtResource("3_31iau")
|
||||
|
|
|
@ -197,6 +197,45 @@ public static class Config
|
|||
{
|
||||
return OS.HasFeature("editor");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>ItemType</para>
|
||||
/// <para>物品类型</para>
|
||||
/// </summary>
|
||||
public static class ItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>Unknown</para>
|
||||
/// <para>未知的</para>
|
||||
/// </summary>
|
||||
public const int Unknown = 0;
|
||||
/// <summary>
|
||||
/// <para>Placeholder</para>
|
||||
/// <para>占位符</para>
|
||||
/// </summary>
|
||||
public const int Placeholder = 1;
|
||||
/// <summary>
|
||||
/// <para>Packsack</para>
|
||||
/// <para>背包</para>
|
||||
/// </summary>
|
||||
public const int Packsack = 2;
|
||||
|
||||
/// <summary>
|
||||
/// <para>ProjectileWeapon</para>
|
||||
/// <para>远程武器</para>
|
||||
/// </summary>
|
||||
public const int ProjectileWeapon = 3;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Magic</para>
|
||||
/// <para>法术</para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///<para>Type of special item used in Projectile weapons</para>
|
||||
///<para>用于远程武器内的特殊物品类型</para>
|
||||
/// </remarks>
|
||||
public const int Magic = 4;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Room Injector ID</para>
|
||||
|
|
|
@ -11,13 +11,13 @@ public partial class HotBar : HBoxContainer
|
|||
{
|
||||
private IItemContainer? _itemContainer;
|
||||
private IItemContainerDisplay? _itemContainerDisplay;
|
||||
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
base._Ready();
|
||||
var universalItemContainer = new UniversalItemContainer(Config.HotBarSize);
|
||||
_itemContainer = universalItemContainer;
|
||||
_itemContainer.CanContainContainer = true;
|
||||
universalItemContainer.AllowItemTypesExceptPlaceholder();
|
||||
_itemContainer.SupportSelect = true;
|
||||
_itemContainerDisplay = new ItemSlotContainerDisplay(this);
|
||||
_itemContainerDisplay.BindItemContainer(_itemContainer);
|
||||
|
|
|
@ -62,6 +62,12 @@ public interface IItem
|
|||
/// <para>最大物品数量</para>
|
||||
/// </summary>
|
||||
int MaxQuantity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>ItemType</para>
|
||||
/// <para>获取物品类型</para>
|
||||
/// </summary>
|
||||
int ItemType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>Check or not</para>
|
||||
|
|
|
@ -20,6 +20,20 @@ public interface IItemContainer
|
|||
/// <para>当物品的数据发生改变时,例如数量增加,减少,或者新物品被添加到容器内触发此事件</para>
|
||||
/// </summary>
|
||||
Action<ItemDataChangeEvent>? ItemDataChangeEvent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>Allow Adding Item By Type</para>
|
||||
/// <para>允许添加指定类型的物品</para>
|
||||
/// </summary>
|
||||
/// <param name="itemType"></param>
|
||||
void AllowAddingItemByType(int itemType);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Disallow Adding Item By Type</para>
|
||||
/// <para>禁止添加指定类型的物品</para>
|
||||
/// </summary>
|
||||
/// <param name="itemType"></param>
|
||||
void DisallowAddingItemByType(int itemType);
|
||||
|
||||
/// <summary>
|
||||
/// <para>Can the specified item be added to the container?</para>
|
||||
|
@ -45,13 +59,7 @@ public interface IItemContainer
|
|||
/// <para>此物品容器是否支持选中</para>
|
||||
/// </summary>
|
||||
bool SupportSelect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>Whether this item container supports items that CanContainItems=true, such as backpacks</para>
|
||||
/// <para>此物品容器是否支持容纳CanContainItems=true的物品,例如背包</para>
|
||||
/// </summary>
|
||||
bool CanContainContainer { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Gets a placeholder object</para>
|
||||
/// <para>获取占位符对象</para>
|
||||
|
|
|
@ -117,7 +117,7 @@ public partial class ItemSlotNode : MarginContainer, IItemDisplay
|
|||
return;
|
||||
}
|
||||
|
||||
if (Item.SelfItemContainer != null)
|
||||
if (Item.SelfItemContainer != null && Item.SelfItemContainer.CanAddItem(sourceItem))
|
||||
{
|
||||
//Use items and place them on the container.
|
||||
//用物品,在物品容器上放置。
|
||||
|
@ -138,7 +138,7 @@ public partial class ItemSlotNode : MarginContainer, IItemDisplay
|
|||
return;
|
||||
}
|
||||
|
||||
if (sourceItem.SelfItemContainer != null)
|
||||
if (sourceItem.SelfItemContainer != null && sourceItem.SelfItemContainer.CanAddItem(Item))
|
||||
{
|
||||
//Use containers and place on top of items.
|
||||
//用容器物品,在物品上放置。
|
||||
|
|
|
@ -12,6 +12,11 @@ namespace ColdMint.scripts.inventory;
|
|||
public partial class Packsack : PickAbleTemplate
|
||||
{
|
||||
private const string Path = "res://prefab/ui/packsackUI.tscn";
|
||||
|
||||
public override int ItemType
|
||||
{
|
||||
get => Config.ItemType.Packsack;
|
||||
}
|
||||
[Export] public int NumberSlots { get; set; }
|
||||
public override void Use(Node2D? owner, Vector2 targetGlobalPosition)
|
||||
{
|
||||
|
@ -54,7 +59,10 @@ public partial class Packsack : PickAbleTemplate
|
|||
base._Ready();
|
||||
if (SelfItemContainer == null)
|
||||
{
|
||||
SelfItemContainer = new UniversalItemContainer(NumberSlots);
|
||||
var universalItemContainer = new UniversalItemContainer(NumberSlots);
|
||||
universalItemContainer.AllowItemTypesExceptPlaceholder();
|
||||
universalItemContainer.DisallowAddingItemByType(Config.ItemType.Packsack);
|
||||
SelfItemContainer = universalItemContainer;
|
||||
SelfItemContainer.SupportSelect = false;
|
||||
}
|
||||
GameSceneDepend.DynamicUiGroup?.RegisterControl(Path, () =>
|
||||
|
|
|
@ -13,17 +13,17 @@ public class PlaceholderItem : IItem
|
|||
|
||||
public void ShowSelf()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void QueueFreeSelf()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void HideSelf()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Texture2D Icon { get; }
|
||||
|
@ -31,6 +31,10 @@ public class PlaceholderItem : IItem
|
|||
public string? Description { get; } = null;
|
||||
public int Quantity { get; set; } = 1;
|
||||
public int MaxQuantity { get; } = 1;
|
||||
public int ItemType
|
||||
{
|
||||
get => Config.ItemType.Placeholder;
|
||||
}
|
||||
public bool IsSelect { get; set; }
|
||||
public bool CanContainItems { get; set; } = false;
|
||||
public IItemContainer? ItemContainer { get; set; }
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using ColdMint.scripts.map.events;
|
||||
|
||||
namespace ColdMint.scripts.inventory;
|
||||
|
@ -32,15 +33,59 @@ public class UniversalItemContainer(int totalCapacity) : IItemContainer
|
|||
/// </remarks>
|
||||
private int _nextAvailableIndex;
|
||||
|
||||
/// <summary>
|
||||
/// <para>The type of item that can be added to the item container</para>
|
||||
/// <para>物品容器允许添加的物品类型</para>
|
||||
/// </summary>
|
||||
private readonly HashSet<int> _allowedItemTypes = new();
|
||||
|
||||
public Action<SelectedItemChangeEvent>? SelectedItemChangeEvent { get; set; }
|
||||
public Action<ItemDataChangeEvent>? ItemDataChangeEvent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>Allow Item Types Except Placeholder</para>
|
||||
/// <para>允许添加除占位符以外的所有物品类型</para>
|
||||
/// </summary>
|
||||
public void AllowItemTypesExceptPlaceholder()
|
||||
{
|
||||
var itemTypeType = typeof(Config.ItemType);
|
||||
//Get all fields
|
||||
//获取所有字段
|
||||
var fields = itemTypeType.GetFields(BindingFlags.Public | BindingFlags.Static);
|
||||
//Traversal field
|
||||
//遍历字段
|
||||
foreach (var field in fields)
|
||||
{
|
||||
//Gets the value of the field
|
||||
//获取字段的值
|
||||
var value = field.GetValue(null);
|
||||
if (value == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var intValue = (int)value;
|
||||
if (intValue == Config.ItemType.Placeholder)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_allowedItemTypes.Add(intValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void AllowAddingItemByType(int itemType)
|
||||
{
|
||||
_allowedItemTypes.Add(itemType);
|
||||
}
|
||||
|
||||
public void DisallowAddingItemByType(int itemType)
|
||||
{
|
||||
_allowedItemTypes.Remove(itemType);
|
||||
}
|
||||
|
||||
public bool CanAddItem(IItem item)
|
||||
{
|
||||
if (item.SelfItemContainer != null && !CanContainContainer)
|
||||
if (!_allowedItemTypes.Contains(item.ItemType))
|
||||
{
|
||||
//The item to be added can hold other items, and this item container does not allow item containers.
|
||||
//要添加的物品能够容纳其他物品,且此物品容器不允许放置物品容器。
|
||||
return false;
|
||||
}
|
||||
//If the capacity is not full, directly return to add items
|
||||
|
@ -200,8 +245,6 @@ public class UniversalItemContainer(int totalCapacity) : IItemContainer
|
|||
}
|
||||
|
||||
public bool SupportSelect { get; set; }
|
||||
public bool CanContainContainer { get; set; }
|
||||
|
||||
|
||||
public IItem GetPlaceHolderItem(int index)
|
||||
{
|
||||
|
@ -247,7 +290,7 @@ public class UniversalItemContainer(int totalCapacity) : IItemContainer
|
|||
|
||||
public bool CanReplaceItem(int index, IItem item)
|
||||
{
|
||||
if (item.SelfItemContainer != null && !CanContainContainer)
|
||||
if (!_allowedItemTypes.Contains(item.ItemType))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
15
scripts/pickable/MagicPickAble.cs
Normal file
15
scripts/pickable/MagicPickAble.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
namespace ColdMint.scripts.pickable;
|
||||
|
||||
/// <summary>
|
||||
/// <para>法术</para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///<para>用于抛射体武器</para>
|
||||
/// </remarks>
|
||||
public partial class MagicPickAble : PickAbleTemplate
|
||||
{
|
||||
public override int ItemType
|
||||
{
|
||||
get => Config.ItemType.Magic;
|
||||
}
|
||||
}
|
|
@ -92,6 +92,10 @@ public partial class PickAbleTemplate : RigidBody2D, IItem
|
|||
public bool Picked { get; set; }
|
||||
|
||||
public int MaxQuantity { get; set; } = 1;
|
||||
public virtual int ItemType
|
||||
{
|
||||
get => Config.ItemType.Unknown;
|
||||
}
|
||||
|
||||
private bool _isSelected;
|
||||
|
||||
|
@ -108,7 +112,7 @@ public partial class PickAbleTemplate : RigidBody2D, IItem
|
|||
OnSelectChange(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public IItemContainer? ItemContainer { get; set; }
|
||||
public IItemContainer? SelfItemContainer { get; set; }
|
||||
|
||||
|
@ -121,7 +125,7 @@ public partial class PickAbleTemplate : RigidBody2D, IItem
|
|||
/// <param name="isSelected"></param>
|
||||
protected virtual void OnSelectChange(bool isSelected)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public IItem? CreateItem(int number)
|
||||
|
@ -348,11 +352,4 @@ public partial class PickAbleTemplate : RigidBody2D, IItem
|
|||
|
||||
pickAbleTemplate.Id = Id;
|
||||
}
|
||||
|
||||
public virtual void Destroy()
|
||||
{
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
public bool CanStackWith(IItem item) => false;
|
||||
}
|
14
scripts/projectile/IMagic.cs
Normal file
14
scripts/projectile/IMagic.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
namespace ColdMint.scripts.projectile;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Magic</para>
|
||||
/// <para>法术</para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///<para>For projectile weapons</para>
|
||||
///<para>用于抛射体武器</para>
|
||||
/// </remarks>
|
||||
public interface IMagic
|
||||
{
|
||||
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
using ColdMint.scripts.debug;
|
||||
using ColdMint.scripts.projectile;
|
||||
using ColdMint.scripts.projectile.decorator;
|
||||
using ColdMint.scripts.utils;
|
||||
using ColdMint.scripts.inventory;
|
||||
using Godot;
|
||||
|
||||
namespace ColdMint.scripts.weapon;
|
||||
|
@ -21,106 +19,28 @@ public partial class ProjectileWeapon : WeaponTemplate
|
|||
/// <para>抛射体的生成位置</para>
|
||||
/// </summary>
|
||||
private Marker2D? _marker2D;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Scattering radians</para>
|
||||
/// <para>散射弧度</para>
|
||||
/// </summary>
|
||||
[Export] protected float OffsetAngle;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Offset angle mode</para>
|
||||
/// <para>偏移角度模式</para>
|
||||
/// </summary>
|
||||
[Export] protected int OffsetAngleMode = Config.OffsetAngleMode.Random;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Whether the last offset angle is positive</para>
|
||||
/// <para>上次的偏移角度是否为正向的</para>
|
||||
/// </summary>
|
||||
private bool _positiveOffsetAngle = true;
|
||||
|
||||
/// <summary>
|
||||
/// <para>The number of projectiles fired at once</para>
|
||||
/// <para>一次可以发射多少个子弹</para>
|
||||
/// </summary>
|
||||
[Export] protected float NumberOfProjectiles = 1;
|
||||
|
||||
[Export] protected PackedScene[] ProjectileScenes { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// <para>Whether to launch in the order of the projectile list</para>
|
||||
/// <para>是否按照抛射体列表的循序发射</para>
|
||||
/// </summary>
|
||||
[Export]
|
||||
protected bool Sequentially { get; set; }
|
||||
|
||||
|
||||
private int _projectileIndex;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Number of slots for ranged weapons</para>
|
||||
/// <para>远程武器的槽位数量</para>
|
||||
/// </summary>
|
||||
[Export] public int NumberSlots { get; set; }
|
||||
|
||||
public override int ItemType
|
||||
{
|
||||
get => Config.ItemType.ProjectileWeapon;
|
||||
}
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
base._Ready();
|
||||
_marker2D = GetNode<Marker2D>("Marker2D");
|
||||
SelfItemContainer = new UniversalItemContainer(NumberSlots);
|
||||
SelfItemContainer.AllowAddingItemByType(Config.ItemType.Magic);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>GetNextProjectileScene</para>
|
||||
/// <para>获取下一个抛射体</para>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private PackedScene GetNextProjectileScene()
|
||||
{
|
||||
if (Sequentially)
|
||||
{
|
||||
_projectileIndex = (_projectileIndex + 1) % ProjectileScenes.Length;
|
||||
return ProjectileScenes[_projectileIndex];
|
||||
}
|
||||
else
|
||||
{
|
||||
return ProjectileScenes[RandomUtils.Instance.Next(ProjectileScenes.Length)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>GetRandomAngle</para>
|
||||
/// <para>获取随机的偏移弧度</para>
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private float GetRandomAngle()
|
||||
{
|
||||
if (OffsetAngle == 0)
|
||||
{
|
||||
//If the offset angle is 0, then return 0
|
||||
//弧度为0,不用偏移。
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (OffsetAngleMode == Config.OffsetAngleMode.Cross)
|
||||
{
|
||||
float result;
|
||||
if (_positiveOffsetAngle)
|
||||
{
|
||||
result = -OffsetAngle / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = OffsetAngle / 2;
|
||||
}
|
||||
|
||||
_positiveOffsetAngle = !_positiveOffsetAngle;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (OffsetAngleMode == Config.OffsetAngleMode.AlwaysSame)
|
||||
{
|
||||
return OffsetAngle;
|
||||
}
|
||||
|
||||
var min = -OffsetAngle / 2;
|
||||
return min + RandomUtils.Instance.NextSingle() * OffsetAngle;
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected override void DoFire(Node2D? owner, Vector2 enemyGlobalPosition)
|
||||
{
|
||||
|
@ -141,39 +61,6 @@ public partial class ProjectileWeapon : WeaponTemplate
|
|||
LogCat.LogError("projectile_container_is_null");
|
||||
return;
|
||||
}
|
||||
|
||||
//Empty list check
|
||||
//空列表检查
|
||||
if (ProjectileScenes is [])
|
||||
{
|
||||
LogCat.LogError("projectiles_is_empty");
|
||||
return;
|
||||
}
|
||||
|
||||
//Get the first projectile
|
||||
//获取第一个抛射体
|
||||
var projectileScene = GetNextProjectileScene();
|
||||
for (int i = 0; i < NumberOfProjectiles; i++)
|
||||
{
|
||||
var projectile = NodeUtils.InstantiatePackedScene<Projectile>(projectileScene);
|
||||
if (projectile == null) return;
|
||||
if (Config.IsDebug())
|
||||
{
|
||||
var nodeSpawnOnKillCharacterDecorator = new NodeSpawnOnKillCharacterDecorator
|
||||
{
|
||||
DefaultParentNode = this,
|
||||
PackedScenePath = "res://prefab/entitys/BlackenedAboriginalWarrior.tscn"
|
||||
};
|
||||
projectile.AddProjectileDecorator(nodeSpawnOnKillCharacterDecorator);
|
||||
}
|
||||
|
||||
NodeUtils.CallDeferredAddChild(GameSceneDepend.ProjectileContainer, projectile);
|
||||
projectile.Owner = owner;
|
||||
projectile.TargetNode = GameSceneDepend.TemporaryTargetNode;
|
||||
projectile.Velocity =
|
||||
(_marker2D.GlobalPosition.DirectionTo(enemyGlobalPosition) * projectile.Speed)
|
||||
.Rotated(GetRandomAngle());
|
||||
projectile.Position = _marker2D.GlobalPosition;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user