본문 바로가기

비주얼 스크립팅 기본 개념

노드와 핀, 실행선과 데이터선을 구분하고 그래프의 실행 순서와 값 전달 과정을 올바르게 읽는 법을 익힙니다.

블루프린트 그래프를 처음 읽을 때 가장 먼저 부딪히는 질문은 두 가지입니다. 이 노드는 언제 실행되는가, 그리고 이 노드가 쓰는 값은 어디서 오는가. 텍스트 코드에서는 위에서 아래로 줄을 읽으면 실행 순서가 대체로 보이지만, 블루프린트에서는 노드가 화면 어디에 놓였는지가 순서를 정하지 않습니다. 순서와 값은 모두 노드 사이의 선이 정하며, 선에도 두 종류가 있습니다.

이 글에서는 비주얼 스크립팅이 무엇인지 짧게 짚은 뒤, 블루프린트의 노드와 핀, 선이 어떻게 생겼고 각각 무엇을 정하는지 살펴봅니다. 그리고 점수 하나를 화면에 출력하는 작은 그래프로, 실행 연결과 값 연결을 따로 읽는 연습을 합니다.


코드를 쓰는 대신 흐름을 그리는 방식

비주얼 스크립팅(visual scripting)은 시각적인 요소를 배치하고 이어서 프로그램을 작성하는 방식입니다. 텍스트 기반 프로그래밍이 코드를 타이핑해 논리를 만든다면, 비주얼 스크립팅은 그림을 그리듯 흐름을 설계합니다. 블루프린트에서는 기능이 담긴 노드(node)를 배치하고, 노드 사이를 선(wire)으로 이어 실행 순서와 데이터의 흐름을 나타냅니다.

그래서 비주얼 스크립팅은 코드 문법보다 로직의 구조를 먼저 이해하기 좋은 방식입니다. 이벤트에서 결과까지 선을 따라가면 전체 흐름이 한눈에 보이고, 문제가 생겼을 때도 어느 노드에서 어떤 값이 잘못 넘어갔는지 화면에서 추적할 수 있습니다. 반대로 노드가 많아지면 선이 얽혀 읽기 어려워지고, 텍스트처럼 검색하거나 비교하기도 불편해집니다. 이 단점은 함수로 묶기, 주석(Comment) 달기, 노드 정렬 같은 정리 습관으로 줄여야 하며, 2장과 이후 장에서 그 방법을 하나씩 다룹니다.


노드: 한 가지 일을 하는 상자

블루프린트에서 기능의 가장 작은 단위는 노드입니다. 노드 하나는 덧셈이나 곱셈 같은 계산, 변수 값 설정, 함수 호출, 조건 확인처럼 정해진 한 가지 작업을 합니다. 노드에는 그 노드가 무슨 일을 하는지 알려 주는 노드 이름이 위쪽에 적혀 있고, 양옆에는 다른 노드와 연결하는 핀(pin)이 붙어 있습니다. 핀은 하는 일에 따라 두 종류로 나뉩니다.

실행 핀(execution pin)은 실행 흐름을 주고받는 핀으로, 흰색 화살표 모양이며 보통 입력은 왼쪽, 출력은 오른쪽에 있습니다. 왼쪽 실행 핀으로 흐름이 들어오면 노드가 작업을 하고, 작업을 마치면 오른쪽 실행 핀으로 다음 노드에 흐름을 넘깁니다. 전기 스위치를 켜듯 "지금 이 노드를 실행하라"는 신호가 지나가는 통로라고 생각하면 됩니다.

데이터 핀(data pin)은 노드가 작업에 필요한 값을 받거나 작업의 결과를 내보내는 핀입니다. 데이터 핀은 정수, 문자열, 불리언처럼 값의 종류(타입)마다 색이 다르게 표시되고, 같은 타입끼리만 연결됩니다. 함수를 호출하는 노드라면 데이터 핀이 그 함수의 매개변수와 반환값에 해당합니다.

