OSWorlds - 게임 블로그 📌 게임 프로그래밍 📌 게임소식 🔑 로그인 📝 회원가입

언리얼 엔진 Accessed None 오류 원인과 해결 방법 총정리

언리얼 엔진에서 블루프린트 작업을 하다 보면 한 번쯤 반드시 만나게 되는 오류가 있습니다. 바로 **Blueprint Runtime Error: Accessed None**입니다.

처음 이 오류를 보면 블루프린트 자체가 잘못됐거나 엔진에 문제가 생긴 것처럼 느껴질 수 있습니다. 하지만 대부분은 생각보다 단순합니다. 사용하려는 Actor, Component, Widget 등의 Object Reference가 비어 있는 상태에서 해당 객체의 변수나 함수를 호출했기 때문​입니다.

저 역시 캐릭터 전투 시스템이나 UI, 적 AI처럼 여러 블루프린트를 연결하다 보면 Accessed None 오류를 자주 만나게 됩니다. 이번 글에서는 Accessed None이 정확히 무엇인지부터 오류가 발생하는 대표적인 원인, 오류 위치를 빠르게 찾는 방법, 그리고 Is Valid를 이용한 안전한 처리 방법까지 정리해보겠습니다.

💡 한 줄 정답 — Accessed None은 블루프린트에서 사용하려는 Object Reference가 None인 상태에서 변수나 함수에 접근했을 때 발생하는 런타임 오류입니다. 단순히 Is Valid를 붙이는 것보다 Reference가 언제 생성되고 어디에서 저장되며 언제 삭제되는지 확인하는 것이 근본적인 해결 방법입니다.

목차


Accessed None 오류란?

언리얼 엔진의 Blueprint 변수는 숫자나 Boolean 값뿐 아니라 Actor, Object, Component 등의 Reference도 저장할 수 있습니다. Epic Games 공식 문서에서도 Blueprint Variable은 월드에 존재하는 Object 또는 Actor에 대한 Reference를 보관할 수 있다고 설명하고 있습니다.

예를 들어 다음과 같은 변수가 있다고 가정해보겠습니다.

TargetEnemy
Type : BP_EnemyBase Object Reference

정상적인 상황이라면 TargetEnemy에는 실제 월드에 존재하는 적 캐릭터가 들어 있어야 합니다.

TargetEnemy
     ↓
BP_EnemyBase_12
     ↓
Get Health

하지만 TargetEnemy에 아무것도 들어 있지 않은 상태라면 다음과 같습니다.

TargetEnemy = None

이 상태에서

TargetEnemy → Get Health

또는

TargetEnemy → Take Damage

같은 함수를 실행하면 언리얼은 접근해야 할 객체를 찾을 수 없습니다.

이때 발생하는 것이 바로 Accessed None입니다.

쉽게 표현하면 다음과 같습니다.

"적의 체력을 가져와."

→ 어떤 적?

"TargetEnemy."

→ TargetEnemy가 비어 있는데?

이것이 Accessed None의 핵심입니다.

[언리얼 엔진 Accessed None 오류가 발생하는 Object Reference 구조]


Accessed None이 발생하는 대표적인 원인

Accessed None은 다양한 상황에서 발생하지만 실제 개발을 해보면 대부분 몇 가지 패턴으로 압축됩니다.

원인대표적인 상황
Reference를 저장하지 않음Cast 결과를 변수에 저장하지 않음
Object가 아직 생성되지 않음Widget 생성 전 접근
Object가 이미 삭제됨Destroy Actor 이후 다시 사용
BeginPlay 실행 순서 문제A가 B보다 먼저 실행
잘못된 Actor 참조원하는 적이 아닌 다른 Actor
Spawn 실패Spawn 결과가 None
배열 값이 없음비어 있는 배열의 Actor Reference
Component Reference 문제Component가 특정 Blueprint에 없음
Cast 실패Cast Failed 이후에도 로직을 계속 실행

특히 초보자에게 많이 발생하는 상황이 Reference 변수를 만들어 놓고 실제 값을 넣지 않은 경우입니다.

예를 들어

EnemyRef

라는 BP_EnemyBase Object Reference 변수를 만들었다고 해서 언리얼이 자동으로 적을 찾아주는 것은 아닙니다.

반드시

Overlap
 ↓
Other Actor
 ↓
Cast To BP_EnemyBase
 ↓
Set EnemyRef

처럼 실제 객체를 저장해야 합니다.

Epic의 Blueprint Communication 문서에서도 특정 Actor와 직접 통신하려면 대상이 되는 Actor Reference가 필요하다고 설명하고 있습니다.


오류가 발생한 블루프린트 위치 찾기

Accessed None 오류가 발생했다면 무작정 모든 Reference에 Is Valid를 붙이는 것은 추천하지 않습니다.

먼저 어디에서 오류가 발생했는지 찾는 것이 가장 중요합니다.

게임을 실행했을 때 Output Log 또는 Message Log에 보통 다음과 비슷한 메시지가 나타납니다.

Blueprint Runtime Error:
"Accessed None trying to read property EnemyRef"

Node: Apply Damage
Graph: EventGraph
Function: Execute Ubergraph BP MainC1
Blueprint: BP_MainC1

이 오류 메시지는 상당히 많은 정보를 제공합니다.

특히 확인해야 할 것은 다음 네 가지입니다.

항목의미
Accessed None trying to read property문제가 발생한 변수
Node오류가 발생한 노드
Graph해당 그래프
Blueprint문제가 발생한 Blueprint

예를 들어

Accessed None trying to read property TargetEnemy

라고 나온다면 가장 먼저 TargetEnemy가 어디에서 Set되는지 확인하면 됩니다.

제가 Accessed None 오류를 찾을 때는 보통 다음 순서로 확인합니다.

1. 오류 메시지 확인
        ↓
2. 문제가 발생한 Reference 변수 확인
        ↓
3. Find References
        ↓
4. Set되는 위치 검색
        ↓
5. Set 이전에 Get이 실행되는지 확인

Blueprint 변수에서 Find References를 사용하면 대규모 블루프린트에서도 상당히 빠르게 원인을 추적할 수 있습니다.


Is Valid 노드로 Accessed None 방지하기

Accessed None 해결 방법을 검색하면 가장 많이 볼 수 있는 것이 Is Valid 노드입니다.

Epic Games의 Unreal Engine 5.8 문서에 따르면 Is Valid는 해당 Object가 사용 가능한 객체인지, 즉 null이 아니며 삭제 대기 상태가 아닌지 확인합니다.

기존 로직이 다음과 같다고 해보겠습니다.

EnemyRef
   ↓
Get Health
   ↓
Apply Damage

이를 다음과 같이 변경할 수 있습니다.

EnemyRef
   ↓
Is Valid?
 ┌─────────────┐
Valid       Is Not Valid
 ↓               ↓
Damage         종료

이렇게 하면 EnemyRef가 None일 때 뒤쪽 함수가 실행되지 않으므로 Accessed None을 막을 수 있습니다.

하지만 Is Valid만 붙이면 해결일까?

여기에서 중요한 부분이 있습니다.

Is Valid → False → 아무것도 안 함

으로 만들어 놓으면 오류 메시지만 사라지고 실제 문제는 그대로 남아 있을 수도 있습니다.

예를 들어 EnemyRef가 반드시 존재해야 하는 시스템인데 계속 Invalid가 발생한다면 문제는 Is Valid가 아닙니다.

다음을 찾아야 합니다.

왜 EnemyRef가 저장되지 않았지?

따라서 저는 Is Valid를 다음 두 용도로 나누는 것을 추천합니다.

Object가 없어도 정상
→ Is Valid로 예외 처리

Object가 반드시 있어야 함
→ Reference 생성 및 저장 로직부터 확인

[언리얼 엔진 Is Valid 해 구조]

Cast 성공 후 Reference 저장하기

Accessed None이 많이 발생하는 또 하나의 이유가 Cast와 Reference의 관계를 제대로 이해하지 못했기 때문입니다.

예를 들어 플레이어가 적과 충돌했을 때 적을 저장한다고 해보겠습니다.

On Component Begin Overlap
            ↓
       Other Actor
            ↓
   Cast To BP_EnemyBase
            ↓
      As BP Enemy Base
            ↓
       Set EnemyRef

이후에는

EnemyRef → Get Health
EnemyRef → Play Hit Animation
EnemyRef → Apply Damage

처럼 사용할 수 있습니다.

Epic 공식 문서에서도 Cast를 사용하려면 먼저 대상이 되는 Actor Reference가 필요하며 Cast가 성공한 경우 해당 클래스가 가진 기능에 접근할 수 있다고 설명합니다.

반대로 Cast Failed가 발생했는데 해당 Reference를 사용할 것으로 예상하고 뒤쪽 로직이 계속 진행되면 문제가 발생할 수 있습니다.

따라서 중요한 것은

Cast 성공 = Reference 획득 가능

이라는 구조입니다.

[언리얼 엔진 Cast 결과를 Object Reference 변수에 저장하는 방법]


