这是一个好几年前我发表在www.52vr.com论坛上的帖子了,论坛已经关闭了,今天翻出来,在CSDN上发一下,对相关新手提供参考借鉴。
前言
vrforces是一个不错的计算机兵力生成平台,严格来讲,是个不错的开发框架,但是里面自带的组件的运行机制离我们想达到的实际装备运行情况还有一定差距,所以除了要在实体构建、opd文件配置、地形生成等方面研究以外,最重要的是要学会实体三大组件(传感器、控制器和执行器)的重新编写。
本文以一个继承于DtMissileTrackEntityController的防空导弹运动控制组件编写方法为例,抛砖引玉,给大家稍作启发。
软件版本:
Visual Studio 2010
vrforces 4.1.1
vrlink4.0.5
makRti4.2
(当然也可以用vrforces3.X VC7 或者vc8的版本,把plugin.cxx、myMissileTrackEntityController.h、myMissileTrackEntityController.cxx插入到工程中,头文件的包含目录要改变一下,可参考具体版本的自带例子)
背景:
vrforces中地面实体发射防空导弹以后,地面实体在产生防空导弹时给导弹赋予一个打击的任务,防空导弹会直接飞向目标(可能是一个要打击的点、也可以是一个实体),这个我们实际的装备运行不一样,所以,需要重写其控制器,使得运行轨迹有一定的扰动误差,使得弹道不是平滑的直线(曲线)。本例不是真实的弹道扰动,只是软件编写方法的思路,大家可按此方法填写自己的真实算法。
废话少说,直接上代码,具体解释都在注释里面了:
源代码
1、myMissileTrackEntityController.h:
#pragma once
#include "vrfmodel/msslTrkEntCtl.h"
//
//模拟防空导弹的螺旋式飞行扰动,代替vrforces自带的直线飞向目标的模式
//
class MyMissileTrackEntityController : public DtMissileTrackEntityController
{
public:
//构造函数
MyMissileTrackEntityController(const DtString& name, DtVrfObject* object,
DtSimManager* simManager, DtComponentDescriptor* compDescriptor,
DtReaderWriterRegistry* parentRegistry = 0);
//虚构函数
virtual ~MyMissileTrackEntityController();
//返回compTypes.h中的字符串,标示组件类型
virtual DtString type() const;
//调用父类函数,得到实际的打击目标位置,然后在其基础之上添加扰动的偏移量
virtual bool setupControlPoint();
public:
//创建函数
static DtSimComponent* creator(const DtString& name, DtVrfObject* object,
DtSimManager* simManager, DtComponentDescriptor* compDescriptor,
DtReaderWriterRegistry* parentRegistry);
public:
//当前的偏移量(弹体自身坐标系),将会添加到 setupControlPoint()中
DtVector myNoiseOffset;
//每个方向的扰动距离(单位:米)
double myNoiseOffsetDistance;
//偏移量的当前方向 0 = 向上, 1 =向右, 2 = 向下, 3 = 向左
int myOffsetDirection;
//上次改变偏移量的仿真时间
double myNoiseOffsetLastUpdateTime;
};
#pragma once
#include "vrfmodel/msslTrkEntCtl.h"
//
//模拟防空导弹的螺旋式飞行扰动,代替vrforces自带的直线飞向目标的模式
//
class MyMissileTrackEntityController : public DtMissileTrackEntityController
{
public:
//构造函数
MyMissileTrackEntityController(const DtString& name, DtVrfObject* object,
DtSimManager* simManager, DtComponentDescriptor* compDescriptor,
DtReaderWriterRegistry* parentRegistry = 0);
//虚构函数
virtual ~MyMissileTrackEntityController();
//返回compTypes.h中的字符串,标示组件类型
virtual DtString type() const;
//调用父类函数,得到实际的打击目标位置,然后在其基础之上添加扰动的偏移量
virtual bool setupControlPoint();
public:
//创建函数
static DtSimComponent* creator(const DtString& name, DtVrfObject* object,
DtSimManager* simManager, DtComponentDescriptor* compDescriptor,
DtReaderWriterRegistry* parentRegistry);
public:
//当前的偏移量(弹体自身坐标系),将会添加到 setupControlPoint()中
DtVector myNoiseOffset;
//每个方向的扰动距离(单位:米)
double myNoiseOffsetDistance;
//偏移量的当前方向 0 = 向上, 1 =向右, 2 = 向下, 3 = 向左
int myOffsetDirection;
//上次改变偏移量的仿真时间
double myNoiseOffsetLastUpdateTime;
};
2、myMissileTrackEntityController.cxx
//以下为要包含的头文件
#include "myMissileTrackEntityController.h"
#include "vrfobjcore/compTypes.h" //组件类型头文件
#include "vrfcore/simMgr.h" //仿真管理器
#include "vrfcore/exClock.h" //时间头文件
#include "vrfobjcore/gndVehSR.h" //地面车辆实体状态机
#include "vrfobjcore/vrfObject.h" //实体对象
#include "vrfobjcore/inputPortGroup.h" //端口输入组头文件
#include "vrfobjcore/conAnalogIOPort.h"
#include "gdb/terrainDb.h" //地形头文件
//构造函数先初始化头文件中定义的变量
MyMissileTrackEntityController::MyMissileTrackEntityController(
const DtString& name,
DtVrfObject* object,
DtSimManager* simManager,
DtComponentDescriptor* compDescriptor,
DtReaderWriterRegistry* const parentRegistry) :
DtMissileTrackEntityController(name, object, simManager,
compDescriptor, parentRegistry),
myNoiseOffset(0,0,0.0),
myNoiseOffsetDistance(200.0),
myNoiseOffsetLastUpdateTime(0),
myOffsetDirection(0)
{
}
MyMissileTrackEntityController::~MyMissileTrackEntityController()
{
}
//返回组件的类型为:追踪导弹实体类型
DtString MyMissileTrackEntityController::type() const
{
return DtMissileTrackEntityType;
}
//重载父类的设置控制点函数(即要飞向的点),这是vrf自带导弹实体机制决定的,给实体一个飞向那个点的任务,导弹就会按照一定规律飞行
//(本函数会周期性自动调用)
bool MyMissileTrackEntityController::setupControlPoint()
{
//此函数主体思想:得到从父类中当前要飞向的点,过一段时间在此基础之上赋上扰动的偏移量,使得导弹弹道改变
//如果从父类中没有得到当前控制点,不能执行后面简单算法,返回。
if (!DtMissileTrackEntityController::setupControlPoint())
{
return false;
}
//每1/4秒切换到下一个方面的偏移量(当前仿真时钟-上次更新偏离量的仿真时间>0.25)
if (mySimManager->exerciseClock()->simTime() - myNoiseOffsetLastUpdateTime > .25)
{
myNoiseOffset = DtVector::zero();
if (myOffsetDirection == 0)
{
//向上设置偏移量
myNoiseOffset.setZ(myNoiseOffsetDistance);
}
else if (myOffsetDirection == 1)
{
//向右设置偏移量
myNoiseOffset.setX(myNoiseOffsetDistance);
}
else if (myOffsetDirection == 2)
{
//向下设置偏移量
myNoiseOffset.setZ(-1.0 * myNoiseOffsetDistance);
}
else if (myOffsetDirection == 3)
{
//向左设置偏移量
myNoiseOffset.setX(-1.0 * myNoiseOffsetDistance);
}
//偏移方面标示累加,如果等于4就回到向上
myOffsetDirection++;
if (myOffsetDirection > 3)
{
myOffsetDirection = 0;
}
//记下当前改变偏离量的仿真时钟
myNoiseOffsetLastUpdateTime = mySimManager->exerciseClock()->simTime();
//打印扰动偏移量为多少,在仿真引擎vrfsim后端能看到
DtInfo << "Noise offset" << myNoiseOffset.string() << std::endl;
}
//调用矩阵计算在导弹弹体坐标系下,扰动误差的矢量,然后加到当前要打击的位置上去,最后重新设置一下新的打击位置,导弹就会朝这个新位置飞去
DtVector targetPoint(targetPoint());
DtVector localTargetErrorOffset;
DtDcm body2Ref = entity()->vrfState()->localOrientationMatrix();
DtDcmVecMul(body2Ref, myNoiseOffset, localTargetErrorOffset);
DtVecAdd(targetPoint, localTargetErrorOffset, targetPoint);
setTargetPoint(targetPoint);
return true;
}
//用组件工厂机制的创建函数
DtSimComponent* MyMissileTrackEntityController::creator(const DtString& name,
DtVrfObject* vrfObject, DtSimManager* simManager,
DtComponentDescriptor* compDescriptor,
DtReaderWriterRegistry* parentRegistry)
{
return new MyMissileTrackEntityController(name, vrfObject, simManager, compDescriptor,
parentRegistry);
}
3、plugin.cxx
//插件注册文件
#include "vrfcgf/vrfPluginExtension.h"
#include "myMissileTrackEntityController.h"
#include <vrfcgf/cgf.h>
#include <vrfcgf/factoryMgr.h>
#include <vrfobjcore/compTypes.h>
extern "C" {
DT_VRF_DLL_PLUGIN void DtPluginInformation(DtVrfPluginInformation& info)
{
info.pluginName = "Missile Noise";
info.pluginVersion = "1.00";
info.pluginCreator = "娃娃鱼";
info.pluginCreatorEmail = "99daodan@163.com";
info.pluginContactWebPage = "www.mak.com";
info.pluginContactMailingAddress = "china simulation";
info.pluginContactPhone = "QQ:515826628";
}
DT_VRF_DLL_PLUGIN bool DtInitializeVrfPlugin(DtCgf* cgf)
{
//通过工厂管理器、组件管理器向工厂中添加新创建的组件
//由于本组件没有使用新的组件类型,而是使用了DtMissileTrackEntityType,所以类似于防空导弹类型的实体控制组件就会被本组件的运行顶替。
cgf->factoryManager()->componentFactory()->addCreatorFcn(
DtMissileTrackEntityType, MyMissileTrackEntityController::creator);
return true;
}
}
运行效果如下: