티스토리 뷰

기본 사용법은 아는 상태에서 보완 및 보강, 실제 제작이 막히는 문제를 해결하기 위해 정리중

정리된 내용은 초보자용이 아니라 제가 놓친 부분입니다

볼 때마다 정리중

www.youtube.com/watch?v=wX145eoLFSM&list=PL9FzW-m48fn2SlrW0KoLT4n5egNdX-W9a

1편

  • Input.is_action_pressed() 보다 Input.get_action_strength() 가 훨씬 나음.

2편

3편

  • move_and_colide() 의 패러미터에는 delta를 곱해야 함.
    move_and_slide() 는 delta를 곱하면 안 됨.
  • move_and_slide() 의 반환값은 새 속도. 제대로 미끄러지려면 미끄러진 뒤의 속도 벡터를 반영해야 함.
    아니면 벽에 부딛혔을 때 덜덜덜 떨릴 것임
    velocity = move_and_slide(velocity)

4편

  • Node (Node2D 말고)는 아직도 아리송한데 이미지나 노드를 Node의 자식으로 드래그 & 드랍 하면 가운데로 간다는 모양.
    x, y 좌표를 처리 못 하는 게 아닐까?
  • YSort 노드 사용시 transform 위치가 기준이므로 노드의 중심 배치에 주의할 것

"분기로 변경" 이 이상해서 "가지로 변경" 으로 weblate 쪽에 반영. 미리 말해두지만 저는 분명히 그냥 브랜치라고 했었습니다.

https://hosted.weblate.org/edit-glossaries/50409/?next=%2Fglossaries%2Fgodot-engine%2Fko%2F

5편

  • AnimationPlayer에 방향별로 다 집어넣음. 왜? 는 다음편에 AnimationTree 를 쓴다고. (이거 쓸 줄 모르는데 잘된듯)
  • onready var 알려줄 거 같았는데 진짜 알려주는데, 그 방식이 재미있음
    • 일단 func _ready(): 에서 멤버 설정하는 걸 보여주고
    • 더 쉬운 방법(쇼트컷) 이 있다 고 알려줌
  • "자식 노드를 스크립트에 접근하기"

6편

  • (따로 문서 읽어봄) anim_player 는 NodePath 타입임.
    • 그냥 pre-parsed 일 뿐이고, Node.get_node() 에서 쓰면 되는 모양.
    • 트리상의 다른 노드를 선택할 때 이걸 export 하면 되는 듯? (에디터에서 이럴 일 많음)
    • 인스턴스화된 노드가 아니라 새로 만들 때에는 PackedScene이었던가...
  • 뭐가 졸 많은데? 일단 State Machine 만 쓴다고.

  • Animation 하나가 State Machine 노드 하나고 상태 전이를 드래그 & 드랍으로 만들 수 있음 (신기하다)
  • 실제로는 StateMachine 이 아니라 BlendSpace2D 를 사용함.
    • 똑같이 상태 전이 가능하고 대신 입력받은 좌표에 따라 애니메이션을 골라주는 고마운 녀석.
    • 원래대로라면 본 기반 애니메이션에서 서로 다른 애니메이션을 섞는 데 썼겠지만 이번에는 혼합 모드를 이산으로 설정해놔서 2D 애니용으로 쓰임.
    • 네 꼭지에 각각의 애니메이션 추가. y 좌표 + 가 게임에서는 아래쪽이지만 에디터에서는 위쪽이라는 점만 유의하면 됨
  • 코드로 조작은 좀 성가신데...
    - animationTree.set("마우스 호버해서 알아낸 속성", input_vector) 랑
    animationTree.get("parameters/playback") 을 animationState로 보관해둔 뒤 travel("이름") 호출.
    왜 속성으로 안 나와있는지 좀 이해가 안 됨.
  • 자동 시작이 빠져있으면 게임이 켜져도 애니메이션이 하나도 재생되지 않음. 동영상에서 이거 놓쳤다가 "쟤는 되는데 왜 나는 안 되지" 하고있었음..
  • 왼쪽, 오른쪽을 우선하게 하는 데에는 트릭을 사용함. BlendSpace2D의 위, 아래 애니메이션을 1.1, -1.1 위치로 옮김.
    • 혼합 모드를 이산(끊긴 점)으로 하지 않으면 지랄발광하므로 주의 (한참 찾았네...)

