realtime development


Unity - GPU Instancing

  • Using Graphics.DrawMeshInstanced with a custom ScriptableObject derived class to instance large mesh counts.

  • Separates creation of PointClouds from their use by allowing configurable instancing using seeding.

  • 500,000,000 Triangles at 15fps at decent quality.

  • Material overrides to come next.

 

Unreal C++ API TIPS

EDITOR/Project

  • Use the Blueprint Template instead of the C++

IDE

  • 4.25 VSCODE bug intellisense wont work until defines in properties.json is updated

Header Files, Includes

  • If autocomplete is not working on an object in visual studio, #include it, the hint of what to include is in the Unreal docs.
  • To decrease compile times use forward declaration to declare classes, simply declare the class using in the header file after any includes; You will also need to #include the class into the body.
class MyClassName

Unreal basic types

  • Unreal uses it’s own basic types. These have many inbuilt helper methods.

STRINGS

  • Use the Text Macro to enclose any string; 
FString MyFooString = FString(TEXT(“MyFoo“));

REFERENCES

  • The reference operator is the ampersand &. References function differently in C++ than in dynamically typed languages. They must be initialised, and they cannot be reassigned.

POINTERS

  • Pointers are a reference, that points to a memory address with a type. 
  • Pointer syntax is tricky, the * operator is the key to creating a pointer. 
  • You also need to use the address operator, &, to point to an address.  The arrow operator, ->, is the way to reach into the pointer to extract it’s member variables.
FString MyString = "Foo";
FString *PtrToThing = &Foo;
PtrToThing->Len();
  • Pointers are variables, so they can be reassigned if they still point to the correct type.
FString MyOtherString = "Baa";
PtrToThing = &MyOtherString
  • Always check your pointers before using them, always initialise them to nullptr
if(PtrSomeRef && PtrSomeRef.DoSomething())

COMPONENTS

  • Creating components can be done in code with the following static method;
CapsuleComp = CreateDefaultSubobject<UCapsuleComponent>(TEXT("Capsule Collider")); 	
RootComponent = CapsuleComp;  	
BaseMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Base Mesh")); 	
BaseMesh->SetupAttachment(RootComponent);

BLUEprint Properties

  • Properties can be exposed using the following decorator;
UPROPERTY()
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=”HEALTH”)


BLUEprint FUNCTIONS & Events

  • Blueprint functions can be called with events with this macro;
  • Blueprint functions can also be pure, they will not have an execution pin, as they will not modify the class.
UFUNCTION(BlueprintImplementableEvent)
void CreateMeInBP();
UFUNCTION(BlueprintPure) 	bool IsDead() const;


Player Input

  • Player input is bound in the project settings, then bound in the SetupPlayerInputComponent() function like this;
PlayerInputComponent->BindAxis(TEXT("LookRight"), this, &AShooterCharacter::LookRight);
PlayerInputComponent->BindAction(TEXT("Jump"), EInputEvent::IE_Pressed, this, &AShooterCharacter::Jump);

Delegates

  • Delegates function exactly the same in Unreal/C++ as they do in Unity/C#. 
  • The AddDynamic method takes a reference to the binding component and a method that matches the signature of the delegate.
GetOwner()->OnTakeAnyDamage.AddDynamic(this, &UHealthComponent::TakeDamage);

DEBUG

  • Debug objects can be drawn by #include "DrawDebugHelpers.h"
DrawDebugCamera(GetWorld(), GetActorLocation(), GetActorRotation(), 90.0f, 2, FColor::Red, true);

Blackboard

  • Implementing a new Blackboard Task node will create a linker error. this can be resolved by adding GameplayTasks to your projects Build.cs file.
  • The node will need a name variable
  • Each node type has a few important virtual methods to override, the primary of those being;
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "GameplayTasks" });

UBTTask_ClearBlackboardValue::UBTTask_ClearBlackboardValue() 
{ 	
    NodeName = TEXT("Clear Blackboard Value"); 
}

EBTNodeResult::Type 

UBTTask_ClearBlackboardValue::ExecuteTask(UBehaviorTreeComponent& OwnerComp, uint8* NodeMemory) 
{ 	
    Super::ExecuteTask(OwnerComp, NodeMemory); 	
    OwnerComp.GetBlackboardComponent()->ClearValue(GetSelectedBlackboardKey()); 	 	
    return EBTNodeResult::Succeeded; 
}