This commit is contained in:
wuyanchen 2025-12-28 17:28:40 +08:00
parent 2f5c67e8ae
commit 735ae054ee
20 changed files with 353 additions and 16 deletions

View File

@ -1,4 +1,5 @@
using MessagePack;
using XNet.Business.Net;
namespace XNet.Business
{

17
XNet.Business/Dto/Vec3.cs Normal file
View File

@ -0,0 +1,17 @@
using MessagePack;
namespace XNet.Business.Dto
{
[MessagePackObject]
public class Vec3
{
[Key("x")]
public float X { get; set; }
[Key("y")]
public float Y { get; set; }
[Key("z")]
public float Z { get; set; }
}
}

View File

@ -0,0 +1,59 @@
using XNet.Business.Dto;
namespace XNet.Business.Entity
{
public class ControlPlayer
{
/// <summary>
/// 用户ID
/// </summary>
public string Id { get; set; } = string.Empty;
/// <summary>
/// 是否碰到非地面障碍物或者碰到其他对象,需要转向
/// </summary>
public bool IsNeedToOtherDir { get; set; } = false;
/// <summary>
/// 是否可以控制动作
/// </summary>
public bool IsCanControl { get; set; } = false;
/// <summary>
/// 上一次位置计时的时候的时间用来判断AI是否走死
/// </summary>
public DateTime PrevToDirTime { get; set; } = DateTime.MinValue;
/// <summary>
/// 临时存储的位置
/// </summary>
public Vec3 TmpPos { get; set; } = new Vec3();
/// <summary>
/// 将要去的位置
/// </summary>
public Vec3 ToPos { get; set; } = new Vec3();
/// <summary>
/// 存储当前的位置
/// </summary>
public Vec3 CurrentPos { get; set; } = new Vec3();
/// <summary>
/// 临时存储的欧拉角
/// </summary>
public Vec3 TmpEuler { get; set; } = new Vec3();
/// <summary>
/// 目标欧拉角,角色朝向
/// </summary>
public Vec3 ToEuler { get; set; } = new Vec3();
/// <summary>
/// 当前线性插值欧拉角,角色朝向
/// </summary>
public Vec3 CurrentEuler { get; set; } = new Vec3();
/// <summary>
/// 路径导航索引下标
/// </summary>
public int AgentIndex { get; set; } = 0;
}
}

View File

@ -0,0 +1,43 @@
using DotRecast.Detour.Crowd;
using System.Collections.Concurrent;
using XNet.Business.Dto;
namespace XNet.Business.Entity
{
/// <summary>
/// 玩家房间实体
/// </summary>
/// <typeparam name="T">玩家实体包括AI</typeparam>
public class PlayerRoom<T>
{
/// <summary>
/// 寻路导航对象
/// </summary>
public DtCrowd Crowd { get; set; } = null!;
/// <summary>
/// 导航实体集合
/// </summary>
public ConcurrentDictionary<string, T> Players { get; set; } = new ConcurrentDictionary<string, T>();
/// <summary>
/// 世界坐标最小值
/// </summary>
public Vec3 WorldMin { get; set; } = new Vec3();
/// <summary>
/// 世界坐标最大值
/// </summary>
public Vec3 WorldMax { get; set; } = new Vec3();
public PlayerRoom() { }
public PlayerRoom(DtCrowd crowd, Vec3 worldMin, Vec3 worldMax)
{
Crowd = crowd;
WorldMin = worldMin;
WorldMax = worldMax;
}
}
}

View File

@ -1,6 +1,7 @@
using Microsoft.Extensions.Hosting;
using System.Diagnostics;
using System.Diagnostics;
using System.Numerics;
using XNet.Business.Net;
using XNet.Business.PathNavigation;
namespace XNet.Business
{

View File

@ -0,0 +1,6 @@
namespace XNet.Business.Manager
{
public abstract class SceneManager
{
}
}

View File

@ -1,6 +1,6 @@
using Microsoft.Extensions.ObjectPool;
namespace XNet.Business
namespace XNet.Business.Net
{

View File

@ -2,11 +2,10 @@
using Microsoft.Extensions.ObjectPool;
using NanoidDotNet;
using System.Collections.Concurrent;
using System.Net.Sockets;
using System.Net.WebSockets;
using System.Text.Json;
namespace XNet.Business
namespace XNet.Business.Net
{
public class WsConnectionManager
{

View File

@ -3,7 +3,7 @@ using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
namespace XNet.Business
namespace XNet.Business.Net
{
public static class WsServer
{

View File

@ -5,7 +5,7 @@ using System;
using System.Collections.Generic;
using System.Text;
namespace XNet.Business
namespace XNet.Business.Parser
{
// 1. 定义一个简单的几何输入类,适配 DotRecast 接口
public class SimpleInputGeomProvider : IInputGeomProvider

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace XNet.Business
namespace XNet.Business.Parser
{
public class SimpleObjParser
{

View File

@ -1,13 +1,12 @@
using DotRecast.Core;
using DotRecast.Core.Numerics;
using DotRecast.Core.Numerics;
using DotRecast.Detour;
using DotRecast.Recast;
using System.Numerics;
using System.Collections.Concurrent;
using System.Buffers; // 引入 ArrayPool
using System.Threading;
using System.Collections.Concurrent;
using System.Numerics;
using XNet.Business.Parser;
namespace XNet.Business
namespace XNet.Business.PathNavigation
{
public class NavMeshManager
{

View File

@ -5,7 +5,7 @@ using DotRecast.Detour.Crowd;
using System.Collections.Concurrent;
using System.Numerics;
namespace XNet.Business
namespace XNet.Business.PathNavigation
{
public class SceneAgent
{

View File

@ -0,0 +1,32 @@
using XNet.Business.Entity;
namespace XNet.Business.Tank.Entities
{
/// <summary>
/// 坦克对象
/// </summary>
public class TankPlayer : ControlPlayer
{
/// <summary>
/// 上一次计算普通攻击的时候的时间用来判断AI是否开始攻击
/// </summary>
public DateTime[] PrevToAttackTimes = Array.Empty<DateTime>();
/// <summary>
/// 第一技能的等级
/// </summary>
public int Skill1Level { get; set; } = 1;
/// <summary>
/// 第二技能的等级
/// </summary>
public int Skill2Level { get; set; } = 1;
/// <summary>
/// 第三技能的等级
/// </summary>
public int Skill3Level { get; set; } = 1;
/// <summary>
/// 第四技能的等级
/// </summary>
public int Skill4Level { get; set; } = 1;
}
}

View File

@ -0,0 +1,100 @@
using System.Text.Json.Serialization;
namespace XNet.Business.Tank.Manager
{
public class BodyDevice
{
[JsonPropertyName("body")]
public string Name { get; set; } = string.Empty;
}
public class WeaponDevice
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("attackPower")]
public float AttackPower { get; set; } = 0.0f;
[JsonPropertyName("findFaceDistance")]
public float FindFaceDistance { get; set; } = 0.0f;
}
public class ArmorDevice
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("armor")]
public float Armor { get; set; } = 0.0f;
[JsonPropertyName("blood")]
public float Blood { get; set; } = 0.0f;
}
public class ChassisDevice
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("speed")]
public float Speed { get; set; } = 0.0f;
}
/// <summary>
/// 设备信息
/// </summary>
public class DeviceInfo
{
/// <summary>
/// 车身核心信息
/// </summary>
[JsonPropertyName("body")]
public BodyDevice[] Body { get; set; } = Array.Empty<BodyDevice>();
/// <summary>
/// 武器信息
/// </summary>
[JsonPropertyName("weapon")]
public WeaponDevice[] Weapon { get; set; } = Array.Empty<WeaponDevice>();
/// <summary>
/// 装甲信息
/// </summary>
[JsonPropertyName("armor")]
public ArmorDevice[] Armor { get; set; } = Array.Empty<ArmorDevice>();
/// <summary>
/// 底盘信息
/// </summary>
[JsonPropertyName("chassis")]
public ChassisDevice[] Chassis { get; set; } = Array.Empty<ChassisDevice>();
}
/// <summary>
/// 设备管理类
/// </summary>
public class DeviceManager
{
public static readonly DeviceManager Instance = new DeviceManager();
public DeviceInfo DeviceInfo { get; set; } = default!;
private DeviceManager() { }
public void Init()
{
string path = Path.Combine(AppContext.BaseDirectory, "role", "device.json");
if (File.Exists(path))
{
string json = File.ReadAllText(path);
DeviceInfo = System.Text.Json.JsonSerializer.Deserialize<DeviceInfo>(json)!;
Console.WriteLine($"角色设备信息配置文件: {path} 加载成功 ");
}
else
{
Console.Write($"角色设备信息配置文件: {path} 不存在 ");
}
}
}
}

View File

@ -0,0 +1,9 @@
using XNet.Business.Manager;
namespace XNet.Business.Tank.Manager
{
public class TankSceneManager : SceneManager
{
}
}

View File

@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Numerics;
using XNet.Business;
using XNet.Business.Manager;
namespace XNet.Api.Controllers
{

View File

@ -1,5 +1,8 @@
using Scalar.AspNetCore;
using XNet.Business;
using XNet.Business.Manager;
using XNet.Business.Net;
using XNet.Business.PathNavigation;
var builder = WebApplication.CreateBuilder(args);
@ -19,6 +22,9 @@ builder.Services.AddSingleton<WsConnectionManager>();
builder.Services.AddHostedService<GameLoopService>();
var app = builder.Build();
// 提供 wwwroot 目录中的文件
app.UseStaticFiles();
// 启动WebSocket服务
app.MapWebSocketServer(app.Services.GetRequiredService<WsConnectionManager>());

View File

@ -31,4 +31,8 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,61 @@
{
"body": [
{
"name": "body0"
},
{
"name": "body1"
},
{
"name": "body2"
}
],
"weapon": [
{
"name": "weapon0",
"attackPower": 20,
"findFaceDistance": 6
},
{
"name": "weapon1",
"attackPower": 18,
"findFaceDistance": 6
},
{
"name": "weapon2",
"attackPower": 25,
"findFaceDistance": 6
}
],
"armor": [
{
"name": "armor0",
"armor": 6,
"blood": 350
},
{
"name": "armor1",
"armor": 5,
"blood": 350
},
{
"name": "armor2",
"armor": 8,
"blood": 350
}
],
"chassis": [
{
"name": "chassis0",
"speed": 2.8
},
{
"name": "chassis1",
"speed": 3.2
},
{
"name": "chassis2",
"speed": 2.4
}
]
}