2024-06-19 14:33:00 +00:00
using System ;
2024-08-03 16:32:49 +00:00
using ColdMint.scripts.character ;
2024-06-10 13:05:18 +00:00
using ColdMint.scripts.debug ;
2024-07-24 13:03:24 +00:00
using ColdMint.scripts.projectile ;
2024-05-07 09:38:50 +00:00
using Godot ;
2024-06-22 11:21:06 +00:00
using Packsack = ColdMint . scripts . inventory . Packsack ;
2024-06-16 12:18:44 +00:00
using PacksackUi = ColdMint . scripts . loader . uiLoader . PacksackUi ;
2024-06-22 11:21:06 +00:00
using WeaponTemplate = ColdMint . scripts . weapon . WeaponTemplate ;
2024-04-28 13:55:19 +00:00
2024-06-13 06:18:11 +00:00
2024-04-28 13:55:19 +00:00
namespace ColdMint.scripts.utils ;
2024-06-05 13:38:45 +00:00
/// <summary>
/// <para>Node Utils</para>
/// <para>节点工具</para>
/// </summary>
public static class NodeUtils
2024-04-28 13:55:19 +00:00
{
/// <summary>
/// <para>Delete all child nodes</para>
/// <para>删除所有子节点</para>
/// </summary>
/// <param name="parent"></param>
2024-05-07 09:38:50 +00:00
public static int DeleteAllChild ( Node parent )
2024-04-28 13:55:19 +00:00
{
2024-05-07 09:38:50 +00:00
var deleteNumber = 0 ;
2024-04-28 13:55:19 +00:00
var count = parent . GetChildCount ( ) ;
2024-05-07 09:38:50 +00:00
if ( count < = 0 ) return deleteNumber ;
for ( var i = 0 ; i < count ; i + + )
2024-04-28 13:55:19 +00:00
{
2024-05-07 09:38:50 +00:00
var node = parent . GetChild ( 0 ) ;
parent . RemoveChild ( node ) ;
node . QueueFree ( ) ;
deleteNumber + + ;
2024-04-28 13:55:19 +00:00
}
2024-05-07 09:38:50 +00:00
return deleteNumber ;
}
2024-06-19 14:33:00 +00:00
2024-06-24 14:19:12 +00:00
/// <summary>
/// <para>Call the method to set the parent node at leisure</para>
/// <para>在空闲时刻调用设置父节点的方法</para>
/// </summary>
/// <param name="parentNode"></param>
/// <param name="childNode"></param>
public static void CallDeferredReparent ( Node parentNode , Node childNode )
{
2024-07-25 12:32:59 +00:00
childNode . CallDeferred ( Node . MethodName . Reparent , parentNode ) ;
2024-06-24 14:19:12 +00:00
}
2024-07-10 15:23:04 +00:00
/// <summary>
/// <para>ShowNode</para>
/// <para>显示节点</para>
/// </summary>
/// <param name="node">
///<para>node</para>
///<para>节点</para>
/// </param>
/// <returns>
///<para>Is it displayed successfully?</para>
///<para>是否显示成功</para>
/// </returns>
public static bool ShowNode ( Node node )
{
if ( node is Node2D node2D )
{
node2D . Show ( ) ;
return true ;
}
if ( node is CanvasItem canvasItem )
{
canvasItem . Show ( ) ;
return true ;
}
return false ;
}
/// <summary>
/// <para>hidden node</para>
/// <para>隐藏节点</para>
/// </summary>
/// <param name="node">
///<para>Node to hide</para>
///<para>要隐藏的节点</para>
/// </param>
/// <returns>
///<para>Hide success or not</para>
///<para>是否隐藏成功</para>
/// </returns>
public static bool HideNode ( Node node )
{
if ( node is Node2D node2D )
{
node2D . Hide ( ) ;
return true ;
}
if ( node is CanvasItem canvasItem )
{
canvasItem . Hide ( ) ;
return true ;
}
return false ;
}
2024-06-24 14:19:12 +00:00
/// <summary>
/// <para>Sets child nodes for a node</para>
/// <para>为某个节点设置子节点</para>
/// </summary>
/// <param name="parentNode"></param>
/// <param name="childNode"></param>
public static void CallDeferredAddChild ( Node parentNode , Node childNode )
{
parentNode . CallDeferred ( "add_child" , childNode ) ;
}
2024-06-19 14:33:00 +00:00
/// <summary>
/// <para>Traverse the child nodes of type T under the parent node</para>
/// <para>遍历父节点下T类型的子节点</para>
/// </summary>
/// <param name="parent"></param>
/// <param name="func">
///<para>A function that handles callbacks and returns true to terminate the traversal of the node</para>
///<para>用于处理回调的函数, 返回true终止遍历节点</para>
/// </param>
/// <typeparam name="T">
///<para>When the type is specified as Node, all child nodes are returned.</para>
///<para>当指定类型为Node时, 将返回所有子节点。</para>
/// </typeparam>
2024-06-24 14:19:12 +00:00
public static void ForEachNode < T > ( Node parent , Func < T , bool > func ) where T : Node
2024-06-19 14:33:00 +00:00
{
var count = parent . GetChildCount ( ) ;
if ( count < = 0 )
{
return ;
}
for ( var i = 0 ; i < count ; i + + )
{
var node = parent . GetChild ( i ) ;
if ( node is not T t ) continue ;
if ( func . Invoke ( t ) )
{
break ;
}
}
}
2024-05-09 13:07:14 +00:00
/// <summary>
/// <para>Gets the node closest to the origin</para>
/// <para>获取距离原点最近的节点</para>
/// </summary>
/// <param name="origin">
///<para>origin</para>
///<para>原点</para>
/// </param>
/// <param name="array">
///<para>Node array</para>
///<para>节点数组</para>
/// </param>
/// <param name="excludeInvisibleNodes">
///<para>Whether or not unseen nodes should be excluded</para>
///<para>是否排除不可见的节点</para>
/// </param>
2024-07-11 15:06:47 +00:00
/// <param name="filter">
///<para>Filter, which returns true within the function to filter the specified node.</para>
///<para>过滤器, 在函数内返回true, 则过滤指定节点。</para>
/// </param>
2024-05-09 13:07:14 +00:00
/// <returns></returns>
2024-07-11 15:06:47 +00:00
public static Node2D ? GetTheNearestNode ( Node2D origin , Node [ ] array ,
bool excludeInvisibleNodes = true , Func < Node2D , bool > ? filter = null )
2024-05-09 13:07:14 +00:00
{
var closestDistance = float . MaxValue ;
Node2D ? closestNode = null ;
foreach ( var node in array )
{
if ( node is not Node2D node2D ) continue ;
if ( excludeInvisibleNodes & & ! node2D . Visible )
{
//If invisible nodes are excluded and the current node is invisible, then the next.
//如果排除不可见的节点,且当前节点就是不可见的,那么下一个。
continue ;
}
2024-07-11 15:06:47 +00:00
if ( filter ! = null & & filter . Invoke ( node2D ) )
2024-05-09 13:07:14 +00:00
{
2024-07-11 15:06:47 +00:00
//If there is a filter, and the filter returns true, then the next.
//如果有过滤器, 且过滤器返回true, 那么下一个。
2024-05-09 13:07:14 +00:00
continue ;
}
2024-06-05 13:38:45 +00:00
var distance = node2D . GlobalPosition . DistanceTo ( origin . GlobalPosition ) ;
if ( distance < closestDistance )
2024-05-09 13:07:14 +00:00
{
2024-06-05 13:38:45 +00:00
closestDistance = distance ;
2024-05-09 13:07:14 +00:00
closestNode = node2D ;
}
}
return closestNode ;
}
2024-06-10 13:05:18 +00:00
/// <summary>
/// <para>Find the corresponding container node based on the child node</para>
/// <para>根据子节点查找对应的容器节点</para>
/// </summary>
/// <remarks>
///<para>We want child nodes to be placed under a specific parent node to facilitate the same management. For example, the weapon node should be placed inside the Weapon container node. We call a parent node of the same type as a child node a "container". This method is used to find the corresponding node container based on the type of the child node.</para>
///<para>我们希望子节点被放置在特定的父节点下,方便同一管理。例如:武器节点应该被放置在“武器容器”节点内。我们将子节点的类型相同的父节点叫做“容器”。此方法用于根据子节点的类型查找对应的节点容器。</para>
/// </remarks>
/// <param name="childNode">
///<para>childNode</para>
///<para>子节点</para>
/// </param>
/// <param name="defaultParentNode">
///<para>Default parent, which returns the default node if it cannot be matched by type.</para>
///<para>默认父节点,当按照类型无法匹配时,将返回默认节点。</para>
/// </param>
/// <returns></returns>
public static Node FindContainerNode ( Node childNode , Node defaultParentNode )
{
2024-10-04 12:53:34 +00:00
if ( GameSceneDepend . AiCharacterContainer ! = null & & childNode is AiCharacter )
2024-08-03 16:32:49 +00:00
{
2024-09-01 15:24:35 +00:00
return GameSceneDepend . AiCharacterContainer ;
2024-08-03 16:32:49 +00:00
}
2024-10-04 12:53:34 +00:00
2024-09-01 15:24:35 +00:00
if ( GameSceneDepend . ProjectileContainer ! = null & & childNode is Projectile )
2024-07-24 13:03:24 +00:00
{
2024-09-01 15:24:35 +00:00
return GameSceneDepend . ProjectileContainer ;
2024-07-24 13:03:24 +00:00
}
2024-10-04 12:53:34 +00:00
if ( GameSceneDepend . MagicContainer ! = null & & childNode is IMagic )
{
return GameSceneDepend . MagicContainer ;
}
2024-09-01 15:24:35 +00:00
if ( GameSceneDepend . WeaponContainer ! = null & & childNode is WeaponTemplate )
2024-06-10 13:05:18 +00:00
{
2024-09-01 15:24:35 +00:00
return GameSceneDepend . WeaponContainer ;
2024-06-10 13:05:18 +00:00
}
2024-06-12 15:42:35 +00:00
2024-09-01 15:24:35 +00:00
if ( GameSceneDepend . PacksackContainer ! = null & & childNode is Packsack )
2024-06-12 15:42:35 +00:00
{
2024-09-01 15:24:35 +00:00
return GameSceneDepend . PacksackContainer ;
2024-06-12 15:42:35 +00:00
}
2024-06-15 09:07:02 +00:00
2024-09-18 12:20:02 +00:00
if ( GameSceneDepend . DynamicUiGroup ! = null & & childNode is PacksackUi )
2024-06-16 12:18:44 +00:00
{
2024-09-18 12:20:02 +00:00
return GameSceneDepend . DynamicUiGroup ;
2024-06-16 12:18:44 +00:00
}
2024-06-17 14:12:51 +00:00
2024-06-10 13:05:18 +00:00
return defaultParentNode ;
}
/// <summary>
2024-06-24 14:19:12 +00:00
/// <para>Instantiate the scene and transform it into a node of the target type</para>
/// <para>实例化场景并将其转换为目标类型的节点</para>
2024-06-10 13:05:18 +00:00
/// </summary>
/// <param name="packedScene">
///<para>packedScene</para>
///<para>打包的场景</para>
/// </param>
2024-06-24 14:19:12 +00:00
/// <typeparam name="T">
///<para>genericity</para>
///<para>泛型</para>
/// </typeparam>
2024-06-15 09:07:02 +00:00
/// <returns>
2024-06-24 14:19:12 +00:00
///<para>If the returned type is the target type, the node converted to the target type is returned, otherwise null is returned</para>
///<para>如果返回的类型是目标类型, 那么返回转换到目标类型的节点, 否则返回null</para>
2024-06-15 09:07:02 +00:00
/// </returns>
2024-06-24 14:19:12 +00:00
public static T ? InstantiatePackedScene < T > ( PackedScene packedScene )
2024-06-15 09:07:02 +00:00
where T : class
{
2024-06-24 14:19:12 +00:00
var node = packedScene . Instantiate ( ) ;
2024-06-22 15:29:24 +00:00
// Check the type conversion and return the result successfully
2024-06-15 09:07:02 +00:00
// 检查类型转化,成功返回结果
if ( node is T result ) return result ;
2024-06-22 15:29:24 +00:00
// If the transformation fails, release the created node
2024-06-15 09:07:02 +00:00
//如果转型失败,释放所创建的节点
2024-07-25 12:32:59 +00:00
LogCat . LogWarningWithFormat ( "warning_node_cannot_cast_to" , LogCat . LogLabel . Default , LogCat . UploadFormat , node ,
2024-07-15 14:36:48 +00:00
nameof ( T ) ) ;
2024-06-15 09:07:02 +00:00
node . QueueFree ( ) ;
return null ;
2024-06-10 13:05:18 +00:00
}
2024-04-28 13:55:19 +00:00
}