1. _physics_process()함수 안에 lerp()함수의 결과값을 RigidBody에 바로 적용시키지 말아야 한다. 적용시에 Snake, Frame drop이 일어나며, 심한 경우에는 Jittering까지 일어난다.

2. 실시간으로 lerp()함수의 결과값을 구하여 RigidBody에 적용하여 물리적 특성을 변경하고자 할 경우, _physics_process()함수 안에서 lerp()함수를 사용하여 결과값을 얻은 후에 _integrate_forces()함수 안에서 적용시켜야 한다.

1. 축(Axis)

X축은 빨간색(좌/우), Y축은 녹색(위/아래) 그리고 Z축은 파란색(앞/뒤)

 

2. 오일러각(Euler Angles)

Gimbal lock 문제가 있슴.

 

3. Transform

Local 변환 : transform

World 변환 : global_transform

 

4. Basis

transform.basis = Vector3(transform.basis.x, transform.basis.y, transform.basis.z)

var basis = Basis()
# Contains the following default values:
basis.x = Vector3(1, 0, 0) # Vector pointing along the X axis
basis.y = Vector3(0, 1, 0) # Vector pointing along the Y axis
basis.z = Vector3(0, 0, 1) # Vector pointing along the Z axis

 

5. 변환하기

x축 기준으로 180(PI)도 회전

# Rotate the transform about the X axis
transform.basis = Basis(Vector3(1, 0, 0), PI) * transform.basis
# shortened
transform.basis = transform.basis.rotated(Vector3(1, 0, 0), PI)

Spatial 노드를 회전할 경우

# Rotate the transform in X axis
rotate(Vector3(1, 0, 0), PI)
# shortened
rotate_x(PI)

Object의 Space(World)를 회전

# Rotate locally
rotate_object_local(Vector3(1, 0, 0), PI)

 

 

6. 직교 정규화

연속적으로 변환을 행한 경우, 부동 소수점으로 인하여 오차가 발생함. 이를 보정하기 위해 직교 정규화를 함.(프레임당 한번만)

transform = transform.orthonormalized()

주의할 점은 스케일(Scale)을 조정해야 할 경우, 하위 노드(예:MeshInstance)의 스케일을 조정하는 것을 권장하며, 직교 정규화를 한 후에 적용을 해야함.

transform = transform.orthonormalized()
transform = transform.scaled(scale)

 

7. 쿼터니언 보간

# Convert basis to quaternion, keep in mind scale is lost
var a = Quat(transform.basis)
var b = Quat(transform2.basis)
# Interpolate using spherical-linear interpolation (SLERP).
var c = a.slerp(b,0.5) # find halfway point between a and b
# Apply back
transform.basis = Basis(c)

 

<참고>
http://docs.godotengine.org/en/stable/tutorials/3d/using_transforms.html#problems-of-euler-angles

Area2D

  • 감지(detection)와 영향(influence) 기능 제공
  • Area2D에 오브젝트가 겹치고 들어오고, 나가는 때 signal 표현 가능
  • Area2D를 사용한 Scene에 정의된 중력이나 댐핑(damping) 같은 물리속성을 무시할 수 있다.(물리 속성을 재정의 가능)
  • 마우스 및 터치 스크린 입력도 가능

 

StaticBody2D

  • 고정된 Body.(주로 고정되거나 움직이는 Platform, 컨베이어 벨트, 벽 및 기타 장애물에 쓰임)
  • 충돌 감지는 하지만 충돌 이후의 물리적인 운동을 하지 않는다. 그러나 충돌한 Body에게는 이동이나 회전을 부여해 줄 수 있다.(관련 특성:constant_linear_velocity, constant_angular_velocity)

 

