Fixed an issue where the health bar was drawn incorrectly.

修复健康条绘制不正确的问题。
This commit is contained in:
Cold-Mint 2024-05-07 17:38:50 +08:00
parent 9435f76fc0
commit 802eb599da
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
7 changed files with 259 additions and 219 deletions

View File

@ -1,138 +1,158 @@
using ColdMint.scripts.utils;
using Godot; using Godot;
namespace ColdMint.scripts; namespace ColdMint.scripts;
public partial class HealthBarUi : HBoxContainer public partial class HealthBarUi : HBoxContainer
{ {
private int _maxHp; private int _maxHp;
private int _currentHp; private int _currentHp;
public int CurrentHp public int CurrentHp
{ {
get => _currentHp; get => _currentHp;
set set
{ {
if (value == _currentHp) if (value == _currentHp)
{ {
return; return;
} }
var heartCount = GetChildCount(); if (_currentHp > _maxHp)
//有几颗心是满的 {
var fullHeartCount = value / Config.HeartRepresentsHealthValue; //Prohibit the current health to exceed the maximum health. When the maximum health is exceeded, the UI cannot be drawn.
for (int i = 0; i < fullHeartCount; i++) //禁止当前血量超过最大血量当超过最大值时无法绘制UI。
{ return;
//把Ui刷满 }
var textureRect = GetChild<TextureRect>(i);
textureRect.Texture = _heartFull;
}
//有多少空心 var heartCount = GetChildCount();
var emptyHeartCount = heartCount - fullHeartCount; //A few hearts are full
//最后那颗剩余多少血 //有几颗心是满的
var leftOverTextureRect = GetChild<TextureRect>(fullHeartCount); var fullHeartCount = value / Config.HeartRepresentsHealthValue;
var leftOver = value % Config.HeartRepresentsHealthValue; for (int i = 0; i < fullHeartCount; i++)
if (leftOver > 0) {
{ //Brush up the Ui
//占总数的百分比 //把Ui刷满
var percent = leftOver / (float)Config.HeartRepresentsHealthValue; var textureRect = GetChild<TextureRect>(i);
leftOverTextureRect.Texture = GetTexture2DByPercent(percent); textureRect.Texture = _heartFull;
emptyHeartCount--; }
}
for (int i = heartCount - emptyHeartCount; i < heartCount; i++) //How many hollows
{ //有多少空心
var textureRect = GetChild<TextureRect>(i); var emptyHeartCount = heartCount - fullHeartCount;
textureRect.Texture = _heartEmpty; if (emptyHeartCount > 0)
} {
//How much blood is left on the last one
//最后那颗剩余多少血
var leftOverTextureRect = GetChild<TextureRect>(fullHeartCount);
var leftOver = value % Config.HeartRepresentsHealthValue;
if (leftOver > 0)
{
//Percentage of total
//占总数的百分比
var percent = leftOver / (float)Config.HeartRepresentsHealthValue;
leftOverTextureRect.Texture = GetTexture2DByPercent(percent);
emptyHeartCount--;
}
}
_currentHp = value;
}
}
public int MaxHp for (int i = heartCount - emptyHeartCount; i < heartCount; i++)
{ {
get => _maxHp; var textureRect = GetChild<TextureRect>(i);
set textureRect.Texture = _heartEmpty;
{ }
if (value == _maxHp)
{
return;
}
var heartCount = value / Config.HeartRepresentsHealthValue; _currentHp = value;
for (var i = 0; i < heartCount; i++) }
{ }
var heart = CreateTextureRect();
heart.Texture = _heartFull;
AddChild(heart);
}
//最后那颗剩余多少血 public int MaxHp
var leftOver = value % Config.HeartRepresentsHealthValue; {
if (leftOver > 0) get => _maxHp;
{ set
var lastHeart = CreateTextureRect(); {
//占总数的百分比 if (value == _maxHp)
var percent = leftOver / (float)Config.HeartRepresentsHealthValue; {
lastHeart.Texture = GetTexture2DByPercent(percent); return;
AddChild(lastHeart); }
}
_maxHp = value; var heartCount = value / Config.HeartRepresentsHealthValue;
} for (var i = 0; i < heartCount; i++)
} {
var heart = CreateTextureRect();
heart.Texture = _heartFull;
AddChild(heart);
}
private TextureRect CreateTextureRect() //How much blood is left on the last one
{ //最后那颗剩余多少血
var textureRect = new TextureRect(); var leftOver = value % Config.HeartRepresentsHealthValue;
return textureRect; if (leftOver > 0)
} {
var lastHeart = CreateTextureRect();
//Percentage of total
//占总数的百分比
var percent = leftOver / (float)Config.HeartRepresentsHealthValue;
lastHeart.Texture = GetTexture2DByPercent(percent);
AddChild(lastHeart);
}
/// <summary> _maxHp = value;
/// <para>Get the texture based on percentage</para> }
/// <para>根据百分比获取纹理</para> }
/// </summary>
/// <param name="percent"></param>
/// <returns></returns>
private Texture2D GetTexture2DByPercent(float percent)
{
if (percent == 0)
{
return _heartEmpty;
}
if (percent <= 0.25f) private TextureRect CreateTextureRect()
{ {
return _heartQuarter; var textureRect = new TextureRect();
} return textureRect;
else if (percent <= 0.5f) }
{
return _heartHalf;
}
else if (percent <= 0.75f)
{
return _heartThreeFourths;
}
else
{
return _heartFull;
}
}
private Texture2D _heartFull; /// <summary>
private Texture2D _heartEmpty; /// <para>Get the texture based on percentage</para>
private Texture2D _heartHalf; /// <para>根据百分比获取纹理</para>
private Texture2D _heartQuarter; /// </summary>
private Texture2D _heartThreeFourths; /// <param name="percent"></param>
/// <returns></returns>
private Texture2D GetTexture2DByPercent(float percent)
{
if (percent == 0)
{
return _heartEmpty;
}
public override void _Ready() if (percent <= 0.25f)
{ {
base._Ready(); return _heartQuarter;
_heartEmpty = GD.Load<Texture2D>("res://sprites/ui/HeartEmpty.png"); }
_heartQuarter = GD.Load<Texture2D>("res://sprites/ui/HeartQuarter.png"); else if (percent <= 0.5f)
_heartHalf = GD.Load<Texture2D>("res://sprites/ui/HeartHalf.png"); {
_heartThreeFourths = GD.Load<Texture2D>("res://sprites/ui/HeartThreeFourths.png"); return _heartHalf;
_heartFull = GD.Load<Texture2D>("res://sprites/ui/HeartFull.png"); }
} else if (percent <= 0.75f)
} {
return _heartThreeFourths;
}
else
{
return _heartFull;
}
}
private Texture2D _heartFull;
private Texture2D _heartEmpty;
private Texture2D _heartHalf;
private Texture2D _heartQuarter;
private Texture2D _heartThreeFourths;
public override void _Ready()
{
base._Ready();
NodeUtils.DeleteAllChild(this);
_heartEmpty = GD.Load<Texture2D>("res://sprites/ui/HeartEmpty.png");
_heartQuarter = GD.Load<Texture2D>("res://sprites/ui/HeartQuarter.png");
_heartHalf = GD.Load<Texture2D>("res://sprites/ui/HeartHalf.png");
_heartThreeFourths = GD.Load<Texture2D>("res://sprites/ui/HeartThreeFourths.png");
_heartFull = GD.Load<Texture2D>("res://sprites/ui/HeartFull.png");
}
}

View File

@ -134,10 +134,10 @@ public partial class CharacterTemplate : CharacterBody2D
} }
_initialHp = GetMeta("InitialHp", "0").AsInt32(); _initialHp = GetMeta("InitialHp", "0").AsInt32();
if (_initialHp <= 0) if (_initialHp <= 0 || _initialHp > MaxHp)
{ {
//If the initial blood volume is less than or equal to 0, the initial blood volume is set to the maximum blood volume //If the initial health is less than or equal to 0 or greater than the maximum health, then set it to the maximum health
//若初始血量小于等于0则将初始血量设置为最大血量 //如果初始血量小于等于0或者大于最大血量那么将其设置为最大血量
_initialHp = MaxHp; _initialHp = MaxHp;
} }

