Blender에서 작업하여 Collada로 export한 결과물을 Godot engine에서 import하여 사용해야할 경우, Bone과 Animation을 하지 않은 경우는 크게 문제가 되지 않으나, Bone을 심어서 Animation 작업을 한 경우에는 제대로 동작하지 않는 경우가 있다.(예를 들면 뼈와 살이 분리되서 움직임)

이러한 경우, Blender에서 Bone 작업시 배치를 다 하고 나서, Bone을 전부 다 선택하고 나서 상속(Set Parent to, Ctrl + P key)를 누른 후, With Automatic Weights를 선택한 다음, Animation 작업을 시작한다.

그리고, Pose 작업을 하고 나서 Key 삽입시(Insert Keyframe, I key)에 LocRotScale을 선택하여 준다.

이렇게 작업을 마친 후에 Blender에서 기본으로 제공하는 Collada를 이용하던, Better export dae를 이용하여 export하던 결과물은 godot engine에서 제대로 동작을 한다.

그리고 godot engine의 버그로 추정되는 것이 하나 있는데, 심은 bone 중 하나가 IDE에서는 보이질 않으나(맨마지막 bone으로 추정됨), 작업하는데는 문제가 없다.(사실 Inspector에서는 정상적으로 존재하는 것으로 나옴. View에서만 안보임)

# -*- coding: utf-8 -*-

import sys
import os
import io
import zipfile
import mmap

if __name__ == "__main__":
	with open("zip 파일"), "r+b") as zf:
		zip_file = zf.read()
	memory_map = mmap.mmap(-1, len(zip_file))
	memory_map.write(zip_file)
	zip_file_data = zipfile.ZipFile(memory_map)

	"""
	여기에 zip 파일을 처리할 코드를
	작성한다.
	
	"""
	
	zip_file_data.close()
	memory_map.close()

<참고>
https://docs.python.org/3.6/library/mmap.html
http://barambunda.tistory.com/12
https://docs.python.org/3.6/library/zipfile.html

1.기본

class Test:
    __name = "John"

    def get_name(self):
        return self.__name
    
    def set_name(self, value):
        self.__name = value

if __name__ == "__main__":
    t = Test()
    print(t.get_name())
    t.set_name("David")
    print(t.get_name())

 

2. property 사용

class Test:
    __name = "John"

    def get_name(self):
        return self.__name
    
    def set_name(self, value):
        self.__name = value

    name = property(get_name, set_name)

if __name__ == "__main__":
    t = Test()
    print(t.name)
    t.name = "David"
    print(t.name)

 

3. @property(데코레이터:Decorator) 사용

class Test:
    __name = "John"

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, value):
        self.__name = value

if __name__ == "__main__":
    t = Test()
    print(t.name)
    t.name = "David"
    print(t.name)

 

4. 여러 속성에 대해서 동일하게 처리해야할 경우, @property를 사용하면 코드가 지저분해지므로, Descriptor를 하면 코드가 깔끔하게 정리됨.

class T:
    __name = ""

    def __get__(self, instance, owner):
        return getattr(instance, "__name")

    def __set__(self, instance, value):
        setattr(instance, "__name", value)

class Test:
    name = T()

if __name__ == "__main__":
    t = Test()
    t1 = Test()
    t2 = Test()
    t.name = "David"
    t1.age = 40
    t2.address = "Korea"
    print(t.name, t1.age, t2.address)

 

<참고>
https://docs.python.org/3/howto/descriptor.html

Python은 접근제어를 하기 위해서 키워드를 제공하지 않는 대신에 명명법(Naming)에 의한 방법으로 설정 가능.


<Public>

    • _(Single underscore)를 접두사로 사용하지 않음.(ex: name)
    • Python의 모든 속성 및 메소드는 기본적으로 public.
    • 외부 클래스에서 접근 가능.

<Protected>

    • _를 접두사로 사용. (ex: _name)
    • 해당 및 하위 클래스에서만 접근 가능.

