Skip to content

Using NimForUE

Examples

The whole Cpp ThirdPersonTemplate in Nim would be like this:

uClass ANimCharacter of ACharacter:
(config=Game)
uprops(EditAnywhere, BlueprintReadOnly, DefaultComponent, Category = Camera): # DefaultComponent ensures the component is created by the constructor
cameraBoom : USpringArmComponentPtr
uprops(EditAnywhere, BlueprintReadOnly, DefaultComponent, Attach=(cameraBoom, SpringEndpoint), Category = Camera):
followCamera : UCameraComponentPtr
uprops(EditAnywhere, BlueprintReadOnly, Category = Input):
defaultMappingContext : UInputMappingContextPtr
(jumpAction, moveAction, lookAction) : UInputActionPtr
defaults: # default values for properties on the cdo
capsuleComponent.capsuleRadius = 40
capsuleComponent.capsuleHalfHeight = 96
bUseControllerRotationYaw = false
characterMovement.jumpZVelocity = 700
characterMovement.airControl = 0.35
characterMovement.maxWalkSpeed = 500
characterMovement.minAnalogWalkSpeed = 20
characterMovement.brakingDecelerationWalking = 2000
characterMovement.bOrientRotationToMovement = true
cameraBoom.targetArmLength = 400
cameraBoom.busePawnControlRotation = true
followCamera.bUsePawnControlRotation = true
ufuncs:
proc setupPlayerInputComponent(playerInputComponent : UInputComponentPtr) = #Notice here we are overriding a native cpp virtual func. You can call `super` self.super(playerInputComponent) or super(self, playerInputComponent)
let pc = ueCast[APlayerController](self.getController())
if pc.isNotNil():
let inputComponent = ueCast[UEnhancedInputComponent](playerInputComponent)
let subsystem = getSubsystem[UEnhancedInputLocalPlayerSubsystem](pc).get()
subsystem.addMappingContext(self.defaultMappingContext, 0)
inputComponent.bindAction(self.jumpAction, ETriggerEvent.Triggered, self, n"jump")
inputComponent.bindAction(self.jumpAction, ETriggerEvent.Completed, self, n"stopJumping")
inputComponent.bindAction(self.moveAction, ETriggerEvent.Triggered, self, n"move")
inputComponent.bindAction(self.lookAction, ETriggerEvent.Triggered, self, n"look")
proc move(value: FInputActionValue) =
let
movementVector = value.axis2D()
rot = self.getControlRotation()
rightDir = FRotator(roll: rot.roll, yaw: rot.yaw).getRightVector()
forwardDir = FRotator(yaw: rot.yaw).getForwardVector()
self.addMovementInput(rightDir, movementVector.x, false)
self.addMovementInput(forwardDir, movementVector.y, false)
proc look(value: FInputActionValue) =
let lookAxis = value.axis2D()
self.addControllerYawInput(lookAxis.x)
self.addControllerPitchInput(lookAxis.y)
uClass ANimGameMode of AGameModeBase:
proc constructor(init:FObjectInitializer) = #Similar to default but allows you to write full nim code
let classFinder = makeClassFinder[ACharacter]("/Game/ThirdPerson/Blueprints/BP_ThirdPersonCharacter")
self.defaultPawnClass = classFinder.class

This code can be found at src/examples/actorexample. There are more examples inside that folder. You can do import examples/example in from Game.nim (see the NimTemplate) to play with it.

#Nim UClasses can derive from the same classes that blueprints can derive from.
uClass AExampleActor of AActor:
(BlueprintType, Blueprintable) #Class specifiers follow the C++ convention.
uprops(EditAnywhere, BlueprintReadWrite): #you can declare multiple UPROPERTIES in one block
exampleValue : FString #They are declare as nim properties.
anotherVale : int #notice int in nim is int64. while in c++ it is int32.
anotherValueInt32 : int32 #this would be equivalent to int32
predValue : FString = "Hello" #you can assign a default value to a property.
predValueInt : int = 20 + 10 #you can even use functions (the execution is deferred)
nameTest : FString = self.getName() #you can even use functions within the actor itself. It is accessible via this or self.
#In general when using the equal symbol in a uClass declaration, a default constructor will be generated.
#you can specify a custom constructor if you want to by defining a regular nim function and adding the pragma uconstructor
proc myExampleActorCostructor(self: AExampleActorPtr, initializer: FObjectInitializer) {.uConstructor.} =
UE_Log "The constructor is called for the actor"
self.anotherVale = 5
#you can override the values set by the default constructor too since they are added adhoc before this constructor is called.
self.predValue = "Hello World"
#Notice that you rarelly will need to define a custom constructor for your class. Since the CDO can be set within the DSL.
#UFunctions
#UFunctions can be added by adding the pragma uFunc, and for each meata, another pragma:
#Since in nim functions are separated from the type they are declared in, you need to specify the type as the first argument.
proc myUFunction(self: AExampleActorPtr, param : FString) : int32 {. ufunc, BlueprintCallable .} =
UE_Log "UFunction called"
5
#You can also use the uFunctions macro to declare multiple uFunctions at once. The preferred way is still to use them in an uClass block like shown above.
uFunctions:
(BlueprintCallable, self:AExampleActorPtr) #you must specify the type and any shared meta like this.
proc anotherUFunction(param : FString) : int32 = 10 #now you can define the function as you normally would.
proc yetAnotherUFunction(param : FString) : FString =
self.getName() #you can access to the actor itself by the name you specify in the uFunctions macro.
proc customPragma(param : FString) : int32 {. BlueprintPure .} = 10 #you can also specify custom pragmas per functions rather than creating a new block
proc callFromTheEditor() {. CallInEditor .} =
UE_Log "Call from the editor"

Which produces: Blueprint