Вы находитесь на странице: 1из 18

//unreal c++

using class viwer to see is-a

inheretence: character "is a" pawn "is a" actor


dog "is a" mammal "is a" animal
more details -> more abstract
2-3 level of inheritance

components are has-a


chair and rock "has a" positionReporter
objects become rich by many components

several place you can write your code


-constructor
-BeginPlay()
-TickComponent()
-EndPlay()

//eject mode: f8

optimize tip
PrimaryComponentTick.bCanEverTick = false, to sleep components or stop them from
take resourse

//all word with capital letter used before compile by compiler


//and used by unreal header tool to cut and paste some code

//what is pawn: is our body, can controll by us

//access to actor parent(button-up)


GetOwner()
//access to childs(top-button)
GetWorld() //access to object in world ouliner

//access to pawn
//when we access to controller, that is a link between player and pawn and then
pawn
Pawn p = GetWorld()->GetFirstPlayerController().GetPawn(); //store pawn .cpp
AActor* myactor = p; //myactor in .h

//access to id-name of component


GetOwner()->GetName() //get id-name of parent

//read method signtures, in case of GetOwner


AActor *UActorComponent::GetOwner() const
//is member function of UActorComponent and return a pointer to a Actor

//trigger volume vs collision volume:


//collision volume: tell to physic engine, what hits what, prevent actor to passing
things as ghost
//trigger volume: trigger code on overlap
//add colider to actor: rmb->edit, then from colltion menu add collition

//maximize playview: f11

//get time and making delay


UPROPERTY() float delay; //user-define, .h
float last; //use by system, .h
TickComponent(){ //.cpp
//store last time action in last
if(somethingOverlap){ActionOnOverlap(); last=GetWorld()->GetTimeSeconds();
//create delay using lasttime
if(last-current>delay){ResponceWithDelay();}
}

//when use bluprint?


//when need smooth animation for components(open/close door)
//when we make templates(plan for build something) of assets, becuase it's
visual/clear

//purpose of game mode?


//determine which default pawn use
//inventory items a player start with
//how many lives are avilable to tim limits
//score needed to end game

/////////////////////////////////////////////////////////////////////////////
//pickup system
#define OUT
TickComponent(){
//create pawn and gameMode blueprint, why blueprint ? to prevent "hardcoding
//of changes and assets" into code
//means if we want to change name of asset then editor will track those changes
//that means we don't end up typing exact name of our modified default pawn intp
code
//if we do that and we change name in editor, then it won't be tracked
//blueprint is useful to binding assets to code
//these blueprint classes inhrit from default pawn
//hardcoding means assets writen into code,
//means we refer to something by its name and file path,
//problem is tracking asset
//"defaultPawn_bp" is a asset

//inherit from class as a blueprint/also we can inherit from class as a c++ class
//1-select "defaultPawn" in eject mode and select blueprint->convert selecyed actor
to blueprint class
//this store in "external dependency"
//2-edit shape in blueprint editor then compile and save
//3-inastate by drag into viewport
//4-create "actor component" in "c++ classes" folder
//5-add new created component to "defaultPawn_bp" in blueprint editor
//6-inherit GameMode_BP from GameMode(in c++ classes) as Blueprint, just like same
we did for "defaultPawn"
//7-in GameMode_BP, set "default pawn class" to BP_DefaultPawn that we created
//8-now in "project setting->maps & modes" set "default GameMode" to BP_GameMode
and "default Pawn class" tp BP_DefaultPawn
//now when we play game and go to eject mode, defaultPawn is BP_DefaultPawn

//9-get actor location and rotation


FVector pos; FRotator rot;
GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(OUT pos, OUT rot);
//now "pos" and "rot" contain actor location/rotation
//OR
FVector pos = GetOwner()->GetActorLocation(); FRotator rot = GetOwner()-
>GetActorRotation();

//where player looking ?


//10- get player viewpoint, for ai mean eye view and for pawn mean camera view
FVector pos; FRotator rot;
GetWorld()->GetFirstPlayerController()->GetPlayerViewpoint(OUT pos, OUT rot);

//what is out-parameters: function change parameters that we given and then return
them
//for example, we send a empty FVecor variable as parameter to "GetPlayerViewPoint"
and it return variable with calculate value
//parameter with perfix out_
//means void getter going to change parameters
//this is confiusing so we can use a macro to annotate these variables
//only declare this in .cpp and after #include: #define OUT
//now place OUT, befere each parameter, where thay have out_ perifx, such as
GetPlayerViewpoint
//how find parameters are out ?
//parameter identifir: out_ in
//collection of references: TArray<Actor*> &OverlapingActor
//look at method document

//how find parameter is optimal ? look at method document

//11- line tracking or raycast out to reach distance(superman laser but with one
eye)
//useful for laser to track bullet path

//"player collision" view is grat to examine hard-body/movable object

//debug functions to visualation


//DrawDebugLine() to visualize vectors, class attach to default pawn
FVector pos; FRotator rot;
GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(OUT pos, OUT rot);
//"reach" determine how far vector can go from start point in cm
FVector end = pos + rot.Vector() * reach;//reach declaration in .h, private float
reach =100.f
DrawDebugLine(GetWorld(), //get current world
pos, //vector start point of pawn
end, //end of vector
FColor(255, 0, 0), //color constructor for color of vector visualize
false, //perisest vector or not ?
0.f, //lifetime of perisest is zero becuase perisest set to false
0.f, //draw in behind or front of other object
1.0f //thickness of line
);

//12-evulate what we hit ?

}
//////////////////////////////////////////////////////////////////////
//convert FRotator to vector
FRotator rot; FVector vec = rot.Vector();

//fast method to test game:


//write code, in unEditor run game and go to eject mode then copile code from
UnEditor

//DrawDebugLine() to visualize vectors, class attach to default pawn


FVector pos; FRotator rot;
GetWorld()->GetFirstPlayerController()->GetPlayerViewPoint(OUT pos, OUT rot);
FVector end = pos + FVector(0.f, 0.f, 50.f);
DrawDebugLine(GetWorld(), //get current world
pos, //vector start point of pawn
end, //end of vector
FColor(255, 0, 0), //color constructor for color of vector visualize
false, //perisest vector or not ?
0.f, //lifetime of perisest is zero becuase perisest set to false
0.f, //draw in behind or front of other object
1.0f //thickness of line
);

//modify actor behavier


//method 1: componentd
//method 2: edit actor and pawn classes directlly

//get information
//1-search subject
//2- examine members after . or ->

//how get info by read signture of method


void PlayerController::GetPlayerViewpoint(FVector Location, FRotator Rotation)
//for access to GetPlayerViewpoint, we need to create a PlayerController
//for access to PlayerContoller, current class is must add to pawn as component
//now in class we access by this way: GetWorld()->GetFirstPlayerController()
//now we can access to ViewPoint:
GetWorld()->GetFirstPlayerController().GetPlayerViewpoint(FVector Location,
FRotator Rotation)

//declare AActor *owner; in .h and define in BeginPlay, now we can in anywhere(more


global)
//use this method for more global-base variable, used too much as GetOwner/GetWorld

//if unreal crashing?


//1-check-out or reset to working commit
//2-delete these folders: .vs, build, binaries, intermadite, saved, .sln,
//3-run .uproject
//4-rmb on .uproject and "generate visual studio project files"

/* FindComponentByClass()
-to find attach component
*/
UComponent* comp; //example UPhysicsHandleComponent - .h
//go to parent, in this case "defualt pawn" then find component specidied in <> -
c++
comp = GetOwner()->FindComponentByClass<UComponent>();
if(comp){}else{UE_LOG(Log_Temp, Warning, TEXT("bal"), *GetOwner()->GetName());}

/*Input Binding
-Settings->Project setting->engine->Input and map key/mouse to action/axis name
-action mapping: on/off
-axis mapping: analog
-in eject mode you can find "PawnInputComponent" in details(native component)
*/
UInputComponent* input; //holder for input - .h
input=GetOwner()->FindComponentByClass<UInputComponent>(); //find input component
at runtime - .cpp
//now we map our function to key
input->BindAction("ActionName", //key to action map in project setting
IE_Pressed, //key press action
this, //current component/class
&MyCurrentClass::MyMethod, //refrence to my method in current class to
execute when key pressed
)

//how memory work


//permanent storage: any unchanged data as const /functions
//:: accessor used to access to content of that class/enum/namespace, access
//heap(free store)/stack: . or -> accessor for things that can vary and do vary at
runtime

//hot loop: is code that get call often, example is TickComponent


//refactoring
//less code

//hover ctrl+alt to find more info

/* generics
-<>
*/

//initalize pointer with 0 address


int* ptr = nullptr;

//Physic Handle component: grab/moving/release physic object - ikeyn grab function


that map to key
//a-LineTraceSingleByObjectType that return hit actor
auto HitResult = GetFirstPhysicBody();
auto ComponentToGrab = HitResult.GetComponent(); //b-component taht hit
//c-get parent of hit component
FVector ComponentToGrabLocation = ComponentToGrab->GetOwner()->GetActorLocation();
//d-now attach parent to physic handle
GrabComponent(ComponentToGrab,//component to grab
NAME_None, //bone name
ComponentToGrabLocation, //which part(component)of actor we grab ?
true //allow rotation
)
//e-if physic handle attach ?(done in TickComponent)
if(handle->GrabbedComponent){
handle->SetTargetLocation(end)//move grab object in each frame, "end" is create by
GetPlayerViewpoint()
}

if(ActorPtr) /* is equal to */ if(ActorPtr != nullptr)

//help
//search name of method in entire of solution and see examples in engine code
//google it

1757295542
5333

09387174326

9904550437
masomehmousavi4@gmail.com

//TArray: grouping elements/many elements same type


//TArray<AActor*>: list of actors
//store all actors inside trigger volume

//TriggerVolume react to actor's mass ?


//.h
float GetTotalMassActorOnPlate();
UPROPERTY(EditAnywhere)
AActor* OverlapActor; ATriggerVolume* PresurePlate;
//.cpp
#define OUT
float OpenDoor::GetTotalMassActorOnPlate(){
TArray<AActor*> OverlapActors; float TotalMass = 0.f;
PresurePlate->GetOverlapActors(OUT OverlapActors); //return array of actors
for(auto& actor : OverlapActors){ //itrate in collection of actors
TotalMass += actor->FindComponentByClass<UPrimitiveComponent>()-
>GetMass(); //add-up actors mass
UE_LOG(LogTemp, Warning, TEXT("Actor %s"), *actor->GetName());
}
return TotalMass;
}
TickComponent{
if(GetTotalMassActorOnPlate() > 50){ //overlap actor in .h: UPROPERTY()
OpenDoor();
}
}

//crashes and pointer protection


//crashes happen when we follow a nulptr
//we must always check pointers before use by "if" statment
//we must initialise pointers to "nulptr" when declare them
//search all pointers in .h then .cpp by search "*" in the code
//now in .cpp find where pointer used as -> or = and place "if(!ptr){return;}"
before that
//where declare attrubute with UPROPERTY(), in .cpp check it with "if" and log
messages
//place if(!ptr){UE_LOG()} in BeginPlay() for some UPROPERTY() as VolumeTrigger

/*
Exposing events to blueprint
1- convert actor to bluepoint by "settings->convert selected actor to bluepoint
class"
2- in .h of class that attached to out bluepoint, add followong code:
*/
//3- declare delegate(event) after pre-processor, #include and before class
declartion
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnOpenDoorEvent);
//4- now declure following code in .h class declaration:
public:
UPROPERTY(BlueprintAssignable)
FOnOpenDoorEvent OnOpenDoorEvent; //now event avilavle from Blueprint editor as
event
//5- now we broadcast event(call for events) in .cpp, OpenDoor() method
OnOpenDoorEvent.Broadcast();//now anythings that connect to our event in blueprint
will execute
//6- now in blueprint editor select "c++ component", rmb and select events
//7- create smooth door open/close by timeline

//using varibles in blueprint


//1-"promote to variable" 2-component pallet in left-side of blueprint editor 3-c++
UPROPERTY
//create varible from node's pin: rmb on pin and select "promote to variable"

//create rotation
//world-space = absolut rotation: object in orgin has r{0,0,0} but when we rotate
it become r{0,0,90}
//relative = door in orgin has r{0,0,0} but when we rotate it, its rotation is
r{0,0,0} again
//so rotaion in worls is addtive but in relative not
//relative is great for components that use anywhere and in any location/rotation
in level
//1- get init rotation: BeginPlay()->GetActorRotation()->variable (blueprint
editor)
//2- open/close event->timeline->CombineRotator(MakeRotator, get_variable)-
>setActorRotation

//add sound to timeline in blueprint


add new event inside timeline node
connect new event to "PlaySoundAtLocation"
connect "getActorLocation" to "PlaySoundAtLocation" location

//compile code in unreal and use "message log", it has useful info

//change node's connections: ctrl+click on pin and drag on another pin

//redline errors
//add Engine.h before generated.h
//switch to Developement_game and then back to Developement_Editor build
configuration

//loging to output window


