BluePrint:
创建Widget蓝图,编辑控件,绑定事件,根据不同情况可能需要getPlayerController->setInputMode,在观看蓝图或者gameMode蓝图内加入该widget。
可以用Promote to Variable产生一个随时可以使用的变量,在绑定控件时就可以使用这个变量(类)中的属性和方法,如:
更改Material的时候要先把普通materail转为Dynamic Material,然后用setParameterValue来更改它的属性,例如以下根据电池电量改变人物颜色的例子:
使用timeline来设置有规律的行为,如石门平滑开启:
使用射线检测来触发雕塑事件(按下某键触发射线检测):
制作昼夜循环:
1.把lightSource改为moveable
2.打开关卡蓝图使用timeline实现光源旋转,Y轴为270~-90
也可以用Cinematics->add Matinee来创建一些动画,比如门的开关,人站到石台上石台自动升高等,先右键->new empty group,然后选中你要操作的物体,再在Mayinee内右键新建movement track或者sound track等等:如果是movemet track 则移动要操作的物体,然后在相应位置添加关键帧来完成动画:
创建顶视角Minimap步骤:
1.在characterBlueprint头顶上新建一个向下的相机(可能需要关闭autoActive以免替换主相机),相机内添加组件SceneCaptureComponent2D
2.ContentBrowser右键material->render target 新建一个,CompressionSetting设置为userInterface2D
3.把刚刚的render target放到SceneCaptureComponent2D的Texture Target中
4.右键render Target->create metarial新建一个材质,连上emmisive color会显示的更好
5.新建widget放入image控件,Image属性设置为刚刚的material
6.运行
可以创建接口蓝图,在里面定义函数,让其他蓝图实现该接口,这样可以对相同事件有不同反馈方式,比如三个box,都是鼠标点击,第一个放大,第二个缩小,第三个旋转,就可以建立鼠标点击接口,然后三个方块蓝图各自实现点击效果。以下是鼠标点击actor然后调用各actor实现的BP_pick接口的三个方法的蓝图。鼠标点击使用射线检测以及世界坐标转换:
无限跑酷中创建无限地图的方法:在一个道路块的终点后面放置一个Arrow用来当做下一块地块的放置位置,并在终点附近设置Collision Box,当人物通过Collison Box使用Spawn Actor创建一个新地块,创建的transform为上一个地块的Arrow的transform,并把这个地块arrow的trasnform记录下来为下一个地块使用。在construct Script内初始化一定数量的地块。
创建可以重复使用的component:(以悬浮组件为例子,越靠近地面收到一个更大的向上力以维持悬浮)
1.父物体设为movable
2.创建sceneComponent类命名为HoverComponent(Actor component蓝图类和Scene component蓝图类的区别在于scene component有relative position)
3.获取父物体的引用:
4.使用射线检测设置反重力的方向和大小:(add damping 是增加阻力以免越弹越高.该例子设置射线长50,离地面越近受到的力越大)
5.把该component作为任意static mesh的子component
控制相机pitch范围的方法:
1.
2.在第三人称模板中
Lerp和Clamp的区别:
lerp的值是(1-alpha)A+alphaB
Clamp是输入在范围内输出=输入,输入在范围外输出=边界值
使用AI跟踪玩家:创建AIcontrollerBP,在场景中添加NavMeshBoundsVolume,在AIcontroller中使用一个timer隔一段时间调用一次AIMoveTo
添加radial force component 可以使物体对其他物体产生力的影响
Projectile movement component可以快速模仿子弹运动
cast的时候右键->convert to pure cast 可以移除顺序连线接口
碰撞无效的时候记得检查Mesh是不是包含Collision组件
使用RemoveFromParent来移除Widget,OpenLevel来打开关卡,SetGamePaused来暂停游戏
使用SpawnXXXAtLocation来在特定位置产生特效或声音
Add Reroute Node 可是使蓝图看起来更整洁
实现更改游戏速度(慢放)的效果,用exctue console command :slomo 0.5 (速度变为0.5倍)
第一人称射击时镜头shake方法:新建类蓝图继承camera shake,更改参数后再第一人称蓝图内射击后调用play world camera shake即可
使用launch character可以重新设置character的速度,比如触碰到某物体时向上弹起(跳跳版)
C++:
UE4 常用标记宏:
UCLASS():
Blueprintable:可以把该类编程蓝图(类名右键)
BlueprintType:该类可以作为其他蓝图类的变量使用
NotBlueprintType :不可作为其他蓝图变量使用
UPROPERTY() :
BlueprintCallable: 属性可以在蓝图中被调用
BlueprintReadOnly:属性可以被蓝图读取,但是不可被修改
BlueprintReasWrite:属性可以被蓝图读取和修改
Category: 为属性添加分类标签
EditAnywhere:该属性可以在属性窗口中修改
EditDefaultOnly:该属性可以在属性窗口中修改,但是只能在基类的属性窗口修改
VisibleAnywhere:该属性可以在属性窗口中看见,但是不可修改
VisibleDefaultsOnly:该属性只可在基类的属性窗口中看见,而且不可修改
UFUNCTION:
BlueprintCallable:该函数可以在类蓝图或者关卡蓝图中调用
BlueprintImplementableEvent:这个函数在头文件声明但是应该在类蓝图或者关卡蓝图中重写,应该和BlueprintCallable一起使用这样蓝图就可以调用它,目的是使非程序员可针对特殊情况(这些情况不存在默认操作或标准行为)创建自定义响应。范例:在宇宙飞船游戏中玩家飞船获得强化道具时发生的事件
BlueprintNativeEvent:这个函数可以在蓝图类中重写,同时拥有C++实现,函数名为FuncName_Implementation,但是调用的时候不用加implementation,和BlueprintCallable一起使用以便在蓝图中调用.可以在蓝图中使用Add Call To Parent Function调用父方法内容
BlueprintPure: 这个函数不会改变对象的数据内容,可以用在get函数上,该函数必须有返回值
Category:为函数添加类别标签
meta说明符:
BlueprintProtected:
这个函数只能由当前对象调用,不能被其他对象调用
变量类型前缀:
模板类以T为前缀
继承自UObject的类以U为前缀
继承自AActor的类以A为前缀
继承自SWidget的类以S为前缀
抽象借口类以I为前缀
枚举类E为前缀
布尔变量以b为前缀
大部分其他类以F为前缀,如FString,FVector
UE4 支持三类字符串:
FString 类似于普通字符数组,
FName是放在全局字符串表里的,通常用来表示不可变的大小写不敏感的字符串
FText一般是表示处理本地化的字符串
和字符串有关的API以及字符串间相互转化:https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/StringHandling/index.html
如何debug:
打印到屏幕:
#include "Engine.h"
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, TEXT("Some debug message!"));
打印到output log:
UE_LOG(LogClass, Log, TEXT("You have collected %s"),*DebugString);
定时器:
FTimerHandle VarName
GetWorldTimerManager().SetTimer(this, &AMatineeActor::CheckPriorityRefresh, 1.0f, true);
GetWorldTimerManager().ClearTimer(this, &AMatineeActor::CheckPriorityRefresh);
GetWorldTimerManager().PauseTimer()
GetWorldTimerManager().UnPauseTimer()
GetWorldTimerManager().IsTimerActive()
GetWorldTimerManager().GetTimerRate()
使Pawn响应玩家输入:
AutoPossessPlayer = EAutoReceiveInput::Player0;
Clamp函数:把一个值规范化到一个范围:
CurrentVelocity.Y = FMath::Clamp(AxisValue, -1.0f, 1.0f)
引用GameplayStatics.h以使用很多有用的函数
#include "Kismet/GameplayStatics.h"
更换摄像机视角
APlayerController* OurPlayerController = UGameplayStatics::GetPlayerController(this,0)
if(camera1 = OurPlayerController->GetViewTarget() )
OurPlayerController->SetViewTarget(Camera2)
OurPlayerController->SetViewTargetWithBlend(Camera2, SmoothBlendTime)
创建带有SpringArm的相机:
OurCameraSpringArm = CreateDefaultSubobject
OurCameraSpringArm->AttachTo(RootComponent); //现在用SetupAttachment
OurCameraSpringArm->SetRelativeLocationAndRotation(FVector(0.0f, 0.0f, 50.0f), FRotator(-60.0f, 0.0f, 0.0f));
OurCameraSpringArm->TargetArmLength = 400.f;
OurCameraSpringArm->bEnableCameraLag = true;
OurCameraSpringArm->CameraLagSpeed = 3.0f;
OurCamera = CreateDefaultSubobject
OurCamera->AttachTo(OurCameraSpringArm, USpringArmComponent::SocketName);
带有SpringArm的相机旋转视角时,yaw方向可以直接旋转Actor,Pitch方向旋转SpringArm,Putch旋转时用Clamp限定旋转角度
NewRotation.Pitch = FMath::Clamp(NewRotation.Pitch + CameraInput.Y, -80.0f, -15.0f);
视域缩放功能:
ZoomFactor = FMath::Clamp
// 基于ZoomFactor来混合相机的视域和弹簧臂的长度,Lerp把ZoomFactor映射到一个范围内的值
OurCamera->FieldOfView = FMath::Lerp
OurCameraSpringArm->TargetArmLength = FMath::Lerp
在代码中直接使用content browser中的素材:
static ConstructorHelpers::FObjectFinder
if (ParticleAsset.Succeeded())
{
OurParticleSystem->SetTemplate(ParticleAsset.Object);
}
代码使用UMG:
在build.cs中:
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "UMG" });
PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
#include "Blueprint/UserWidget.h"
TSubclassOf
UUserWidget* CurrentWidget
CurrentWidget = CreateWidget
CurrentWidget->AddToViewport();
获取一定3D空间内随机一点:
GetWhereToSpawn()返回一个boxComponent
#include "kismet/KismetMathLibrary.h"
FVector ASpawnVolume::GetRandomPointToVolume()
{
FVector MeshOrigin = GetWhereToSpawn()->Bounds.Origin;
FVector MeshExt = GetWhereToSpawn()->Bounds.BoxExtent
return UKismetMathLibrary::RandomPointInBoundingBox(MeshOrigin, MeshExt);
}
其他随机函数:
FMath::FRand()
FMath::FRandRange(MinNum,MaxNum)
枚举类型在UCLASS标记前声明:
UENUM(BlueprintType)
enum class EBatteryPlayState
{
EPlaying, //可以选择显示名称放在逗号内 UMETA(DisplayName="Dance")
EGameOver,
EWon,
EUnknown
};
EBatteryPlayState status;
OR
TEnumAsByte
找到属于某一个类的所有Actors并存入数组:
TArray
UGameplayStatics::GetAllActorsOfClass(GetWorld(),ASpawnVolume::StaticClass() , FoundActors);
判断某一个变量是不是属于某个类型只需cast一下然后看是不是空:
ASpawnVolume TestSpawnVolume = Cast
if(TestSpawnVolume!=nullptr)
{
// do something
}
找到overlap的所有Actors并存入数组,首先声明一个USphereComponent,然后:
TArray
CollectionSphere->GetOverlappingActors(OverlappedActors);
PlayerCharacter里可以调用很多有用方法:*
UGameplayStatics::GetPlayerCharacter()
MyCharacter->getMesh()
MyCharacter->getMovementComponent()
使用TSubclassOf
TSubclassOf
结构体声明:
新建一个C++类,
#include "Chapter2.h"
#include "ColoredTexture.generated.h"
USTRUCT()
struct CHAPTER2_API FColoredTexture
{
GENERATED_USTRUCT_BODY()
public:
UPROPERTY( EditAnywhere, BlueprintReadWrite, Category =
HUD )
UTexture* Texture;
UPROPERTY( EditAnywhere, BlueprintReadWrite, Category =
HUD )
FLinearColor Color;
};
创建可重复使用component(随机移动组件为例):
#pragma once
#include "Components/ActorComponent.h"
#include "RandomMovementComponent.generated.h"
UCLASS( ClassGroup=(Custom),
meta=(BlueprintSpawnableComponent) )
class UE4COOKBOOK_API URandomMovementComponent : public
UActorComponent
{
GENERATED_BODY()public:
URandomMovementComponent();
virtual void BeginPlay() override;
virtual void TickComponent( float DeltaTime, ELevelTick
TickType, FActorComponentTickFunction* ThisTickFunction )
override;
UPROPERTY()
float MovementRadius;
};
#include "UE4Cookbook.h"
#include "RandomMovementComponent.h"
URandomMovementComponent::URandomMovementComponent()
{
bWantsBeginPlay = true;
PrimaryComponentTick.bCanEverTick = true;
MovementRadius = 5;
}
void URandomMovementComponent::BeginPlay()
{
Super::BeginPlay();
}
void URandomMovementComponent::TickComponent( float
DeltaTime, ELevelTick TickType,
FActorComponentTickFunction* ThisTickFunction )
{
Super::TickComponent( DeltaTime, TickType,
ThisTickFunction );
AActor* Parent = GetOwner();
if (Parent)
{
Parent->SetActorLocation(
Parent->GetActorLocation() +
FVector(
FMath::FRandRange(-1, 1)* MovementRadius,
FMath::FRandRange(-1, 1)* MovementRadius,
FMath::FRandRange(-1, 1)* MovementRadius));
}
}
使用委托(delegate与UFUNCTION绑定)举例:
在gamemod投文件UCLASS前声明:
DECLARE_DELEGATE(FStandardDelegateSignature)
FStandardDelegateSignature MyStandardDelegate; //创建委托成员变量
在另外的actor类中创建需要绑定的UFUNCTION,如“开灯”函数,在beginplay函数中获取gamemode实例,并绑定“开灯”函数:
MyGameMode->MyStandardDelegate.BindUObject(this,&ADelegateListener::EnableLight);
在需要执行委托时,使用一下代码执行委托:
AGameMode* GameMode = UGameplayStatics::GetGameMode(TheWorld);
AUE4CookbookGameMode * MyGameMode = Cast
MyGameMode->MyStandardDelegate.ExecuteIfBound();
使用以下代码解除委托:
MyGameMode->MyStandardDelegate.Unbind();
使用带参数的委托:
DECLARE_DELEGATE_OneParam(FParamDelegateSignature,FLinearColor) 其他地方相同,调用的时候传递参数即可
使用广播委托:
假设有一个TriggerVolume 来触发委托
在gamemode 头文件里声明 DECLARE_MULTICAST_DELEGATE(FMulticastDelegateSignature)
在MulticastDelegateListener 的类(灯)里面,声明变量:
FDelegateHandle MyDelegateHandle;
绑定委托:
MyDelegateHandle = MyGameMode->MyMulticastDelegate.AddUObject(this,&AMulticastDelegateListener::ToggleLight);
结束委托:
MyGameMode->MyMulticastDelegate.Remove(MyDelegateHandle);
其他类也可以通过使自己的方法绑定一个MyDelegateHandle来触发相应委托,只要调用
MyGameMode->MyMulticastDelegate.Broadcast(); 所有绑定的委托都会调用
广播委托也可以有参数
委托的缺陷是需要使用第三方类来调用委托,它的执行方法是public的
Custome Event
在MyTriggerVolume (触发事件的actor)里面声明:
DECLARE_EVENT(AMyTriggerVolume, FPlayerEntered)第一个参数是需要调用broadcast的类,第二个参数是事件函数签名的类名
在类中添加一个event signature:FPlayerEntered OnPlayerEntered;
在AMyTriggerVolume::NotifyActorBeginOverlap 中添加OnPlayerEntered.Broadcast();
创建一个TriggerVolEventListener 类(灯所在类),在里面声明:
UPROPERTY()
UPointLightComponent* PointLight;
UPROPERTY(EditAnywhere)
AMyTriggerVolume* TriggerEventSource;
UFUNCTION()
void OnTriggerEvent();
在beginplay里面绑定事件:
TriggerEventSource->OnPlayerEntered.AddUObject(this,&ATriggerVolEventListener::OnTriggerEvent)
接口Interface
要在c++中使用接口,要手动创建.h 和.cpp文件,在UE4编辑器内无法创建
//接口类
//h
#pragma once
#include "ReactsToTimeOfDay.generated.h"
/* must have BlueprintType as a specifier to have this interface exposed to blueprints
with this line you can easily add this interface to any blueprint class */
UINTERFACE(BlueprintType)
class MYPROJECT_API UReactsToTimeOfDay : public UInterface
{
GENERATED_UINTERFACE_BODY()
};
class MYPROJECT_API IReactsToTimeOfDay
{
GENERATED_IINTERFACE_BODY()
public:
//classes using this interface must implement ReactToHighNoon
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "MyCategory")
bool ReactToHighNoon();
//classes using this interface may implement ReactToMidnight
UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "MyCategory")
bool ReactToMidnight();
};
//cpp
#include "MyProject.h"
#include "ReactsToTimeOfDay.h"
UReactsToTimeOfDay::UReactsToTimeOfDay(const class FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
//实现接口的类:
//h
#include "ReactsToTimeOfDay.h"
#include "ASkeletalMeshActor.generated.h"
UCLASS()
class AFlower : public ASkeletalMeshActor, public IReactsToTimeOfDay
{
GENERATED_BODY()
public:
/*
... other AFlower properties and functions declared ...
*/
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "MyCategory")
bool ReactToHighNoon();
virtual bool ReactToHighNoon_Implementation() override;
};
//cpp
bool AFlower::ReactToHighNoon_Implementation()
{
//Default behaviour for how flower would react at noon
//OpenPetals();
//AcceptBugs();
//...
return true;
}
再次注意BlueprintNativeEvent是在cpp内有一个实现,函数名加implementation,蓝图内可重写
BlueprintImplementableEvent是必须在蓝图内实现检查某个类是否实现了某接口,可以有2个方法:1.把那个类cast 成 检查的interface,cast成功则实现了,null则没实现2.使用if (SpawnedActor->GetClass()->ImplementsInterface(UMyInterface::StaticClass())) 来检查
使用cast可以把实现了相同接口的不同对象当做一类对象来使用,比如把它们放进数组
原文链接: https://www.cnblogs.com/yang-xiong/p/6392350.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/249320
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!