RigidBody2D

  • 다음과 같은 4가지 모드가 제공된다.
    1. Rigid - 기본모드. 외력에 의한 물리적인 반응(다른 Body와의 충돌이나 임의로 힘을 가한 경우)을 한다.
    2. Static - StaticBody2D와 같고 움직이지 않음.
    3. Character - Rigid와 비슷하지만, 회전은 할 수 없다.(아마 외력에 의한 회전이 안된다는 의미인 듯)
    4. Kinematic - KinematicBody2D처럼 물리적인 반응을 하며, 이동은 직접 코드를 작성해야 함.
  • position, linear_velocity 및 기타 다른 물리적 특성을 변경하면, 정상적으로 동작하지 않을 수 있다.(직접 제어를 하지 말아야 함)
  • 물리적인 특성을 변경해야 하는 경우가 생긴다면, _physics_process() 대신에 _integrate_forces()를 이용하면 된다.
  • RigidBody가 sleeping 상태가 되면 _integrate_forces() 함수는 호출되지 않는다.(can_sleep을 비활성화 시키거나, 충돌이 일어났을때만 호출함. 대신 이렇게 하면 성능 저하가 생길 수 있다고 매뉴얼에 써 있다.)
  • Scene 안에 RigidBody가 많으면 많을 수록 필요한 메모리가 늘어난다. 그래서 Godot에서는 contact_reported가 0으로 설정(추적 안함)되어 있다. 추적을 하려면 0대신 다른 값으로 설정한다.

 

KinematicBody2D

  • 다른 Body와 충돌만 감지. 중력이나 마찰 같은 물리 특성에 영향을 받지 않는다. 이부분은 직접 코드로 구현해야 한다.
  • move_and_collide()나 move_and_slide()를 이용해야지 직접 position을 건드리면 안된다.
  • 충돌이 감지되면 즉시 멈추므로, 충돌 후 반응은 직접 코드로 구현해야 한다.
  • move_and_collide()와 move_and_slide()는 _physics_process() 안에서 사용할 수 있고, move_and_slide() 함수에 벡터를 넣을 때, delta(Timestep)를 곱하지 않아야 한다.(move_and_slide()함수는 자동으로 Timestep를 적용해서 계산함)

 

<참고>
http://docs.godotengine.org/en/3.0/tutorials/physics/physics_introduction.html

Unity 혹은 그외에 다른 엔진에서 LerpAngle() 함수가 있다. 이 함수는 선형보간함수인 Lerp() 함수에 각도 A에서 각도 B로 회전을 할 경우, [0, π] 범위내의 회전각으로 각도 B에 도달할 수 있는 기능이 추가된 함수이다.

이 함수는 2D나 3D에서 매우 자주 쓰인다(예:캐릭터의 회전). 하지만 아쉽게도 Godot Engine(3.0.4 기준)에서는 lerp() 함수는 지원하지만 Unity의 LearAngle() 같은 함수는 아직 지원하지 않는다.

func lerp_angle(from_angle, to_angle, weight_value):
	if abs(from_angle - to_angle) >= PI: 
		if from_angle > to_angle:
			to_angle += 2 * PI
		else:
			from_angle += 2 * PI
	return lerp(from_angle, to_angle, weight_value)

<참고>
https://godotengine.org/qa/28776/rotate-kinematicbody2d-based-mouse-position-varying-rate

1. 2.x버전의 _fixed_process() 함수가 3.x버전부터는 _physics_process() 함수로 변경되었다.

2. _physics_process(delta) 함수내에 코드가 작성된 상태라면, _ready() 함수내에서 set_physics_process(true)를 자동으로 호출한다. 물론 필요에 따라서 수동으로 set_physics_process(false)를 하여 _physics_process() 함수를 비활성화 할 수도 있다.

3. _process() 함수를 사용하여, 2D 혹은 3D에서 오브젝트(나의 경우는 RigidBody)를 이동시킬 때, 오브젝트가 shaking(간혈적으로 흔들리거나 떨리는) 현상이 발생한다면, _physics_process() 함수로 변경하면 shaking 현상이 호전되거나 사라질 수 있다. 하지만 Jittering 현상이면 이걸로는 해결할 수 없다.

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

+ Recent posts