모든 노드가 두 핀을 다 가지는 것은 아닙니다. 이벤트 노드는 실행이 시작되는 곳이므로 실행 입력 핀이 없고 출력 핀만 있습니다. 반대로 변수 값을 읽는 Get 노드(Getter)나 순수 함수(pure function) 노드에는 실행 핀이 아예 없고 데이터 핀만 있습니다.


선: 실행 순서와 값의 흐름

선은 핀과 핀을 이어 노드 사이의 관계를 정합니다. 핀이 두 종류이듯 선도 두 종류입니다.

실행 선(execution wire)은 실행 핀끼리 이은 흰색 선으로, 노드가 어떤 순서로 실행될지 정합니다. A 노드의 출력 실행 핀을 B 노드의 입력 실행 핀에 이으면 "A를 실행한 뒤 B를 실행하라"는 뜻이 됩니다. 에디터에서 플레이하는 동안에는 실행이 지나간 실행 선이 잠시 밝게 강조되었다가 서서히 원래대로 돌아오므로, 어느 경로가 실제로 실행됐는지 볼 수 있습니다.

데이터 선(data wire)은 데이터 핀끼리 이은 선으로, 한 노드의 값을 다른 노드에 넘깁니다. "A 노드의 계산 결과를 B 노드의 입력으로 써라"는 뜻이며, 선의 색은 넘기는 값의 타입 색과 같습니다. 데이터 선은 언제 실행할지를 정하지 않는다는 점이 중요합니다. 실행 입력 핀이 있는 노드에 데이터 선을 연결해도, 실행 선이 그 노드까지 오지 않으면 노드는 실행되지 않습니다.

실행 핀이 없는 순수 노드는 그 값을 쓰는 노드가 실행될 때 평가됩니다. 공식 문서에 따르면 순수 함수는 연결된 노드마다 한 번씩 호출됩니다. 그래서 같은 순수 노드를 실행 노드 두 개에 이어 두면 계산도 두 번 일어나며, 무거운 계산이라면 결과를 변수에 한 번 저장해 쓰는 편이 낫습니다.


실행 연결과 값 연결을 따로 읽기

두 종류의 선이 함께 있는 작은 그래프를 따라가 보겠습니다. 어떤 액터에 설명을 위해 PlayerScore라는 정수 변수를 만들고 값을 20으로 두었다고 가정합니다. 이 변수는 이 예제를 위해 만든 것이며, 엔진이 모든 블루프린트에 자동으로 주는 점수가 아닙니다. 그래프에서는 PlayerScore의 Getter가 내놓은 정수를 문자열로 바꾼 뒤 Print String 노드의 In String 핀에 넣고, BeginPlay 이벤트의 실행 핀을 Print String의 실행 입력에 잇습니다.

실행 입력과 값 입력은 서로 다른 역할입니다

본문에서 만든 PlayerScore 정수 변수의 값 20을 선택한다. BeginPlay가 Print String을 실행할 때 Getter의 20을 문자열로 변환해 출력하는 값·실행 경계를 보여 준다. 데이터선만 남고 실행선을 제거한 사본은 출력되지 않는 별도 비교이다.

EXECUTION · VALUE DEPENDENCY

실행 순서와 값 의존성을 따로 읽습니다

BeginPlay는 Print String의 실행을 시작합니다. PlayerScore Getter는 출력할 값이 필요할 때 평가되며 실행 핀이 없습니다.

Print String으로 들어가는 두 연결BeginPlay의 실행 연결은 Print String을 실행한다. Get PlayerScore의 점선은 출력할 값을 공급한다. Getter에는 실행 핀이 없다.실행 순서값 입력Event BeginPlayPrint String실행할 때 값을 사용Get PlayerScore실행 핀 없음
Print String으로 들어가는 두 연결BeginPlay의 실행 연결은 Print String을 실행한다. Get PlayerScore의 점선은 출력할 값을 공급한다. Getter에는 실행 핀이 없다.실행 순서값 입력Event BeginPlayPrint String실행할 때 값을 사용Get PlayerScore실행 핀 없음

