Remove useless dependencies and add logic for AI to find weapons.

移除无用依赖,加入AI查找武器的逻辑。
This commit is contained in:
Cold-Mint 2024-07-17 22:54:42 +08:00
parent dd16e14947
commit 7812d9c570
Signed by: Cold-Mint
GPG Key ID: C5A9BF8A98E0CE99
11 changed files with 150 additions and 56 deletions

View File

@ -10,8 +10,6 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0-preview.6.24327.7" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" />
<PackageReference Include="YamlDotNet" Version="15.1.6" />
</ItemGroup>
</Project>

View File

@ -72,11 +72,15 @@ log_state_processor_not_found,找不到状态处理器{0}。,State processor {0}
log_chase_no_enemy,追逐没有敌人。,Chase no enemy.,敵がいない追跡です。
log_bubble_not_found,找不到气泡{0}。,Bubble {0} not found.,バブル{0}が見つかりません。
log_owner_is_not_AiCharacter,所有者不是AiCharacter。,Owner is not AiCharacter.,所有者はAiCharacterではありません。
log_weaponContainer_is_null,武器容器为空。,Weapon container is null.,武器コンテナが空です。
log_find_nearest_item,查找最近的物品。,Find the nearest item.,最も近いアイテムを見つけます。
log_float_label_instantiate_failed,浮动标签实例化失败。,Float label instantiation failed.,フロートラベルのインスタンス化に失敗しました。
log_pickable_picked_up,可拾捡物被捡起了,那么不显示标签。,"If the pickable item is picked up, the label is not displayed.",でも、拾得物が拾い上げられたら、ラベルは表示されません。
log_start_uploading,开始上传{0}条日志。,Start uploading {0} logs.,{0}個のログをアップロードを開始します。
log_upload_successful,上传成功,已上传{0}条日志,剩余{1}条日志待上传。,"Upload successful, {0} logs uploaded, {1} logs remaining.",アップロードが成功しました、{0}個のログがアップロードされ、{1}個のログが残っています。
log_upload_failed,上传失败,错误代码:{0},剩余{1}条日志待上传。,"Upload failed, error code: {0}, {1} logs remaining.",アップロードに失敗しました、エラーコード:{0}、{1}個のログが残っています。
log_upload_status,已记录{0}条日志,上传阈值为{1}。,"{0} logs recorded, upload threshold is {1}.",{0}個のログが記録され、アップロード閾値は{1}です。
log_upload_status,已记录{0}条日志,上传阈值为{1}。,"{0} logs recorded, upload threshold is {1}.",{0}個のログが記録され、アップロード閾値は{1}です。
log_weapon_detected,检测到武器。,Weapon detected.,武器が検出されました。
log_no_weapon_detected,没有检测到武器。,No weapon detected.,武器が検出されません。
log_weapon_lost,武器丢失。,Weapon lost.,武器が失われました。
log_nearest_node_is_null,最近的节点为空。,The nearest node is null.,最も近いノードが空です。
log_node_is_not_WeaponTemplate,节点不是WeaponTemplate。,The node is not a WeaponTemplate.,ードはWeaponTemplateではありません。
1 id zh en ja
72 log_owner_is_not_AiCharacter 所有者不是AiCharacter。 Owner is not AiCharacter. 所有者はAiCharacterではありません。
73 log_weaponContainer_is_null log_find_nearest_item 武器容器为空。 查找最近的物品。 Weapon container is null. Find the nearest item. 武器コンテナが空です。 最も近いアイテムを見つけます。
74 log_find_nearest_item log_float_label_instantiate_failed 查找最近的物品。 浮动标签实例化失败。 Find the nearest item. Float label instantiation failed. 最も近いアイテムを見つけます。 フロートラベルのインスタンス化に失敗しました。
log_float_label_instantiate_failed 浮动标签实例化失败。 Float label instantiation failed. フロートラベルのインスタンス化に失敗しました。
75 log_pickable_picked_up 可拾捡物被捡起了,那么不显示标签。 If the pickable item is picked up, the label is not displayed. でも、拾得物が拾い上げられたら、ラベルは表示されません。
76 log_start_uploading 开始上传{0}条日志。 Start uploading {0} logs. {0}個のログをアップロードを開始します。
77 log_upload_successful 上传成功,已上传{0}条日志,剩余{1}条日志待上传。 Upload successful, {0} logs uploaded, {1} logs remaining. アップロードが成功しました、{0}個のログがアップロードされ、{1}個のログが残っています。
78 log_upload_failed 上传失败,错误代码:{0},剩余{1}条日志待上传。 Upload failed, error code: {0}, {1} logs remaining. アップロードに失敗しました、エラーコード:{0}、{1}個のログが残っています。
79 log_upload_status 已记录{0}条日志,上传阈值为{1}。 {0} logs recorded, upload threshold is {1}. {0}個のログが記録され、アップロード閾値は{1}です。
80 log_weapon_detected 检测到武器。 Weapon detected. 武器が検出されました。
81 log_no_weapon_detected 没有检测到武器。 No weapon detected. 武器が検出されません。
82 log_weapon_lost 武器丢失。 Weapon lost. 武器が失われました。
83 log_nearest_node_is_null 最近的节点为空。 The nearest node is null. 最も近いノードが空です。
84 log_node_is_not_WeaponTemplate 节点不是WeaponTemplate。 The node is not a WeaponTemplate. ノードはWeaponTemplateではありません。
85
86