<Private>

    • __(Double underscore)를 접두사로 사용.(ex: __name)
    • 해당 클래스 이외에는 접근 불가능.(단, Property Get, Set을 이용하면 접근가능)

※Protected와 Private에서 _를 접미사로 사용할 경우, 한개는 허용하지만, 두개 이상이면 Public으로 간주함.

    • _name_은 Protected, _name__은 Public으로 간주.


extends Spatial

var camera_distance = 2

func _ready():
	set_process(true)

	$Spatial/Spatial/Camera.translation = camera_distance * Vector3(0, 5, 5)
	$Spatial/Spatial/Camera.rotation_degrees = Vector3(-35, 0, 0)
	
func _process(delta):
	# Left & Right Rotation
	if Input.is_key_pressed(KEY_Q):
		$Spatial.rotate_y(5 * delta)
	elif Input.is_key_pressed(KEY_E):
		$Spatial.rotate_y(-5 * delta)

	# Up & Down Rotation
	if Input.is_key_pressed(KEY_W):
		$Spatial/Spatial.rotate_x(5 * delta)
	elif Input.is_key_pressed(KEY_S):
		$Spatial/Spatial.rotate_x(-5 * delta)

	# Zoomin & Zoomout
	if Input.is_key_pressed(KEY_EQUAL):
		$Spatial.set_scale($Spatial.get_scale() - Vector3(0.8, 0.8, 0.8) * delta)
	elif Input.is_key_pressed(KEY_MINUS):
		$Spatial.set_scale($Spatial.get_scale() + Vector3(0.8, 0.8, 0.8) * delta)

 

<참고>
http://www.bitoutsidethebox.com/godot-tutorial-5-2-axis-gimbal-camera-for-3d-games/

extends Node
...
signal my_signal


func _ready():
    connect("my_signal", self, "signal_handler")
    ...
    var otherNode = get_node("someNode")
    otherNode.connect("my_signal", self, "signal_handler")

func SomeFunc():
    ...
    # causes self.signal_handler() to be called
    emit_signal("my_signal")
    ...

func signal_handler():
    ...

 

[참고] https://godotengine.org/qa/3218/how-to-create-a-custom-signal-in-gdscript

Scene 편집 도구를 이용해도 되지만, GD Script만으로 코딩을 하고 싶을 경우(?)에는 아래 예제를 참고하여 작성하면 된다.

extends Node

func _ready():
	
	var timer = Timer.new()
	add_child(timer)

	timer.connect("timeout", self, "_on_timeout")

	timer.set_wait_time(10)
	timer.start()
	
func _on_timeout():
	
	print("Time out!")

 

[참고] http://docs.godotengine.org/en/3.0/classes/class_timer.html

RigidBody2D에서 총알(Bullet)을 발사하여 벽(Block)에 충돌하였을 경우, 충돌한 객체의 정보를 얻어내기 위해서는 func _ready() 안에 다음 code를 추가한다.

func _ready():
    set_contact_monitor(true)
    set_max_contacts_reported(5) # 0보다 큰 정수를 지정해주면 된다.

그다음 편집기에서 signals에서 함수를 연결하면 되지만, 직접 Gdscript에서 code를 추가하여보자. 그렇기 위해선 _ready() 함수 루틴에 다음과 같이 signal을 연결하는 code를 추가한다.

func _ready():
    set_contact_monitor(true)
    set_max_contacts_reported(5)
    connect("body_entered", self, "collision_detected")

그리고 collision_detected() 함수를 작성한다.

func collision_detected(obj):
    print(self.get_name(), " is colliding with ", obj.get_name())

더 자세한 정보를 얻고 싶을때는 get_colliding_bodies()를 이용하면 된다.

 

<참고>
 https://www.reddit.com/r/godot/comments/3ofhwj/how_can_i_use_body_enter_function/

+ Recent posts