一.首先gamemode里有actor数组,组装直线路,和左右路
#include "coreminimal.h"
#include "gameframework/gamemodebase.h"
#include "rungangamemode.generated.h"
uclass(minimalapi)
class arungangamemode : public agamemodebase
{
generated_body()
uproperty()
tarray<tsubclassof<class aactor>> straitarray;
uproperty()
tarray<tsubclassof<class aactor>> leftrightarray;
uproperty()
tsubclassof<aactor> newroad;
uproperty()
ftransform nexttransforms;
public:
arungangamemode();
tsubclassof<aactor> randominputfloor();
virtual void beginplay();
//添加我们地板
void addfloor();
};
uproperty()不会被gc掉
tsubclassof
在unreal中经常会有在蓝图或者c++中声明某些uclass,便于后续用来创建对应的对象,但是如果只是填了一个uclass指针的话,这并不好用。这是因为uclass*可以指代任意uobject,所以在蓝图或者编辑器中选择对应的uclass的时候不好选择,因为基本上所有的uclass都会出现在下拉框内。unreal也提出对应的解决方案,那就是tsubclassof,它能够避免能上面说的问题,tsubclassof能够约束下拉框中只会出现继承于t的类或者t本身,并且c++层面也能实现类型安全,如果给tsubclassof对象赋值一个类型不兼容的uclass,则会得到编译错误。
二.在gamemode构造函数时,可以使用动态加载 actor到路面类型。静态加载主角到playerpawnbpclass类中,再设置到gamemode默认的pawn里(defaultpawnclass)。
#include "rungangamemode.h"
#include "rungancharacter.h"
#include "uobject/constructorhelpers.h"
#include "actor/collisioninteraction/runroad.h"
arungangamemode::arungangamemode()
{
// set default pawn class to our blueprinted character
static constructorhelpers::fclassfinder<apawn> playerpawnbpclass(text("/game/thirdperson/blueprints/bp_thirdpersoncharacter"));
if (playerpawnbpclass.class != null)
{
defaultpawnclass = playerpawnbpclass.class;
}
straitarray.add(loadclass<aactor>(null,text("/script/engine.blueprint'/game/environment/bp/bp_straightroad_1.bp_straightroad_1_c'")));
straitarray.add(loadclass<aactor>(null, text("/script/engine.blueprint'/game/environment/bp/bp_straightroad_2.bp_straightroad_2_c'")));
straitarray.add(loadclass<aactor>(null, text("/script/engine.blueprint'/game/environment/bp/bp_straightroad_3.bp_straightroad_3_c'")));
straitarray.add(loadclass<aactor>(null, text("/script/engine.blueprint'/game/environment/bp/bp_straightroad_4.bp_straightroad_4_c'")));
leftrightarray.add(loadclass<aactor>(null, text("/script/engine.blueprint'/game/environment/bp/bp_turnleftroad.bp_turnleftroad_c'")));
leftrightarray.add(loadclass<aactor>(null, text("/script/engine.blueprint'/game/environment/bp/bp_turnrightroad_2.bp_turnrightroad_2_c'")));
}
constructorhelpers::fclassfinder()和fobjectfinder()
静态加载指的是在构造函数中完成的加载方式,这种方式的弊端明显,就是需要写死路径,一旦改变路径读取失败很容易造成程序崩溃。
loadobject<uclass>。
也就是说loadobject和loadclass函数都用于在运行时加载uobject派生的对象,但是它们的用途和返回值有所不同。
`loadobject`用于加载单个对象,可以是任何uobject派生类的实例,包括uclass、utexture、umaterial等。它会返回加载的对象,或者在加载失败时返回nullptr
同时,如果使用loadclass()方法,路径名也必须带_c后缀(loadobject不需要带_c后缀),例如,蓝图路径是:blueprint'/game/blueprints/test', 加后缀以后,则是:blueprint'/game/blueprints/test_c'
三.通过fmath::randrange随机数从不同的类型中生成下个路面。并在一开始设置生成一个路面的位置。
tsubclassof<aactor> arungangamemode::randominputfloor()
{
int32 i = fmath::randrange(1,100);
if (i <= 80)
{
int32 index = fmath::randrange(0,straitarray.num()-1);
return straitarray[index];
}
else
{
int32 index = fmath::randrange(0, leftrightarray.num() - 1);
return leftrightarray[index];
}
return tsubclassof<aactor>();
}
void arungangamemode::beginplay()
{
super::beginplay();
if (getworld())
{
nexttransforms = getworld()->getfirstplayercontroller()->getpawn()->gettransform();
fvector inlocation = nexttransforms.getlocation();
inlocation.y += 100.f;
inlocation.z -= 200.f;
nexttransforms.setlocation(inlocation);
for (int32 i = 0; i < 9; i++)
{
addfloor();
}
}
}
四.添加地板逻辑,拼贴点位。
//添加我们的地板
void arungangamemode::addfloor()
{
newroad = randominputfloor();
if (newroad != null)
{
fvector const mylocation = nexttransforms.getlocation();
frotator myrotation(nexttransforms.rotator());
if (arunroad* myrunroad = getworld()->spawnactor<arunroad>(newroad, mylocation, myrotation))
{
myrunroad->setactorscale3d(fvector(10.f));
nexttransforms = myrunroad->getattacktotransform(mylocation);
}
}
}
五.addfloor里使用的getattacktotransform是使用每个,路面自己对准的下一个路面的位置。
ftransform arunroad::getattacktotransform(const fvector& mylocation)
{
ftransform transform;
transform.setlocation(spawnpointmiddle->getcomponenttoworld().getlocation());
transform.setrotation(spawnpointmiddle->getcomponentquat());
return transform;
}
六.通过跑步碰撞,判断。开启角色可以转弯的功能,
#include "turnbox.h"
#include "components/boxcomponent.h"
#include "../../rungancharacter.h"
// sets default values
aturnbox::aturnbox()
{
// set this actor to call tick() every frame. you can turn this off to improve performance if you don't need it.
primaryactortick.bcanevertick = false;
box = createdefaultsubobject<uboxcomponent>(text("turnbox"));
rootcomponent = box;
}
// called when the game starts or when spawned
void aturnbox::beginplay()
{
super::beginplay();
box->oncomponentbeginoverlap.adddynamic(this,&aturnbox::characteroverlapstart);
box->oncomponentendoverlap.adddynamic(this, &aturnbox::characteroverlapend);
}
// called every frame
void aturnbox::tick(float deltatime)
{
super::tick(deltatime);
}
void aturnbox::characteroverlapstart(uprimitivecomponent* overlappedcomponent, aactor* otheractor, uprimitivecomponent* othercomp, int32 otherbodyindex, bool bfromsweep, const fhitresult& sweepresult)
{
if (arungancharacter* incharacter = cast<arungancharacter>(otheractor))
{
incharacter->bturn = true;
}
}
void aturnbox::characteroverlapend(uprimitivecomponent* overlappedcomponent, aactor* otheractor, uprimitivecomponent* othercomp, int32 otherbodyindex)
{
if (arungancharacter* incharacter = cast<arungancharacter>(otheractor))
{
incharacter->bturn = false;
}
}
turnbox,位置不对。可以用蓝图具象化调整。
碰撞显示
bp_turnbox 的位置就是arrow的位置,记住dlay延迟一下,预防scale位置会有问题偏差。
发表评论