UE_LOG, a macro to print to output console, search on net
UE_LOG(LogTemp, Warning, TEXT("message")); //in beginplay
//embed varible in message
//*Object here is not a dereferencing, it's overloding becuase use in macros
UE_LOG(LogTemp, Warning, TEXT("message %s"),*FStringVar);

//get actor transform


FVector fpos = GetOwner()->GetActorLocation();
//or
FVector fpos = GetOwner()->GetTransform().GetLocation();
FString spos = fpos.ToString();//convert to string for logging purpose, *spos when
use in UE_LOG

//rotate actors
//set "mobality" to "movable"
Rotator rot = Rotator(); //define rotation vector
GetOwner()->SetActorRotation(rot);

//view->show fps to measure performence

//display private prperties in "details"


private: //or public, dosen't matter
UPROPERTY(VisibleAnywhere)
float Angle;

//create trigger volume property to select trigger volume


UPROPERTY(EditAnywhere)
ATriggerVolume* volume;

//trigger volume overlap response by "IsOverlapingActor()"


UPROPERTY(EditAnywhere)
AActor* OverlapActor; /*or more specific*/ APawn* OverlapActor; //choose pawn in
"eject mode"
//Polling vs Event Driven
//polling: check overlap in everyframe and when overlap happen do right thing
void MyClass::TickComponent(){ //polling, check every frame
//TriggerVolume and ActorOverlap are custom properties that add by UPROPERTY
if(TriggerVolume->IsOverlapingActor(ActorOverlap) ){
OpenDoor(); //our custom function that execute after overlap
}
}
//event driven: using event delegates

//create light: hold l+click

//create a material

//get a reference to material

//edit material properties

//change mesh material

//temery actors: in eject mode we can see them

//message on screen
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("This is an on screen
message!"));
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("Some
variable values: x: %f, y: %f"), x, y));
//or use this MACRO at the begin of your cpp, so we can use a regular lovely
print(); inside to all
//To prevent your screen from being flooded, you can change the first parameter,
key, to a positive number. Any message printed with that key will remove any other
messages on screen with the same key. This is great for things you want to log
frequently
#define print(text) if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 1.5,
FColor::White,text)

/*
EVENT handling
-allows call member function on c++ objrcts and dynamically bind to function and
call functions on object
-degates are combination of function/variable and
-events handle by delgates
-delgates using templetes and typedefs heavy
-declare by macros and many predifined macros based on varius comination of
function signtures
so signture of function nound to macro :
*/
void foo() = DECLARE_DELEGATE(DelegateName)
void foo(ParamType param1) = DECLARE_DELEGATE_OneParam(DelegateName, Param1Type,
Param1Name)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FActorBeginOverlapSignture, class
AActor*, OtherActor);
//compiler bound this delegate with function format below:
void MyOverlap(AActor* OtherActor)
/*FActorBeginOverlapSignature, associates a type with this delegates signature.
Delegate signatures are stored in the header files of their respective classes
and super-classes(in this case AActor)
Children can and do inherit their status with delegates from their parents.
look in the headers of base classes to find more info about delegates signatures */
//how add event handler to delegate list of callbacks
//delegate will except an event handler with same signture
//if signture has no type/name argument then function you define must also have no
argument
//first parameter is delegate signture and is a type that use in other parts of
system
//1-declare event handler(exact singture as delegate signture)in MyOverlap.h
UFUNCTION()
void OnOverlap(AActor* OtherActor)
//2-define handler in MyOverlap.cpp
void MyOverlap::OnOverlap(AActor* OtherActor){
// what happend when overlap meet
}
//3-now we add our function to delegate's list of callbacks
//this done by calling delegate's AddDynamic in MyOverlap.cpp
//first argument,"this" means reference to myslef
//secend argument is a reference to function that will called in event of event
OnActorBeginOverlap.AddDynamic(this, &MyOverlap::OnOverlap);
//wenever MyOverlap and another actor overlap, OnBeginAcorOverlap delegate which
will call
//MyOverlap::OnOverlap(AActor* OtherActor) passing in a pointer to other AActor
overlaping it
//(OtherActor)
//optimize building
project->myproject properties->nmake->addtional option = /yu

//using int32 insted of int


//FString vs FText: string used inside of code(class),
//ftext used to display and interaction to user and used in main.cpp

comments
-place comment on sifntures in header, when hover cursor on method in .cpp,
comments appear
great way to sure about what we did before

declare/create component
make component as root
destroy when actor overlap
make actor random scale

actor spawn
declare/create component to choose spawn actor
display only actors devired from our class

//U: any devied calss of UObject


//find parameter of api methods: go to difination