어 근데 AnimationTree 가 이런거면 그냥 AnimationTreePlayer 쓰면 안 되는건가? 합쳐져있는 거처럼 생겼는데?
-> 추가해보니까 Deprecated 라고.

7편

  • 스프라이트의 반복 기능. 아무리 반복을 체크하고 reimport 해도 안 됐던 게 리전을 활성화하니 마법같이 됨!
    이거 예전부터 못 해서 진짜 애먹었는데...
    • 리전은 원래 여러 스프라이트 이미지를 뭉쳐서 하나로 만들어놓은 커다란 아틀라스의 일부분을 표시하기 위한 기능인데, (리전 사용이 체크된 채로) 스프라이트가 "반복"이 체크된 채로 import 되었다면 리전의 의향을 존중해서 반복되어 늘어나주는 모양. :respect_bmcoe:
    • 리전은 아래쪽의 텍스처 영역(리전인데 번역이...) 에서도 설정 가능
  • 오토타일이라는 게 생겼는데, 비트마스크로 인접하게 배치될 타일을 결정하는 방식. 문서를 읽어봐야할듯
    • 한 타일 이미지에 여러 종류의 타일셋을 넣을 수 있는 모양!
      • 2.x 의 수동 타일맵 굽기에서 장족의 발전을 이뤘네요 충돌 설정도 되고
    • 비트마스크 2x2 모드는 생각하는 그대로 동작하는데, 최소 비트 하나는 있어야 타일을 쓸 수 있음
      -> 2 *2 - 1 = 15개 셀
    • 3x3 (미니멀) 은 코너에 점이 있으면 코너 두 옆면 중 하나는 비트가 설정이 되어있어야 함.
      아무것도 연결 안 된 셀은 가운데에 마스크를 하나 설정해야 함
      -> 47개 셀
    • 3x3 은 256개 셀
    • "ignore" 비트는 Shift + click 이라는데 이게 뭔지는 모르것
      • 빨갛게 설정된 비트: 옆에 닿아있는 셀들이 전부 빨개야 함
      • 안 설정된 비트: 옆에 닿아있는 셀 중 최소 하나는 빨갛지 않아야 함
      • 무시된 비트: 위 규칙 다 무시함
        aha

8편

  • 아직 충돌 상자 넣는 게 되게 불편한데, 사각형을 꽉 채울 생각이라면 번거로워짐
    • 그래도 댓글에서 PageUp / PageDown 으로 현재 선택된 타일을 바꿀 수 있다는 걸 확인함
    • 이슈
  • 타일의 Z Order를 변경하면 트리 순서를 무시하고 글로벌로 반영됨.
    • z-order는 Node2D에도 있음. UI가 아닌 2D 노드에 모두 Z 인덱스가 있다는 소리.
    • CanvasLayer 및 이것의 CanvasTransforms 와는 다른 것임.  z-order를 변경하는 편이 차라리 성능이 더 나음
  • 그림자 캐스팅 (Occlusion) 도 있는데 이 튜토리얼에서는 다루지 않는다고.
  • 언덕 위에 있는지, 언덕 밑에 있는지에 따라서 충돌 영역 밖의 내용을 가리는 건 어려운듯? 이렇게 할거면 트리 구성을 잘 생각해봐야 할지도.
    • YSort 노드 말고 TileMap 에도 YSort 옵션이 있는데 이런다고 해결되지 않음. 검색해봤는데 타일맵이 자기 자식을 정렬한다고. 다수의 타일맵 개체를 쓰는 경우에는 문제가 될 듯. 그게 아니라 타일맵이 하나면...
    • 차라리 유효한 해결법은 RPG Maker의 모델을 상정해서 땅, 언덕 위, 물 타일셋 세 개로 나누고 플레이어를 그 셋 중 하나의 자식으로 두는 것도 방법이 아닐까?