View File

@ -4,4 +4,3 @@ slogan_1,Kawaii!,Kawaii!,Kawaii!
slogan_2,魔法是想象的世界。,Magic is an imaginary world.,魔法は想像の世界です。
slogan_3,也试试《Minecraft》,Also try 'Minecraft'!,「Minecraft」もやってみて
slogan_4,也试试《Terraria》,Also try 'Terraria'!,「Terraria」もやってみて
slogan_5,你好,Hello,こんにちは
1 id zh en ja
4 slogan_2 魔法是想象的世界。 Magic is an imaginary world. 魔法は想像の世界です。
5 slogan_3 也试试《Minecraft》! Also try 'Minecraft'! 「Minecraft」もやってみて!
6 slogan_4 也试试《Terraria》! Also try 'Terraria'! 「Terraria」もやってみて!
slogan_5 你好 Hello こんにちは

View File

@ -34,7 +34,6 @@ radius = 233.808
collision_layer = 64
collision_mask = 38
script = ExtResource("1_ubaid")
InitWeaponRes = "res://prefab/weapons/staffOfTheUndead.tscn"
LootListId = "test"
metadata/CampId = "Mazoku"
metadata/MaxHp = 50
@ -95,7 +94,7 @@ scale = Vector2(2.04, 3.05)
[node name="ScoutArea2D" type="Area2D" parent="."]
collision_layer = 0
collision_mask = 68
collision_mask = 76
[node name="CollisionShape2D" type="CollisionShape2D" parent="ScoutArea2D"]
shape = SubResource("CircleShape2D_fowd5")

View File

@ -265,7 +265,6 @@ vertical_alignment = 1
libraries = {
"": SubResource("AnimationLibrary_mraly")
}
autoplay = "startup"
[node name="NameLabel" type="Label" parent="."]
modulate = Color(1, 1, 1, 0)

View File

