티스토리 뷰

https://github.com/JunHwaPark/SFMLFortress

깃허브 원격저장소를 삭제했습니다. 필요하신 분은 메일을 보내주세요.

wnsghk1025@naver.com


 

1.       코드 설명

먼저 이 프로그램을 만들면서 사용한 텍스처와 스프라이트에 대해서 간략하게 설명하겠습니다. 나눠주신 이미지 파일들을 이용하여 탱크, 배경화면, 상태 창, HP및 파워 게이지, 포탄에 대한 텍스처와 스프라이트를 선언했고, 탱크와 HP및 파워 게이지는 한 개의 텍스처에 각각 두 개의 스프라이트를 세팅했습니다.


다음으로는 사용한 변수에 대해 설명하겠습니다. 위 캡처화면에 모두 설명이 되어있는대로, 정수형 변수인 turn은 턴 구분을 위한 변수, dir1,2 1플레이어와 2플레이어 각각의 탱크가 바라보는 방향을 판단하기 위한 불 변수, 또 포탄의 파워를 의미하는 power변수와 스페이스바가 여러 번 눌리지 않도록 하기 위한 키 입력 딜레이를 담당하는 delay변수가 있습니다. Max_power변수는 포탄의 최대 파워를 제한하고, 실시간으로 올라가는 파워 게이지의 크기를 조절하는 역할을 합니다. 이 외에도 space는 파워 게이지가 올라가는 중인지 판단하고, ball_air는 미사일이 공중에 있을 때 스페이스바를 사용하여 포탄이 사라지는 것을 방지하는 불 변수입니다.


가장 큰 while문에 들어오면 제일 먼저 Clock 변수를 선언하여 루프를 돌기 시작할 때부터 시간을 재기 시작합니다. 이 이유는 뒷부분에서 설명하도록 하겠습니다. SFML의 대부분의 프로그램이 그러하듯, window.pollEvent while문으로 감싸 프로그램 종료를 설정한 후, pollEvent루프가 아닌 window.isOpen루프로 돌아와 스페이스바를 눌렀을 때의 작동의 정의했습니다.

이전에 스페이스바를 누른 후 최소 0.2초가 지난 후에 스페이스바를 눌렀는데 포탄이 공중에 있지 않으면 if문으로 들어갑니다. 조건문으로 들어가면 우선 위에서 선언했던 space라는 불 변수를 반전시킵니다. true이면 false, false이면 true로 전환을 시킵니다. 왜냐하면, 처음 프로그램을 작동시켰을 때에는 spacevalue false입니다. 이 상태에서 스페이스바를 누르면 true가 되고, 파워 게이지가 올라갑니다. 또 그 상태에서 스페이스바를 누르면 space valuefalse에서 true로 바뀌며, 파워 게이지가 초기화되고 포탄이 날아갑니다. 따라서 파워 게이지를 조작 중인지 판단하기 위해 스페이스바를 누를 때마다 spacevalue를 반전시킵니다. 하지만 이렇게 하면 파워게이지가 끝도 없이 올라갈 수 있기 때문에, max_power라는 변수를 선언하고, 이 변수가 340보다 커지면 이 조건문에 들어올 수 있는 조건을 추가했습니다.

spacevalue를 반전시킨 후, turn변수의 값을 1 증가시킵니다. 뒤에서 나오겠지만, turn 4로 나누어 나오는 나머지를 이용하는데, 처음 시작했을 때에는 0이니 스페이스바를 누를 때마다 turnvalue 1씩 증가한다고 치면 나머지 0 11플레이어의 차례이고, 23 2플레이어의 차례라는 것을 알 수 있습니다.

max_power space value true가 되면 루프를 한 번 돌 때마다 값이 일정치 증가합니다. 이 값을 그대로 포탄의 파워에 넣으면 너무 강하기 때문에, 60으로 나눠 대입했습니다. 그럼 루프가 한 번 돌 때마다 증가하는 max_power의 증가값을 1/60로 줄이면 되지 않느냐?’라고 생각하실 수 있지만, max_power의 값을 여러 방면에서 계산하기 쉽게 설정해서, power에 대입할 때만 60으로 나누는 것이 낫겠다고 판단했습니다.