Create Widget에서 자주 발생하는 Accessed None

UMG 작업에서도 Accessed None은 정말 많이 발생합니다.

예를 들어 Pause Menu를 만든다고 해보겠습니다.

정상적인 구조는 다음과 같습니다.

Create Widget
WB_PauseMenu
       ↓
Return Value
       ↓
Set PauseMenuRef
       ↓
Add To Viewport

이후

PauseMenuRef
      ↓
Set Visibility

를 실행해야 합니다.

그런데 PauseMenuRef를 저장하지 않고 다른 이벤트에서 바로 사용하면

PauseMenuRef = None

이기 때문에 Accessed None이 발생할 수 있습니다.

특히 다음 구조는 주의해야 합니다.

키 입력
 ↓
Create Widget
 ↓
Add To Viewport

키를 누를 때마다 Widget을 새로 생성하면 같은 Widget이 여러 개 만들어질 수도 있습니다.

일반적인 메뉴라면 차라리

BeginPlay
 ↓
Create Widget
 ↓
Set PauseMenuRef

그리고 사용할 때

PauseMenuRef
 ↓
Is Valid
 ↓
Set Visibility

처럼 Reference를 관리하는 편이 구조를 이해하기 쉽습니다.


Destroyed Actor를 참조할 때 발생하는 문제

처음에는 정상적으로 작동하다가 특정 순간부터 Accessed None이 발생한다면 Actor가 Destroy되었는지도 확인해야 합니다.

예를 들어 적 캐릭터를 저장했다고 가정해보겠습니다.

EnemyRef = BP_Enemy_01

적이 죽으면서

Destroy Actor

가 실행됩니다.

그런데 Player Blueprint에는 여전히 기존 EnemyRef를 사용하는 로직이 남아 있을 수 있습니다.

Enemy 죽음
 ↓
Destroy Actor

그 이후

EnemyRef
 ↓
Get Health

이런 상황에서도 유효하지 않은 Reference 접근 문제가 발생할 수 있습니다.

따라서 적이 사라질 수 있는 시스템이라면

Is Valid EnemyRef

검사가 특히 중요합니다.

또는 적이 죽는 순간

Set EnemyRef = None

으로 명시적으로 Reference를 초기화하고 타깃 재탐색 로직을 실행하는 방법도 사용할 수 있습니다.


BeginPlay 실행 순서 문제

조금 복잡한 프로젝트에서 의외로 많이 발생하는 문제가 초기화 타이밍입니다.

예를 들어 Player Blueprint와 Combat Component가 있다고 해보겠습니다.

Player에서

BeginPlay
 ↓
CombatComponent → StartCombat

을 실행합니다.

그런데 CombatComponent 내부에서 필요한

TargetActor

가 아직 초기화되지 않았다면 문제가 발생합니다.

즉,

A Blueprint 초기화
 ↓
B Blueprint 초기화

라고 개발자가 생각했지만 실제 로직에서는 B에서 필요한 Reference가 만들어지기 전에 접근하는 상황입니다.

이런 오류를 Delay로 해결하는 경우도 있습니다.

BeginPlay
 ↓
Delay 0.2
 ↓
실행

당장은 작동할 수도 있습니다.

하지만 Delay는 근본적인 해결 방법이 아닙니다.

가능하다면

객체 생성
 ↓
Reference 저장
 ↓
초기화 함수 호출
 ↓
게임 로직 시작

처럼 초기화 순서를 명확하게 만드는 것이 좋습니다.


Accessed None을 줄이는 블루프린트 설계 방법

프로젝트가 커질수록 Accessed None을 하나씩 막는 것보다 처음부터 Reference 관리 방식을 정리하는 것이 중요합니다.

1. Reference 변수 이름을 명확하게 만든다

좋지 않은 예:

Enemy
Object
Target
Temp

추천:

CurrentTargetEnemy
PauseMenuRef
CombatComponentRef
PlayerCharacterRef
CurrentWeaponRef

변수 이름만 봐도 어떤 객체인지 알 수 있어야 합니다.

2. Reference를 어디에서 Set하는지 명확하게 만든다

예를 들어

CurrentTargetEnemy

가 있다면 해당 변수의 Set 위치가 프로젝트 전체에 10개씩 존재하는 구조는 디버깅하기 어렵습니다.

가능하면 Reference 관리 지점을 제한하는 것이 좋습니다.

3. 항상 존재하지 않는 객체는 Is Valid를 사용한다

예를 들어 타깃 시스템이라면 적이 없는 순간이 정상적으로 발생합니다.

CurrentTarget
 ↓
Is Valid

검사가 필요합니다.