@ -46,6 +46,12 @@ public sealed partial class AiCharacter : CharacterTemplate
/// </summary>
private List<CharacterTemplate>? _enemyInTheScoutRange;
/// <summary>
/// <para>Every weapon in the recon area</para>
/// <para>在侦察范围内所有的武器</para>
/// </summary>
private List<WeaponTemplate>? _weaponInTheScoutRange;
/// <summary>
/// <para>Obstacle detection ray during attack</para>
@ -107,6 +113,7 @@ public sealed partial class AiCharacter : CharacterTemplate
_enemyInTheAttackRange = new List<CharacterTemplate>();
_enemyInTheScoutRange = new List<CharacterTemplate>();
_weaponInTheScoutRange = new List<WeaponTemplate>();
_screenEnabler2D = GetNode<VisibleOnScreenEnabler2D>("VisibleOnScreenEnabler2D");
_screenEnabler2D.ScreenEntered += () =>
{
@ -182,7 +189,7 @@ public sealed partial class AiCharacter : CharacterTemplate
//You must create an item container for the character before you can pick up the item.
//必须为角色创建物品容器后才能拾起物品。
var universalItemContainer = new UniversalItemContainer();
var itemSlotNode = universalItemContainer.AddItemSlot(this);
var itemSlotNode = universalItemContainer.AddItemSlot(this);
itemSlotNode?.Hide();
ProtectedItemContainer = universalItemContainer;
//Add initial weapon
@ -209,6 +216,7 @@ public sealed partial class AiCharacter : CharacterTemplate
{
return;
}
NodeUtils.CallDeferredAddChild(this, weaponTemplate);
PickItem(weaponTemplate);
}
@ -260,6 +268,36 @@ public sealed partial class AiCharacter : CharacterTemplate
return _enemyInTheScoutRange.Count > 0;
}
/// <summary>
/// <para>Any weapons found in the recon area</para>
/// <para>侦察范围内是否发现武器</para>
/// </summary>
/// <returns></returns>
public bool ScoutWeaponDetected()
{
if (_weaponInTheScoutRange == null)
{
return false;
}
return _weaponInTheScoutRange.Count > 0;
}
/// <summary>
/// <para>Get weapons in the recon area</para>
/// <para>获取侦察范围内的武器</para>
/// </summary>
/// <returns></returns>
public WeaponTemplate[]? GetWeaponInScoutArea()
{
if (_weaponInTheScoutRange == null)
{
return null;
}
return _weaponInTheScoutRange.ToArray();
}
/// <summary>
/// <para>Get the first enemy in range</para>
/// <para>获取第一个进入侦察范围的敌人</para>
@ -308,6 +346,11 @@ public sealed partial class AiCharacter : CharacterTemplate
/// <param name="node"></param>
private void EnterTheScoutArea(Node node)
{
if (node is WeaponTemplate weaponTemplate)
{
_weaponInTheScoutRange?.Add(weaponTemplate);
}
CanCauseHarmNode(node, (canCause, characterTemplate) =>
{
if (canCause && characterTemplate != null)
@ -329,6 +372,11 @@ public sealed partial class AiCharacter : CharacterTemplate
return;
}
if (node is WeaponTemplate weaponTemplate)
{
_weaponInTheScoutRange?.Remove(weaponTemplate);
}
if (node is CharacterTemplate characterTemplate)
{
_enemyInTheScoutRange?.Remove(characterTemplate);

View File

@ -4,9 +4,6 @@ using System.Text;
using ColdMint.scripts.openObserve;
using ColdMint.scripts.utils;
using Godot;
using Microsoft.Extensions.Logging;
using OpenTelemetry.Exporter;
using OpenTelemetry.Logs;
namespace ColdMint.scripts.debug;
@ -20,6 +17,12 @@ public static class LogCat
/// </summary>
public const string Default = "Default";
/// <summary>
/// <para>LookForWeaponProcessor</para>
/// <para>查找武器处理器</para>
/// </summary>
public const string LookForWeaponProcessor = "LookForWeaponProcessor";
/// <summary>
/// <para>PatrolStateProcessor</para>
/// <para>巡逻状态处理器</para>
@ -119,25 +122,6 @@ public static class LogCat
private static HashSet<string> DisabledLogLabels { get; } = [];
public static void Init()
{
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddOpenTelemetry(options => { options.AddOtlpExporter(OtlpExporterOptions); });
});
var logger = loggerFactory.CreateLogger("323");
logger.Log(LogLevel.Debug, "你好");
}
public static void OtlpExporterOptions(OtlpExporterOptions options)
{
options.Protocol = OtlpExportProtocol.HttpProtobuf;
options.Endpoint = new Uri("http://test.coldmint.top/api/default/traces");
options.Headers =
"Authorization=Basic cm9vdEBleGFtcGxlLmNvbTp5V0kwVzZYcWhteTBzQml3,organization=default,stream-name=default";
}
/// <summary>
/// <para>Disable log Label</para>
/// <para>禁用某个日志标签</para>

View File

@ -23,6 +23,8 @@ public partial class SplashScreenLoader : UiLoaderTemplate
private Label? _loadingLabel;
private PackedScene? _mainMenuScene;
private AnimationPlayer? _animationPlayer;
private string _startup = "startup";
private Label? _nameLabel;
public override void InitializeData()
{
@ -31,9 +33,22 @@ public partial class SplashScreenLoader : UiLoaderTemplate
public override void InitializeUi()
{
_nameLabel = GetNode<Label>("NameLabel");
_loadingLabel = GetNode<Label>("loadingStateLabel");
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
_animationPlayer.AnimationFinished += AnimationFinished;
//Disable animation in Debug mode.
//在Debug模式禁用动画。
if (Config.IsDebug())
{
_loadingLabel.Modulate = Colors.White;
_nameLabel.Modulate = Colors.White;
AnimationFinished(_startup);
}
else
{
_animationPlayer.Play(_startup);
_animationPlayer.AnimationFinished += AnimationFinished;
}
}
private async void AnimationFinished(StringName name)

View File

@ -24,5 +24,7 @@ public class PatrolStateMachine : StateMachineTemplate
RegisterProcessor(patrolStateProcessor);
var chaseStateProcessor = new ChaseStateProcessor();
RegisterProcessor(chaseStateProcessor);
var lookForWeaponProcessor = new LookForWeaponProcessor();
RegisterProcessor(lookForWeaponProcessor);
}
}