이 도식의 실선은 실행 순서, 점선은 값 의존성입니다. 정수에서 문자열로 바꾸는 변환 노드는 생략했습니다.

이 예의 조건

  • 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
  • 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
실행 진입

PlayerScore=20인 액터에서 BeginPlay의 실행 핀이 Print String에 도달한다.

  • 저장값: PlayerScore=20
  • 실행: BeginPlay → Print String
  • 데이터 핀은 출력할 값을 공급하지만 실행 입력이 필요한 Print String의 시작을 대신하지 않는다.
필요 값 평가

Print String이 입력값을 필요로 할 때 Getter의 정수 20을 문자열로 변환한다.

  • Getter: PlayerScore의 현재 값 20
  • In String: 문자열 "20"
  • Getter에는 실행 핀이 없으며 필요한 값이 평가된다. 정수→문자열 변환은 원 도표에서 생략된 값 전달이다.
출력

실행이 시작된 Print String이 입력 문자열 "20"을 출력한다.

  • 출력: 20
  • 저장값: PlayerScore=20 유지
  • 값선은 무엇을 출력할지, 실행선은 언제 출력할지 정한다. 실행선이 없고 다른 실행 이벤트도 없는 사본은 출력되지 않는다.

실행 입력과 값 입력은 서로 다른 역할입니다

본문에서 만든 PlayerScore 정수 변수의 값 20을 선택한다. BeginPlay가 Print String을 실행할 때 Getter의 20을 문자열로 변환해 출력하는 값·실행 경계를 보여 준다. 데이터선만 남고 실행선을 제거한 사본은 출력되지 않는 별도 비교이다.

EXECUTION · VALUE DEPENDENCY

실행 순서와 값 의존성을 따로 읽습니다

BeginPlay는 Print String의 실행을 시작합니다. PlayerScore Getter는 출력할 값이 필요할 때 평가되며 실행 핀이 없습니다.

Print String으로 들어가는 두 연결BeginPlay의 실행 연결은 Print String을 실행한다. Get PlayerScore의 점선은 출력할 값을 공급한다. Getter에는 실행 핀이 없다.실행 순서값 입력Event BeginPlayPrint String실행할 때 값을 사용Get PlayerScore실행 핀 없음
Print String으로 들어가는 두 연결BeginPlay의 실행 연결은 Print String을 실행한다. Get PlayerScore의 점선은 출력할 값을 공급한다. Getter에는 실행 핀이 없다.실행 순서값 입력Event BeginPlayPrint String실행할 때 값을 사용Get PlayerScore실행 핀 없음

이 도식의 실선은 실행 순서, 점선은 값 의존성입니다. 정수에서 문자열로 바꾸는 변환 노드는 생략했습니다.

이 예의 조건

  • 본문과 원 도표에 제시된 사례의 입력·조건을 사용합니다. 설명용 수치나 독립 비교 경로는 각 단계에 표시합니다.
  • 현재 상태·값과 전환 근거의 위치는 모든 단계에서 같습니다. 조건이 맞지 않거나 실행되지 않은 경로를 성공한 동작으로 해석하지 않습니다.
예의 값과 변화
관찰·상황값·보충 정보변화·이유
실행 진입

PlayerScore=20인 액터에서 BeginPlay의 실행 핀이 Print String에 도달한다.

  • 저장값: PlayerScore=20
  • 실행: BeginPlay → Print String
  • 데이터 핀은 출력할 값을 공급하지만 실행 입력이 필요한 Print String의 시작을 대신하지 않는다.
필요 값 평가

