콘텐츠로 이동

UE5 Verse 언어 입문 — UEFN 스크립팅

Verse는 Epic Games가 UEFN(Unreal Editor for Fortnite)을 위해 개발한 함수형 + 객체지향 혼합 프로그래밍 언어입니다. 결정론적 동시성, 실패 가능(failable) 표현식, 강력한 타입 시스템이 특징이며, 향후 UE 엔진 전체로 확장될 예정입니다.


# 주석은 #으로 시작
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# 변수 선언
var Count : int = 0 # 가변 변수
Name : string = "Player" # 불변 변수
# 타입 추론
var Score := 100 # int로 추론
# 함수 선언
Greet(PlayerName : string) : string =
"안녕하세요, {PlayerName}님!"
# 반환 타입 없는 void 함수
PrintScore(Score : int) : void =
Print("점수: {Score}")

# 기본 타입
var I : int = 42
var F : float = 3.14
var B : logic = true # bool 대신 logic
var S : string = "hello"
# 옵션 타입 (nullable 대신)
var MaybePlayer : ?player = false # 없음
if (P := MaybePlayer?): # 언래핑
Print("플레이어 있음: {P}")
# 배열
var Items : []string = array{"sword", "shield"}
Items += array{"potion"}
# 맵
var Scores : [string]int = map{"Alice"=>100, "Bob"=>85}
# 튜플
var Pos : tuple(float, float, float) = (1.0, 2.0, 3.0)

# Verse의 핵심 개념: 표현식은 성공 또는 실패할 수 있음
# if 블록이 실패 컨텍스트를 제공
FindPlayer(Name : string) : ?player =
# 실패 가능 컨텍스트
if (P := GetPlayerByName(Name)?):
P
else:
false # 실패 반환
# 연쇄 실패: 하나라도 실패하면 전체 실패
if:
Player := FindPlayer("Alice")?
Health := Player.GetHealth()?
Health > 0
then:
Print("Alice는 살아있습니다")
else:
Print("Alice를 찾을 수 없거나 사망")
# 실패 가능 함수 정의
GetTopPlayer()<decides><transacts> : player =
Players := GetActivePlayers()
Players[0] # 비어있으면 실패

# Verse의 구조적 동시성
# spawn: 비동기 태스크 시작
MyTask := spawn:
loop:
Sleep(1.0)
UpdateScoreboard()
# race: 먼저 완료된 것만 선택
race:
block:
Sleep(10.0)
Print("10초 경과")
block:
WaitForPlayerAction()
Print("플레이어가 먼저 행동함")
# sync: 모두 완료될 때까지 대기
sync:
LoadAssetA()
LoadAssetB()
LoadAssetC()
Print("모든 에셋 로드 완료")
# 채널 통신
Channel := channel(int){}
spawn:
Channel.Send(42)
Value := Channel.Receive()
Print("수신: {Value}")

# 인터페이스 정의
damageable := interface:
TakeDamage(Amount : float) : void
GetHealth() : float
# 클래스 구현
enemy := class(damageable):
var Health : float = 100.0
Name : string
# 인터페이스 구현
TakeDamage(Amount : float) : void =
set Health = Max(0.0, Health - Amount)
if (Health <= 0.0):
OnDeath()
GetHealth() : float = Health
OnDeath() : void =
Print("{Name} 사망")
# 상속
boss_enemy := class(enemy):
var Phase : int = 1
override TakeDamage(Amount : float) : void =
# 1페이즈에서 데미지 감소
ActualDamage := if (Phase = 1): Amount * 0.5 else Amount
super.TakeDamage(ActualDamage)

# 트리거 디바이스와 연동
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
trigger_handler := class(creative_device):
# 에디터에서 드래그한 디바이스 참조
@editable
MyTrigger : trigger_device = trigger_device{}
@editable
var RewardAmount : int = 100
# 게임 시작 시 자동 호출
OnBegin<override>()<suspends> : void =
# 트리거 이벤트 구독
MyTrigger.TriggeredEvent.Await()
OnTriggered()
OnTriggered() : void =
Print("트리거 발동! 보상: {RewardAmount}")
# 모든 플레이어에게 점수 지급
for (P : GetActivePlayers()):
if (FortChar := P.GetFortCharacter[]):
FortChar.GiveScore(RewardAmount)

# 실패 가능 + 옵션 조합 패턴
SafeDivide(A : float, B : float)<decides> : float =
B <> 0.0 # B가 0이면 실패
A / B
# 사용
if (Result := SafeDivide(10.0, 0.0)?):
Print("결과: {Result}")
else:
Print("0으로 나눌 수 없음")
# 기본값 패턴
GetPlayerScore(P : player) : int =
if (Score := ScoreMap[P]?): Score
else: 0

Verse의 핵심은 실패 가능 표현식구조적 동시성입니다. if/else가 단순 조건분기가 아니라 실패 컨텍스트를 제공하며, ? 연산자로 옵션 값을 안전하게 언래핑합니다. spawn, race, sync로 비동기 게임플레이 로직을 명확하게 구조화하고, @editable로 에디터에서 디바이스를 연결하는 패턴이 UEFN 개발의 기본 워크플로입니다.