View File

@ -1,4 +1,5 @@
using ColdMint.scripts.character;
using System.Collections.Generic;
using ColdMint.scripts.character;
using ColdMint.scripts.debug;
using ColdMint.scripts.utils;
using ColdMint.scripts.weapon;
@ -12,32 +13,73 @@ namespace ColdMint.scripts.stateMachine.StateProcessor;
/// </summary>
public class LookForWeaponProcessor : StateProcessorTemplate
{
protected WeaponTemplate weaponTemplate;
protected WeaponTemplate? TargetWeapon;
protected override void OnExecute(StateContext context, Node owner)
{
//Find weapons around your character.
//查找角色周围的武器。
if (owner is not AiCharacter aiCharacter)
{
LogCat.LogError("owner_is_not_AiCharacter");
LogCat.LogError("owner_is_not_AiCharacter", LogCat.LogLabel.LookForWeaponProcessor);
return;
}
if (GameSceneNodeHolder.WeaponContainer == null)
if (TargetWeapon != null)
{
LogCat.LogError("weaponContainer_is_null");
//If the nearest weapon is found, move the character to the weapon.
//如果有最近的武器被找到了,那么将角色移动到武器旁边。
aiCharacter.SetTargetPosition(TargetWeapon.GlobalPosition);
return;
}
NodeUtils.ForEachNode<WeaponTemplate>(GameSceneNodeHolder.WeaponContainer, template =>
if (aiCharacter.ScoutWeaponDetected())
{
if (template.GlobalPosition.DistanceTo(aiCharacter.GlobalPosition) > 100)
//Weapons were found in the character's recon area.
//在角色的侦察范围内发现了武器。
//We search for the nearest weapon.
//我们搜索最近的武器。
LogCat.Log("weapon_detected", LogCat.LogLabel.LookForWeaponProcessor);
var weaponTemplates = aiCharacter.GetWeaponInScoutArea();
if (weaponTemplates == null || weaponTemplates.Length == 0)
{
weaponTemplate = template;
return true;
//The weapon may have been lost or taken by someone else.
//武器可能已丢失,或被他人占用。
LogCat.Log("weapon_lost", LogCat.LogLabel.LookForWeaponProcessor);
return;
}
return false;
});
var nodes = new List<Node>();
foreach (var weapon in weaponTemplates)
{
if (weapon is Node newNode)
{
nodes.Add(newNode);
}
}
var node = NodeUtils.GetTheNearestNode(aiCharacter, nodes.ToArray());
if (node == null)
{
//When looking for the nearest node, return null.
//查找最近的节点时返回null。
LogCat.Log("nearest_node_is_null", LogCat.LogLabel.LookForWeaponProcessor);
return;
}
if (node is WeaponTemplate weaponTemplate)
{
TargetWeapon = weaponTemplate;
}
else
{
LogCat.LogError("node_is_not_WeaponTemplate", LogCat.LogLabel.LookForWeaponProcessor);
}
}
else
{
//No weapons detected
//没有检测到武器
LogCat.Log("no_weapon_detected", LogCat.LogLabel.LookForWeaponProcessor);
}
}
public override State State => State.LookForWeapon;

