当前位置: 代码网 > it编程>编程语言>C/C++ > UE5 C++跑酷练习(Part2)

UE5 C++跑酷练习(Part2)

2024年08月02日 C/C++ 我要评论
一.首先GameMode里有Actor数组,组装直线路,和左右路。

一.首先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位置会有问题偏差。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com