GNU의 C에서 함수 혹은 구조체, 변수등에 컴파일러가 코드를 컴파일 할 때 특정 방향으로 컴파일 할 수 있도록 속성을 설정할 수 있는 것이 __attribute__ 이다.

GNU의 C 코드에서 간혹 __attribute__ 라고 써있는 것을 볼 수 있다.
_ 2개를 attribute 끝에 붙여서 사용한다. 그리고 그 뒤에 괄호 두개 사이에 원하는 속성을 넣으면 된다.

예로 이렇게 사용한다.
내가 how2heap의 house of spirit을 분석하다가 마주한 코드이다.

unsigned long long fake_chunks[10] __attribute__ ((aligned (16)));

위와 같이 사용한다.
사용할 수 있는 속성은 굉장히 많다.

예로 든 aligned 속성은 메모리의 정렬 단위를 설정하는 것이다.
해당 내용은 memory alignment를 검색해보면 찾아 볼 수 있다.

간단히 설명하면 메모리에서 입출력을 할 때 가져오는 단위 WORD 로 가져오기 때문에 메모리에 값을 저장할 때 신경을 써야한다. 
예를 들어서 좋지 않은 경우를 보겠다.

32비트 컴퓨터라고 하자. 그렇다면 WORD의 단위는 4바이트이다. 그렇다면 메모리에서 4바이트 단위로 값을 가져온다.
여기서 우리가 int 의 값을 저장한다고 하자.( int 는 4바이트(word의 값))
메모리 주소 0번지 부터 저장한다 치면 주소 0,1,2,3 에 우리의 값이 적혀지게 되고
이 값을 부를 때 0번지 주소를 부르게 되면 4바이트 단위로 값을 가져오기 때문에 0,1,2,3 주소의 값을 가져오게 되어 한번의 호출로 우리가 저장한 값을 가져올 수 있다.

하지만 만약 2번지 주소에 저장되었다 치자.
그러면 2,3,4,5 주소에 우리의 int 값이 저장된다. 이 값을 호출 하기위해 메모리 주소를 2번부터 부를 수 있을까? 그렇지 않다. 32비트의 컴퓨터이므로 4바이트 단위로 메모리에서 값을 가져오기 때문에
만약 2번지 주소에 저장되어있다면
0번부터 불러서 0,1,2,3 을 부른 후, 다시 4번부터 또 불러 4,5,6,7 을 가져와서
우리가 저장했던 값을 가져온다. 즉, 메모리 호출을 2번 하게 되는 것이다. 메모리에서 값을 가져오고 쓰는 과정은 굉장히 비싼 작업이다. (시간이 오래걸린다.) 그렇기 때문에 메모리에 값을 저장할 때 신경을 써줘야한다. 보통 이 작업을 컴파일러가 알아서 해준다. 하지만 프로그래머가 특별히 어떠한 단위로 저장을 원할 경우 __attribute__의 aligned 속성을 사용해 지정해 줄 수 있다.

*  __attribute__ ((aligned(4))); 를 이용한 해결
위의 경우 2번지에 저장이 되었는데 그 앞에 char 변수 2개가 들어있는 구조체라고 하자.
그렇다면 위의 상황이 나온다. (보통 요즘의 컴파일러들이 알아서 구조체에서 가장 큰 사이즈의 단위로 alignment를 해주지만 안해준다고 치자!)
그렇다면 여기서 우리는 구조체 선언할 때 뒤에 __attribute__ ((aligned(4)));를 붙이므로써 이 문제를 해결할 수 있다.
그렇게 되면 0번지부터 char 변수 2개가 들어가고, 메모리 2,3 주소에 패딩이 들어간다.
패딩이란 메모리 단위를 맞춰주기위한 더미값? 이라고 생각하면된다.
그리고 int값을 쓸 때는 4번지 주소부터 적게 되어 아까 위의 문제가 발생하지 않게 되는 것이다.


지난 포스팅에서 우주선 자체가 깜빡 거리는 것 까지 했다.

이번에는 우주선이 움직이는 것을 표현해 볼 것이다.

