#include #include #include #define WIDTH 720 #define HEIGHT 720 #define FONTSIZE 32 #define BALLSIZE 16 #define BALLSPEED 16 #define SPEED 9 #define PI 3.1415926535897323846 SDL_Renderer* renderer; SDL_Window* window; TTF_Font* font; SDL_Color color; bool running; int frameCount, timerFPS, lastFrame, fps; SDL_Rect player, npc, ball, scoreboard, leveldisplay; float xvelocity, yvelocity, ballvelocity, ballsize; std::string score, slevel; int lscore, rscore, level, games; bool turn, isgameover; std::string version = "1.0.0"; void serve() { player.y = npc.y = (HEIGHT/2) - (player.h/2); if (turn) { ball.x = player.x + (player.w * 4); xvelocity = (BALLSPEED*ballvelocity)/2; turn = false; } else { ball.x = npc.x - (player.w * 4); xvelocity = -(BALLSPEED*ballvelocity)/2; turn = true; } yvelocity = 0; ball.y = HEIGHT / 2 - ((BALLSIZE-ballsize)/2); } void write(std::string text, int x, int y) { SDL_Surface *surface; SDL_Texture *texture; const char* t = text.c_str(); surface = TTF_RenderText_Solid(font, t, color); texture = SDL_CreateTextureFromSurface(renderer, surface); // スコアボード scoreboard.w = surface->w; scoreboard.h = surface->h; scoreboard.x = x - scoreboard.w; scoreboard.y = y - scoreboard.h; // レベル表示 leveldisplay.w = surface->w; leveldisplay.h = surface->h; leveldisplay.x = x - scoreboard.w + 8; leveldisplay.y = y - scoreboard.h + 8; // 掃除 SDL_FreeSurface(surface); SDL_RenderCopy(renderer, texture, NULL, &scoreboard); SDL_DestroyTexture(texture); } void gameover() { xvelocity = yvelocity = ballvelocity = 0; } void update() { // ボールとコンピュータの衝突検出 if (SDL_HasIntersection(&ball, &npc)) { double rel = (npc.y + (npc.h / 2)) - (ball.y + ((BALLSIZE-ballsize) / 2)); double norm = rel / (npc.h / 2); double bounce = norm * (5 * PI / 12); xvelocity = -(BALLSPEED*ballvelocity) * cos(bounce); yvelocity = (BALLSPEED*ballvelocity) * -sin(bounce); } // ボールとプレイヤーの衝突検出 if (SDL_HasIntersection(&ball, &player)) { double rel = (player.y + (player.h / 2)) - (ball.y + ((BALLSIZE-ballsize) / 2)); double norm = rel / (player.h / 2); double bounce = norm * (5 * PI / 12); xvelocity = (BALLSPEED*ballvelocity) * cos(bounce); yvelocity = (BALLSPEED*ballvelocity) * -sin(bounce); } // コンピュータがボールの方向を付いてくる if (ball.y > npc.y + (npc.h/2)) npc.y += ((SPEED+level*0.5f)*ballvelocity); if (ball.y < npc.y + (npc.h/2)) npc.y -= ((SPEED+level*0.5f)*ballvelocity); // ボールが左右に逃げたら、スコアアップにして、最初フレームから再開 if (ball.x <= 0) { rscore++; serve(); } else if (ball.x + (BALLSIZE-ballsize) >= WIDTH) { lscore++; serve(); games++; } // コンピュータさんを十分倒したら、レベルアップにする if (games == ((level + 1) * 2)) { level++; ballvelocity += 0.25f; ballsize -= 0.2f; games = 0; } // コンピュータのスコアが10になったら、ゲームオーバーだ if (rscore > 9) { isgameover = true; } // ボールが上下に逃げる事に対して守る if (ball.y <= 0 || ball.y + (BALLSIZE-ballsize) >= HEIGHT) yvelocity = -yvelocity; // ボールの移動 ball.x += xvelocity; ball.y += yvelocity; // スコアやレベルの文字 score = std::to_string(lscore) + " " + std::to_string(rscore); slevel = "Lv" + std::to_string(level); // プレイヤーを上下に逃げられない為 if (player.y < 0) player.y = 0; if (player.y + player.h > HEIGHT) player.y = HEIGHT-player.h; // コンピューターを上下に逃げられない為 if (npc.y < 0) npc.y = 0; if (npc.y + npc.h > HEIGHT) npc.y = HEIGHT-npc.h; } void input() { SDL_Event e; const Uint8 *keystates = SDL_GetKeyboardState(NULL); while (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) { running = false; } } if (keystates[SDL_SCANCODE_Q]) running = false; // Qでゲームを終了 if (!isgameover) { if (keystates[SDL_SCANCODE_UP]) player.y -= (SPEED*ballvelocity); // ↑でプレイヤーを上がる if (keystates[SDL_SCANCODE_DOWN]) player.y += (SPEED*ballvelocity); // ↓でプレイヤーを下げる } } void render() { // 黒色背景 SDL_SetRenderDrawColor(renderer, 0x00, 0x00, 0x00, 255); SDL_RenderClear(renderer); frameCount++; timerFPS = SDL_GetTicks() - lastFrame; if (timerFPS < (1000/60)) { SDL_Delay((1000/60) - timerFPS); } // 背景以外もレンダーして SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, 255); // プレイヤー、コンピュータ、とボールを創作 if (!isgameover) { SDL_RenderFillRect(renderer, &player); SDL_RenderFillRect(renderer, &npc); SDL_RenderFillRect(renderer, &ball); } write(score, WIDTH/2+FONTSIZE, FONTSIZE*2); write(slevel, WIDTH/2+FONTSIZE, FONTSIZE*3); if (isgameover) { write("GAME OVER", WIDTH/2+84, HEIGHT/2); } write("076.moe SUWAKO NO PONG v" + version, WIDTH-150, HEIGHT-20); SDL_RenderPresent(renderer); } int main(void) { // SDLを初期化 if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { std::cout << "SDL_Init()に失敗" << '\n'; return -1; } // ウィンドウとレンダーを創作 if (SDL_CreateWindowAndRenderer(WIDTH, HEIGHT, 0, &window, &renderer) < 0) { std::cout << "SDL_CreateWindowAndRenderer()に失敗" << '\n'; SDL_Quit(); return -1; } // フォントを読込 TTF_Init(); font = TTF_OpenFont("Peepo.ttf", FONTSIZE); if (!font) { std::cout << "フォントを読込に失敗" << '\n'; SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return -1; } // 初期設定 running = true; static int lastTime = 0; color.r = color.g = color.b = 255; lscore = rscore = games = 0; ballvelocity = ballsize = 1.0f; level = 1; player.x = 32; player.h = (HEIGHT/4)/(ballsize*1.15f); player.y = (HEIGHT/2) - (player.h/2); player.w = 12; npc = player; npc.x = WIDTH - npc.w - 32; ball.w = ball.h = (BALLSIZE-ballsize); serve(); // ゲームループ while (running) { lastFrame = SDL_GetTicks(); if (lastFrame >= (lastTime + 1000)) { lastTime = lastFrame; fps = frameCount; frameCount = 0; } if (!isgameover) { update(); input(); render(); } else { gameover(); input(); render(); } } // 掃除 TTF_CloseFont(font); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; }