航弹院项目:
-
解决移动问题
-
界面-图表-指令发送界面-配置等等
-
使用套接字发送指令与图片,并且为飞机类每个人配置一个套接字用于发送指令
-
了解一下如何获取和写入数据到GameINstance而不是在gamemode中
-
如何直接平滑调动pawn还是没有头绪. 最坏情况下,改用character,再次测试为什么不动
-
功能分解:
-
指令控制功能:
- 设计指令数据包.
- 写到配置文件里并实时读取配置
- 在飞机里增加套接字,用于针对性的发送指令
- 写一个下拉菜单调用发送指令的功能
-
实验科目功能
- 读取配置文件,初始化实验场地
- 在gamemode蓝图中?进行读取并放置的操作
-
-
通信配置界面功能
- 配置基础通信(基本实现)
- 配置每架飞机的ip和端口.如何设置?动态获取飞机对象列表,然后调用其中的套接字的设置.
-
数据显示界面
- 接受外部信息 动力学 节点数量 需要单开一个套接字
- 数据存在哪里?gamemode还是GameINstance?
- 读取图片并显示
-
一期未完成功能
- 平滑移动 已经解决
- 轨迹与飞机重叠
- 卡顿问题
- 地图问题(增加一个海洋,已有解决方案)
平滑移动问题:
- 目前思路:
-
所有myactor类继承到character中
-
看看先用默认的controller类控制它们
-
使用之前项目里的那种,计算当前位置和下一个点的向量差, 然后根据数据点之间的时间算出来一个速度,然后算出来一个vectoi加到当前的charactor上看看
-
新建一个继承自character的类看看要补什么函数
-
插值法
-
c++里增加四个变量和一个定时器
-
c++去实现movetolocation和updatelocation
-
在接收到移动指令的movetotransfoembyinterp里,调用一个movetolocation,然后执行后面的update等功能
-
一期功能测试:
- 场景设计
- udp通信
- 态势显示
- 仿真回放 基本完成
- 视角切换
1.三维仿真运行是实时的,和飞机导弹等同步展示
2.三维场景下的飞机只需要展示飞机的状态轨迹携带两种弹药的数量 没写这个飞机携带的弹药数量
3.弹药显示出飞行状态轨迹,自己的类型(a还是b), a还是b没有区分弹药种类
4.生成的目标具有5种类型(常见的地面目标就行,建筑坦克车辆等) 好像只写了坦克,需要增加种类
5.用不同颜色显示出地面站画出来的各种区域 实现
void UConfigManager::LoadConfig()
{
// 定义自定义配置文件路径(可以是项目的Config目录下)
FString CustomConfigPath = FPaths::ProjectConfigDir() / TEXT("CustomConfig.ini");
// 使用 FConfigCacheIni 读取自定义配置文件
GConfig->LoadFile(CustomConfigPath);
// 从自定义配置文件中读取数据
GConfig->GetString(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("LocalIP"), LocalIP, CustomConfigPath);
GConfig->GetString(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("MulticastIP"), MulticastIP, CustomConfigPath);
GConfig->GetInt(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("Port"), Port, CustomConfigPath);
GConfig->GetInt(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("MultiPort"), MultiPort, CustomConfigPath);
GConfig->GetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("LatitudeOffset"), LatitudeOffset, CustomConfigPath);
GConfig->GetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("LongitudeOffset"), LongitudeOffset, CustomConfigPath);
GConfig->GetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("Scale"), GeoScale, CustomConfigPath);
GConfig->GetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("XOffset"), XOffset, CustomConfigPath);
GConfig->GetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("YOffset"), YOffset, CustomConfigPath);
GConfig->GetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("ZOffset"), ZOffset, CustomConfigPath);
GConfig->GetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("XYZScale"), XYZScale, CustomConfigPath);
GConfig->GetInt(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("AircraftCount"), AircraftCount, CustomConfigPath);
GConfig->GetInt(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("MissileCount"), MissileCount, CustomConfigPath);
AircraftConfigs.Empty();
// 读取每个飞机的配置
for (int32 i = 1; i <= AircraftCount; ++i)
{
FString SectionName = FString::Printf(TEXT("Aircraft_%d"), i);
int32 ID, Type;
FString PositionStr, RotationStr;
FVector Position;
FRotator Rotation;
GConfig->GetInt(*SectionName, TEXT("ID"), ID, CustomConfigPath);
GConfig->GetInt(*SectionName, TEXT("Type"), Type, CustomConfigPath);
GConfig->GetString(*SectionName, TEXT("Position"), PositionStr, CustomConfigPath);
GConfig->GetString(*SectionName, TEXT("Rotation"), RotationStr, CustomConfigPath);
FDefaultValueHelper::ParseVector(PositionStr, Position);
FDefaultValueHelper::ParseRotator(RotationStr, Rotation);
FAircraftConfig NewConfig = { ID, Type, Position, Rotation };
AircraftConfigs.Add(NewConfig);
}
}
void UConfigManager::SaveConfigToFile()
{
// 定义自定义配置文件路径(可以是项目的Config目录下)
FString CustomConfigPath = FPaths::ProjectConfigDir() / TEXT("CustomConfig.ini");
// 使用 FConfigCacheIni 读取自定义配置文件
GConfig->LoadFile(CustomConfigPath);
// 写入网络配置
GConfig->SetString(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("LocalIP"), *LocalIP, CustomConfigPath);
GConfig->SetString(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("MulticastIP"), *MulticastIP, CustomConfigPath);
GConfig->SetInt(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("Port"), Port, CustomConfigPath);
GConfig->SetInt(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("MultiPort"), MultiPort, CustomConfigPath);
// 写入地图设置
GConfig->SetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("LatitudeOffset"), LatitudeOffset, CustomConfigPath);
GConfig->SetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("LongitudeOffset"), LongitudeOffset, CustomConfigPath);
GConfig->SetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("Scale"), GeoScale, CustomConfigPath);
GConfig->SetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("XOffset"), XOffset, CustomConfigPath);
GConfig->SetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("YOffset"), YOffset, CustomConfigPath);
GConfig->SetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("ZOffset"), ZOffset, CustomConfigPath);
GConfig->SetFloat(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("XYZScale"), XYZScale, CustomConfigPath);
// 写入飞机数量
GConfig->SetInt(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("AircraftCount"), AircraftCount, CustomConfigPath);
GConfig->SetInt(TEXT("/Script/MissileSimulation.ConfigManager"), TEXT("MissileCount"), MissileCount, CustomConfigPath);
// 写入每个飞机的配置
for (int32 i = 1; i <= AircraftCount; ++i)
{
FString SectionName = FString::Printf(TEXT("Aircraft_%d"), i);
const FAircraftConfig& Config = AircraftConfigs[i - 1];
GConfig->SetInt(*SectionName, TEXT("ID"), Config.ID, CustomConfigPath);
GConfig->SetInt(*SectionName, TEXT("Type"), Config.Type, CustomConfigPath);
FString PositionStr = FString::Printf(TEXT("%f,%f,%f"), Config.Position.X, Config.Position.Y, Config.Position.Z);
FString RotationStr = FString::Printf(TEXT("%f,%f,%f"), Config.Rotation.Pitch, Config.Rotation.Yaw, Config.Rotation.Roll);
GConfig->SetString(*SectionName, TEXT("Position"), *PositionStr, CustomConfigPath);
GConfig->SetString(*SectionName, TEXT("Rotation"), *RotationStr, CustomConfigPath);
}
// 保存配置到文件
GConfig->Flush(false, GGameIni);
}
点击查看代码
import socket
import struct
import math
import time
from threading import Timer
# UDP 目标 IP 和端口
TARGET_IP = "192.168.1.105"
TARGET_PORT = 12345
# 创建 UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 导弹编队行列数
formation_rows = 10
formation_columns = 10
# 导弹数量和单包数量
total_missiles = formation_rows * formation_columns
MissileCount = 25 # 每个 UDP 包内发送的导弹数量
# 导弹生成,每个导弹的初始位置按照网格排列
config = {
'missiles': [
{
'id': i * formation_columns + j + 1,
'valid': 1,
'movement': 'straight',
'center': (i * 200, j * 200), # 网格排列
'speed': 2000,
'start_altitude': 1500
}
for i in range(formation_rows)
for j in range(formation_columns)
],
'delays': {
'missile_spawn': 3 # 导弹生成延迟时间(秒)
}
}
def send_missile_data_batch(missiles, t):
packet_data = b''
for missile in missiles:
center_x, center_y = missile['center']
x = center_x + 0
y = center_y + t * missile['speed']
z = missile['start_altitude'] # 初始高度保持
state = 1 # 发射中
# 如果导弹有效,加入数据包
if missile['valid'] == 1:
data = struct.pack('=BBBBddd', 2, missile['id'], 0, state, x, y, z)
packet_data += data
# 如果数据包已满(即包含25个导弹),则发送
if len(packet_data) >= MissileCount * struct.calcsize('=BBBBddd'):
sock.sendto(packet_data, (TARGET_IP, TARGET_PORT))
packet_data = b''
# 发送剩余未满25导弹的数据包
if packet_data:
sock.sendto(packet_data, (TARGET_IP, TARGET_PORT))
def main():
start_time = time.time()
def spawn_missiles():
while True:
t = time.time() - (start_time + config['delays']['missile_spawn'])
if t >= 0:
for i in range(0, len(config['missiles']), MissileCount):
missile_batch = config['missiles'][i:i + MissileCount]
send_missile_data_batch(missile_batch, t)
time.sleep(0.2)
# 启动导弹生成计时器
missile_timer = Timer(config['delays']['missile_spawn'], spawn_missiles)
missile_timer.start()
# 主循环运行
while True:
time.sleep(0.2)
if __name__ == "__main__":
main()