/*
1-create components, find more in engine/classes/components/
A-declare in .h file
*/
#include "Components/BoxComponent.h" // before generated.h
PROPERTY(EditAnywhere) //will be editable in detail view
UBoxComponent* box; //define box collision component
B- in .cpp
box = CreateDefaultSubobject<UBoxComponent>("box"); //create/naming component

/*
2-create overlap event
-event called when something overlap with this component as player with trigger or
object have a blocking collision(player hit wall)
A-in .cpp call function when event trigger
*/
box->onComponentBeginOverlap.addDynamic(this, &OurClassName::OnExecuteWhenOverlap);
/*
when comp in OnExecuteWhenOverlap ovelap with box comp, ovelap event trigger and
function OnExecuteWhenOverlap will be call
B-declare function in .h
*/
UFUNCTION()
void OnExecuteWhenOverlap(UPrimitiveComponent* overlappedComp,
AActor* otherActor,
UPrimitiveComponent* otherComp,
int32 otherBodyIndex,
bool bFromSweep,
const FHitResult& SweepResult)
/*
C-define function in .cpp
*/
#include "Kismet/GameplayStatics.h"
MyClass::OnExecuteWhenOverlap(as above){
//if component overlap with player?
if(otherActor == UGameplayStatics::GetPlayerCharacter(this, 0)){
Destroy(); //when overlap trigger, this fumction call and destroy
component
}

}
//UGamePlayStatics is in fact a helper class, and it contains a variety of
functions that
//you may need to call on the fly, such as spawning particles

/*
determine root component ?
1-just reorder CreateDefaultSubobject in .cpp
*/
box=CreateDefaultSubobject<>(); //box is root
mesh=CreateDefaultSubobject<>(); //static mesh is child
/* 2- using RootComponent */
RootComponent = mesh; //cancel out reorder and now mesh is root

/* set mesh relative scale to a random vector in begin of game */


FVector newScale = FVector(FMath::RandRange(0.1f, 0.7f)); // in .h, produce vector
of random number
mesh->SetWorldScale3D(newScale); //in .cpp, set relative scale to vector

/* spawn custom component in game */


/* 1-create a actor class in unreal, PickupSpawner */
/* 2-declare root component(box) in .h */
PROPERTY(EditAnywhere)
UBoxComponent* SpawnBox;
/* 3-create root component(box) in .cpp */
SpawnBox = CreateDefaultSubobject<UBoxComponent>("Spawn Box");
/* 4-devired from our custom component(base) in .h */
UCLASS()
class MYPROJECT_API PickupSpawner:public AActor {
GENERATED_BODY()
public:
//method 1: is unsafe and any UObject subclass can used
UPROPERTY(EditDefaultsOnly, Category=Component)
UClass* PickupToSpawn;
//method 2: safe way, only derived class from CustomComponentClass display
PROPERTY(EditAnywhere)
TSubClassOf<class APickup> PickupToSpawn;
}
/* 5-declare spawn function in .h */
void SpawnPickup();
/* 6-set timer to call spawen function at a set interval in .cpp BeginPlay */
FTimerHandle handle;
GetWorldTimerManager().SetTimer(handle, this, &PickupSpawner::SpawnPickup, 3.0f,
true);
/* 7-definition spawn function in .cpp */
#include "Pickup.h"
#include "Kismet/KismetMathLibrary.h" //advance math
void PickupSpawner::SpawnPickup(){ //spawn component that created in Pickup class
//spawn component, with location this is randomly inside bouning box of
component and no rotation
GetWorld->SpawnActor<APickup>(PickupToSpawn,
//random point inside of spawnbox bounding box
UKismetMathLibrary::RandomPointInBoundingBox(SpawnBox->Bounds->Origin,

SpawnBox->Bounds->BoundExtent),

FRotator::ZeroRotator);
}

attach components in .cpp->BeginPlay, child follow parent


//child parent
PichupBox->AttachToComponent(PickupMesh, FAttachmentTransformRules::bla);

/////////////////////////////////////////////////////////////////////////////////
actor: anything that place in 3d world
-many actors ship with engine, they are accessable from "modes"
-why we create custom actors ?
1-add functionality to existing class
2-combine components in a combination not present in default sub classes
3-add additional member variables to a class

-Actor subclasses(native classes) begin with A

-.generated.h create by unreal header tool(uht) based on macros(UCLASS, ...) in


file

-when inherit from actor, #include point to Actor.h, becuase new class is subclass
of actor

