C++ 및 opencv 공부겸 저격 게임을 만들어봤습니다.ㅋㅋ
게임 방법은 아주 간단합니다. 마우스 좌클릭만 할 줄 알면 됩니다. 원이 일정 시간 간격으로 화면에 나타나는데 원의 중심을 클릭하시면 됩니다. 원의 중심에 가까울수록 좋은 점수를 받을 수 있고, 원의 중심을 정확하게 클릭한 경우에는 보너스 점수를 받게 됩니다. 일정 점수를 넘게 되면 다음 라운드로 진출하게 되고 점점 원의 크기도 커지고, 원이 나타나는 시간 간격도 짧아집니다. 많은 원을 없애지 못한 경우에 다음 라운드로 넘어가지 못하고 게임이 종료되니 빠르고 정확히 원들을 없애는 것에 목표를 두시면 됩니다.
게임 파일은 아래 링크에 있으니 다운받으신 후에 압축푸시고, ImSniper.exe 실행하시면 됩니다. 티스토리는 파일 업로드가 10메가바이트 밖에 안되서 ..ㅠ 네이버 클라우드를 사용했습니다.
아임스나이퍼 게임을 해보신 분들은 자신의 기록을 댓글로 남겨주시면 감사하겠습니다! ^^ 참고로 제 기록은 23865점입니다. 재미있게 즐기셨다면 주변 친구들에게도 소개해주세요. ㅎㅎ
아래 게임 실행 영상을 보시죠.
원의 중심을 정확히 맞출 때의 그 쾌감!
한번 느껴보시길. ㅎㅎ
위 게임을 만들기 위해 사용한 C++ 소스코드는 다음과 같습니다.
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | // MyGame_20180131.cpp: 콘솔 응용 프로그램의 진입점을 정의합니다. // #include "stdafx.h" #include <iostream> #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp> //rectangle() 사용을 위해 #include <stdlib.h> //srand() 사용을 위해 #include <time.h> //time() 사용을 위해 #include <Windows.h> // Sleep() 사용을 위해 #include <process.h> // 쓰레드 사용을 위해 #include <mmsystem.h> // PlaySound() 사용을 위해 #pragma comment(lib, "winmm.lib") #define SOUND_NAME1 "water001.wav" // 사각형 출현시 사운드 #define SOUND_NAME2 "scifi054.wav" // 클릭시 사운드 #define SOUND_NAME3 "musical097.wav" // 라운드 통과시 사운드 #define SOUND_NAME4 "battle003.wav" // 원 완전 제거시 사운드 => 바꾸기 // 전역변수들 int ing = 100; int circle_size = 30; // 1단계 원 반지름 int circle_num = 0; // 원 갯수 int click_num = 0; // 좌클릭 수 int circles[100][2]; int bonus = 10; // 보너스 점수 int total_bonus = 0; unsigned _stdcall TIMER(void *arg) { srand((int)time(NULL)); int sec = 20; std::cout << "남은 시간 " <<std::endl; for (int i = 1; i <= sec; i++) { ing = 1; if ((sec - i) < 10) std::cout << 0 << sec - i; else std::cout << sec - i; Sleep(1000); if ((sec-i) != 0) std::cout << "\r"; } ing = 0; return 0; } void onMouse(int event, int x, int y, int flags, void* param); int main() { int round = 1; // 몇 라운드인지. int round_score = 0; // 라운드 점수 초기 설정. int pixel_score = 0; int score = 0; // 종합 점수. int goal = 80; // 라운드 목표 점수. int speed = 3000; int height = 700; // 게임창 세로 길이 int width = 1200; // 게임창 가로 길이 srand((int)time(NULL)); //현재 시간을 이용해서 씨드 설정 std::cout << "<<ImSniper>>\n"<< std::endl; std::cout << "게임시작 3초전..." << std::endl; Sleep(3000); while (1) { cv::Mat bg_img(height, width, CV_8UC3, cv::Scalar(0.0, 0.0, 0.0)); // 검정 배경 화면 만들기 600 x 1000 cv::imshow("Game", bg_img); cv::setMouseCallback("Game", onMouse, reinterpret_cast<void*>(&bg_img)); // 게임 창에 마우스 핸들러 설정 std::cout << "\n\n<Round " << round << ">" << std::endl; _beginthreadex(NULL, 0, TIMER, 0, 0, NULL); // 쓰레드 while (1) //라운드 종료될 때까지 계속 { // 너무 가장자리에는 원이 생겨나면 안됨. int P_x = circle_size + rand() % (width - 2*circle_size); int P_y = circle_size + rand() % (height - 2*circle_size); cv::circle(bg_img, cv::Point(P_x, P_y), circle_size, cv::Scalar(rand() % 255, rand() % 255, rand() % 255), -1, 1, 0); cv::circle(bg_img, cv::Point(P_x, P_y), 5, cv::Scalar(0, 0, 255), -1, 1, 0); circles[circle_num][0] = P_x; circles[circle_num][1] = P_y; circle_num++; PlaySound(TEXT(SOUND_NAME1), NULL, SND_FILENAME | SND_ASYNC); cv::imshow("Game", bg_img); cv::waitKey(speed); if (ing == 0) { break; } } double color_pixel_num = 0; for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (bg_img.at<cv::Vec3b>(y, x) != cv::Vec3b(0, 0, 0)) { color_pixel_num++; // 없애지 못한 픽셀들 } } } pixel_score = (int)((height*width - color_pixel_num) / (height*width) * 100); round_score = pixel_score + total_bonus; score = score + round_score; std::cout << "\n\nRound "<< round << " 점수>> " << round_score <<std::endl; std::cout << "종합 점수>> " << score << std::endl; if (pixel_score >= goal) { PlaySound(TEXT(SOUND_NAME3), NULL, SND_FILENAME | SND_ASYNC); round++; std::cout << "Go to Round " << round << "!\n\n" << std::endl; circle_size = circle_size * 1.1; speed = speed * 0.9; Sleep(2000); // 다음 라운드로 넘어가기 전에 2초간 쉬자. click_num = 0; circle_num = 0; total_bonus = 0; bonus = bonus * 1.5; ing = 100; } else { std::cout << "다음 라운드 진출 실패! 게임 끝!\n\n" << std::endl; std::cout << "최종 점수: " << score << std::endl << std::endl; Sleep(5000); break; } } return 0; } void onMouse(int event, int x, int y, int flags, void* param) { cv::Mat *im = reinterpret_cast<cv::Mat*>(param); switch (event) // 이벤트 전달 { case CV_EVENT_LBUTTONDOWN: // 마우스 좌클릭시 이벤트 if (click_num <= circle_num && ing == 1) // 클릭 수가 사각형 수보다 적고, 라운드 진행 중일때만 리무버 작동. { //cv::rectangle(*im, cv::Point(x - (int)circle_size / 2, y - (int)circle_size / 2), cv::Point(x + (int)circle_size / 2, y + (int)circle_size / 2), cv::Scalar(0.0, 0.0, 0.0), -1, 1, 0); // 검정색 정사각형을 덧그리자. cv::circle(*im, cv::Point(x, y), circle_size, cv::Scalar(0.0, 0.0, 0.0), -1, 1, 0); PlaySound(TEXT(SOUND_NAME2), NULL, SND_FILENAME | SND_ASYNC); // 만약에 클릭한 위치가 원의 중심이라면 보너스 점수 + 10 주기!!! 이거 중요. 좀 더 재밌게 즐기려면. 랜덤으로 생겨난 좌표값들을 전역변수로 저장해놓을 필요가 있을듯. 그래서 지금 클릭한 것과 맞는지 확인. for (int k = 0; k < 100; k++) { if ((x == circles[k][0] && y == circles[k][1]) || ((x -1) == circles[k][0] && (y - 1) == circles[k][1]) || ((x + 1) == circles[k][0] && (y + 1) == circles[k][1]) || (x == circles[k][0] && (y - 1) == circles[k][1]) || ((x - 1) == circles[k][0] && y == circles[k][1]) || (x == circles[k][0] && (y + 1) == circles[k][1]) || ((x + 1) == circles[k][0] && y == circles[k][1]) || ((x + 1) == circles[k][0] && (y - 1) == circles[k][1]) || ((x - 1) == circles[k][0] && (y + 1) == circles[k][1])) { total_bonus = total_bonus + bonus; std::cout << "sec: bonus point " << bonus <<"!" << std::endl; PlaySound(TEXT(SOUND_NAME4), NULL, SND_FILENAME | SND_ASYNC); } } click_num++; } break; } // 클릭할 때마다 효과음 주기. // 클릭수에 한계를 줘서 무한 클릭하지 않도록 방지. 생성된 정사각형 수만큼만 클릭 가능. } | cs |
'Dev > C, C++' 카테고리의 다른 글
[opencv와 C++로 컴퓨터 비전] 영상 재매핑 처리 (0) | 2018.03.21 |
---|---|
[opencv와 C++로 컴퓨터 비전] 두 개의 영상 가중합하기 (0) | 2018.03.19 |
[opencv와 C++로 컴퓨터 비전] 영상 선명하게 만들기 (0) | 2018.03.07 |
[opencv와 C++로 컴퓨터 비전] 영상 내 컬러 개수 감소 (0) | 2018.02.15 |
[opencv와 C++로 컴퓨터 비전] 예쁜 타이머 만들기 (타이머 종료시 음악 재생) (6) | 2018.02.02 |
[opencv와 C++로 컴퓨터 비전] 영상에 소금-후추 잡음(salt-and-pepper noise) 넣기 (2) | 2018.02.01 |
[opencv와 C++로 컴퓨터 비전] 영상 위에 로고 넣기 (0) | 2018.01.31 |
[opencv와 C++로 컴퓨터 비전] 영상 위에 그림 그리기 및 글쓰기 (0) | 2018.01.30 |