Print String이 입력값을 필요로 할 때 Getter의 정수 20을 문자열로 변환한다.

  • Getter: PlayerScore의 현재 값 20
  • In String: 문자열 "20"
  • Getter에는 실행 핀이 없으며 필요한 값이 평가된다. 정수→문자열 변환은 원 도표에서 생략된 값 전달이다.
출력

실행이 시작된 Print String이 입력 문자열 "20"을 출력한다.

  • 출력: 20
  • 저장값: PlayerScore=20 유지
  • 값선은 무엇을 출력할지, 실행선은 언제 출력할지 정한다. 실행선이 없고 다른 실행 이벤트도 없는 사본은 출력되지 않는다.

위 그림은 Print String으로 들어가는 두 연결을 나누어 보여 줍니다. 실선은 실행 순서로, Event BeginPlay가 Print String의 실행을 시작합니다. 점선은 값 의존성으로, Get PlayerScore가 출력할 값을 공급하며 이 Getter에는 실행 핀이 없습니다. 그림에서는 정수를 문자열로 바꾸는 변환 노드를 생략했지만, 실제 그래프에서는 정수 핀을 In String에 끌어다 놓으면 에디터가 변환 노드를 끼워 넣습니다.

단계 그림은 같은 그래프가 실행되는 순서를 세 단계로 나눕니다. 첫 단계에서 PlayerScore가 20인 액터의 BeginPlay가 실행되고, 실행 선을 따라 흐름이 Print String에 도착합니다. 둘째 단계에서 Print String이 In String의 값을 필요로 하므로, 그제야 Getter가 정수 20을 내놓고 그 값이 문자열 "20"으로 바뀝니다. 마지막 단계에서 실행이 시작된 Print String이 "20"을 화면에 출력합니다. 정리하면 값의 연결은 무엇을 출력할지를, 실행 연결은 언제 출력할지를 정합니다.

이 구분은 문제를 찾을 때 그대로 쓰입니다. 출력이 아예 나오지 않는다면 값이 아니라 실행 이벤트에서 출력 노드까지 흰 실행 선이 이어졌는지를 먼저 봅니다. 반대로 출력은 나오는데 값이 기대와 다르다면, 실행 선은 정상이므로 데이터 선으로 들어온 실제 입력값과 그 값을 가진 인스턴스가 맞는지를 조사합니다.


그래프를 읽는 순서

그래프를 읽을 때는 화면 왼쪽 위부터 훑지 말고 시작 노드부터 따라갑니다. 이벤트 노드에서 출발해 실행 선을 따라가면 어떤 노드가 어떤 순서로 실행되는지가 나오고, 각 실행 노드에서 데이터 핀을 거꾸로 따라가면 그 노드가 쓰는 값이 어디서 왔는지가 나옵니다. 실행 선이 닿지 않는 실행 노드는 아무리 그럴듯하게 연결되어 있어도 실행되지 않으므로, 이렇게 읽어야 실제로 일어나는 일과 그래프의 겉모습을 구분할 수 있습니다.

그래프를 만들 때도 다시 읽을 사람을 생각합니다. 변수와 함수에는 PlayerScore처럼 역할이 드러나는 이름을 붙이고, 여러 노드가 함께 하는 일은 주석(Comment)으로 묶어 설명을 남깁니다. 오류가 나면 실제로 문제를 일으킨 인스턴스를 디버그 오브젝트(Debug Object)로 골라, 마지막으로 도달한 실행 노드와 그 노드의 입력값을 나누어 확인합니다. 디버깅 도구는 블루프린트 디버깅 기초에서 자세히 다룹니다.