4. Blueprint 간 통신 방법을 목적에 맞게 사용한다

무조건 Cast만 사용하는 것도 좋은 구조는 아닙니다.

Epic에서는 Blueprint/Actor 통신 방법으로 Direct Communication, Casting, Interface, Event Dispatcher 등을 제공하고 있습니다. 각각 사용하는 목적이 다릅니다.

방식사용하기 좋은 상황
Direct Reference특정 Actor 하나를 직접 제어
CastObject가 특정 Class인지 확인
Blueprint Interface서로 다른 Actor에 같은 명령 전달
Event Dispatcher하나의 이벤트를 여러 객체에 알림

프로젝트가 커질수록 무분별하게 서로의 Reference를 가지고 있는 구조보다 목적에 따라 통신 구조를 나누는 것이 Accessed None뿐 아니라 유지보수 측면에서도 유리합니다.


자주 하는 실수

Reference 변수를 만들었으니 자동으로 값이 들어간다고 생각하는 경우

PlayerRef : BP_Player Object Reference

변수를 만들었다고 해서 Player가 자동으로 들어가는 것이 아닙니다.

반드시

Get Player Character
 ↓
Cast
 ↓
Set PlayerRef

등의 초기화 과정이 필요합니다.

Cast 노드만 있으면 Reference 문제가 해결된다고 생각하는 경우

Cast는 객체를 생성하는 기능이 아닙니다.

기존에 존재하는 객체 Reference가 특정 클래스인지 확인하는 과정에 가깝습니다.

따라서 Cast의 Object 입력 자체가 올바르지 않으면 원하는 결과를 얻을 수 없습니다. Epic 역시 Blueprint Casting은 대상 Actor Reference를 필요로 한다고 설명합니다.

모든 곳에 Is Valid를 붙이는 경우

Is Valid
Is Valid
Is Valid
Is Valid

이렇게 만들면 오류는 줄어들 수 있지만 왜 Reference가 None이 됐는지 파악하기 어려워집니다.

Is Valid는 안전장치이지 Reference 초기화를 대신하는 노드가 아닙니다.

Delay로 해결하는 경우

BeginPlay
 ↓
Delay
 ↓
Reference 사용

Delay 뒤에서 우연히 객체 생성이 완료돼 정상 작동할 수 있지만 PC 성능, 레벨 로딩 구조, 네트워크 환경 등에 따라 다시 문제가 발생할 가능성이 있습니다.

초기화 순서를 직접 관리하는 것이 더 좋습니다.


Accessed None 오류가 발생했을 때 확인할 체크리스트

Accessed None이 발생하면 아래 순서만 기억해도 대부분의 문제를 빠르게 찾을 수 있습니다.

Accessed None 발생
       ↓
Output Log 확인
       ↓
어떤 Property가 None인지 확인
       ↓
해당 변수 Find References
       ↓
Reference가 Set됐는지 확인
       ↓
Set보다 Get이 먼저 실행되는지 확인
       ↓
Actor가 Destroy됐는지 확인
       ↓
Cast가 실패했는지 확인
       ↓
필요하면 Is Valid 추가

특히 가장 중요한 질문은 이것입니다.

“이 Object Reference에는 누가, 언제, 어떤 객체를 넣어주는가?”

이 질문에 바로 답할 수 없다면 Reference 구조부터 확인해보는 것이 좋습니다.


마무리

언리얼 엔진의 Accessed None은 처음 접하면 상당히 어려운 오류처럼 보이지만 원리는 단순합니다.

존재하지 않거나 아직 연결되지 않은 Object Reference를 사용하려고 했다는 뜻입니다.

따라서 Accessed None이 발생했다면 무조건 Is Valid부터 추가하기보다는 먼저

Reference 생성
 ↓
Reference 저장
 ↓
Reference 사용
 ↓
Reference 삭제

이 과정이 올바르게 연결되어 있는지 확인하는 것이 좋습니다.

특히 캐릭터 전투 시스템, 적 AI, Widget UI, Skill System처럼 Blueprint끼리 서로 연결하는 시스템이 많아질수록 Reference 관리가 중요해집니다.

Accessed None을 제대로 이해하기 시작하면 단순히 이 오류 하나를 해결하는 데서 끝나는 것이 아니라 Blueprint의 Object Reference, Cast, Widget 생성, Actor 생명주기와 Blueprint 간 통신 구조까지 자연스럽게 이해할 수 있게 됩니다.


참고 사이트

이번 글은 Unreal Engine 5.8 기준 Epic Games 공식 문서를 우선 참고했습니다.

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

위로 스크롤