commit 5a9f93e4ea2521b427fbff8c5bc2691b0c30dce0 Author: 諏訪子 Date: Fri Nov 17 11:42:20 2023 +0900 今度から、1レポジトリでやります diff --git a/1.pong/.gitignore b/1.pong/.gitignore new file mode 100644 index 0000000..8e55469 --- /dev/null +++ b/1.pong/.gitignore @@ -0,0 +1 @@ +pong diff --git a/1.pong/CHANGELOG.md b/1.pong/CHANGELOG.md new file mode 100644 index 0000000..0a0d870 --- /dev/null +++ b/1.pong/CHANGELOG.md @@ -0,0 +1,2 @@ +# 1.0.0 +* 最初リリース diff --git a/1.pong/Makefile b/1.pong/Makefile new file mode 100644 index 0000000..8926e8c --- /dev/null +++ b/1.pong/Makefile @@ -0,0 +1,24 @@ +NAME=pong +VERSION=1.0.0 +# Linux、Haiku、かIllumos = /usr、FreeBSDかOpenBSD = /usr/local、NetBSD = /usr/pkg +PREFIX=/usr/local +CC=clang++ +CFLAGS=-I${PREFIX}/include -L${PREFIX}/lib +LDFLAGS=-lSDL2 -lSDL2_ttf +FILES=main.cc + +all: + ${CC} ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS} + +clean: + rm -f ${NAME} + +install: all + mkdir -p ${DESTDIR}${PREFIX}/bin + cp -f ${NAME} ${DESTDIR}${PREFIX}/bin + chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME} + +uninstall: + rm -f ${DESTDIR}${PREFIX}/bin/${NAME} + +.PHONY: all clean install uninstall diff --git a/1.pong/Peepo.ttf b/1.pong/Peepo.ttf new file mode 100644 index 0000000..45a8c38 Binary files /dev/null and b/1.pong/Peepo.ttf differ diff --git a/1.pong/README.md b/1.pong/README.md new file mode 100644 index 0000000..2a5231c --- /dev/null +++ b/1.pong/README.md @@ -0,0 +1,37 @@ +# pong + +初めてSDLだけでゲームを作りました。\ +2時間以内で完成しました。 + +このpongゲームはレベルアップシステムがあり、レベルが上がると徐々に難しくなります。\ +また、NPCが10ポイントを獲得すると、ゲームオーバーになります。 + +## 勉強点 +* C++、超ひさしぶりですから(´・ω・`) +* SDL2(今まではC言語だけで座ったことがある) +* フォントライブラリ +* スコア +* プレイヤーの移動 +* NPCの移動 +* レベルアップ +* ゲームオーバー +* ゲームループ + +## ソフト +* SDL2 +* SDL2_ttf + +## Linux +```sh +make +``` + +## \*BSD +```sh +gmake +``` + +## Illumos +```sh +gmake PREFIX=/usr +``` diff --git a/1.pong/main.cc b/1.pong/main.cc new file mode 100644 index 0000000..027e136 --- /dev/null +++ b/1.pong/main.cc @@ -0,0 +1,256 @@ +#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; +} diff --git a/2.brickbreaker/.gitignore b/2.brickbreaker/.gitignore new file mode 100644 index 0000000..517b0c7 --- /dev/null +++ b/2.brickbreaker/.gitignore @@ -0,0 +1 @@ +brickbreaker diff --git a/2.brickbreaker/Makefile b/2.brickbreaker/Makefile new file mode 100644 index 0000000..b0e3832 --- /dev/null +++ b/2.brickbreaker/Makefile @@ -0,0 +1,15 @@ +NAME=brickbreaker +# Linux、Haiku、かIllumos = /usr、FreeBSDかOpenBSD = /usr/local、NetBSD = /usr/pkg +PREFIX=/usr/local +CC=clang++ +CFLAGS=-I${PREFIX}/include -L${PREFIX}/lib +LDFLAGS=-lSDL2 -lSDL2_mixer -lSDL2_ttf +FILES=main.cc src/ball.cc src/brick.cc src/render.cc + +all: + ${CC} ${CFLAGS} -o ${NAME} ${FILES} ${LDFLAGS} + +clean: + rm -f ${NAME} + +.PHONY: all clean diff --git a/2.brickbreaker/README.md b/2.brickbreaker/README.md new file mode 100644 index 0000000..6c730e8 --- /dev/null +++ b/2.brickbreaker/README.md @@ -0,0 +1,32 @@ +# ブリックブレイカー + +7つレベルがあり、レベルを上がるとより難しくなります。\ +「YOU WIN」と表示されたら、ハイスコアを教えて下さいね。(´・ω・`) + +## 音楽 +[Stas Gavrikさんより](https://youtube.owacon.moe/playlist?list=PLyc7oozhSJMytXF1eWMUAU2zl84W0Nkqg) + +## 勉強点 +* BGM +* オブジェクト指向プログラミング +* オブジェクトを非表示にする事 + +## ソフト +* SDL2 +* SDL2_mixer +* SDL2_ttf + +## Linux +```sh +make +``` + +## \*BSD +```sh +gmake +``` + +## Illumos +```sh +gmake PREFIX=/usr +``` diff --git a/2.brickbreaker/ass/1.ogg b/2.brickbreaker/ass/1.ogg new file mode 100644 index 0000000..c505c21 Binary files /dev/null and b/2.brickbreaker/ass/1.ogg differ diff --git a/2.brickbreaker/ass/2.ogg b/2.brickbreaker/ass/2.ogg new file mode 100644 index 0000000..aa9054c Binary files /dev/null and b/2.brickbreaker/ass/2.ogg differ diff --git a/2.brickbreaker/ass/3.ogg b/2.brickbreaker/ass/3.ogg new file mode 100644 index 0000000..50c0854 Binary files /dev/null and b/2.brickbreaker/ass/3.ogg differ diff --git a/2.brickbreaker/ass/4.ogg b/2.brickbreaker/ass/4.ogg new file mode 100644 index 0000000..19b6d66 Binary files /dev/null and b/2.brickbreaker/ass/4.ogg differ diff --git a/2.brickbreaker/ass/5.ogg b/2.brickbreaker/ass/5.ogg new file mode 100644 index 0000000..b23a90b Binary files /dev/null and b/2.brickbreaker/ass/5.ogg differ diff --git a/2.brickbreaker/ass/6.ogg b/2.brickbreaker/ass/6.ogg new file mode 100644 index 0000000..62d2a6c Binary files /dev/null and b/2.brickbreaker/ass/6.ogg differ diff --git a/2.brickbreaker/ass/7.ogg b/2.brickbreaker/ass/7.ogg new file mode 100644 index 0000000..39315d3 Binary files /dev/null and b/2.brickbreaker/ass/7.ogg differ diff --git a/2.brickbreaker/font.ttf b/2.brickbreaker/font.ttf new file mode 100644 index 0000000..b070b9b Binary files /dev/null and b/2.brickbreaker/font.ttf differ diff --git a/2.brickbreaker/main.cc b/2.brickbreaker/main.cc new file mode 100644 index 0000000..f0d71a2 --- /dev/null +++ b/2.brickbreaker/main.cc @@ -0,0 +1,76 @@ +#include +#include +#include +#include + +#include "src/render.hh" +#include "src/ball.hh" +#include "src/player.hh" +#include "src/brick.hh" + +int main(void) { + Render r; + Player p(r); + Ball bl(r, p); + Brick br(r); + + if (SDL_Init(SDL_INIT_EVERYTHING) < 0) { + std::cout << "SDL_Init()に失敗" << '\n'; + return -1; + } + + if (SDL_CreateWindowAndRenderer(r.width, r.height, 0, &r.window, &r.renderer) < 0) { + std::cout << "SDL_CreateWindowAndRenderer()に失敗" << '\n'; + SDL_Quit(); + return -1; + } + + if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048) < 0) { + std::cout << "Mix_OpenAudio()に失敗" << '\n'; + SDL_DestroyRenderer(r.renderer); + SDL_DestroyWindow(r.window); + SDL_Quit(); + return -1; + } + + SDL_SetWindowTitle(r.window, "ブリックブレイカー"); + + TTF_Init(); + r.font = TTF_OpenFont("font.ttf", r.fontsize); + if (!r.font) { + std::cout << "フォントを読込に失敗" << '\n'; + SDL_DestroyRenderer(r.renderer); + SDL_DestroyWindow(r.window); + Mix_CloseAudio(); + SDL_Quit(); + return -1; + } + + static int lastTime = 0; + br.resetBricks(r, p, bl); + + while (r.running) { + r.lastFrame = SDL_GetTicks(); + if (r.lastFrame >= lastTime + 1000) { + lastTime = r.lastFrame; + r.fps = r.frameCount; + r.frameCount = 0; + } + + if (!r.gameover) { + r.update(r, p, bl, br); + } + r.input(p); + r.render(p, bl, br); + } + + TTF_CloseFont(r.font); + SDL_DestroyRenderer(r.renderer); + SDL_DestroyWindow(r.window); + SDL_Quit(); + Mix_FreeMusic(r.music); + Mix_CloseAudio(); + TTF_Quit(); + + return 0; +} diff --git a/2.brickbreaker/src/ball.cc b/2.brickbreaker/src/ball.cc new file mode 100644 index 0000000..d7fa4c3 --- /dev/null +++ b/2.brickbreaker/src/ball.cc @@ -0,0 +1,9 @@ +#include "ball.hh" + +void Ball::resetBall(Render &r, Player &p) { + p.player.x = (r.width / 2) - (p.player.w / 2); + Ball::ball.y = p.player.y - (p.player.h * 4); + Ball::yvelocity = Ball::ballspeed / 2; + Ball::xvelocity = 0; + Ball::ball.x = r.width / 2 - (Ball::size / 2); +} diff --git a/2.brickbreaker/src/ball.hh b/2.brickbreaker/src/ball.hh new file mode 100644 index 0000000..9f03519 --- /dev/null +++ b/2.brickbreaker/src/ball.hh @@ -0,0 +1,30 @@ +#ifndef BALL_H +#define BALL_H + +#include +#include + +#include "player.hh" + +class Ball { + public: + float ballspeed = 8.0f; + int size = 16; + + float xvelocity; + float yvelocity; + + SDL_Rect ball; + + void resetBall(Render &r, Player &p); + + Ball(Render& r, Player& p) { + ball.y = p.player.y - (p.player.h / 2); + yvelocity = ballspeed / 2; + xvelocity = ball.x = 0; + ball.w = ball.h = size; + ball.x = r.width / 2 - (size / 2); + } +}; + +#endif diff --git a/2.brickbreaker/src/brick.cc b/2.brickbreaker/src/brick.cc new file mode 100644 index 0000000..f28c4e4 --- /dev/null +++ b/2.brickbreaker/src/brick.cc @@ -0,0 +1,67 @@ +#include +#include +#include +#include + +#include "render.hh" +#include "player.hh" +#include "ball.hh" +#include "brick.hh" + +void Brick::resetBricks(Render &r, Player &p, Ball &bl) { + srand(static_cast(time(nullptr))); + r.c1r = rand() % 256; + r.c1g = rand() % 256; + r.c1b = rand() % 256; + r.c2r = rand() % 256; + r.c2g = rand() % 256; + r.c2b = rand() % 256; + r.c3r = rand() % 256; + r.c3g = rand() % 256; + r.c3b = rand() % 256; + r.c4r = rand() % 256; + r.c4g = rand() % 256; + r.c4b = rand() % 256; + r.c5r = rand() % 256; + r.c5g = rand() % 256; + r.c5b = rand() % 256; + r.c6r = rand() % 256; + r.c6g = rand() % 256; + r.c6b = rand() % 256; + + + if (r.level > 1) { + Mix_HaltMusic(); + } + + std::string music = "ass/" + std::to_string(r.level) + ".ogg"; + r.music = Mix_LoadMUS(music.c_str()); + if (Mix_PlayMusic(r.music, -1) < 0) { + std::cout << "OGGファイルのエラー:" << Mix_GetError() << '\n'; + r.running = false; + TTF_CloseFont(r.font); + SDL_DestroyRenderer(r.renderer); + SDL_DestroyWindow(r.window); + SDL_Quit(); + Mix_CloseAudio(); + TTF_Quit(); + } + + for (int i = 0; i < Brick::col * Brick::row; i++) { + Brick::bricks[i] = 1; + } + + bl.size -= 2; + bl.ballspeed += 1.4f; + p.player.w -= 1.4f; + p.player.x = (r.width / 2) - (p.player.w / 2); + bl.ball.y = p.player.y - (p.player.h * 4); + bl.yvelocity = bl.ballspeed / 2; + bl.xvelocity = 0; + bl.ball.x = r.width / 2 - (bl.size / 2); +} + +void Brick::setBricks(int i) { + Brick::brick.x = (((i%Brick::col) + 1) * Brick::gaps) + ((i%Brick::col) * Brick::brick.w) - (Brick::gaps/2); + Brick::brick.y = Brick::brick.h * 3 + (((i%Brick::row) + 1) * Brick::gaps) + ((i%Brick::row) * Brick::brick.h) - (Brick::gaps/2); +} diff --git a/2.brickbreaker/src/brick.hh b/2.brickbreaker/src/brick.hh new file mode 100644 index 0000000..61f9125 --- /dev/null +++ b/2.brickbreaker/src/brick.hh @@ -0,0 +1,31 @@ +#ifndef BRICK_H +#define BRICK_H + +#include +#include + +#include "render.hh" +#include "player.hh" +#include "ball.hh" + +class Brick { + public: + int col = 7; + int row = 5; + int gaps = 16; + + bool bricks[7*5]; + + SDL_Color color = {255, 255, 255}; + SDL_Rect brick; + + void resetBricks(Render &r, Player &p, Ball &bl); + void setBricks(int i); + + Brick(Render& r) { + brick.w = (r.width - (gaps * col)) / col; + brick.h = 22; + } +}; + +#endif diff --git a/2.brickbreaker/src/player.hh b/2.brickbreaker/src/player.hh new file mode 100644 index 0000000..3e2cd05 --- /dev/null +++ b/2.brickbreaker/src/player.hh @@ -0,0 +1,25 @@ +#ifndef PLAYER_H +#define PLAYER_H + +#include +#include + +#include "render.hh" + +class Player { + public: + SDL_Rect player, lives; + + int score = 0; + int scoreMultiplier = 1; + int livesCount = 3; + + Player(Render& r) { + player.h = 12; + player.y = r.height - player.h - 32; + player.w = r.width / 4; + player.x = (r.width / 2) - (player.w / 2); + } +}; + +#endif diff --git a/2.brickbreaker/src/render.cc b/2.brickbreaker/src/render.cc new file mode 100644 index 0000000..ca999c7 --- /dev/null +++ b/2.brickbreaker/src/render.cc @@ -0,0 +1,170 @@ +#include "render.hh" +#include "ball.hh" +#include "player.hh" +#include "brick.hh" + +#define PI 3.14 + +void Render::gameOver(Player &p, Brick &br, bool winner) { + if (winner) { + Render::winner = true; + } else { + Render::winner = false; + } + + Render::gameover = true; + Mix_HaltMusic(); +} + +void Render::write(Player &p, Brick &br, std::string text, int x, int y) { + SDL_Surface *surface; + SDL_Texture *texture; + const char* t = text.c_str(); + surface = TTF_RenderText_Solid(Render::font, t, br.color); + texture = SDL_CreateTextureFromSurface(Render::renderer, surface); + + p.lives.w = surface->w; + p.lives.h = surface->h; + p.lives.x = x - p.lives.w; + p.lives.y = y - p.lives.h; + + SDL_FreeSurface(surface); + SDL_RenderCopy(Render::renderer, texture, NULL, &p.lives); + SDL_DestroyTexture(texture); +} + +void Render::update(Render &r, Player &p, Ball &bl, Brick &br) { + if (p.livesCount <= 0) { + gameOver(p, br, false); + } + + if (SDL_HasIntersection(&bl.ball, &p.player)) { + double rel = (p.player.x + ((float)p.player.w/2)) - ((float)bl.ball.x + ((float)bl.size/2)); + double norm = rel / ((float)p.player.w/2); + double bounce = norm * (5*PI/12); + + bl.yvelocity = -bl.ballspeed * cos(bounce); + bl.xvelocity = bl.ballspeed * -sin(bounce); + p.scoreMultiplier = 1; + } + + if (bl.ball.y <= 0) { + bl.yvelocity = -bl.yvelocity; + } + if (bl.ball.y + bl.size >= Render::height) { + bl.yvelocity = -bl.yvelocity; + p.livesCount--; + bl.resetBall(r, p); + } + if (bl.ball.x <= 0 || bl.ball.x + bl.size >= Render::width) { + bl.xvelocity = -bl.xvelocity; + } + bl.ball.x += bl.xvelocity; + bl.ball.y += bl.yvelocity; + if (p.player.x < 0) { + p.player.x = 0; + } + if (p.player.x + p.player.w > Render::width) { + p.player.x = Render::width - p.player.w; + } + + bool reset = true; + for (int i = 0; i < br.col*br.row; i++) { + br.setBricks(i); + + if (SDL_HasIntersection(&bl.ball, &br.brick) && br.bricks[i]) { + br.bricks[i] = 0; + p.score += 100 * p.scoreMultiplier; + p.scoreMultiplier++; + + if (bl.ball.x >= br.brick.x) { + bl.xvelocity = -bl.xvelocity; + bl.ball.x -= 1; + } + if (bl.ball.x <= br.brick.x) { + bl.xvelocity = -bl.xvelocity; + bl.ball.x += 1; + } + if (bl.ball.y <= br.brick.y) { + bl.yvelocity = -bl.yvelocity; + bl.xvelocity = -bl.xvelocity; + bl.ball.y -= 1; + } + if (bl.ball.y >= br.brick.y) { + bl.yvelocity = -bl.yvelocity; + bl.xvelocity = -bl.xvelocity; + bl.ball.y += 1; + } + } + + if (br.bricks[i]) { + reset = false; + } + } + + if (reset) { + Render::level++; + if (r.level > 7) { + gameOver(p, br, true); + } else { + br.resetBricks(r, p, bl); + } + } +} + +void Render::input(Player &p) { + SDL_Event e; + const Uint8 *keystates = SDL_GetKeyboardState(NULL); + + while (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT) { + Render::running = false; + } + } + + if (keystates[SDL_SCANCODE_Q]) Render::running = false; + if (!Render::gameover) { + if (keystates[SDL_SCANCODE_LEFT]) p.player.x -= Render::xpos; + if (keystates[SDL_SCANCODE_RIGHT]) p.player.x += Render::xpos; + } +} + +void Render::render(Player &p, Ball &bl, Brick &br) { + SDL_SetRenderDrawColor(Render::renderer, 0x00, 0x00, 0x00, 255); + SDL_RenderClear(Render::renderer); + + Render::frameCount++; + Render::timerFPS = SDL_GetTicks() - Render::lastFrame; + + if (Render::timerFPS < (1000/60)) { + SDL_Delay((1000/60) - Render::timerFPS); + } + + SDL_SetRenderDrawColor(Render::renderer, 255, 255, 255, 255); + SDL_RenderFillRect(Render::renderer, &p.player); + SDL_RenderFillRect(Render::renderer, &bl.ball); + write(p, br, "SCORE: " + std::to_string(p.score), Render::width, Render::fontsize*1.5f); + write(p, br, "LIVES: " + std::to_string(p.livesCount), 130, Render::fontsize*1.5f); + write(p, br, "LEVEL: " + std::to_string(Render::level), 130, Render::fontsize*3.5f); + + if (Render::gameover) { + if (Render::winner) write(p, br, "YOU WIN", Render::width/2+Render::fontsize, Render::height/2); + else write(p, br, "YOU LOSS", Render::width/2+Render::fontsize, Render::height/2); + } + + for (int i = 0; i < br.col*br.row; i++) { + SDL_SetRenderDrawColor(Render::renderer, c1r, c1g, c1b, 255); + if (i%2 == 0) SDL_SetRenderDrawColor(Render::renderer, c2r, c2g, c2b, 255); + if (i%3 == 0) SDL_SetRenderDrawColor(Render::renderer, c3r, c3g, c3b, 255); + if (i%4 == 0) SDL_SetRenderDrawColor(Render::renderer, c4r, c4g, c4b, 255); + if (i%5 == 0) SDL_SetRenderDrawColor(Render::renderer, c5r, c5g, c5b, 255); + if (i%6 == 0) SDL_SetRenderDrawColor(Render::renderer, c6r, c6g, c6b, 255); + + if (br.bricks[i]) { + br.setBricks(i); + SDL_RenderFillRect(Render::renderer, &br.brick); + } + } + + SDL_RenderPresent(Render::renderer); +} diff --git a/2.brickbreaker/src/render.hh b/2.brickbreaker/src/render.hh new file mode 100644 index 0000000..a929a82 --- /dev/null +++ b/2.brickbreaker/src/render.hh @@ -0,0 +1,52 @@ +#ifndef RENDER_H +#define RENDER_H + +#include +#include +#include +#include + +class Player; +class Ball; +class Brick; + +class Render { + public: + bool running, gameover, winner; + int frameCount, timerFPS, lastFrame, fps = 0; + + int width = 620; + int height = 720; + int fontsize = 16; + int xpos = 9; + int level = 1; + + // 色 + int c1r, c1g, c1b; + int c2r, c2g, c2b; + int c3r, c3g, c3b; + int c4r, c4g, c4b; + int c5r, c5g, c5b; + int c6r, c6g, c6b; + + SDL_Window *window; + SDL_Renderer *renderer; + TTF_Font* font; + Mix_Music* music; + + void update(Render &r, Player &p, Ball &bl, Brick &br); + void input(Player &p); + void render(Player &p, Ball &bl, Brick &br); + + Render() { + winner = false; + gameover = false; + running = true; + } + + private: + void gameOver(Player &p, Brick &br, bool winner); + void write(Player &p, Brick &br, std::string text, int x, int y); +}; + +#endif