Add PickAbleItem.Change item icon and backgrounds.
加入可拾捡物,更换物品图标和背景。
|
@ -1,4 +1,4 @@
|
|||
- id: packsack
|
||||
scene_path: res://prefab/packsacks/packsack.tscn
|
||||
icon_path: res://sprites/Player.png
|
||||
icon_path: res://sprites/packsack.png
|
||||
max_stack_value: 1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
- id: staff_of_the_undead
|
||||
scene_path: res://prefab/weapons/staffOfTheUndead.tscn
|
||||
icon_path: res://sprites/weapon/staffOfTheUndead.png
|
||||
icon_path: res://sprites/weapon/staffOfTheUndead_icon.png
|
||||
max_stack_value: 1
|
||||
|
|
|
@ -1,20 +1,34 @@
|
|||
[gd_scene load_steps=4 format=3 uid="uid://cn10fimoem04m"]
|
||||
[gd_scene load_steps=5 format=3 uid="uid://cn10fimoem04m"]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/item/Packsack.cs" id="1_slakl"]
|
||||
[ext_resource type="Texture2D" uid="uid://b1twcink38sh0" path="res://sprites/Player.png" id="2_e1ale"]
|
||||
[ext_resource type="Texture2D" uid="uid://dvx10dfjctn7t" path="res://sprites/packsack.png" id="2_40jca"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_brthl"]
|
||||
size = Vector2(21, 29)
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_xqyue"]
|
||||
size = Vector2(41, 57)
|
||||
size = Vector2(21, 29)
|
||||
|
||||
[node name="RigidBody2D" type="RigidBody2D"]
|
||||
collision_layer = 8
|
||||
collision_mask = 38
|
||||
script = ExtResource("1_slakl")
|
||||
Id = "packsack"
|
||||
_minContactInjury = null
|
||||
_maxContactInjury = null
|
||||
|
||||
[node name="Player" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("2_e1ale")
|
||||
[node name="DamageArea2D" type="Area2D" parent="."]
|
||||
collision_layer = 8
|
||||
collision_mask = 102
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="DamageArea2D"]
|
||||
position = Vector2(-2.5, 1.5)
|
||||
shape = SubResource("RectangleShape2D_brthl")
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
position = Vector2(-0.5, 3.5)
|
||||
position = Vector2(-2.5, 1.5)
|
||||
shape = SubResource("RectangleShape2D_xqyue")
|
||||
|
||||
[node name="Packsack" type="Sprite2D" parent="."]
|
||||
scale = Vector2(0.5, 0.5)
|
||||
texture = ExtResource("2_40jca")
|
||||
|
|
|
@ -45,42 +45,18 @@ script = ExtResource("2_6p8mv")
|
|||
|
||||
[node name="StaffOfTheUndead" parent="." instance=ExtResource("3_ud0w8")]
|
||||
position = Vector2(231, 116)
|
||||
_minContactInjury = null
|
||||
_maxContactInjury = null
|
||||
_firingIntervalAsMillisecond = null
|
||||
_recoil = null
|
||||
|
||||
[node name="StaffOfTheUndead2" parent="." instance=ExtResource("3_ud0w8")]
|
||||
position = Vector2(113, 149)
|
||||
_minContactInjury = null
|
||||
_maxContactInjury = null
|
||||
_firingIntervalAsMillisecond = null
|
||||
_recoil = null
|
||||
|
||||
[node name="StaffOfTheUndead5" parent="." instance=ExtResource("3_ud0w8")]
|
||||
position = Vector2(213, 177)
|
||||
_minContactInjury = null
|
||||
_maxContactInjury = null
|
||||
_firingIntervalAsMillisecond = null
|
||||
_recoil = null
|
||||
|
||||
[node name="StaffOfTheUndead6" parent="." instance=ExtResource("3_ud0w8")]
|
||||
position = Vector2(290, 167)
|
||||
_minContactInjury = null
|
||||
_maxContactInjury = null
|
||||
_firingIntervalAsMillisecond = null
|
||||
_recoil = null
|
||||
|
||||
[node name="StaffOfTheUndead3" parent="." instance=ExtResource("3_ud0w8")]
|
||||
position = Vector2(70, 88)
|
||||
_minContactInjury = null
|
||||
_maxContactInjury = null
|
||||
_firingIntervalAsMillisecond = null
|
||||
_recoil = null
|
||||
|
||||
[node name="StaffOfTheUndead4" parent="." instance=ExtResource("3_ud0w8")]
|
||||
position = Vector2(367, 85)
|
||||
_minContactInjury = null
|
||||
_maxContactInjury = null
|
||||
_firingIntervalAsMillisecond = null
|
||||
_recoil = null
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
[node name="ItemSlot" type="MarginContainer"]
|
||||
offset_right = 38.0
|
||||
offset_bottom = 38.0
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/margin_left = 3
|
||||
theme_override_constants/margin_top = 3
|
||||
theme_override_constants/margin_right = 3
|
||||
|
@ -16,16 +17,18 @@ script = ExtResource("1_fbwot")
|
|||
layout_mode = 2
|
||||
texture = ExtResource("1_y2wyt")
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="BackgroundTexture"]
|
||||
layout_mode = 2
|
||||
offset_right = 160.0
|
||||
offset_bottom = 160.0
|
||||
[node name="IconTextureRect" type="TextureRect" parent="BackgroundTexture"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 3.0
|
||||
offset_top = 3.0
|
||||
offset_right = -3.0
|
||||
offset_bottom = -3.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
scale = Vector2(0.2, 0.2)
|
||||
|
||||
[node name="IconTextureRect" type="TextureRect" parent="BackgroundTexture/CenterContainer"]
|
||||
layout_mode = 2
|
||||
expand_mode = 1
|
||||
|
||||
[node name="Control" type="Control" parent="."]
|
||||
layout_mode = 2
|
||||
|
|
|
@ -9,7 +9,6 @@ anchor_right = 1.0
|
|||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
script = ExtResource("1_xwjh1")
|
||||
|
||||
|
@ -17,6 +16,8 @@ script = ExtResource("1_xwjh1")
|
|||
layout_mode = 1
|
||||
anchors_preset = 10
|
||||
anchor_right = 1.0
|
||||
offset_left = 20.0
|
||||
offset_right = -1082.0
|
||||
offset_bottom = 39.0
|
||||
grow_horizontal = 2
|
||||
theme_override_font_sizes/font_size = 25
|
||||
|
@ -27,6 +28,9 @@ layout_mode = 1
|
|||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_top = 51.0
|
||||
offset_left = 15.0
|
||||
offset_top = 45.0
|
||||
offset_right = -14.0
|
||||
offset_bottom = -6.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
|
32
prefab/ui/packsackUI.tscn
Normal file
|
@ -0,0 +1,32 @@
|
|||
[gd_scene load_steps=2 format=3 uid="uid://dsat7xk63bfg2"]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/inventory/PacksackUi.cs" id="1_jgs18"]
|
||||
|
||||
[node name="PacksackUi" type="Control"]
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 33.0
|
||||
offset_top = 81.0
|
||||
offset_right = -58.0
|
||||
offset_bottom = -35.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_jgs18")
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Label" type="Label" parent="."]
|
||||
layout_mode = 0
|
||||
offset_left = 3.0
|
||||
offset_top = -43.0
|
||||
offset_right = 43.0
|
||||
offset_bottom = -18.0
|
||||
text = "背包"
|
|
@ -15,16 +15,16 @@ collision_layer = 8
|
|||
collision_mask = 34
|
||||
script = ExtResource("1_w8hhv")
|
||||
ProjectileScenes = [ExtResource("2_34250")]
|
||||
_firingIntervalAsMillisecond = null
|
||||
_recoil = null
|
||||
Id = "staff_of_the_undead"
|
||||
_minContactInjury = null
|
||||
_maxContactInjury = null
|
||||
_firingIntervalAsMillisecond = null
|
||||
_recoil = null
|
||||
metadata/Projectiles = PackedStringArray("res://prefab/projectile/curseOfTheUndead.tscn")
|
||||
|
||||
[node name="DamageArea2D" type="Area2D" parent="."]
|
||||
collision_layer = 8
|
||||
collision_mask = 71
|
||||
collision_mask = 70
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="DamageArea2D"]
|
||||
position = Vector2(25.5, 0.5)
|
||||
|
|
|
@ -153,7 +153,7 @@ locale/translations=PackedStringArray("res://locals/DeathInfo.en.translation", "
|
|||
2d_physics/layer_1="RoomArea"
|
||||
2d_physics/layer_2="Ground"
|
||||
2d_physics/layer_3="Player"
|
||||
2d_physics/layer_4="Weapon"
|
||||
2d_physics/layer_4="PickAbleItem"
|
||||
2d_physics/layer_5="Projectile"
|
||||
2d_physics/layer_6="Platform"
|
||||
2d_physics/layer_7="Mob"
|
||||
|
|
|
@ -377,7 +377,7 @@ public static class Config
|
|||
public const int RoomArea = 1;
|
||||
public const int Ground = 2;
|
||||
public const int Player = 3;
|
||||
public const int Weapon = 4;
|
||||
public const int PickAbleItem = 4;
|
||||
public const int Projectile = 5;
|
||||
public const int Platform = 6;
|
||||
public const int Mob = 7;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using ColdMint.scripts.utils;
|
||||
using ColdMint.scripts.utils;
|
||||
|
||||
using Godot;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ using ColdMint.scripts.inventory;
|
|||
using ColdMint.scripts.item;
|
||||
using ColdMint.scripts.utils;
|
||||
using ColdMint.scripts.item.weapon;
|
||||
|
||||
using ColdMint.scripts.pickable;
|
||||
using Godot;
|
||||
|
||||
namespace ColdMint.scripts.character;
|
||||
|
@ -309,14 +309,14 @@ public partial class CharacterTemplate : CharacterBody2D
|
|||
//设置捡起物品的常规处理。
|
||||
//You can supplement picking up state handling for more types of objects here.
|
||||
//您可以在这里补充更多类型对象的捡起状态处理。
|
||||
if (pickAbleItem is WeaponTemplate weaponTemplate)
|
||||
if (pickAbleItem is PickAbleTemplate pickAbleTemplate)
|
||||
{
|
||||
weaponTemplate.Owner = this;
|
||||
weaponTemplate.Picked = true;
|
||||
weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, false);
|
||||
weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Ground, false);
|
||||
weaponTemplate.EnableContactInjury = false;
|
||||
weaponTemplate.Sleeping = true;
|
||||
pickAbleTemplate.Owner = this;
|
||||
pickAbleTemplate.Picked = true;
|
||||
pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, false);
|
||||
pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Ground, false);
|
||||
pickAbleTemplate.EnableContactInjury = false;
|
||||
pickAbleTemplate.Sleeping = true;
|
||||
}
|
||||
|
||||
if (itemSlotNode.GetItem() != null && itemSlotNode.GetItem() == item && _currentItem == null)
|
||||
|
@ -674,31 +674,31 @@ public partial class CharacterTemplate : CharacterBody2D
|
|||
CallDeferred("NodeReparent", node2D);
|
||||
switch (item)
|
||||
{
|
||||
case WeaponTemplate weaponTemplate:
|
||||
case PickAbleTemplate pickAbleTemplate:
|
||||
if (GameSceneNodeHolder.WeaponContainer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
weaponTemplate.Picked = false;
|
||||
pickAbleTemplate.Picked = false;
|
||||
var timer = new Timer();
|
||||
weaponTemplate.AddChild(timer);
|
||||
pickAbleTemplate.AddChild(timer);
|
||||
timer.WaitTime = _itemCollisionRecoveryTime;
|
||||
timer.OneShot = true;
|
||||
timer.Timeout += () =>
|
||||
{
|
||||
//We cannot immediately resume the physical collision when the weapon is discharged, which will cause the weapon to collide with the ground and platform earlier, preventing the weapon from flying.
|
||||
//仍出武器时,我们不能立即恢复物理碰撞,立即恢复会导致武器更早的与地面和平台碰撞,阻止武器的飞行。
|
||||
weaponTemplate.EnableContactInjury = true;
|
||||
weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Ground, true);
|
||||
weaponTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, true);
|
||||
pickAbleTemplate.EnableContactInjury = true;
|
||||
pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Ground, true);
|
||||
pickAbleTemplate.SetCollisionMaskValue(Config.LayerNumber.Platform, true);
|
||||
timer.QueueFree();
|
||||
};
|
||||
timer.Start();
|
||||
weaponTemplate.Sleeping = false;
|
||||
pickAbleTemplate.Sleeping = false;
|
||||
//Setting an initial speed of 0 for items here prevents the problem of throwing items too fast.
|
||||
//在这里给物品设置一个为0的初始速度,可防止扔出物品时速度过快的问题。
|
||||
weaponTemplate.LinearVelocity = Vector2.Zero;
|
||||
pickAbleTemplate.LinearVelocity = Vector2.Zero;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@ using System.Threading.Tasks;
|
|||
|
||||
using ColdMint.scripts.damage;
|
||||
using ColdMint.scripts.deathInfo;
|
||||
using ColdMint.scripts.debug;
|
||||
using ColdMint.scripts.item;
|
||||
using ColdMint.scripts.map.events;
|
||||
using ColdMint.scripts.utils;
|
||||
using ColdMint.scripts.item.weapon;
|
||||
|
||||
using ColdMint.scripts.pickable;
|
||||
using Godot;
|
||||
|
||||
namespace ColdMint.scripts.character;
|
||||
|
@ -24,7 +24,7 @@ public partial class Player : CharacterTemplate
|
|||
|
||||
//Empty object projectile
|
||||
//空的物品抛射线
|
||||
private readonly Vector2[] _emptyVector2Array = new[] { Vector2.Zero };
|
||||
private readonly Vector2[] _emptyVector2Array = [Vector2.Zero];
|
||||
|
||||
//抛物线
|
||||
private Line2D? _parabola;
|
||||
|
@ -337,9 +337,9 @@ public partial class Player : CharacterTemplate
|
|||
base.Flip();
|
||||
//If there is a weapon, flip it too
|
||||
//如果有武器的话,也要翻转
|
||||
if (CurrentItem is WeaponTemplate weapon)
|
||||
if (CurrentItem is PickAbleTemplate pickAbleTemplate)
|
||||
{
|
||||
weapon.Flip(FacingLeft);
|
||||
pickAbleTemplate.Flip(FacingLeft);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -408,16 +408,16 @@ public partial class Player : CharacterTemplate
|
|||
: new Vector2(0, -PromptTextDistance);
|
||||
_floatLabel.RotationDegrees = 0 - rotationDegreesNode2D;
|
||||
var label = _floatLabel.GetNode<Label>("Label");
|
||||
if (node is WeaponTemplate weapon)
|
||||
if (node is PickAbleTemplate pickAbleTemplate)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
if (weapon.Owner is CharacterTemplate characterTemplate)
|
||||
if (pickAbleTemplate.Owner is CharacterTemplate characterTemplate)
|
||||
{
|
||||
stringBuilder.Append(characterTemplate.ReadOnlyCharacterName);
|
||||
stringBuilder.Append(TranslationServerUtils.Translate("de"));
|
||||
}
|
||||
|
||||
stringBuilder.Append(TranslationServerUtils.Translate(weapon.Name));
|
||||
stringBuilder.Append(TranslationServerUtils.Translate(pickAbleTemplate.Name));
|
||||
label.Text = stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,12 @@ public class ContributorData
|
|||
/// </summary>
|
||||
public string? Url { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>ToolTip</para>
|
||||
/// <para>工具提示</para>
|
||||
/// </summary>
|
||||
public string? ToolTip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>Type of contribution</para>
|
||||
/// <para>贡献的类型</para>
|
||||
|
|
|
@ -18,19 +18,27 @@ public static class ContributorDataManager
|
|||
{
|
||||
Name = "Cold-Mint",
|
||||
Url = "https://github.com/Cold-Mint",
|
||||
ContributorTypes = [ContributorType.Coder]
|
||||
ContributorTypes = [ContributorType.Coder],
|
||||
},
|
||||
new ContributorData
|
||||
{
|
||||
Name = "Web13234",
|
||||
Name = "霧雨烨",
|
||||
Url = "https://github.com/Web13234",
|
||||
ContributorTypes = [ContributorType.Coder]
|
||||
},
|
||||
new ContributorData
|
||||
{
|
||||
Name = "HYPERLINK BLOCKED",
|
||||
Name = "[HYPERLINK BLOCKED]",
|
||||
Url = "https://www.pixiv.net/users/74412798",
|
||||
ContributorTypes = [ContributorType.Artist]
|
||||
ContributorTypes = [ContributorType.Artist],
|
||||
ToolTip = "贡献死灵法杖和背包的贴图。"
|
||||
},
|
||||
new ContributorData
|
||||
{
|
||||
Name = "\u2605如爱生",
|
||||
Url = "https://space.bilibili.com/425243934",
|
||||
ContributorTypes = [ContributorType.Artist],
|
||||
ToolTip = "贡献了一些枪械贴图。"
|
||||
}
|
||||
];
|
||||
|
||||
|
|
|
@ -70,7 +70,9 @@ public static class LogCat
|
|||
}
|
||||
|
||||
StringBuilder.Append(DateTime.Now.ToString(" yyyy-M-d HH:mm:ss : "));
|
||||
StringBuilder.Append(TranslationServerUtils.Translate($"log_{message}"));
|
||||
var key = $"log_{message}";
|
||||
var translationResult = TranslationServerUtils.Translate(key);
|
||||
StringBuilder.Append(translationResult == key ? message : translationResult);
|
||||
return StringBuilder;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using ColdMint.scripts.item;
|
||||
using ColdMint.scripts.item.itemStacks;
|
||||
|
||||
using Godot;
|
||||
|
||||
namespace ColdMint.scripts.inventory;
|
||||
|
@ -193,7 +191,10 @@ public interface IItemContainer : IEnumerable<ItemSlotNode>
|
|||
/// <para>Match the first item slot that satisfies the predicate</para>
|
||||
/// <para>匹配首个拥有满足指定条件的物品槽</para>
|
||||
/// </summary>
|
||||
/// <param name="predicate"></param>
|
||||
/// <param name="predicate">
|
||||
///<para>predicate</para>
|
||||
///<para>谓语</para>
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// <para>Return null if there is no slot satisfies the predicate</para>
|
||||
/// <para>若没有满足条件的槽位,返回null</para>
|
||||
|
|
|
@ -327,7 +327,7 @@ public partial class ItemSlotNode : MarginContainer
|
|||
_backgroundTextureWhenSelect = GD.Load<Texture2D>("res://sprites/ui/ItemBarFocus.png");
|
||||
_backgroundTextureRect =
|
||||
GetNode<TextureRect>("BackgroundTexture");
|
||||
_iconTextureRect = GetNode<TextureRect>("BackgroundTexture/CenterContainer/IconTextureRect");
|
||||
_iconTextureRect = GetNode<TextureRect>("BackgroundTexture/IconTextureRect");
|
||||
_quantityLabel = GetNode<Label>("Control/QuantityLabel");
|
||||
_control = GetNode<Control>("Control");
|
||||
_quantityLabel.Hide();
|
||||
|
|
60
scripts/inventory/PacksackUi.cs
Normal file
|
@ -0,0 +1,60 @@
|
|||
using ColdMint.scripts.utils;
|
||||
using Godot;
|
||||
|
||||
namespace ColdMint.scripts.inventory;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Backpack UI</para>
|
||||
/// <para>背包UI</para>
|
||||
/// </summary>
|
||||
public partial class PacksackUi : Control
|
||||
{
|
||||
private IItemContainer? _itemContainer;
|
||||
|
||||
private PackedScene? _packedScene;
|
||||
|
||||
private GridContainer? _gridContainer;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Packsack</para>
|
||||
/// <para>背包</para>
|
||||
/// </summary>
|
||||
public IItemContainer? ItemContainer
|
||||
{
|
||||
get => _itemContainer;
|
||||
set
|
||||
{
|
||||
_itemContainer = value;
|
||||
PlaceItemSlot(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Place item slots according to item information</para>
|
||||
/// <para>根据物品信息放置物品槽</para>
|
||||
/// </summary>
|
||||
/// <param name="itemContainer"></param>
|
||||
private void PlaceItemSlot(IItemContainer? itemContainer)
|
||||
{
|
||||
if (_gridContainer == null || itemContainer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NodeUtils.DeleteAllChild(_gridContainer);
|
||||
foreach (var itemSlotNode in itemContainer)
|
||||
{
|
||||
itemSlotNode.Reparent(_gridContainer);
|
||||
}
|
||||
}
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_packedScene = GD.Load<PackedScene>("res://prefab/ui/ItemSlot.tscn");
|
||||
_gridContainer = GetNode<GridContainer>("GridContainer");
|
||||
_gridContainer.Columns = Config.HotBarSize;
|
||||
//If the item container was set before this node was placed in the node tree, load it here.
|
||||
//若物品容器在此节点放置到节点树之前被设置了,那么在这里加载。
|
||||
PlaceItemSlot(_itemContainer);
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ namespace ColdMint.scripts.item;
|
|||
/// </summary>
|
||||
public static class ItemTypeManager
|
||||
{
|
||||
//用于yaml反序列化
|
||||
//Use for yaml deserialization
|
||||
private record struct ItemTypeInfo(string Id, string ScenePath, string IconPath, int MaxStackValue) { }
|
||||
|
||||
|
@ -27,32 +28,37 @@ public static class ItemTypeManager
|
|||
{
|
||||
LogCat.Log("start_item_register_from_file");
|
||||
|
||||
// 初始化yaml反序列化器
|
||||
// initialize yaml deserializer
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(UnderscoredNamingConvention.Instance) // convent snake_case
|
||||
.Build();
|
||||
|
||||
// initialize file dir
|
||||
string itemRegsDirPath = "res://data/itemRegs/";
|
||||
//初始化文件目录
|
||||
//initialize file dir
|
||||
var itemRegsDirPath = "res://data/itemRegs/";
|
||||
var itemRegsDir = DirAccess.Open(itemRegsDirPath);
|
||||
if (DirAccess.GetOpenError() is not Error.Ok)
|
||||
{
|
||||
LogCat.LogError("error_when_open_item_regs_dir");
|
||||
}
|
||||
|
||||
// traverse the dir, find files to register
|
||||
//遍历目录,找到要注册的文件
|
||||
//traverse the dir, find files to register
|
||||
foreach (var file in itemRegsDir.GetFiles())
|
||||
{
|
||||
if (file is null) continue;
|
||||
LogCat.LogWithFormat("item_register_from_file", file);
|
||||
|
||||
// read file, parse to an IEnumerable of type infos
|
||||
//读取文件,解析为类型为info的IEnumerable
|
||||
//read file, parse to an IEnumerable of type infos
|
||||
var yamlFile = FileAccess.Open($"{itemRegsDirPath}/{file}", FileAccess.ModeFlags.Read);
|
||||
var yamlString = yamlFile.GetAsText();
|
||||
var typeInfos = deserializer.Deserialize<IEnumerable<ItemTypeInfo>>(yamlString);
|
||||
yamlFile.Close();
|
||||
|
||||
// traverse type infos and register them.
|
||||
//遍历类型信息并注册它们。
|
||||
//traverse type infos and register them.
|
||||
foreach (var typeInfo in typeInfos)
|
||||
{
|
||||
LogCat.LogWithFormat("item_register_find_item_in_file", typeInfo.Id);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using ColdMint.scripts.inventory;
|
||||
using ColdMint.scripts.item.itemStacks;
|
||||
using ColdMint.scripts.pickable;
|
||||
using ColdMint.scripts.utils;
|
||||
using Godot;
|
||||
|
||||
namespace ColdMint.scripts.item;
|
||||
|
@ -8,22 +9,12 @@ namespace ColdMint.scripts.item;
|
|||
/// <para>packsack</para>
|
||||
/// <para>背包</para>
|
||||
/// </summary>
|
||||
public partial class Packsack : RigidBody2D, IItem
|
||||
public partial class Packsack : PickAbleTemplate
|
||||
{
|
||||
[Export] public string Id { get; protected set; } = "place_holder_id";
|
||||
private PackedScene? _packedScene;
|
||||
private PacksackUi? _packsackUi;
|
||||
|
||||
protected Texture2D? UniqueIcon { get; set; }
|
||||
public Texture2D Icon => UniqueIcon ?? ItemTypeManager.DefaultIconOf(Id);
|
||||
|
||||
protected string? UniqueName { get; set; }
|
||||
public new string Name => UniqueName ?? ItemTypeManager.DefaultNameOf(Id);
|
||||
|
||||
protected string? UniqueDescription { get; set; }
|
||||
public string? Description => UniqueDescription ?? ItemTypeManager.DefaultDescriptionOf(Id);
|
||||
|
||||
public void Use(Node2D? owner, Vector2 targetGlobalPosition) { }
|
||||
|
||||
public void Destroy()
|
||||
public override void Destroy()
|
||||
{
|
||||
if (ItemContainer == null) return;
|
||||
foreach (var itemSlot in ItemContainer)
|
||||
|
@ -34,13 +25,18 @@ public partial class Packsack : RigidBody2D, IItem
|
|||
QueueFree();
|
||||
}
|
||||
|
||||
public bool CanStackWith(IItem item) => false;
|
||||
|
||||
public IItemStack SpecialStack()
|
||||
public override void Use(Node2D? owner, Vector2 targetGlobalPosition)
|
||||
{
|
||||
return new PacksackStack(this);
|
||||
if (_packedScene == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (_packsackUi == null)
|
||||
{
|
||||
_packsackUi = NodeUtils.InstantiatePackedScene<PacksackUi>(_packedScene,this);
|
||||
}
|
||||
_packsackUi?.Show();
|
||||
}
|
||||
|
||||
|
||||
public IItemContainer? ItemContainer { get; private set; }
|
||||
|
||||
|
@ -48,5 +44,7 @@ public partial class Packsack : RigidBody2D, IItem
|
|||
{
|
||||
base._Ready();
|
||||
ItemContainer = new UniversalItemContainer();
|
||||
_packedScene = GD.Load<PackedScene>("res://prefab/ui/packsackUI.tscn");
|
||||
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
using System;
|
||||
|
||||
using ColdMint.scripts.camp;
|
||||
using ColdMint.scripts.character;
|
||||
using ColdMint.scripts.damage;
|
||||
using ColdMint.scripts.pickable;
|
||||
using Godot;
|
||||
|
||||
namespace ColdMint.scripts.item.weapon;
|
||||
|
@ -11,57 +9,14 @@ namespace ColdMint.scripts.item.weapon;
|
|||
/// <para>WeaponTemplate</para>
|
||||
/// <para>武器模板</para>
|
||||
/// </summary>
|
||||
public abstract partial class WeaponTemplate : RigidBody2D, IItem
|
||||
public abstract partial class WeaponTemplate : PickAbleTemplate
|
||||
{
|
||||
private float _gravity = ProjectSettings.GetSetting("physics/2d/default_gravity").AsSingle();
|
||||
|
||||
//Implements IItem
|
||||
[Export] public virtual string Id { get; private set; } = "ID";
|
||||
|
||||
protected Texture2D? UniqueIcon { get; set; }
|
||||
public Texture2D Icon => UniqueIcon ?? ItemTypeManager.DefaultIconOf(Id);
|
||||
|
||||
protected string? UniqueName { get; set; }
|
||||
public new string Name => UniqueName ?? ItemTypeManager.DefaultNameOf(Id);
|
||||
|
||||
protected string? UniqueDescription { get; set; }
|
||||
public string? Description => UniqueDescription ?? ItemTypeManager.DefaultDescriptionOf(Id);
|
||||
|
||||
|
||||
public void Use(Node2D? owner, Vector2 targetGlobalPosition)
|
||||
public override void Use(Node2D? owner, Vector2 targetGlobalPosition)
|
||||
{
|
||||
Fire(owner, targetGlobalPosition);
|
||||
}
|
||||
|
||||
public virtual void Destroy()
|
||||
{
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
public bool CanStackWith(IItem item) => false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Whether the weapon is currently picked up</para>
|
||||
/// <para>当前武器是否被捡起了</para>
|
||||
/// </summary>
|
||||
public bool Picked { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>Owner</para>
|
||||
/// <para>主人</para>
|
||||
/// </summary>
|
||||
public new Node2D? Owner { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Enabled contact injury</para>
|
||||
/// <para>启用接触伤害</para>
|
||||
/// </summary>
|
||||
public bool EnableContactInjury;
|
||||
|
||||
[Export] private int _minContactInjury = 1;
|
||||
[Export] private int _maxContactInjury = 2;
|
||||
|
||||
private DateTime? _lastFiringTime;
|
||||
|
||||
|
@ -83,115 +38,15 @@ public abstract partial class WeaponTemplate : RigidBody2D, IItem
|
|||
/// </remarks>
|
||||
[Export] private Vector2 _recoil;
|
||||
|
||||
/// <summary>
|
||||
/// <para>This area represents the collision range of the weapon, and when other nodes enter this area, they will deal damage.</para>
|
||||
/// <para>这个区域表示武器的碰撞范围,当其他节点进入此区域时,会造成伤害。</para>
|
||||
/// </summary>
|
||||
private Area2D? _damageArea2D;
|
||||
|
||||
/// <summary>
|
||||
/// <para>The number of tile maps in contact with this weapon</para>
|
||||
/// <para>与此武器接触的瓦片地图数量</para>
|
||||
/// </summary>
|
||||
private int _tileMapNumber;
|
||||
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_damageArea2D = GetNode<Area2D>("DamageArea2D");
|
||||
_damageArea2D.BodyEntered += OnBodyEnter;
|
||||
_damageArea2D.BodyExited += OnBodyExited;
|
||||
|
||||
_firingInterval = TimeSpan.FromMilliseconds(_firingIntervalAsMillisecond);
|
||||
}
|
||||
|
||||
private void OnBodyExited(Node node)
|
||||
{
|
||||
if (Picked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//If it leaves the ground or walls.
|
||||
//如果离开了地面或墙壁。
|
||||
if (node is TileMap)
|
||||
{
|
||||
_tileMapNumber--;
|
||||
if (_tileMapNumber == 0)
|
||||
{
|
||||
//No longer in contact with any shingles can cause injury
|
||||
//不再与任何瓦片接触后,可以造成伤害
|
||||
EnableContactInjury = true;
|
||||
SetCollisionMaskValue(Config.LayerNumber.Player, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Use weapons against the enemy</para>
|
||||
/// <para>使用武器砸敌人</para>
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
private void OnBodyEnter(Node node)
|
||||
{
|
||||
if (Picked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (node is TileMap)
|
||||
{
|
||||
_tileMapNumber++;
|
||||
EnableContactInjury = false;
|
||||
//Items can be pushed by the player when they are on the ground
|
||||
//当物品在地面上时,可被玩家推动
|
||||
SetCollisionMaskValue(Config.LayerNumber.Player, true);
|
||||
}
|
||||
else if (node is CharacterTemplate characterTemplate)
|
||||
{
|
||||
if (!EnableContactInjury)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (Owner is not CharacterTemplate ownerCharacterTemplate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Determine if your side can cause damage
|
||||
//判断所属的阵营是否可以造成伤害
|
||||
var canCauseHarm = CampManager.CanCauseHarm(CampManager.GetCamp(ownerCharacterTemplate.CampId),
|
||||
CampManager.GetCamp(characterTemplate.CampId));
|
||||
if (!canCauseHarm)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//If allowed to cause harm
|
||||
//如果允许造成伤害
|
||||
var damage = new Damage
|
||||
{
|
||||
MaxDamage = Math.Abs(_maxContactInjury),
|
||||
MinDamage = Math.Abs(_minContactInjury),
|
||||
Attacker = ownerCharacterTemplate
|
||||
};
|
||||
damage.CreateDamage();
|
||||
damage.MoveLeft = LinearVelocity.X < 0;
|
||||
damage.Type = Config.DamageType.Physical;
|
||||
characterTemplate.Damage(damage);
|
||||
//Reduce speed after hitting enemies.
|
||||
//击中敌人后减少速度。
|
||||
LinearVelocity *= 1 - Config.ThrownItemsHitEnemiesReduceSpeedByPercentage;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>翻转武器</para>
|
||||
/// </summary>
|
||||
/// <param name="facingLeft"></param>
|
||||
public void Flip(bool facingLeft) { }
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -73,8 +73,18 @@ public partial class ContributorGroupLoader : UiLoaderTemplate
|
|||
foreach (var contributorData in contributorDataArray)
|
||||
{
|
||||
var linkButton = new LinkButton();
|
||||
linkButton.Underline = LinkButton.UnderlineMode.OnHover;
|
||||
linkButton.Text = contributorData.Name;
|
||||
linkButton.Uri = contributorData.Url;
|
||||
var toolTip = contributorData.ToolTip;
|
||||
if (toolTip == null)
|
||||
{
|
||||
linkButton.TooltipText = contributorData.Url;
|
||||
}
|
||||
else
|
||||
{
|
||||
linkButton.TooltipText = contributorData.ToolTip;
|
||||
}
|
||||
_flowContainer.AddChild(linkButton);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using ColdMint.scripts.contribute;
|
||||
using ColdMint.scripts.contribute;
|
||||
using ColdMint.scripts.utils;
|
||||
using Godot;
|
||||
|
||||
|
|
165
scripts/pickable/PickAbleTemplate.cs
Normal file
|
@ -0,0 +1,165 @@
|
|||
using System;
|
||||
using ColdMint.scripts.camp;
|
||||
using ColdMint.scripts.character;
|
||||
using ColdMint.scripts.damage;
|
||||
using ColdMint.scripts.item;
|
||||
using Godot;
|
||||
|
||||
namespace ColdMint.scripts.pickable;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Templates for all fallen objects</para>
|
||||
/// <para>所有掉落物的模板</para>
|
||||
/// </summary>
|
||||
public partial class PickAbleTemplate : RigidBody2D, IItem
|
||||
{
|
||||
[Export] public virtual string Id { get; set; } = "ID";
|
||||
protected Texture2D? UniqueIcon { get; set; }
|
||||
public Texture2D Icon => UniqueIcon ?? ItemTypeManager.DefaultIconOf(Id);
|
||||
protected string? UniqueName { get; set; }
|
||||
public new string Name => UniqueName ?? ItemTypeManager.DefaultNameOf(Id);
|
||||
protected string? UniqueDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>Owner</para>
|
||||
/// <para>主人</para>
|
||||
/// </summary>
|
||||
public new Node2D? Owner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// <para>Enabled contact injury</para>
|
||||
/// <para>启用接触伤害</para>
|
||||
/// </summary>
|
||||
public bool EnableContactInjury;
|
||||
|
||||
[Export] private int _minContactInjury = 1;
|
||||
[Export] private int _maxContactInjury = 2;
|
||||
|
||||
public string? Description => UniqueDescription ?? ItemTypeManager.DefaultDescriptionOf(Id);
|
||||
|
||||
/// <summary>
|
||||
/// <para>The number of tile maps that come into contact with this item</para>
|
||||
/// <para>与此物品接触的瓦片地图数量</para>
|
||||
/// </summary>
|
||||
private int _tileMapNumber;
|
||||
|
||||
/// <summary>
|
||||
/// <para>This area represents the collision range of the weapon, and when other nodes enter this area, they will deal damage.</para>
|
||||
/// <para>这个区域表示武器的碰撞范围,当其他节点进入此区域时,会造成伤害。</para>
|
||||
/// </summary>
|
||||
private Area2D? _damageArea2D;
|
||||
|
||||
/// <summary>
|
||||
/// <para>Whether the item is currently picked up</para>
|
||||
/// <para>当前物品是否被捡起了</para>
|
||||
/// </summary>
|
||||
public bool Picked { get; set; }
|
||||
|
||||
public virtual void Use(Node2D? owner, Vector2 targetGlobalPosition)
|
||||
{
|
||||
}
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
_damageArea2D = GetNode<Area2D>("DamageArea2D");
|
||||
_damageArea2D.BodyEntered += OnBodyEnter;
|
||||
_damageArea2D.BodyExited += OnBodyExited;
|
||||
}
|
||||
|
||||
private void OnBodyExited(Node node)
|
||||
{
|
||||
if (Picked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//If it leaves the ground or walls.
|
||||
//如果离开了地面或墙壁。
|
||||
if (node is TileMap)
|
||||
{
|
||||
_tileMapNumber--;
|
||||
if (_tileMapNumber == 0)
|
||||
{
|
||||
//No longer in contact with any shingles can cause injury
|
||||
//不再与任何瓦片接触后,可以造成伤害
|
||||
EnableContactInjury = true;
|
||||
SetCollisionMaskValue(Config.LayerNumber.Player, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>Use objects to smash enemies</para>
|
||||
/// <para>使用物品砸敌人</para>
|
||||
/// </summary>
|
||||
/// <param name="node"></param>
|
||||
private void OnBodyEnter(Node node)
|
||||
{
|
||||
if (Picked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (node is TileMap)
|
||||
{
|
||||
_tileMapNumber++;
|
||||
EnableContactInjury = false;
|
||||
//Items can be pushed by the player when they are on the ground
|
||||
//当物品在地面上时,可被玩家推动
|
||||
SetCollisionMaskValue(Config.LayerNumber.Player, true);
|
||||
}
|
||||
else if (node is CharacterTemplate characterTemplate)
|
||||
{
|
||||
if (!EnableContactInjury)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (Owner is not CharacterTemplate ownerCharacterTemplate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Determine if your side can cause damage
|
||||
//判断所属的阵营是否可以造成伤害
|
||||
var canCauseHarm = CampManager.CanCauseHarm(CampManager.GetCamp(ownerCharacterTemplate.CampId),
|
||||
CampManager.GetCamp(characterTemplate.CampId));
|
||||
if (!canCauseHarm)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//If allowed to cause harm
|
||||
//如果允许造成伤害
|
||||
var damage = new Damage
|
||||
{
|
||||
MaxDamage = Math.Abs(_maxContactInjury),
|
||||
MinDamage = Math.Abs(_minContactInjury),
|
||||
Attacker = ownerCharacterTemplate
|
||||
};
|
||||
damage.CreateDamage();
|
||||
damage.MoveLeft = LinearVelocity.X < 0;
|
||||
damage.Type = Config.DamageType.Physical;
|
||||
characterTemplate.Damage(damage);
|
||||
//Reduce speed after hitting enemies.
|
||||
//击中敌人后减少速度。
|
||||
LinearVelocity *= 1 - Config.ThrownItemsHitEnemiesReduceSpeedByPercentage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>Flip item</para>
|
||||
/// <para>翻转物品</para>
|
||||
/// </summary>
|
||||
/// <param name="facingLeft"></param>
|
||||
public void Flip(bool facingLeft) { }
|
||||
|
||||
public virtual void Destroy()
|
||||
{
|
||||
QueueFree();
|
||||
}
|
||||
|
||||
public bool CanStackWith(IItem item) => false;
|
||||
}
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
sprites/packsack.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
34
sprites/packsack.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dvx10dfjctn7t"
|
||||
path="res://.godot/imported/packsack.png-ba078a68a3754f332c41ffcad073a395.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://sprites/packsack.png"
|
||||
dest_files=["res://.godot/imported/packsack.png-ba078a68a3754f332c41ffcad073a395.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
|
Before Width: | Height: | Size: 159 B After Width: | Height: | Size: 136 B |
Before Width: | Height: | Size: 148 B After Width: | Height: | Size: 224 B |
Before Width: | Height: | Size: 1011 B After Width: | Height: | Size: 1.0 KiB |
BIN
sprites/weapon/staffOfTheUndead_icon.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
34
sprites/weapon/staffOfTheUndead_icon.png.import
Normal file
|
@ -0,0 +1,34 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dg5vwprt66w4j"
|
||||
path="res://.godot/imported/staffOfTheUndead_icon.png-4ca5c1341e2dac55b2ef4a0fc05b6e6c.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://sprites/weapon/staffOfTheUndead_icon.png"
|
||||
dest_files=["res://.godot/imported/staffOfTheUndead_icon.png-4ca5c1341e2dac55b2ef4a0fc05b6e6c.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
|