View File

@ -1,5 +1,6 @@
using ColdMint.scripts.character;
using ColdMint.scripts.debug;
using ColdMint.scripts.weapon;
using Godot;
namespace ColdMint.scripts.stateMachine.StateProcessor;
@ -11,6 +12,7 @@ namespace ColdMint.scripts.stateMachine.StateProcessor;
public class PatrolStateProcessor : StateProcessorTemplate
{
public Vector2[]? Points { get; set; }
/// <summary>
/// <para>Whether to guard the origin</para>
/// <para>是否需要守护原点</para>
@ -45,14 +47,14 @@ public class PatrolStateProcessor : StateProcessorTemplate
{
//Once the enemy enters the reconnaissance range, we first see if the character has a weapon, if so, then pursue the enemy, otherwise, the patrol state changes to looking for weapons.
//发现敌人进入侦察范围后,我们先看角色是否持有武器,如果有,那么追击敌人,否则,巡逻状态转换为寻找武器。
// if (aiCharacter.CurrentItem is WeaponTemplate weaponTemplate)
// {
context.CurrentState = State.Chase;
// }
// else
// {
// context.CurrentState = State.LookForWeapon;
// }
if (aiCharacter.CurrentItem is WeaponTemplate weaponTemplate)
{
context.CurrentState = State.Chase;
}
else
{
context.CurrentState = State.LookForWeapon;
}
LogCat.Log("patrol_enemy_detected", label: LogCat.LogLabel.PatrolStateProcessor);
return;
@ -78,7 +80,7 @@ public class PatrolStateProcessor : StateProcessorTemplate
_originPosition = aiCharacter.GlobalPosition;
LogCat.LogWithFormat("patrol_origin_position", LogCat.LogLabel.PatrolStateProcessor,
LogCat.UploadFormat,_originPosition);
LogCat.UploadFormat, _originPosition);
}
var point = _originPosition + Points[_index];
@ -87,7 +89,8 @@ public class PatrolStateProcessor : StateProcessorTemplate
{
//No need to actually come to the patrol point, we just need a distance to get close.
//无需真正的来到巡逻点,我们只需要一个距离接近了就可以了。
LogCat.LogWithFormat("patrol_arrival_point", LogCat.LogLabel.PatrolStateProcessor, LogCat.UploadFormat,point);
LogCat.LogWithFormat("patrol_arrival_point", LogCat.LogLabel.PatrolStateProcessor, LogCat.UploadFormat,
point);
_index++;
if (_index >= Points.Length)
{
@ -96,7 +99,8 @@ public class PatrolStateProcessor : StateProcessorTemplate
}
else
{
LogCat.LogWithFormat("patrol_to_next_point", label: LogCat.LogLabel.PatrolStateProcessor, LogCat.UploadFormat,point,
LogCat.LogWithFormat("patrol_to_next_point", label: LogCat.LogLabel.PatrolStateProcessor,
LogCat.UploadFormat, point,
aiCharacter.GlobalPosition, Points[_index],
distance);
aiCharacter.SetTargetPosition(point.Value);