9편

  • State machine을 간단한 enum 으로 넣기. GDScript 의 enum은 Dictionary의 syntatic sugar 라서 타입 취급이 안 되는 점이 불편 (닫힌 이슈)
  • AnimationTree의 Tree Root로 AnimationNodeStateMachine (리소스) 를 만들어 넣었었고 까맣게 잊고 있었음.
    • 공격이 끝난 뒤에 내부 State Machine의 enum 변수까지 바꾸기 위해 애니메이션 종료 시그널... 그런 거 아무리 찾아도 안 나옴.
      • 심지어 AnimationNodeStateMachinePlayback 에도 그런 건 업1따
      • 내부 트리 구성이 바뀔때의 이벤트가 있는데 대체 무슨 필요?
      • 가만 생각해보면 엔진 디자인하는 입장에서 보면 애니메이션 트리 자체가 블렌딩이 가능해야 하는데 시그널을 넣는다는 것 자체가 좀 껄끄러운 일이기 함.
    • 유효한 해결법은 각 애니메이션의 트랙에 스크립트 트랙을 넣어서 메서드를 호출하는 방법 뿐...

10편

  • YSort 자식으로 YSort가 올 수 있습니다. 같이 소팅됩니다. (충격)
  • 이번 영상에서는 시그널을 가르쳐주는데, yield가 있다는 걸 생각해냈습니다.
  • 파일 시스템 독에서 코드에 끌어넣으면 바로 그 경로가 코드로... 와...
  • get_tree() 로 root SceneTree 를 가져올 수 있는 건 알고 있었는데, 그걸 런타임 트리보기로 이해시키는 건 와 대단해
    • 그러면서 인스펙팅 하는 거까지 가르쳐줌. 기회를 놓치지 않는 heartbeast 씨
  • 나는 항상 self를 적는데, 그럴 필요가 없음. 만약 가르치게 된다면 둘 다 얘기해놔야지 나중에 질문이 안 들어온다...
  • 근데 왜 preload가 아니고 load()를 콜하죠?

11편

오늘은 원래 하던 프로젝트가 손에 없어서 편집기만 열어서 살펴보기만.

  • 이펙트는 별도 씬에 만드네요. 이유는 충돌 해제 코드를 짜기가 싫어서인듯. queue_free() 하면 끝나고 나중에 바꿀 수도 있으니까요.
  • HitBox, HurtBox 두 개의 충돌상자 전용 씬을 만듭니다. (인-터레스팅-)
    • 저는 하위 씬 편집 허용은 가급적이면 피하는 편인데 (원본 씬을 수정하면 어떻게 될 지 모름) 이 분 적극적으로 쓰시네요... 차라리 Area2D는 그대로 두고 CollisionShape2D만 따로 씬 하위에 넣는 게 낫지 않았을까요. 그럼 편집 허용을 할 필요는 없잖아요? 되나? 잘 되네요
  • 씬 트리의 쁠러스 옆에 있는 링크 버튼이 인스턴스 씬 추가였습니다. 고걸 몰랏내!
  • 검의 히트박스 Area2D를 Point2D 의 자식으로 옮기고, 검 휘두르는 애니메이션에 포함. (Rotation)
    • CollisionShape는 알다시피 컴파일 될 때 구워버리니까... 부모를 옮기는 건 맞는데 Area2D를 옮겼어도 괜찮았을 것.
  • 놀랍게도 충돌 여부 변경은 CollisionShape2D의 Disabled 프로퍼티를 애니메이션에 추가 (저거 굽는 거 아니었어?)
  • Collision Layer와 Mask 소개.
    • 속성에서 이름 지정이 가능한데 자꾸 까먹음. Layer -> 내 충돌상자, Mask -> 내가 검사할 충돌 대상. KinematicBody2D 같은 내장 Physics 엔진 기반 노드들도 영향 받음

개념도

CollisionObject (Area2D) -> CollisionShape2D (Editor only)

