·
This commit is contained in:
parent
a6b48f0e3c
commit
94770ceca3
@ -20,7 +20,7 @@ namespace XNet.Business.Entity
|
||||
/// <summary>
|
||||
/// 是否碰到非地面障碍物或者碰到其他对象,需要转向
|
||||
/// </summary>
|
||||
public bool IsNeedToOtherDir { get; set; } = false;
|
||||
public bool IsNeedToOtherDir { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 是否可以控制动作
|
||||
@ -44,7 +44,7 @@ namespace XNet.Business.Entity
|
||||
/// <summary>
|
||||
/// 上一次位置计时的时候的时间,用来判断AI是否走死
|
||||
/// </summary>
|
||||
public DateTime PrevToDirTime { get; set; } = DateTime.MinValue;
|
||||
public DateTime? PrevToDirTime { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 临时存储的位置
|
||||
|
||||
@ -3,6 +3,7 @@ using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
using XNet.Business.Net;
|
||||
using XNet.Business.PathNavigation;
|
||||
using XNet.Business.Tank.Manager;
|
||||
|
||||
namespace XNet.Business
|
||||
{
|
||||
@ -11,14 +12,16 @@ namespace XNet.Business
|
||||
private readonly NavMeshManager _navMeshManager;
|
||||
private readonly SceneAgent _sceneAgent;
|
||||
private readonly WsConnectionManager _wsManager; // 新增WebSocket管理器
|
||||
private readonly AIManager _aiManager;
|
||||
|
||||
private const int TARGET_FPS = 30;
|
||||
private const int FRAME_TIME_MS = 1000 / TARGET_FPS;
|
||||
public GameLoopService(NavMeshManager navMeshManager, SceneAgent sceneAgent, WsConnectionManager wsManager)
|
||||
public GameLoopService(NavMeshManager navMeshManager, SceneAgent sceneAgent, WsConnectionManager wsManager, AIManager aiManager)
|
||||
{
|
||||
_navMeshManager = navMeshManager;
|
||||
_sceneAgent = sceneAgent;
|
||||
_wsManager = wsManager;
|
||||
_aiManager = aiManager;
|
||||
}
|
||||
|
||||
|
||||
@ -43,27 +46,10 @@ namespace XNet.Business
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ControlAIPlayer()
|
||||
{
|
||||
foreach (var rooms in _wsManager.InstanceSubscribers.Values)
|
||||
{
|
||||
var room = rooms.FirstOrDefault().Value;
|
||||
if (room != null)
|
||||
{
|
||||
var template = _navMeshManager.GetNavTemplate(room.MapKey);
|
||||
if (template == null) return;
|
||||
var min = template.Bmin;
|
||||
var max = template.Bmax;
|
||||
foreach(var player in room.Players)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SyncAllMessageToClient()
|
||||
{
|
||||
await _aiManager.ControlAIPlayer();
|
||||
await SendSyncLocationMessage();
|
||||
}
|
||||
|
||||
|
||||
@ -167,9 +167,8 @@ namespace XNet.Business.PathNavigation
|
||||
return true;
|
||||
}
|
||||
|
||||
public NavMeshTemplate? GetNavTemplate(string roomId)
|
||||
public NavMeshTemplate? GetNavTemplate(string templateId)
|
||||
{
|
||||
if (!_instanceMap.TryGetValue(roomId, out var templateId)) return null;
|
||||
if (!_templates.TryGetValue(templateId, out var template)) return null;
|
||||
|
||||
return template;
|
||||
|
||||
117
XNet.Business/Tank/Manager/AIManager.cs
Normal file
117
XNet.Business/Tank/Manager/AIManager.cs
Normal file
@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using XNet.Business.Entity;
|
||||
using XNet.Business.Net;
|
||||
using XNet.Business.PathNavigation;
|
||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||
|
||||
namespace XNet.Business.Tank.Manager
|
||||
{
|
||||
public class AIManager
|
||||
{
|
||||
|
||||
private readonly NavMeshManager _navMeshManager;
|
||||
private readonly SceneAgent _sceneAgent;
|
||||
private readonly WsConnectionManager _wsManager;
|
||||
public AIManager(NavMeshManager navMeshManager, SceneAgent sceneAgent, WsConnectionManager wsManager)
|
||||
{
|
||||
_navMeshManager = navMeshManager;
|
||||
_sceneAgent = sceneAgent;
|
||||
_wsManager = wsManager;
|
||||
}
|
||||
|
||||
|
||||
private void MoveAIPlayer(string roomId, ControlPlayer player, Vector3 min, Vector3 max)
|
||||
{
|
||||
bool isNeedToMove = false;
|
||||
DateTime now = DateTime.Now;
|
||||
if (player.IsNeedToOtherDir)//间隔时间大于3s转向一次
|
||||
{
|
||||
var random = new Random();
|
||||
if (player.PrevToDirTime == null)
|
||||
{
|
||||
player.PrevToDirTime = now;
|
||||
isNeedToMove = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//概率再移动
|
||||
if (random.NextDouble() < 0.95)
|
||||
{
|
||||
//在概率范围内,经过指定时间再移动
|
||||
if ((now - player.PrevToDirTime).Value.TotalMilliseconds > 2000)
|
||||
{
|
||||
isNeedToMove = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isNeedToMove)
|
||||
{
|
||||
//地形四边边缘坐标限制
|
||||
float x1 = min.X * 1.1f;
|
||||
float x2 = max.X * 0.9f;
|
||||
float z1 = min.Z * 1.1f;
|
||||
float z2 = max.Z * 0.9f;
|
||||
|
||||
float xMoveTo = (float)random.NextDouble() * x2;
|
||||
xMoveTo = Math.Clamp(xMoveTo, x1, x2);
|
||||
if (random.NextDouble() < 0.5)
|
||||
{
|
||||
xMoveTo *= -1;
|
||||
}
|
||||
|
||||
float zMoveTo = (float)random.NextDouble() * z2;
|
||||
zMoveTo = Math.Clamp(zMoveTo, z1, z2);
|
||||
if (random.NextDouble() < 0.5)
|
||||
{
|
||||
zMoveTo *= -1;
|
||||
}
|
||||
|
||||
var gotoPt = _navMeshManager.GetClosetPoint(roomId, new Vector3(xMoveTo, player.CurrentPos.Y, zMoveTo), out long startRef);
|
||||
if (gotoPt != null)
|
||||
{
|
||||
_sceneAgent.AgentGoto(roomId, player.Agent.idx, gotoPt.Value);
|
||||
}
|
||||
player.IsNeedToOtherDir = false;
|
||||
player.PrevToDirTime = now;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (player.PrevToDirTime == null)
|
||||
{
|
||||
player.PrevToDirTime = now;
|
||||
}
|
||||
var time = (now - player.PrevToDirTime!.Value).TotalMilliseconds;
|
||||
if (time > 3000)
|
||||
{
|
||||
player.IsNeedToOtherDir = true;
|
||||
player.PrevToDirTime = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ControlAIPlayer()
|
||||
{
|
||||
foreach (var rooms in _wsManager.InstanceSubscribers.Values)
|
||||
{
|
||||
var room = rooms.FirstOrDefault().Value;
|
||||
if (room != null && room.StartGameTime != null)
|
||||
{
|
||||
var template = _navMeshManager.GetNavTemplate(room.MapKey);
|
||||
if (template == null) return;
|
||||
var min = template.Bmin;
|
||||
var max = template.Bmax;
|
||||
foreach (var player in room.Players.Values)
|
||||
{
|
||||
if (player.IsCanControl && !player.IsAI)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
MoveAIPlayer(room.RoomId, player, min, max);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@ using XNet.Business;
|
||||
using XNet.Business.Manager;
|
||||
using XNet.Business.Net;
|
||||
using XNet.Business.PathNavigation;
|
||||
using XNet.Business.Tank.Manager;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
@ -27,17 +28,20 @@ builder.Services.AddCors(c =>
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
|
||||
//注入游戏地图导航服务
|
||||
// 1. 注册 MapAgent 为单例
|
||||
// 1. 注册 各地图服务 为单例
|
||||
builder.Services.AddSingleton<NavMeshManager>();
|
||||
builder.Services.AddSingleton<SceneAgent>();
|
||||
|
||||
builder.Services.AddSingleton<WsConnectionManager>();
|
||||
builder.Services.AddSingleton<AIManager>();
|
||||
|
||||
// 2. 注册 SimulationLoop 为 HostedService (后台运行)
|
||||
builder.Services.AddHostedService<GameLoopService>();
|
||||
var app = builder.Build();
|
||||
|
||||
//使用跨域方案
|
||||
app.UseCors("Policy");
|
||||
|
||||
// 提供 wwwroot 目录中的文件
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user