Using Haxe with the Unreal Engine 4
https://slides.com/cauewaneck/unreal-hx/live
By Cauê Waneck ( @cwaneck )
[~]$ whoami
C++ can be difficult to integrate with itself let alone other languages
Closed beta this year!
package unreal;
/**
Actor is the base class for an Object that can be placed or spawned in a level.
Actors may contain a collection of ActorComponents, which can be used to control how actors move, how they are rendered, etc.
The other main function of an Actor is the replication of properties and function calls across the network during play.
@see https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Actors/
@see UActorComponent
**/
@:glueCppIncludes("GameFramework/Actor.h")
@:uextern extern class AActor extends unreal.UObject {
/**
Array of ActorComponents that are created by blueprints and serialized per-instance.
**/
public var BlueprintCreatedComponents : unreal.TArray<unreal.UActorComponent>;
#if WITH_EDITORONLY_DATA
/**
Local space pivot offset for the actor
**/
private var PivotOffset : unreal.FVector;
#end // WITH_EDITORONLY_DATA
/**
Returns the point of view of the actor.
Note that this doesn't mean the camera, but the 'eyes' of the actor.
For example, for a Pawn, this would define the eye height location,
and view rotation (which is different from the pawn rotation which has a zeroed pitch component).
A camera first person view will typically use this view point. Most traces (weapon, AI) will be done from this view point.
@param OutLocation - location of view point
@param OutRotation - view rotation of actor.
**/
@:thisConst public function GetActorEyesViewPoint(OutLocation : unreal.PRef<unreal.FVector>, OutRotation : unreal.PRef<unreal.FRotator>) : Void;
/**
Script exposed version of FindComponentByClass
**/
public function GetComponentByClass(ComponentClass : unreal.TSubclassOf<unreal.UActorComponent>) : unreal.UActorComponent;
package unreal;
/**
Actor is the base class for an Object that can be placed or spawned in a level.
Actors may contain a collection of ActorComponents, which can be used to control how actors move, how they are rendered, etc.
The other main function of an Actor is the replication of properties and function calls across the network during play.
@see https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Actors/
@see UActorComponent
**/
@:glueCppIncludes("GameFramework/Actor.h")
@:uextern class AActor extends unreal.UObject {
/**
Array of ActorComponents that are created by blueprints and serialized per-instance.
**/
public var BlueprintCreatedComponents(get,set):unreal.PPtr<unreal.TArray<unreal.UActorComponent>>;
@:glueCppIncludes("GameFramework/Actor.h", "uhx/Wrapper.h")
@:glueHeaderIncludes("IntPtr.h", "VariantPtr.h")
@:glueHeaderCode("static void GetActorEyesViewPoint(unreal::UIntPtr self, unreal::VariantPtr OutLocation, unreal::VariantPtr OutRotation);")
@:glueCppCode("void uhx::glues::AActor_Glue_obj::GetActorEyesViewPoint(unreal::UIntPtr self, unreal::VariantPtr OutLocation, unreal::VariantPtr OutRotation) {\n\t( (AActor *) self )->GetActorEyesViewPoint(*::uhx::StructHelper< FVector >::getPointer(OutLocation), *::uhx::StructHelper< FRotator >::getPointer(OutRotation));\n}")
@:thisConst
public function GetActorEyesViewPoint(OutLocation : unreal.PRef<unreal.FVector>, OutRotation : unreal.PRef<unreal.FRotator>) : Void {
uhx.glues.AActor_Glue.GetActorEyesViewPoint(unreal.helpers.HaxeHelpers.getUObjectWrapped(this), OutLocation, OutRotation);
}
@:glueCppIncludes("GameFramework/Actor.h", "uhx/Wrapper.h", "Containers/Array.h", "Components/ActorComponent.h", "uhx/glues/TArrayImpl_Glue_UE.h")
@:glueHeaderIncludes("IntPtr.h", "VariantPtr.h")
@:glueHeaderCode("static unreal::VariantPtr get_BlueprintCreatedComponents(unreal::UIntPtr self);")
@:glueCppCode("unreal::VariantPtr uhx::glues::AActor_Glue_obj::get_BlueprintCreatedComponents(unreal::UIntPtr self) {\n\treturn ::uhx::TemplateHelper<TArray<UActorComponent *>>::fromPointer( (&(( (AActor *) self )->BlueprintCreatedComponents)) );\n}")
@:final @:nonVirtual
private function get_BlueprintCreatedComponents() : unreal.PPtr<unreal.TArray<unreal.UActorComponent>> {
return ( @:privateAccess unreal.TArrayImpl.fromPointer( uhx.glues.AActor_Glue.get_BlueprintCreatedComponents(unreal.helpers.HaxeHelpers.getUObjectWrapped(this)) ) : unreal.PPtr<unreal.TArray<unreal.UActorComponent>> );
}
/**
Script exposed version of FindComponentByClass
**/
@:glueCppIncludes("GameFramework/Actor.h", "UObject/ObjectBase.h", "Components/ActorComponent.h")
@:glueHeaderIncludes("IntPtr.h")
@:glueHeaderCode("static unreal::UIntPtr GetComponentByClass(unreal::UIntPtr self, unreal::UIntPtr ComponentClass);")
@:glueCppCode("unreal::UIntPtr uhx::glues::AActor_Glue_obj::GetComponentByClass(unreal::UIntPtr self, unreal::UIntPtr ComponentClass) {\n\treturn ( (unreal::UIntPtr) (( (AActor *) self )->GetComponentByClass(( (TSubclassOf<UActorComponent>) (UClass *) ComponentClass ))) );\n}")
public function GetComponentByClass(ComponentClass : unreal.TSubclassOf<unreal.UActorComponent>) : unreal.UActorComponent {
return ( cast unreal.UObject.wrap(uhx.glues.AActor_Glue.GetComponentByClass(unreal.helpers.HaxeHelpers.getUObjectWrapped(this), unreal.helpers.HaxeHelpers.getUObjectWrapped(ComponentClass))) : unreal.UActorComponent );
}
// you define templated functions and types!
@:glueCppIncludes('Templates/SharedPointer.h')
@:uextern extern class TSharedPtr<T> {
@:global
public static function MakeShareable<T>(ptr:PPtr<T>):TSharedPtr<T>;
/**
* Constructs an empty shared pointer
*/
@:uname('.ctor') public static function create<T>():TSharedPtr<T>;
/* snip ... */
}
// you can also define C++ enums!
@:glueCppIncludes("IHttpRequest.h")
@:uname("EHttpRequestStatus.Type")
@:uextern extern enum EHttpRequestStatus {
NotStarted;
Processing;
Failed;
Succeeded;
}
// and delegates! Yes you can bind normal Haxe functions to them
@:glueCppIncludes("IHttpRequest.h")
@:uname('FHttpRequestCompleteDelegate')
typedef FHttpRequestCompleteDelegate = Delegate<FHttpRequestCompleteDelegate, TSharedPtr<IHttpRequest>->TThreadSafeSharedPtr<IHttpResponse>->Bool->Void>;
// also C++ method pointers:
/**
* Binds a delegate function to an Action defined in the project settings.
* Returned reference is only guaranteed to be valid until another action is bound.
*/
public function BindAction(actionName:Const<FName>, keyEvent:EInputEvent, object:UObject, func:MethodPointer<UObject,Void->Void>) : PRef<FInputActionBinding>;
// also some operators are supported
@:glueCppIncludes("Array.h")
@:uextern @:noCopy extern class TIndexedContainerIterator<Ar, El, Ind> {
public function op_Increment() : Void;
public function op_Decrement() : Void;
public function op_Dereference() : PRef<El>;
public function op_Not() : Bool;
}
package platformer;
import unreal.*;
using unreal.CoreAPI;
// define a new delegate
typedef FRoundFinishedDelegate = DynamicMulticastDelegate<FRoundFinishedDelegate, Void->Void>;
// you can define your own UENUMs through Haxe - which can be used by C++!
@:uenum
enum EGameState {
Intro;
Waiting;
Playing;
Finished;
Restarting;
}
@:uclass
// you can use @:uname to define the target name, without having to use that
@:uname("APlatformerGameMode")
class GameMode extends AGameMode {
var someHaxeArray:Array<String>;
var someUnrealArray:TArray<Int8>;
@:uexpose var someExposedUnrealArray:TArray<FString>;
/** delegate to broadcast about finished round */
@:uproperty(BlueprintAssignable)
public var OnRoundFinished:FRoundFinishedDelegate;
public function someHaxeFunction(json:{ name:String, age:Int }):Void { /* ... */ }
@:uexpose public function someUnrealFunction(char:Character, basicType:Bool):Void { /* ... */ }
/* snip .. */
}
@:uclass(Abstract)
@:uname("APlatformerCharacter")
class Character extends ACharacter {
/** player pawn initialization */
override public function PostInitializeComponents():Void {
super.PostInitializeComponents();
SetActorRotation(FRotator.createWithValues(0,0,0));
}
/* snip ... */
}
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "PlatformerClimbMarker.generated.h"
UCLASS(Blueprintable)
class APlatformerClimbMarker : public AActor
{
GENERATED_UCLASS_BODY()
private:
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category=Mesh, meta=(AllowPrivateAccess="true"))
UStaticMeshComponent* Mesh;
public:
/** Returns Mesh subobject **/
FORCEINLINE UStaticMeshComponent* GetMesh() const { return Mesh; }
};
class FPlatformerMessageData
{
/** text to display */
FString Message;
/** how long this FMessageData will be displayed in seconds */
float DisplayDuration;
/** TimeSeconds when this FMessageData was first shown */
float DisplayStartTime;
/** x axis position on screen <0, 1> (0 means left side of the screen) ; text will be centered */
float PosX;
/** y axis position on screen <0, 1> (0 means top of the screen) ; text will be centered */
float PosY;
/** text scale */
float TextScale;
/** if red border should be drawn instead of blue */
bool bRedBorder;
};
C++ | Haxe |
---|---|
FSomeStruct | FSomeStruct |
FSomeStruct& | PRef<FSomeStruct> |
FSomeStruct * | PPtr<FSomeStruct> or POwnedPtr<FSomeStruct> |
const FSomeStruct& | Const<PRef<FSomeStruct>> |
FSomeStruct ** | <not supported... yet> |
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "PlatformerClimbMarker.generated.h"
UCLASS(Blueprintable)
class APlatformerClimbMarker : public AActor
{
GENERATED_UCLASS_BODY()
private:
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category=Mesh, meta=(AllowPrivateAccess="true"))
UStaticMeshComponent* Mesh;
public:
/** Returns Mesh subobject **/
FORCEINLINE UStaticMeshComponent* GetMesh() const { return Mesh; }
};
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "PlatformerClimbMarker.generated.h"
UCLASS(Blueprintable)
class APlatformerClimbMarker : public AActor
{
GENERATED_UCLASS_BODY()
private:
UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category=Mesh, meta=(AllowPrivateAccess="true"))
UStaticMeshComponent* Mesh;
public:
/** Returns Mesh subobject **/
FORCEINLINE UStaticMeshComponent* GetMesh() const { return Mesh; }
};
package platformer;
import unreal.*;
@:uclass(Blueprintable)
@:uname("APlatformerClimbMarker")
class ClimbMarker extends AActor {
@:uproperty(VisibleDefaultsOnly, BlueprintReadOnly, Category=Mesh, meta=[AllowPrivateAccess="true"])
private var Mesh:UStaticMeshComponent;
inline public function GetMesh() {
return Mesh;
}
}
C++ | Haxe |
---|---|
FSomeStruct | FSomeStruct |
FSomeStruct& | PRef<FSomeStruct> |
FSomeStruct * | PPtr<FSomeStruct> or POwnedPtr<FSomeStruct> |
const FSomeStruct& | Const<PRef<FSomeStruct>> |
FSomeStruct ** | <not supported... yet> |
Uses Haxe abstracts!
package unreal;
/**
Base class for all tick functions.
**/
@:glueCppIncludes("GameFramework/Actor.h")
@:uextern extern class FTickFunction {
/**
The frequency in seconds at which this tick function will be executed. If less than or equal to 0 then it will tick every frame
**/
public var TickInterval : unreal.Float32;
/**
If false, this tick function will never be registered and will never tick. Only settable in defaults.
**/
public var bCanEverTick : Bool;
/* snip... */
}
package unreal;
/**
Base class for all tick functions.
**/
@:glueCppIncludes("GameFramework/Actor.h")
@:uextern
@:ueGluePath("uhx.glues.FTickFunction_Glue")
@:forward(dispose,isDisposed) abstract FTickFunction(unreal.Struct) to unreal.Struct to unreal.VariantPtr {
/**
The frequency in seconds at which this tick function will be executed. If less than or equal to 0 then it will tick every frame
**/
public var TickInterval(get,set):cpp.Float32;
/**
If false, this tick function will never be registered and will never tick. Only settable in defaults.
**/
public var bCanEverTick(get,set):Bool;
/**
Invokes the copy constructor of the referenced C++ class.
This has some limitations - it won't copy the full inheritance chain of the class if it wasn't typed as the exact class
it will also be a compilation error if the wrapped class forbids the C++ copy constructor;
in this case, the extern class definition should contain the `@:noCopy` metadata
**/
@:glueCppIncludes("uhx/Wrapper.h", "GameFramework/Actor.h")
@:glueHeaderIncludes("VariantPtr.h")
@:glueHeaderCode("static unreal::VariantPtr copy(unreal::VariantPtr self);")
@:glueCppCode("unreal::VariantPtr uhx::glues::FTickFunction_Glue_obj::copy(unreal::VariantPtr self) {\n\treturn ::uhx::StructHelper<FTickFunction>::fromStruct(FTickFunction(*::uhx::StructHelper< FTickFunction >::getPointer(self)));\n}")
public function copy() : unreal.FTickFunction {
return ( @:privateAccess unreal.FTickFunction.fromPointer( uhx.glues.FTickFunction_Glue.copy(this) ) : unreal.FTickFunction );
}
@:glueCppIncludes("<uhx/TypeTraits.h>", "uhx/Wrapper.h", "GameFramework/Actor.h")
@:glueHeaderIncludes("VariantPtr.h")
@:glueHeaderCode("static bool equals(unreal::VariantPtr self, unreal::VariantPtr other);")
@:glueCppCode("bool uhx::glues::FTickFunction_Glue_obj::equals(unreal::VariantPtr self, unreal::VariantPtr other) {\n\tif (self.raw == other.raw) { return true; }if (self.raw == 0 || other.raw == 0) { return false; }return uhx::TypeTraits::Equals<FTickFunction>::isEq(*::uhx::StructHelper< FTickFunction >::getPointer(self), *::uhx::StructHelper< FTickFunction >::getPointer(other));\n}")
public function equals(other : unreal.PPtr<unreal.FTickFunction>) : Bool {
return uhx.glues.FTickFunction_Glue.equals(this, other);
}
@:glueCppIncludes("uhx/Wrapper.h", "GameFramework/Actor.h")
@:glueHeaderIncludes("VariantPtr.h", "<hxcpp.h>")
@:glueHeaderCode("static cpp::Float32 get_TickInterval(unreal::VariantPtr self);")
@:glueCppCode("cpp::Float32 uhx::glues::FTickFunction_Glue_obj::get_TickInterval(unreal::VariantPtr self) {\n\treturn ::uhx::StructHelper< FTickFunction >::getPointer(self)->TickInterval;\n}")
@:final @:nonVirtual
@:nonVirtual
private function get_TickInterval() : cpp.Float32 {
return uhx.glues.FTickFunction_Glue.get_TickInterval(this);
}
@:glueCppIncludes("uhx/Wrapper.h", "GameFramework/Actor.h")
@:glueHeaderIncludes("VariantPtr.h", "<hxcpp.h>")
@:glueHeaderCode("static void set_TickInterval(unreal::VariantPtr self, cpp::Float32 value);")
@:glueCppCode("void uhx::glues::FTickFunction_Glue_obj::set_TickInterval(unreal::VariantPtr self, cpp::Float32 value) {\n\t::uhx::StructHelper< FTickFunction >::getPointer(self)->TickInterval = value;\n}")
@:final @:nonVirtual
@:nonVirtual
@:final @:nonVirtual
@:nonVirtual
private function set_TickInterval(value : cpp.Float32) : cpp.Float32 {
uhx.glues.FTickFunction_Glue.set_TickInterval(this, value);
return value;
}
@:glueCppIncludes("uhx/Wrapper.h", "GameFramework/Actor.h")
@:glueHeaderIncludes("VariantPtr.h")
@:glueHeaderCode("static bool get_bCanEverTick(unreal::VariantPtr self);")
@:glueCppCode("bool uhx::glues::FTickFunction_Glue_obj::get_bCanEverTick(unreal::VariantPtr self) {\n\treturn ::uhx::StructHelper< FTickFunction >::getPointer(self)->bCanEverTick;\n}")
@:final @:nonVirtual
@:nonVirtual
private function get_bCanEverTick() : Bool {
return uhx.glues.FTickFunction_Glue.get_bCanEverTick(this);
}
@:glueCppIncludes("uhx/Wrapper.h", "GameFramework/Actor.h")
@:glueHeaderIncludes("VariantPtr.h")
@:glueHeaderCode("static void set_bCanEverTick(unreal::VariantPtr self, bool value);")
@:glueCppCode("void uhx::glues::FTickFunction_Glue_obj::set_bCanEverTick(unreal::VariantPtr self, bool value) {\n\t::uhx::StructHelper< FTickFunction >::getPointer(self)->bCanEverTick = value;\n}")
@:final @:nonVirtual
@:nonVirtual
@:final @:nonVirtual
@:nonVirtual
private function set_bCanEverTick(value : Bool) : Bool {
uhx.glues.FTickFunction_Glue.set_bCanEverTick(this, value);
return value;
}
/* snip... */
}
No pass-by-value in Haxe!
struct FSceneView {
bool WorldToPixel(const FVector& WorldPoint,
FVector2D& OutPixelLocation);
};
// use like:
FVector2D pixelLocation;
Fvector somePoint = FVector(1,1,1);
FSceneView& view = getSomeView();
view.WorldToPixel(somePoint, pixelLocation);
// on Externs
extern class FSceneView {
function WorldToPixel(WorldPoint:Const<PRef<FVector>>,
OutPixelLocation:PRef<FVector2D>):Bool;
}
// use like:
var pixelLocation = FVector2D.create(); // we need to create this! otherwise it gets sent as null
var somePoint = new FVector(1,1,1);
var view = getSomeView();
view.WorldToPixel(somePoint, pixelLocation);