CollisionObject -> ShapeOwner (노드가 아님) -> Shape, Shape, Shape, ...
                    -> ShapeOwner (노드가 아님) -> Shape, Shape, Shape, ...

CollisionShape가 {ShapeOwner -> Shape} 쌍으로 변하는 듯? 그래서 disabled 같은 걸 조작하는 게 먹는 듯. 실제로는 CollisionObject에서 ShapeOwner를 key 삼아 조작해야 함.

충돌의 단위가 ShapeOwner 인 듯?
shape_owner_set_disabled ( int owner_id, bool disabled ) 같은 게 있으니

문서

https://docs.godotengine.org/en/latest/classes/class_collisionshape2d.html f

https://docs.godotengine.org/en/latest/classes/class_collisionobject2d.html#class-collisionobject2d-method-create-shape-owner

질답

https://godotengine.org/qa/62180/clarification-about-collisionobject2d

https://www.reddit.com/r/godot/comments/fi3erf/what_are_shape_owners_and_how_do_they_work/

충돌상자 코드로 런타임에 모양이나 크기 같은 거 조작 안 할거면 굳이 알 필요 없을듯.

12편

정리하는 걸 깜빡 잊음.

동영상과는 다르게 다른 영상에서 봤던 StateMachine을 구현... 하느라 정신이 팔렸고 덕분에 정리를 스킵했었음

  • GDScript 상의 클래스의 베이스 클래스는 무엇?
    • 별도로 명시하지 않으면 기본적으로 Reference 클래스임 (GC가 아니라는 거야 알고있었고)
      (이게 제일 궁금했었음)
    • Object를 상속하는 경우 메모리 관리를 직접 해야 함
    • Object -> Reference -> 기타등등

13편

박쥐 적과 공격 knockback

  • 인스턴스화된 씬에 스크립트를 붙이는 경우, 원본 씬에는 반영되지 않으므로 안심하고 붙여도 될 듯
    (스크립트를 상속해서 펼치는 거야 두말할 것도 없고)
  • 플레이어 히트박스에서 넉백 값을 가져옴. 감지는 적 히트박스(HurtBox)에서.
    • 이동하는 방향인 roll_vector를 쓴다는 게 특이점
    • 프로퍼티가 개체에 있는지 확인하는 방법
  • 내 프로젝트에서는 박쥐가 풀잎에 한 번 더 튕기는 현상이 있었는데 Monitoring, Monitored 쪽을 수정해야 하는 모양. 관련 버그도 있음
    github.com/godotengine/godot/issues/7644
    • Area2D는 같은 Layer에 있는 Monitorable도 Monitor 하는 것 같음.
    • 어차피 공격을 탐지하는 거니까, Layer는 필요없고 Mask만 있으면 됨 (충격)
      www.youtube.com/watch?v=UZu8NwlkXcU
  • 풀떼기 없애는 데 자꾸 나는 에러는 충돌 탐지중에 충돌을 비활성해서 나는 문제였던 모양.
    godotengine.org/qa/38401/does-cant-change-this-state-while-flushing-queries-error-mean
    • 수정은 시그널 연결하는 부분에서 지연(deferred) 체크하고 하는 김에 1회(oneshot)도 체크

14편

  • Stats 라는 별도의 노드를 만들어서 거기에 체력을 넣음.
    • setget
    • died 시그널.
    • 재사용 가능한 프로퍼티의 has-a 관계화 (노드화) 는 계속 생각중인 건데도 이렇게 간단하게 해버리는 걸 보니 너무 내가 과도했던 게 아닌가 싶기도...
  • 소드에 데미지를 주기 위해 소드 히트박스 (PlayerHitbox) 에 export(float) damage 를 함.
    • 충돌한 게 area 니까 area.damage 를 빼면 그만이었던 거시다...

15편