오른쪽으로 이동하면서 우주선이 빙글빙글 돌면서 날라간다. 날라가면서 크기도 작아진다. 그리고 화면 밖으로 벗어나게 되면 그 반대에서 다시 나타나서 계속 움직이는 것을 만들 것이다.


(update)


update 함수를 수정해주면 된다.

우주선을 회전하게 하는 것을 각도 설정, 크기 설정에서 크기만 넣어주면 된다. 어떻게 작아지는지 어떻게 이미지 생성 위치가 바뀌는지에 대한 것은 애니메이션 그리는 것에서 우리가 다 만들어 놓은 것이다. 우리는 단지 회전각도와 위치만 설정해주면 된다.



(상수)


위 코드에 대한 상수값들이다.
회전 상수는 180으로 정의 되있어서 초당 180도를 회전한다는 의미이다.
SCALE_RATE 상수는 0.2로 정의 되어있어 초당 100픽셀만큼 움직인다는 의미이다.

SHIP_SCALE 상수는 1.5로 정의되어있는데 우주선이 원래 크기에서 1.5배로 커진다는 의미이다.


(실행 화면)


실행 시 깜빡이는 우주선이 오른쪽으로 한없이 날라다닌다.

이제는 화살표 키 입력을 받아 우주선의 움직임을 통제 해 볼것이다.



(update)


위에서 한것과 같이 단순히 키 입력만 확인하여 그에 따라 위치만 바꾸어 주면된다.

(실행화면)


실행시 키 입력에 따라 우주선이 움직인다. ( 사진으로 해놔서 의미가 있는지 모르겠다... )

그런데 키를 때면 바로 우주선이 멈춘다.
키를 때도 그 방향으로 계속 움직이게 수정해 줄 것이다.
반대 키를 누르면 그 방향에대한 속도가 줄게 할 것이다. 그러기 위해서는 속도라는 값이 들어가야한다.

키 입력에 따라 속도 값을 수정해주고, 그 속도만큼 움직이게 하면 되는 것이다.



(update)


위 처럼 해두니 키를 때었을 때 계속 날라다니는 현상이 있었다.

키를 때었을 때 점차 속도가 줄어들게 하고 싶었다. 그래서 update 아래에 아래 코드를 추가했다.



(추가한 코드)


GRAVITY는 실제 중력값은 아니고 속도가 감소한다는 의미의 상수를 넣었다.



(추가 상수)



(실행 화면)


실행 해보니 우주선이 잘 움직였고, 키를 때었을 때 점차 속도가 감소하였다.

마지막으로
속도가 좀 느리다는 느낌이 있었다.

그래서 스페이스바를 누르면 부스트 모드로 기존 속도의 2배로 날라가게 만들었다.


(추가한 코드)


스페이스바 입력을 받게 하기 위해 상수로 추가했다.



(스페이스바 추가)


그리고 boost 여부에 따라 2배로 움직이게 만들었다.



(boost 모드)


실행시 아주 아주 잘 동작하였다.
키 입력을 받아 우주선이 움직이게 하는 것까지 마무리했다.!!

(* 참조 - 2D 게임 프로그래밍, 찰스 켈리)



저번에 그렸던 이미지에서 간단한 애니메이션을 추가해 볼 것이다.

우주선을 추가할 것인데, 우주선 주변에 불이 깜빡깜빡하는 아주 간단한 애니메이션을 추가해 볼 것이다.
가장 먼저 해야할 일은 우주선을 추가해주어야하는 일이다.

저번에 이미지를 그렸을 때와 같이 우주선 textureManager와 Image 클래스를 만들어준다.

(우주선 추가)


그 후 초기화 함수에도 추가해준다.


(텍스처 초기화)



(이미지 초기화)


이미지 클래스 초기화 후

우주선의 화면 위치를 설정해준다. 여기서는 좌측상단에 나타나도록 설정해두었다.
그 애래의 코드들은 우주선 애니메이션과 각도에 관한 설정들이다.
뒤에서 설명하겠다.!