스페이스바를 한 번 더 누르거나 파워 게이지 끝까지 누르지 않으면 포탄이 나가면서, 다시 조건문으로 들어와 max_power0으로 초기화시킵니다. 또한, delay변수도 0으로 초기화하여 스페이스바를 누른 시점부터 키 딜레이 시간을 계산합니다.


다음은 좌우 방향키 입력에 대한 부분입니다. 좌우는 음수가 양수로 바뀌고, dir변수가 true에서 false로 바뀐다는 차이점밖에 없기 때문에 우측 방향키로 설명을 하겠습니다. 우선 키보드에 우측 방향키를 입력하면 위 조건문에 들어갈 2개의 조건 중 하나를 만족합니다. 다른 하나는 포탄이 공중에 있지 않을 것입니다.


inair함수는 이렇게 정의되어 있습니다. y라는 스프라이트를 인자로 받아, 그 인자의 Y좌표가 400()보다 큰지(아래에 있는지) 작은지(위에 있는지) 판단하여 크면 false, 작으면 true를 반환합니다.

다시 우측 방향키로 돌아와서, 조건문으로 들어가면 switch문이 있습니다. 위에서 설명했던 turn변수를 이용한 플레이어 턴 구분방식입니다. 처음에 프로그램을 실행하면 turn 0입니다. 1플레이어가 탱크를 움직인 후, 포탄을 쏘기 위해 스페이스바를 누르면 turn 1이 됩니다. 적당한 파워가 되어 스페이스바를 누르거나, 끝까지 누르지 않아 최고 파워가 되면 turn 3으로 바뀌면서 포탄이 날아가고, 2플레이어의 차례가 됩니다. 따라서 1플레이어가 탱크를 움직이는 상황은 turn 4로 나눈 나머지가 0인 상황이고, 2플레이어가 탱크를 움직이는 상황은 2인 상황이 되기 때문에, 이렇게 case를 나눴습니다.

우측 방향키를 누르면 탱크가 오른쪽으로 움직입니다. 하지만, 맵 바깥으로 나가는 것을 방지하기 위해 X좌표가 760을 넘어가면 더 이상 오른쪽으로 움직일 수 없게 하였고, 우측으로 움직이면 dir변수도 true가 되도록 했습니다. 참고로 왼쪽으로 움직이면 false입니다.


탱크가 좌우로 움직인다고 끝이 아니기에, 왼쪽으로 움직일 때는 왼쪽을 바라보고, 오른쪽을 바라볼 때에는 오른쪽을 바라보도록 설정했습니다. 열심히 구글링을 통해 setTextureRect에 너비와 높이를 저런 식으로 입력하면 좌우가 반전된다는 것을 알아냈고, dir변수를 통해 판단하여 탱크가 바라보는 방향을 설정했습니다.


1플레이어가 파워가 적당히 올랐을 때 스페이스바를 누르면 turn 2가 됩니다. 이 때, 파워 게이지는 초기화가 되고 포탄을 날아가기 시작합니다. 스페이스바를 눌러 power max_power로 초기화되면 무조건 위 조건문에 들어옵니다. 그 상황의 delay값은 0이므로 플레이어의 탱크 중앙으로 포탄의 위치를 이동시키고, 플레이어의 탱크가 바라보고 있는 방향에 따라 왼쪽 혹은 오른쪽으로 포탄을 쏩니다. 포탄은 위로 올라가는 속도와 좌 또는 우로 움직이는 속도가 같기 때문에 45도로 움직이며, delayloop를 회전함에 따라 증가하기 때문에 0.3이라는 중력에 곱해져 포탄을 그만큼 아래로 이동시킵니다. 그에 따라 시간이 지나면 Y축 이동량이 음수에서 점차 커지다가 양수로 변해 떨어지기 시작하며, ball_air라는 불 변수를 true로 바꿉니다. 물론 위에서 스페이스바에 ball_air라는 조건을 추가하여 공이 날아가는 중간에 상대방이 스페이스바를 누르지 못하도록 했습니다.