-UCLASS is a macro which indicate this class will be exposed to unreal reflection
system
this system allows us to inspect and iterate object properties during runtime +
manage
references to our objects for garbage collection

-MYPROJECT_API macro after class help project compile properly on windows and
ensuring
that our project's module's classes exported correctly in directlly

-GENERATED_BODY() is another UHT macto that has been expanded to include


automaticlly
generated functions that underlying UE type system requires

PrimaryActorTick.bCanEverTick=true
-implement inside of constructor
-enable ticking for this actor
-all actors have a function called Tick and "bCanEverTick" means that actor will
have
that function called once per frame and enabling actor to perform actions in every
frame
-for performance optimization, we can disiable it

//Instanting an actor using SpawnActor


//1-inherit "AMyActor" from "Actor" class
//content browser->add new->new c++ class->actor /file->new c++ class->actor
//2-inherit "AMyGameMode" from "GameModeBase" class: same as 1
//3-declare in .h:
virtual void BeginPlay() override;
UPROPERTY() AMyActor* SpawnActor = nulptr; //store spawned actor
UFUNCTION() void DestroyActor();
//4-implement(define) BeginPlay():
#include <MyActor>
void AMyGameMode::BeginPlay(){
Super::BeginPlay();
GEngine->AddOnScreenDebugMessage(-1, -1, FColor::Red, TEXT("spawn actor"));
UWorld* World = GetWorld();
if(world){
//assign spawned Actor to new UPROPERTY
SpawnedActor = World->SpawnActor<AMyActor>(AMyActor::StaticClass(),
FVector(0,0,0), FRotator(0,0,0));
}
FTimerHandle Timer;
GetWorldTimerManager().SetTimer(Timer, this, AMyGameMode::DestroyActor, 10);
}
//5-implement DestroyActor()
void AMyGameMode::DestroyActor(){
if(SpawnedActor != nulptr){
SpawnedActor->Destroy();
}
}
//6-World Settings->GameMode Override->change to "GameModeTest" that we created
//7-play and look "World Outliner", GameMode spawn a copy of AMyActor in world
//8-look ouliner, actor will deleted afet 10 sec

/*
GameMode:
-special type of actor, map's GameMode is instantiated by engine when game starts
-is part of unreal game framework

FTransform
-by default constructed to have 0 rotation and location at Origin
-define actor location

UPROPERTY

GetWorld
-reference to current level's UWorld instance then call SpawnActor and give it
actor location

FTimerHandle

GetWorldTimerManager().SetTimer()
-call our method on object pointed by this pointer after 10 sec
-SetTimer return an object(handler) to allow us to cancel timer
-take a FTimerHandle object as reference
*/

Destroy Actor after delay


1-inherit a actor class
2-SetLifeSpan(10); in BeginPLay(), after 10 sec actor call its own Destroy()
3-drag actor in viewport, it will die after 10 sec
/*
Implementing Actor functionality by Composition
-custom actors without components don't have a location and can't be attached to
other actors
-without a root component, an actor dosen't have a base transform and ot has no
location
-we create custom actors theough composition by adding components to our actors
where each component provides some of functionality
*/
//1-inherit a actor class
//2-declure component inside our actor .h
//is a pointer to hold component we are using as a subobject of our actor
//we use static mesh but any of actor component subclasses would work
public:
UPROPERTY()
UStaticMeshComponent* mesh = nulptr;
//3-create component in constructor of our actor .cpp
//initialize pointer to a known valid value by using "templete function"
//this function is responsible for calling engine code to initalize component
//and return a pointer to newly constructed object
//so that we can give out component pointer a default value
//this is important to ensure that pinter has a valid value at all times and
minimizing
//risk of dereferencing uninitalize memory
mesh = CreateDefaultSubobject<UStaticMeshComponent>("show in details");
//4-drag instance of class from "Content Browser" out into game
//5-now it has transform and other properties such as "Static Mesh"

/*UPROPERTY macro
ensuring that object declared in pointer is considered to be referenced
and won't be garbage-collected(that is, deleted) out from under us, leavng pointer
dangling*/

/*
CreateDefaultSubobject<>()
is templete based on type of object to create
first parameter is name of subobject
second is whater object should be transient(that is not saved along with parent
object)
*/