View File

@ -1,6 +1,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ColdMint.scripts.debug; using ColdMint.scripts.debug;
using ColdMint.scripts.utils;
using ColdMint.scripts.weapon; using ColdMint.scripts.weapon;
using Godot; using Godot;
@ -19,6 +20,7 @@ public partial class HotBar : HBoxContainer, IItemContainer
public override void _Ready() public override void _Ready()
{ {
base._Ready(); base._Ready();
NodeUtils.DeleteAllChild(this);
_itemSlotNodes = new List<ItemSlotNode>(); _itemSlotNodes = new List<ItemSlotNode>();
_itemSlotPackedScene = GD.Load<PackedScene>("res://prefab/ui/ItemSlot.tscn"); _itemSlotPackedScene = GD.Load<PackedScene>("res://prefab/ui/ItemSlot.tscn");
for (var i = 0; i < Config.HotBarSize; i++) for (var i = 0; i < Config.HotBarSize; i++)

View File

@ -1,3 +1,4 @@
using System.Threading.Tasks;
using ColdMint.scripts.debug; using ColdMint.scripts.debug;
using ColdMint.scripts.inventory; using ColdMint.scripts.inventory;
using ColdMint.scripts.loader.uiLoader; using ColdMint.scripts.loader.uiLoader;
@ -15,82 +16,80 @@ namespace ColdMint.scripts.loader.sceneLoader;
public partial class GameSceneLoader : SceneLoaderTemplate public partial class GameSceneLoader : SceneLoaderTemplate
{ {
private IMapGenerator _mapGenerator; private IMapGenerator _mapGenerator;
private IMapGeneratorConfig _mapGeneratorConfig; private IMapGeneratorConfig _mapGeneratorConfig;
public override void InitializeData() public override async Task InitializeData()
{ {
//加载血条场景 //加载血条场景
var healthBarUI = GetNode<HealthBarUi>("CanvasLayer/Control/VBoxContainer/HealthBarUi"); var healthBarUI = GetNode<HealthBarUi>("CanvasLayer/Control/VBoxContainer/HealthBarUi");
NodeUtils.DeleteAllChild(healthBarUI); GameSceneNodeHolder.HealthBarUi = healthBarUI;
GameSceneNodeHolder.HealthBarUi = healthBarUI; //加载HotBar
//加载HotBar var hotBar = GetNode<HotBar>("CanvasLayer/Control/VBoxContainer/HotBar");
var hotBar = GetNode<HotBar>("CanvasLayer/Control/VBoxContainer/HotBar"); GameSceneNodeHolder.HotBar = hotBar;
NodeUtils.DeleteAllChild(hotBar); //加载操作提示
GameSceneNodeHolder.HotBar = hotBar; var operationTip = GetNode<Label>("CanvasLayer/Control/VBoxContainer/OperationTip");
//加载操作提示 GameSceneNodeHolder.OperationTipLabel = operationTip;
var operationTip = GetNode<Label>("CanvasLayer/Control/VBoxContainer/OperationTip"); //加载武器容器
GameSceneNodeHolder.OperationTipLabel = operationTip; var weaponContainer = GetNode<Node2D>("WeaponContainer");
//加载武器容器 GameSceneNodeHolder.WeaponContainer = weaponContainer;
var weaponContainer = GetNode<Node2D>("WeaponContainer");
GameSceneNodeHolder.WeaponContainer = weaponContainer;
_mapGenerator = new MapGenerator();
_mapGenerator.TimeOutPeriod = 15;
_mapGenerator.RoomHolder = new RoomHolder();
_mapGenerator.RoomSlotsMatcher = new RoomSlotsMatcher();
var roomProvider = new RoomProvider();
//添加房间模板
var initialRoom = new RoomTemplate("res://prefab/roomTemplates/dungeon/initialRoom.tscn");
var utilityRoom = new RoomTemplate("res://prefab/roomTemplates/dungeon/utilityRoom.tscn");
initialRoom.MaxNumber = 1;
var horizontalCorridorWithSewer =
new RoomTemplate("res://prefab/roomTemplates/dungeon/horizontalCorridorWithSewer.tscn");
var horizontalCorridor = new RoomTemplate("res://prefab/roomTemplates/dungeon/horizontalCorridor.tscn");
roomProvider.AddRoom(initialRoom);
roomProvider.AddRoom(horizontalCorridor);
roomProvider.AddRoom(horizontalCorridorWithSewer);
roomProvider.AddRoom(utilityRoom);
_mapGenerator.RoomProvider = roomProvider;
var roomPlacer = new RoomPlacer(); _mapGenerator = new MapGenerator();
_mapGeneratorConfig = new MapGeneratorConfig(GetNode<Node2D>("MapRoot"), 1); _mapGenerator.TimeOutPeriod = 15;
roomPlacer.MapGeneratorConfig = _mapGeneratorConfig; _mapGenerator.RoomHolder = new RoomHolder();
_mapGenerator.RoomPlacer = roomPlacer; _mapGenerator.RoomSlotsMatcher = new RoomSlotsMatcher();
} var roomProvider = new RoomProvider();
//添加房间模板
var initialRoom = new RoomTemplate("res://prefab/roomTemplates/dungeon/initialRoom.tscn");
var utilityRoom = new RoomTemplate("res://prefab/roomTemplates/dungeon/utilityRoom.tscn");
initialRoom.MaxNumber = 1;
var horizontalCorridorWithSewer =
new RoomTemplate("res://prefab/roomTemplates/dungeon/horizontalCorridorWithSewer.tscn");
var horizontalCorridor = new RoomTemplate("res://prefab/roomTemplates/dungeon/horizontalCorridor.tscn");
roomProvider.AddRoom(initialRoom);
roomProvider.AddRoom(horizontalCorridor);
roomProvider.AddRoom(horizontalCorridorWithSewer);
roomProvider.AddRoom(utilityRoom);
_mapGenerator.RoomProvider = roomProvider;
public override void LoadScene() var roomPlacer = new RoomPlacer();
{ _mapGeneratorConfig = new MapGeneratorConfig(GetNode<Node2D>("MapRoot"), 1);
_mapGenerator.Generate(_mapGeneratorConfig); roomPlacer.MapGeneratorConfig = _mapGeneratorConfig;
var packedScene = GD.Load<PackedScene>("res://prefab/entitys/Character.tscn"); _mapGenerator.RoomPlacer = roomPlacer;
//Register players in the holder }
//在持有者内注册玩家
var node2D = (Node2D)packedScene.Instantiate();
if (node2D is Player player)
{
GameSceneNodeHolder.Player = player;
//Allow the player to pick up items.
//使玩家可以捡起物品。
player.ItemContainer = GameSceneNodeHolder.HotBar;
}
var gameRoot = GetNode<Node2D>(".");
gameRoot.AddChild(node2D);
node2D.Position = new Vector2(55, 70);
var delivererOfDarkMagicPackedScene = GD.Load<PackedScene>("res://prefab/entitys/DelivererOfDarkMagic.tscn"); public override async Task LoadScene()
var delivererOfDarkMagicPackedSceneNode2D = (Node2D)delivererOfDarkMagicPackedScene.Instantiate(); {
gameRoot.AddChild(delivererOfDarkMagicPackedSceneNode2D); await _mapGenerator.Generate(_mapGeneratorConfig);
delivererOfDarkMagicPackedSceneNode2D.Position = new Vector2(70, 70); var packedScene = GD.Load<PackedScene>("res://prefab/entitys/Character.tscn");
//Register players in the holder
//在持有者内注册玩家
var node2D = (Node2D)packedScene.Instantiate();
if (node2D is Player player)
{
GameSceneNodeHolder.Player = player;
//Allow the player to pick up items.
//使玩家可以捡起物品。
player.ItemContainer = GameSceneNodeHolder.HotBar;
}
//Load a weapon var gameRoot = GetNode<Node2D>(".");
//加载武器 gameRoot.AddChild(node2D);
var w = GD.Load<PackedScene>("res://prefab/weapons/staffOfTheUndead.tscn"); node2D.Position = new Vector2(55, 70);
for (int i = 0; i < 3; i++)
{ var delivererOfDarkMagicPackedScene = GD.Load<PackedScene>("res://prefab/entitys/DelivererOfDarkMagic.tscn");
var wn = (Node2D)w.Instantiate(); var delivererOfDarkMagicPackedSceneNode2D = (Node2D)delivererOfDarkMagicPackedScene.Instantiate();
wn.Position = new Vector2(55, 90); gameRoot.AddChild(delivererOfDarkMagicPackedSceneNode2D);
GameSceneNodeHolder.WeaponContainer.AddChild(wn); delivererOfDarkMagicPackedSceneNode2D.Position = new Vector2(70, 70);
}
} //Load a weapon
} //加载武器
var w = GD.Load<PackedScene>("res://prefab/weapons/staffOfTheUndead.tscn");
for (int i = 0; i < 3; i++)
{
var wn = (Node2D)w.Instantiate();
wn.Position = new Vector2(55, 90);
GameSceneNodeHolder.WeaponContainer.AddChild(wn);
}
}
}

View File

@ -1,3 +1,5 @@
using System.Threading.Tasks;
namespace ColdMint.scripts.loader.sceneLoader; namespace ColdMint.scripts.loader.sceneLoader;
public interface ISceneLoaderContract public interface ISceneLoaderContract
@ -6,11 +8,11 @@ public interface ISceneLoaderContract
/// <para>initialization data</para> /// <para>initialization data</para>
/// <para>初始化数据</para> /// <para>初始化数据</para>
/// </summary> /// </summary>
void InitializeData(); Task InitializeData();
/// <summary> /// <summary>
/// <para>load scene</para> /// <para>load scene</para>
/// <para>加载场景</para> /// <para>加载场景</para>
/// </summary> /// </summary>
void LoadScene(); Task LoadScene();
} }

View File

@ -1,3 +1,4 @@
using System.Threading.Tasks;
using Godot; using Godot;
namespace ColdMint.scripts.loader.sceneLoader; namespace ColdMint.scripts.loader.sceneLoader;
@ -8,19 +9,20 @@ namespace ColdMint.scripts.loader.sceneLoader;
/// </summary> /// </summary>
public partial class SceneLoaderTemplate : Node2D, ISceneLoaderContract public partial class SceneLoaderTemplate : Node2D, ISceneLoaderContract
{ {
public sealed override void _Ready() public sealed override async void _Ready()
{ {
InitializeData(); await InitializeData();
LoadScene(); await LoadScene();
} }
public virtual void InitializeData()
{
}
public virtual void LoadScene() public virtual Task InitializeData()
{ {
return Task.CompletedTask;
} }
}
public virtual Task LoadScene()
{
return Task.CompletedTask;
}
}

View File

@ -1,4 +1,5 @@
using Godot; using System.Threading.Tasks;
using Godot;
namespace ColdMint.scripts.utils; namespace ColdMint.scripts.utils;
@ -9,16 +10,30 @@ public class NodeUtils
/// <para>删除所有子节点</para> /// <para>删除所有子节点</para>
/// </summary> /// </summary>
/// <param name="parent"></param> /// <param name="parent"></param>
public static void DeleteAllChild(Node parent) public static int DeleteAllChild(Node parent)
{ {
var deleteNumber = 0;
var count = parent.GetChildCount(); var count = parent.GetChildCount();
if (count > 0) if (count <= 0) return deleteNumber;
for (var i = 0; i < count; i++)
{ {
for (int i = 0; i < count; i++) var node = parent.GetChild(0);
{ parent.RemoveChild(node);
var node = parent.GetChild(0); node.QueueFree();
node.QueueFree(); deleteNumber++;
}
} }
return deleteNumber;
}
/// <summary>
/// <para>All child nodes are removed asynchronously</para>
/// <para>异步删除所有子节点</para>
/// </summary>
/// <param name="parent"></param>
/// <returns></returns>
public static async Task<int> DeleteAllChildAsync(Node parent)
{
return await Task.Run<int>(() => DeleteAllChild(parent));
} }
} }