애니메이션을 동작시키기 위해 애니메이션이 있는 이지미를 계속 업데이트해줘야한다.

이 과정은 게임 클래스 안의 update 함수 안에서 해당 이미지의 업데이트를 추가해주므로써 구현한다.



(이미지 update)


우주선의 업데이트 함수를 호출했다. 여기에 인자는 frameTime을 넣었다.
예전에 게임엔진 틀을 만들 때 frameTime을 계산해주기 위해 내부 타이머를 이용해 시간을 계산해주는 작업을 한 것이 기억날 것이다. 이런 곳에 사용하기 위해 계산을 해둔 것이다.

이미지클래스의 update를 확인해보자


(update 함수)


넘어온 frameTime은 한 루프가 돌면서 지난 시간이다. (이전 게임엔진 틀을 만들 때 만들었었다.)
먼저 체크하는 것은 애니메이션 동작이 있는 스프라이트인지 체크한다.
애니메이션 동작이 있는 것이라면 먼저 경과 시간을 계산해준다.
우리가 원하는 frameDelay마다 동작하게 하기 위해서이다. 그래서 그 다음으로 frameDelay보다 큰지 확인하고 크면 update를 하고 크지 않으면 다음 루프에서 update를 하게하기 위해서이다.
그 후 애니메이션 타이머에서 frameDelay를 빼준다. (다음 번 update에서 사용하기 위해서)
그리고 현재 프레임수를 1증가시킨다.
그리고 동작하는 것이 setRect() 함수이다.

이제 이 setRect() 함수를 보면 애니메이션이 이해가 갈 것이다.



(setRect() 함수)


이 함수에서는 이미지에서 특정 영역을 설정하는 함수인데, 현재frame을 기준으로 바뀌는 것을 볼 수 있다. 우리가 올린 이미지는 아래와 같다.


(우주선 이미지)


위의 이미지에서 하나씩 가져다 쓰는데 4개를 번갈아가면서 화면에 출력해주는 것이다.
그렇기에 우주선 주위에 불빛이 빤짝거리게 되는 원리이다.

즉, 움직이게 하고 싶은 이미지 마다 위와 같은 과정으로 프레임을 설정해 주는 것이다.

맨 처음에 봤던 우주선 애니메이션활성화 설정을 다시 볼 것이다.


(애니메이션 설정)


setFrames는 처음 프레임과, 마지막 프레임을 설정하는 것이다. 변수의 값은 아래 사진과 같다.


(상수)


프레임은 0에서 3까지 총 4개의 프레임이고 위의 사진에서 보았듯이 4개의 우주선 모양이 있는 것을 확인 할 수 있다. 그리고 setCurrentFrame 함수로 현재 프레임을 우주선의 시작 프레임으로 설정해주는 것이다. (초기화 함수이기 때문에)



(setCurrentFrame 함수)


currentFrame에 넘어온 인자를 넘겨준다. 그리고 영역을 설정한다.(현재 프레임에 맞는 그림)

자! 이제 실행해 볼 것이다!

그 전에! 추가해줘야할 것이 있다. render() 함수에 우주선 이미지 그리는 것을 추가해줘야한다.!


(우주선 그리기)


이제 빌드 후 실행??
나는 여기서 빌드 후 실행하고 잘 되는 줄 알았다.
그리고 곧 문제점을 깨달았다.
전체화면으로 바꾸려고 했을 때 되지 않았다.!! 화면이 까매지기만 했다. 디바이스 로스트 상황이었다.

코드를 다시 보다가 이해했다. 디바이스 로스트 때 돌아가는 것 중 우리가 우주선 이미지를 추가하면서 우주선 textureManager를 추가해줬는데 이것도 핸들해줘야하기 때문이다.


(로스트 처리)


이렇게 로스트 처리하게 되면 창전환도 괜찮았다.



(실행 화면)



우주선 주변의 불빛이 깜빡거리는 간단한 애니메이션을 추가해보았다.

(* 참조 - 2D 게임 프로그래밍, 찰스 켈리)

+ Recent posts