정리

  • 비주얼 스크립팅은 노드를 배치하고 선으로 이어 실행 순서와 데이터의 흐름을 나타내는 방식입니다.
  • 노드에는 실행 흐름을 주고받는 흰색 실행 핀과, 타입마다 색이 다른 데이터 핀이 있습니다. 이벤트에는 실행 입력이 없고, Getter와 순수 노드에는 실행 핀이 없습니다.
  • 실행 선은 언제 실행할지를, 데이터 선은 무엇을 쓸지를 정합니다. 데이터 선만 연결해서는 실행 노드가 실행되지 않습니다.
  • 순수 노드는 그 값을 쓰는 노드가 실행될 때, 연결된 노드마다 한 번씩 평가됩니다.
  • 그래프는 이벤트 노드에서 실행 선을 따라 읽고, 각 실행 노드에서 데이터 핀을 거꾸로 따라가 값의 출처를 찾습니다.

연습 문제

1. 실행 선 하나를 지웠을 때

같은 액터에서 PlayerScore Getter와 In String의 데이터 연결은 그대로 두고, BeginPlay에서 Print String으로 가는 실행 선만 지웠습니다. 다른 이벤트에서 Print String을 실행하지도 않습니다. 점수 20은 게임이 시작될 때 자동으로 출력될까요?

해설 보기

출력되지 않습니다. 출력할 값은 연결되어 있지만, Print String의 실행을 시작할 실행 선이 없기 때문입니다. 데이터 선은 무엇을 출력할지만 정할 뿐 언제 실행할지는 정하지 않습니다.

이럴 때는 점수를 다시 저장해 볼 필요가 없습니다. 실행 이벤트에서 출력 노드까지 흰 실행 선이 이어졌는지를 확인합니다. 반대로 실행 선이 있는데도 값이 기대와 다르다면, 그때 실제 입력값과 디버그 오브젝트로 고른 인스턴스를 조사합니다.

2. 바뀌지 않는 변수

BeginPlay에서 PlayerScore에 10을 더하려고, 덧셈 노드의 결과를 Set PlayerScore 노드의 값 입력에 연결했습니다. 그런데 BeginPlay의 실행 핀은 바로 Print String에 이어져 있고, Set PlayerScore의 실행 입력에는 아무 선도 연결하지 않았습니다. 출력되는 값은 20일까요, 30일까요?

해설 보기

20이 출력됩니다. Set PlayerScore는 변수를 바꾸는 실행 노드라서 실행 선이 들어와야 동작합니다. 값 입력에 덧셈 결과가 연결되어 있어도 실행 흐름이 이 노드를 지나지 않으므로 변수는 그대로 20입니다.

30을 출력하려면 BeginPlay의 실행 핀을 먼저 Set PlayerScore에 잇고, Set PlayerScore의 출력 실행 핀을 Print String에 이어야 합니다. 실행 선과 데이터 선을 혼동하면 이처럼 "연결은 했는데 값이 안 바뀌는" 버그가 생깁니다.

3. 같은 순수 노드를 두 곳에 연결하기

무작위 정수를 만드는 순수 노드 하나를 Print String 두 개의 In String에 함께 연결하고, 두 Print String을 실행 선으로 차례로 이었습니다. 두 줄에 같은 숫자가 출력된다고 기대해도 될까요?

해설 보기

기대하면 안 됩니다. 순수 함수는 연결된 노드마다 한 번씩 호출되므로, 첫 Print String이 실행될 때 한 번, 둘째 Print String이 실행될 때 또 한 번 무작위 정수를 만듭니다. 두 숫자는 우연히 같을 수는 있어도 같다는 보장이 없습니다.

같은 값을 두 곳에서 쓰려면 무작위 정수를 먼저 변수에 저장하는 실행 노드를 두고, 두 Print String이 그 변수를 읽게 합니다.

노드와 핀, 선의 종류는 언리얼 엔진 공식 문서의 노드 설명에서, 순수 함수의 호출 방식은 함수 문서에서 확인할 수 있습니다.

다음 글 블루프린트 에디터 인터페이스에서는 이 노드와 선을 실제로 배치하고 편집하는 블루프린트 에디터의 화면 구성을 살펴봅니다.