257 行
6.6 KiB
C++
257 行
6.6 KiB
C++
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL_ttf.h>
|
|
#include <iostream>
|
|
|
|
#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;
|
|
}
|