위 캡처화면은 2플레이어 공의 움직임에 대한 정의인데, 1플레이어와 다른 점이 있습니다. 바로 turn 4로 나눈 나머지값이 0일 때 포탄을 쏘는데, 프로그램을 시작하자마자 포를 쏘면 안되기 때문에, turn > 1이라는 조건을 하나 더 만들었습니다.


그렇게 포탄이 떨어지다보면 땅보다 아래로 떨어질 것입니다. Y좌표는 대략 400이며, 따라서 포탄의 Y좌표가 400보다 커지면(땅보다 아래이면) 포탄의 위치를 (0, 800)으로 이동시켜 화면에서 보이지 않도록 처리했습니다.(화면의 크기는 (800, 600)입니다.) 또한 공이 떨어졌음을 확인했으니 ball_airvalue false로 변경했습니다.

스페이스바를 누르면 spacetrue가 되고, max_power가 한 loop를 돌 때마다 0.5씩 증가하도록 했습니다. 이에 따라 파워 게이지의 크기가 우측으로 늘어나도록 했는데, 20으로 나눈 이유는 나눠주신 파일의 크기가 20*20픽셀이기 때문에 후에 계산하기 쉽도록 하기 위해서 입니다.

또한, 스페이스바를 누른 뒤 딜레이를 계산하기 위해 loop가 돌 때마다 delay의 값이 0.1씩 증가하도록 설정했습니다.


화면을 초기화 한 후, 배경과 상태창, 탱크 등을 그린 후, display를 했습니다. 다만, 포탄은 turn 4로 나눈 나머지가 0혹은 2일때만 필요하기 때문에, 조건문을 걸었습니다.

위에서 while문에 들어오자마자 Clock 변수를 선언하여 시간을 재기 시작했습니다. loop가 돌고 마지막에 그 시간을 재는데, 이 시간이 4000마이크로초가 되지 않으면 지금까지 실행한 시간을 포함하여 4000마이크로초가 지난 다음에 다시 loop를 돌게 설계했습니다. 왜냐하면, 이 내용을 넣지 않는다면 예를 들어 연산능력이 뛰어난 컴퓨터는 1초에 1억번을 연산하여 1초동안 우측 방향키를 누르면 탱크가 50000000만큼 이동하게 됩니다. 당연히 그만큼 파워 게이지가 올라가는 속도나 포탄의 이동속도도 빠를 것입니다. 반면에, 연산능력이 좋지 않은 컴퓨터에서 1초에 1000번을 연산한다면, 1초동안 우측 방향키를 누르면 탱크가 500밖에 움직이지 않아 플레이어가 많이 답답하고, 무엇보다 각기 다른 사용환경에서 다른 느낌을 받을 수 있기 때문입니다.

sleep하는 시간을 크게 하고 비교하는 시간을 계속 조절하면서 얻은 결과로는, 제 컴퓨터는 1loop를 돌릴 때 100에서 200마이크로초의 시간이 소요되며, 비교적 연산능력이 좋지 않은 노트북은 1loop를 돌릴 때 600마이크로초가 소요됐습니다. 이 노트북도 충분한 자료라고 생각했지만, 훨씬 더 좋지 않은 컴퓨터를 가정해봤고, 지연시간을 계속 조정하며 얻은 결과로는 4000마이크로초까지는 한 번씩 loop를 돌리면 프로그램이 멈추는 것을 사람이 멈추는 것은 인식하지 못한다고 판단했습니다. (아마 저 프로그램의 loop를 한 번 돌리는데 4000마이크로초보다 더 걸리는 컴퓨터는 없을 것이라고 생각합니다.)





이미 프로젝트가 끝난지 오래됐지만, 귀찮(...)아서 안올리고 있었는데 이제야 올립니다. 1차와 2차 프로젝트를 나눠서 한번에 올립니다. 참고로 1차 프로젝트가 끝난 시점은 2018년 6월 14일 입니다. (깃허브를 참고하실 분들을 위해)

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함