15편에서는 스크립트만 떼서 재사용을 하는데, 난 그건 됐고 다른 방안을 살펴봄.

  • option 1: 스크립트만 재사용 (하는 김에 connect(), preload 도 가르쳐줌)
    영상에 나옴
  • option 2: 같은 씬을 만들고 리소스만 갈아치우자
    • 여러 삽질을 해봤는데
      • class_name Effect를 정의하고 static method에서 인스턴스를 하는 간편 메소드
        -> (preload()나 Effect).instance() 를 Effect.gd에서 하는 순간 순환 참조가 되어버림
        • load()로 바꾸면 되는데 석연찮음
    • remove_and_skip() 은 내 자식을 죄다 부모로 옮기고 나를 없애므로 이펙트만 넣으려는 이 상황에는 매우 부적합함
    • 스프라이트의 오프셋을 바꿀 수 없는 치명적인 문제가 있음
      (SpriteFrame 리소스에는 오프셋이나 트랜스폼, 포지션이 없지롱)
  • option 3: 씬 상속 (해보니 제일 나음)
    • (씬 상속 방법은 설명하지 않음)
    • 위험요소는 씬 상속이 이해하기 어렵다는 건데,
      클래스 상속이 아닌 프로토타입 상속에 가깝다고 보면 될 듯. 이제 이해했으니 맘대로 써도 된당 :>
    • 스프라이트의 오프셋 문제가 여전히 있긴 한데, 해결 방법은 두 가지
      • Effect.tscn 자체가 AnimationSprite 노드이게 만들지 말고 다시 Node2D의 자식으로 만들던가
      • 자식으로 삽입할 때 global_position을 대뜸 할당하지 말던가 (바로 아래의 코드)

내 부모에 내 위치 기준으로 새 노드 삽입하기

func add_to_parent_of(target: Node2D):
	var parent = target.get_parent()
	if parent:
		parent.add_child(self)
		self.global_position = target.global_position + self.position
	else:
		self.queue_free()

물론 이렇게 하면 회전이 유지 안 될텐데, transform으로 어떻게 처리해봐야 할 텐데 그 쪽 개념을 잘 몰라서, 아니 헷갈리고 잘 몰라서. 해보니 아래 코드로 고치면 되는데, 이걸 이해하려면 선형대수의 매트릭스 선형 결합 쪽이라 3b1b 영상 하나고도엔진 글 하나를 읽어야 함. (역행렬까지 필요 없었네...)

func add_to_parent_of(target: Node2D):
	var parent = target.get_parent()
	if parent:
		parent.add_child(self)
		# 둘 다 됨
#		self.global_transform = self.global_transform * target.global_transform
		self.transform = target.transform * self.transform
	else:
		self.queue_free()

씬 상속

Effect.tscn

[gd_scene load_steps=2 format=2]

[ext_resource path="res://Effects/Effect.gd" type="Script" id=1]

[node name="Effect" type="AnimatedSprite"]
script = ExtResource( 1 )
test_var = 3

GrassEffect.tscn

  • [node name="GrassEffect"] 는 리소스 Effect.tscn 의 인스턴스임.
  • Effect.tscn 은 Effect 인스턴스를 직렬화한 씬 파일 리소스임.
  • 즉,
    Effect 인스턴스
    -> 인스턴스를 직렬화된 Effect.tscn
    -> 이걸 인스턴스화한 GrassEffect 인스턴스
    -> 이걸 직렬화한 GrassEffect.tscn 리소스
    라는 관계가 성립함.
  • 즉, 씬 상속은 루트 노드가 인스턴스화된 노드인 것과 동일하다는 말.
[gd_scene load_steps=9 format=2]
// 뭐 첫 줄은 그 리소스가 뭔지 아니겠습니까.
// 레퍼런스는 안 찾아봤지만 딱 보면 삘이 온다 아입니까

[ext_resource path="res://Effects/Effect.tscn" type="PackedScene" id=1]
[ext_resource path="res://Effects/GrassEffect.png" type="Texture" id=2]
// ext_resource는 뭐 외부 리소스겠죠

고유 리소스 생략

[node name="GrassEffect" instance=ExtResource( 1 )]
position = Vector2( 8, 8 )
frames = SubResource( 6 )

// 노드는 한참 아래에 적혀있더군요.
// 부모인 Effect.tscn에는 type 속성이 있었지만
// 자식에는 대신 instance가 있습니다.

 

 

최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함