/*
//Load Assets from Actor Class Constructor
1-define following code in constructor after "CreateDefaultSubobject":
2-rmb on your asset in "Content Browser" and choise "Copy References"
then paste inside TEXT()
*/
mesh = CreateDefaultSubobject<UStaticMeshComponent>("bla");
/*
-we create an instance of "FObjectFinder" class and passing in type of asset that
-we are trying to load as a templete parameter
-FObjectFinder is a class templete that help us to load assets
-when we construct it, we pass in a string that contains a path to asset that we
are trying to load

-use auto to avoid trying out our whole object type in its declaration,
compiler deduces it for us, without auto we declare asset as :
ConstructorHelper::FObjectFinder<UStaticMesh> asset;
-"FObjectFinder" has "Object" property that will either have a pointer to asset or
NULL
if asset could not be found
*/
auto asset =
Constructor::FObjectFinder<UStaticMesh>(TEXT("StaticMesh'/Engine/BasicShapes/Cube.C
ube'"));
//string inside TEXT() is format "{ObjectType}"'/Path/To/Asset.asset'
if(asset.Object != nulptr){mesh->SetStaticMesh(asset.Object);}

/*
Implementing Actor functionality by Inheritance
-second way to implement a custom Actor
-done by make a new subclass which add member variables/functions/component to
existing Actor class
-int32: use to ensure of portability between various compilers that UE supports
-UPROPERTY: when use, variables garbage collect appropriately
-UFUNCTION:
1-can call or overridden by blueprint
2-can be marked as "exec" that means they can be run as console commands
by player/developer during play session, which enables debuging
*/
//1-inherit from "GameState" base class(content browser/file -> new c++ class)
//2-declare following code in header
public:
UFUNCTION()
void SetScore(uint32 NewScore);
UFUNCTION()
void GetScore(); //retrieve current score
private:
UPROPERTY()
int32 CurrentScore;
//define in .cpp
AMyGameState::AMyGameState(){CurrentScore = 0;} //constructor
int32 AMyGameState::GetScore(){return CurrentScore;}
void AMyGameState::SetScore(uint32 NewScore){CurrentScore = NewScore;}

/*
Attaching components to create a hierarchy
-attaching components together creates a relationship where transformations applied

to parent component will also affect components that are attached to it


*/
//1- create Actor subclass
//2- declare following properties in header
public:
UPROPERTY() //for each properties delclation
USceneComponent* Root = nulptr; USceneComponent *Child = nulptr;
UStaticMeshComponent* BoxOne = nulptr; UStaticMeshComponent *BoxTwo;
//3- define in constructor in .cpp
Root = CreateDefaultSubobject<USceneComponent>("Root");
Child = CreateDefaultSubobject<USceneComponent>("Child");
BoxOne = CreateDefaultSubobject<UStaticMeshComponent>("BoxOne");
BoxTwo = CreateDefaultSubobject<UStaticMeshComponent>("BoxTwo");
auto MeshAsset =
ConstructorHelper::FObjectFinder<UStaticMesh>("StaticMesh'/Engine/BasicShapes/Cube.
Cube'");
if(MeshAsset.Object){
BoxOne->SetStaticMesh(MeshAsset.Object); BoxTwo-
>SetStaticMesh(MeshAsset.Object);
}//set first SceneComponent as Actor root
RootComponent = Root;//this component will determine transformation applied to all
other components
BoxOne->AttachTo(Root);
//attach second box to our child scene component
BoxTwo->AttachTo(Child);//how changing transform on that scene component affect its
childern but no other components in object
Child->AttachTo(Root);
//set relative transform of that SceneComponent, so that it moves a certain
distance
//away from origin and is one-tenth of scale
//this means that in Editor, you can see that BoxTwo component has inherited
//translation and scaling of its parent component, Child Component
Child-
>SetRelativeTransform(FTransform(FRotator(0,0,0),FVector(255,0,0),FVector(0.1f)));
//4- drag a instance into view and verify components hierarchy in details

/*Creating a Custom Actor Component


-actor components are an easy way to implemetn common functionality
that should be shared between actors
-they aren't rendered but can still perform actions as subscibing to events or
communicating with other components of actor that they are present within
-BlueprintSpawnableComponent: means instances of component can be added to
blueprint classes in editor
-ClassGroup: allows us to indicate what category of class our component belongs
(add component menu)
*/
//1-inherit from "ActorComponent"
//2-add following "class soecifiers" to UCLASS macro
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
//3-declare in .h
public:
UPROPERTY() float MovementRadius;
//4-define in constructor in .cpp
MovementRadius = 5;
//5-add to implementation of "TickComponent"
//get current location of component's owner that is Actor(empty actor) that
contains our component
AActor* Parent = GetOwner();
if(Parent){
Parent->SetActorLocation( //generate an offset in world space
Parent->GetActorLocation() + //add random offset to current location
FVector(
FMath::FRandRange(-1, 1) * MovementRadius,
FMath::FRandRange(-1, 1) * MovementRadius,
FMath::FRandRange(-1, 1) * MovementRadius)
);
}
//6-in editor, create an "empty actor" and add this component to it
//7-now add a "cube component" to visulize and play

/*
Creating a Custom Scene Component
-scene component is subclass of Actor
-have transform tat is relative location/rotation/scale
-like actors, aren't render themselves
-we use their transform for various things as spawning other object at fixed offset
from actor
-TSubclassOf is a template type that allows us to restrict pointer to either base
class or subclasses
also means inside editor we will get a pre-filtered list of classes to pick
*/
//1-create custom "ScenComponent" by inherit from "ActorComponent"
//2-declare following in header:
public:
UFUNCTION() void Spawn();
UPROPERTY() TSubClassOf<AActor>ActorToSpawn;
//3-implement function in .c++
void UActorSpawnComponent::Spawn(){
UWorld* World = GetWorld(); //access to our world
if(World){
//SpawnActor wants FTransform* to specify location to spawn new actor
//so this variable has current component's transform
FTransform ComponentTransform(this->GetComponentTransform());
//spawn an instance of subclass and passing address of FTransform
World->SpawnActor(ActorToSpawn, &ComponentTransform);
}
}
//4- create "Empty Actor" and add this component to it
//5-select component and in details change "ActorToSpawn"
//now whenever spawn() is called on an instance of your component
//and it will instantiate a copy of actor class specific in ActorToSpawn

/*
Creating a custom Primitive Component READ MORE 132
-are most complex type of actor component becuase they nit have transform also
rendered
*/
//1-inherit from "MeshComponent"
//2- declare in .h
UCLASS(ClassGroup=Experimental, meta=(BlueprintSpawnableComponent))
public:
virtual FPrimitiveSceneProxy* CreateSceneProxy() override;
TArray<int32> Indices;
TArray<FVector> Vertices;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Materials)
UMaterial* material = nullptr;
//implemet "CreateAceneProxy"
FPrimitiveSceneProxy* UMyMeshComponent::CreateSceneProxy(){
FPrimitiveSceneProxy* proxy = NULL;
proxy = new FMySceneProxy(this);
return proxy;
}

/*
Creating an InventoryComponent for an RPG
-enables its containing Actor to store InventoryActors in its
inventory, and place them back into the game world
*/
//1- ActorComponent called InventoryComponent
//2- add following to header
UPROPERTY()
TArray<AInventoryActor*> CurrentInventory;
UFUNCTION()
int32 AddToInventory(AInventoryActor* ActorToAdd);
UFUNCTION()
void RemoveFromInventory(AInventoryActor* ActorToRemove);
//3- implementation
int32 UInventoryComponent::AddToInventory(AInventoryActor* ActorToAdd)
{return CurrentInventory.Add(ActorToAdd);}
void UInventoryComponent::RemoveFromInventory(AInventoryActor* ActorToRemove)
{CurrentInventory.Remove(ActorToRemove);}
//4-create a new StaticMeshActor subclass called InventoryActor. Add to declaration
virtual void PickUp();
virtual void PutDown(FTransform TargetLocation);
//5-Implement the new functions
void AInventoryActor::PickUp()
{SetActorTickEnabled(false); SetActorHiddenInGame(true);
SetActorEnableCollision(false);}
void AInventoryActor::PutDown(FTransform TargetLocation)
{
SetActorTickEnabled(true);SetActorHiddenInGame(false);SetActorEnableCollision(true)
;
SetActorLocation(TargetLocation.GetLocation());}
//6-change the constructor
AInventoryActor::AInventoryActor()
:Super()
{
PrimaryActorTick.bCanEverTick = true;
auto MeshAsset =
ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("StaticMesh'/Engine/BasicShapes
/Cube.Cube'"));
if (MeshAsset.Object != nullptr)
{
GetStaticMeshComponent()->SetStaticMesh(MeshAsset.Object);
GetStaticMeshComponent()->SetCollisionProfileName
(UCollisionProfile::Pawn_ProfileName);
}
GetStaticMeshComponent()->SetMobility(EComponentMobility::Movable);
SetActorEnableCollision(true);
}
//7-add an InventoryComponent to our character so that we have an
//inventory that we can store items in. Create a new SimpleCharacter subclass
//using the editor, and add the following to its declaration

Вам также может понравиться