[ Clock 만들기 ]
URL : http://catlikecoding.com/unity/tutorials/basics/game-objects-and-scripts/
Build a clock with simple objects.
Write a C# script.
Rotate the clock's arms to show the time.
Animate the arms.
[ 1 Building a Simple Clock ]
Customize the editor (layout)
Game Window(Free Aspect)
[ 1.1 Create a Game Object ] - 시계전체를 감싸는 GameObject 만들기
Main Camera, Directional Light in The Default Scene
Main Camera : 씬을 렌더링할 때 사용되는 카메라 (Game Object)
참고 : 에디터 화면 시점으로 카메라 옮기기 ( Ctrl + Shift + F)
Directional Light : 씬에 빛을 나타내는 Game Object
Create “Empty” GameObject ( Clock )
Menu : Game Object >> Create Empty
Inspector View : Transform
Position / Rotation / Scale : (0,0,0) / (0,0,0) / (1,1,1)
Transform : Unity에서 제공되는 모든 GameObject는 필수적으로 Transform Component를 가지고 있음
Inspector Window : GameObject의 상세한 정보 제공 ( GameObject 이외에도 다른 Resources[prefab, Material, Script 등]들에 대한 상세한 정보를 알려 줌)
[ 1.2 Creating the Face of the Clock ] - 시계 판 만들기
Menu : GameObject >> 3D Object >> Cylinder
Mesh Filter : 이미 만들어져 있는 Cylinder Mesh에 대한 참조 값을 가지고 있음
Capsule Collider : 3D 형태의 Capsule 충돌체
유니티는 Cylinder 형태의 Collider가 없는 관계로 Capsule 형태를 사용하고 있음
우리 프로젝트에서는 필요 없으니 Collider는 삭제
Mesh Renderer : Mesh Filter에 정의되어 있는 Mesh를 이미 만들어진 Default-Material로 정의된 Material로 렌더링될 수 있도록 설정되어 있음
Cylinder를 시계판으로 만들기 위해서 Scale 조정하기
이름 바꾸기 및 Clock의 자식 객체로 만들기
Cylinder >> Face
Hierarchy window : Face 드래그 >> (to) Clock
[ 1.3 Creating the Clock Periphery ] - 시계 눈금(Indicator) 만들기
시계 눈금을 원점을 기준으로 회전해야 한다.
시계의 맨 위쪽(12시 방향)에 위치하는 Hour Indicator 만들기
Menu : GameObject >> 3D Object / Cube
Name : Hour Indicator
Position, Scale 변경
Indicator 색깔 바꾸기
Project Window : Asset >> Create >> Material
Name : Clock Dark
Albedo : Latin word로 whiteness 를 의미하지만, 그냥 material의 색깔이라고 일단 인지하고 있으면 됨
RGBA(73,73,73,255)
Clock Dark 드래그 >> (to) Hour Indicator
여러 개(12개)의 Indicator 만들기
GameObject >> Empty Object
Tranform : position, rotaion >> 0, scale >> 1 (Transform Component의 Reset을 사용하면 편함)
Hour Indicator 복사하기 ( Crtl + d )
Hour Indicator(한개)를 Empty Object 자식으로 만들기
Hour Indicator 드래그 >> (to) Empty Object
Empty Object 회전하기( 30도를 회전하면 1시 위치에 Indicator가 위치하게 됨)
Transform : Y rotation >> 30
Indicator를 Face로 옮김 ( 유니티가 Indicator의 Transform을 자동 계산해서 값을 대입해 줌)
Indicator 드래그 >> (to) Face
Indicator : Rotation 값이 0에서 30으로 바뀐 것 확인해 보기 바람
Empty Object는 삭제
이렇게 나머지 Indicator들을 만들어서 12개를 만듬
[ 1.4 Creating the Arms ] - 시침, 분침, 초침 만들기
Menu : GameObject >> 3D Object / Cube (시침 만들기)
Name : Arm
Position, Rotation, Scale 처리(아래 그림 처럼)
Material은 이미 만든 Clock Dark로 사용
Arm이 향후에 회전할 수 있도록 하기 위해 Parent Object를 생성
GameObject >> Empty Object
Tranform : position, rotaion >> 0, scale >> 1
Name : Hours Arm
Arm 드래그 >> (to) Hours Arm
Hours Arm 드래그 >> (to) Clock
이렇게 Minutes Arm, Seconds Arm 생성
Arm(Minutes)
Position ( 0, 0.375, 1) / Scale (0.2, 0.15, 4)
Material : Clock Dark
Arm(Seconds)
Position ( 0, 0.5, 1.25) / Scale (0.1, 0.1, 5)
Material : Clock Red
Project Window : Asset >> Create >> Material
Name : Clock Dark
Albedo : RGBA (197,0,0, 255)
씬 저장
제공하고 있는 Package Import해 보기
[ 2 Animating the Clock ] - 스크립트 생성해 보기
Project View : Create >> C# Script
name : Clock
[ 2.1 Defining a Component Type ]
class와 instance에 대한 설명
class는 자료형
자료형으로 만들어 낸 것(메모리에 할당 된 것)이 instance
public class Clock;
외부에서 접근해서 Clock 클래스를 사용할 수 있도록 함
Monobehaviour
이것을 상속 받지 않으면 유니티에서 제공하는 기능들을 사용할 수 없게 됨
namespace
코드들을 조직화하고 코드의 충돌을 방지하기 위해 사용
Clock 클래스 인스턴스
Clock 스크립트 드래그 >> (to) Clock 게임오브젝트
[ 2.2 Getting Hold of an Arm ] -
시침의 Transform(GameObject)를 Clock(Script)에서 사용할 수 있도록 멤버 변수(hoursTransform)를 생성하고 Hours Arm 오브젝트를 대입
Transform hoursTransform;
Transform : 위치(position), 회전(rotation), 크기(Scale)을 가지고 있는 자료형 (Component)
public Transform hoursTransform;
public 변수 : 유니티 Inspector window에서 보여짐
hoursArm(게임 오브젝트)를 Clock 스크립트의 변수에 연결
결론적으로 Clock 클래스 내에서 hoursTransform이라는 변수를 이용하여, hourArm(게임오브젝트)에 접근할 수 있게됨
[ 2.3 Knowing all Three Arms ]
세개(hours, minutes, seconds)의 Arm(GameObject)을 저장할 수 있도록 변수 생성
public Transform hoursTransform, minutesTransform, secondsTransform;
[ 2.4 Knowing the Time ]
현재 시간 구하기
Awake()
Component가 실행될 때, 호출되는 함수(메소드)
Unity가 알아서 호출해주는 함수(메소드)
Debug.Log()
UnityEngine.Debug 클래스에 정의된 함수로 디버그 메시지를 콘솔창에 출력할 때 사용
UnityEngine.Time 클래스
시간과 관련된 정보를 가지고 있는 클래스
Time.time : 프로젝트가 시작된지 얼마가 되었는지의 정보들 담고 있음
DateTime : 실행중인 컴퓨터의 시스템 시간을 억세스할 수 있는 Structure
using System; 을 통해 사용할 수 있음
DateTime.Now : 현재 시스템 날짜 및 시간을 포함한 정보를 담고 있음
DataTime.Now.Hour : 핸재 시간 단위를 알 수 있음
using System;
using UnityEngine;
public class Clock : MonoBehaviour {
public Transform hoursTransform, minutesTransform, secondsTransform;
void Awake() {
Debug.Log ("Test"); // Test 1
Debug.Log (Time.time); // Test 2
Debug.Log (DateTime.Now); // Test 3
Debug.Log (DateTime.Now.Hour); // Test 4
}
}
[ 2.5 Rotating the Arms ]
using System;
using UnityEngine;
public class Clock : MonoBehaviour {
public Transform hoursTransform, minutesTransform, secondsTransform;
const float degreesPerHour = 30f; // 시간 단위의 각도 : 360 /12 = 30
void Awake() {
if (hoursTransform == null) // 이 부분을 안넣으면 에러 메시지 등장
return;
hoursTransform.localRotation = Quaternion.Euler (0f, DateTime.Now.Hour * degreesPerHour, 0f);
}
}
Quaternion : 복소수 표현방식을 이용하여 3차원 회전을 표현하는 식(gimbal lock 현상을 없앨 수 있음)
UnityEngine.Quaternion : Class가 아닌 Structure 자료형
Quaternion.Euler() : 오일러 각도를 매개변수로 x, y, z값을 넣어 회전하는 함수
Quaternion.Euler(0f, DateTime.Now.Hour * 30f, 0f);
Hour의 값에 따라 y축을 기준으로 0, 30, 60, 90 ... 330 까지의 값을 가지게 됨 (즉, 시를 표현할 수 있게됨)
const
해당되는 변수의 값이 실행타임에 절대로 바뀌지 않도록 하는 예약어, 컴파일 타임에 계산되고 사용된 모든 변수들이 이 값으로 대치됨
localRotation
Transform의 멤버변부로 지역 좌표계에서의 회전 좌표 값
지역 좌표계 : 부모 좌표계와 독립된 자기 자신만이 가지고 있는 좌표계
시 / 분 / 초 바늘 움직이기
using System;
using UnityEngine;
public class Clock : MonoBehaviour {
public Transform hoursTransform, minutesTransform, secondsTransform;
const float degreesPerHour = 30f, degreePerMinute = 6f, degreePerSecond = 6f;
void Awake() {
if (hoursTransform == null || minutesTransform == null || secondsTransform == null)
return;
//hoursTransform.localRotation = Quaternion.Euler (0f, 90f, 0f);
hoursTransform.localRotation = Quaternion.Euler (0f, DateTime.Now.Hour * degreesPerHour, 0f);
minutesTransform.localRotation = Quaternion.Euler (0f, DateTime.Now.Minute * degreePerMinute, 0f);
secondsTransform.localRotation = Quaternion.Euler (0f, DateTime.Now.Second * degreePerSecond, 0f);
}
}
현재 시간 16:29:06
DateTime.Now
현재 시간(시/분/초)을 알려 주는 변수
void Awake() {
if (hoursTransform == null || minutesTransform == null || secondsTransform == null)
return;
DateTime time = DateTime.Now;
hoursTransform.localRotation = Quaternion.Euler (0f, time.Hour * degreesPerHour, 0f);
minutesTransform.localRotation = Quaternion.Euler (0f, time.Minute * degreePerMinute, 0f);
secondsTransform.localRotation = Quaternion.Euler (0f, time.Second * degreePerSecond, 0f);
}
[ 2.6 Animation the Arms ]
Update()
매 프레임마다 호출되는 함수
Awake에서 정의했던 내용을 그대로 Update()로 옮겨 와서 실행
using System;
using UnityEngine;
public class Clock : MonoBehaviour {
public Transform hoursTransform, minutesTransform, secondsTransform;
const float degreesPerHour = 30f, degreePerMinute = 6f, degreePerSecond = 6f;
void Update() {
if (hoursTransform == null || minutesTransform == null || secondsTransform == null)
return;
DateTime time = DateTime.Now;
hoursTransform.localRotation = Quaternion.Euler (0f, time.Hour * degreesPerHour, 0f);
minutesTransform.localRotation = Quaternion.Euler (0f, time.Minute * degreePerMinute, 0f);
secondsTransform.localRotation = Quaternion.Euler (0f, time.Second * degreePerSecond, 0f);
}
}
[ 2.7 Continuously Rotating ]
디지털 시계와 아날로그 시계
bool Continuous : true 인 경우 아날로그 바늘 형태로 움직임 ,false인 경우는 디지털 바늘 형태로 움직임
TimeSpan
시간 간격을 담는 자료형
DateTime.Now.TimeofDay : 전날 자정부터 현재까지 흐른 시간(TimeSpan 자료형)을 얻어옴
TimeSpan의 자료형은 double형 이므로 float형으로 강제 형변환 시키고 있음
void Update() {
if (continuous) {
UpdateContinuous ();
} else {
UpdateDiscrete ();
}
}
void UpdateContinuous() {
if (hoursTransform == null || minutesTransform == null || secondsTransform == null)
return;
TimeSpan time = DateTime.Now.TimeOfDay;
hoursTransform.localRotation = Quaternion.Euler (0f, (float)time.TotalHours * degreesPerHour, 0f);
minutesTransform.localRotation = Quaternion.Euler (0f, (float)time.TotalMinutes * degreePerMinute, 0f);
secondsTransform.localRotation = Quaternion.Euler (0f, (float)time.TotalSeconds * degreePerSecond, 0f);
}
void UpdateDiscrete() {
if (hoursTransform == null || minutesTransform == null || secondsTransform == null)
return;
DateTime time = DateTime.Now;
hoursTransform.localRotation = Quaternion.Euler (0f, time.Hour * degreesPerHour, 0f);
minutesTransform.localRotation = Quaternion.Euler (0f, time.Minute * degreePerMinute, 0f);
secondsTransform.localRotation = Quaternion.Euler (0f, time.Second * degreePerSecond, 0f);
}