Poniżej jeszcze plik .cpp “silnika” gry:
#include "game.h"
#include <SDL2/SDL_image.h>
#include <iostream>
#include "board.h"
#include "utilities.h"
#include "enums.h"
Game::Game(int argc, char* argv[]) :
//SDL2 and it's subsystems initialization
sdl_init_was_correct_(SDL_Init(SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS) == 0 ? true : false),
img_init_was_correct_(!(IMG_Init(IMG_INIT_PNG) & IMG_INIT_PNG) == 0 ? true : false),
mixer_init_was_correct_(Mix_OpenAudio(MIX_DEFAULT_FREQUENCY, MIX_DEFAULT_FORMAT, 2, 1024) == 0 ? true : false),
ttf_init_was_correct_(TTF_Init() == 0 ? true : false),
//Create textures
score_texture_(load_texture("../img/score.png", renderer_)),
boost_texture_(load_texture("../img/boost.png", renderer_)),
wall_texture_(load_texture("../img/wall.png", renderer_)),
pacman_open_texture_(load_texture("../img/pacman_open.png", renderer_)),
pacman_close_texture_(load_texture("../img/pacman_close.png", renderer_)),
pacman_boost_texture_(load_texture("../img/pacman_boost.png", renderer_)),
clyde_texture_(load_texture("../img/clyde.png", renderer_)),
pinky_texture_(load_texture("../img/pinky.png", renderer_)),
blinky_texture_(load_texture("../img/blinky.png", renderer_)),
inky_texture_(load_texture("../img/inky.png", renderer_)),
live_texture_(load_texture("../img/live.png", renderer_)),
cherry_texture_(load_texture("../img/cherry.png", renderer_)),
strawberry_texture_(load_texture("../img/strawberry.png", renderer_)),
orange_texture_(load_texture("../img/orange.png", renderer_)),
apple_texture_(load_texture("../img/apple.png", renderer_)),
melon_texture_(load_texture("../img/melon.png", renderer_)),
galaxian_texture_(load_texture("../img/galaxian.png", renderer_)),
bell_texture_(load_texture("../img/bell.png", renderer_)),
key_texture_(load_texture("../img/key.png", renderer_)),
eyes_texture_(load_texture("../img/eyes.png", renderer_)),
scared_texture_(load_texture("../img/scared.png", renderer_)),
//Prepare sound effects
beginning_sound_(Mix_LoadWAV("../wav/beginning.wav")),
move_sound_(Mix_LoadWAV("../wav/move.wav")),
death_sound_(Mix_LoadWAV("../wav/death.wav")),
eat_fruit_sound_(Mix_LoadWAV("../wav/eat_fruit.wav")),
eat_ghost_sound_(Mix_LoadWAV("../wav/eat_ghost.wav")),
booster_sound_(Mix_LoadWAV("../wav/booster.wav")),
game_over_sound_(Mix_LoadWAV("../wav/over.wav")),
//Make window and it's renderer
window_(SDL_CreateWindow("Pacman", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_width_, screen_height_, SDL_WINDOW_SHOWN)),
renderer_(SDL_CreateRenderer(window_, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)),
//Make board with ASCII representation of the game
board_(new Board(board_txt_path_)),
//Make Pacman (ghosts can't be defined here - they're in body of constructor)
pacman_(new Pacman(board_->get_starting_position_y(symbols::PACMAN), board_->get_starting_position_x(symbols::PACMAN))),
//Other stuff
score_(0),
highest_score_(0),
lives_(3),
eaten_scores_(0),
eaten_ghosts_(0),
time_of_status_change_(0),
time_from_start_(0),
time_from_chase_(0),
time_from_random_(20'000),
update_actual_score_(true),
update_highest_score_(true),
render_game_over_(true),
render_pacman_new_status_(true),
exit_(false),
start_(false),
win_(false),
game_over_(false),
was_reset_(true),
update_time_from_chase_(false),
update_time_from_random_(false),
new_direction_(direction::NONE),
stored_direction_(direction::NONE),
if_possible_direction_(direction::NONE)
{
//Disable cursor and check if you succeed
SDL_ShowCursor(SDL_DISABLE);
if(SDL_ShowCursor(SDL_QUERY) == SDL_DISABLE) {
cursor_was_disabled_ = true;
} else {
cursor_was_disabled_ = false;
}
make_ghosts();
Mix_AllocateChannels(7);
was_init_correct();
if(!Mix_Playing(6)) {
Mix_HaltChannel(-1);
Mix_PlayChannel(6, beginning_sound_, 0);
}
}
Game::~Game()
{
delete board_;
delete pacman_;
delete_ghosts();
Mix_FreeChunk(beginning_sound_);
Mix_FreeChunk(move_sound_);
Mix_FreeChunk(death_sound_);
Mix_FreeChunk(eat_fruit_sound_);
Mix_FreeChunk(eat_ghost_sound_);
Mix_FreeChunk(booster_sound_);
Mix_FreeChunk(game_over_sound_);
SDL_DestroyTexture(score_texture_);
SDL_DestroyTexture(boost_texture_);
SDL_DestroyTexture(wall_texture_);
SDL_DestroyTexture(pacman_open_texture_);
SDL_DestroyTexture(pacman_close_texture_);
SDL_DestroyTexture(pacman_boost_texture_);
SDL_DestroyTexture(clyde_texture_);
SDL_DestroyTexture(pinky_texture_);
SDL_DestroyTexture(inky_texture_);
SDL_DestroyTexture(blinky_texture_);
SDL_DestroyTexture(live_texture_);
SDL_DestroyTexture(cherry_texture_);
SDL_DestroyTexture(strawberry_texture_);
SDL_DestroyTexture(orange_texture_);
SDL_DestroyTexture(apple_texture_);
SDL_DestroyTexture(melon_texture_);
SDL_DestroyTexture(galaxian_texture_);
SDL_DestroyTexture(bell_texture_);
SDL_DestroyTexture(key_texture_);
SDL_DestroyTexture(eyes_texture_);
SDL_DestroyTexture(scared_texture_);
SDL_DestroyRenderer(renderer_);
SDL_DestroyWindow(window_);
IMG_Quit();
Mix_CloseAudio();
SDL_Quit();
}
void Game::was_init_correct()
{
if(!sdl_init_was_correct_) {
std::cerr << "Game::was_init_correct(): SDL_Error: " << SDL_GetError() << std::endl;
throw "SDL_Init() failed!";
} else if(!img_init_was_correct_) {
std::cerr << "Game::was_init_correct(): IMG_Error: " << IMG_GetError() << std::endl;
throw "IMG_Init() failed!";
} else if(!mixer_init_was_correct_) {
std::cerr << "Game::was_init_correct(): Mix_Error: " << Mix_GetError() << std::endl;
throw "Mix_OpenAudio() failed!";
} else if(!ttf_init_was_correct_) {
std::cerr << "Game::was_init_correct(): TTF_Error: " << TTF_GetError() << std::endl;
throw "TTF_Init() failed!";
} else if(!cursor_was_disabled_) {
std::cerr << "Game::was_init_correct(): SDL_Error: " << SDL_GetError() << std::endl;
throw "SDL_ShowCursor() failed! Cursor was not disabled!";
} else if(Mix_AllocateChannels(-1) != 7) {
std::cerr << "Game:was_init_correct(): Mix_AllocateChannels(-1): " << Mix_AllocateChannels(-1) << std::endl;
throw "Mix_AllocateChannels() failed! Number of channels have to be 7!";
}
}
void Game::make_ghosts()
{
ghosts_[0] = new Clyde(board_->get_starting_position_x(symbols::CLYDE), board_->get_starting_position_y(symbols::CLYDE), 100'000, 100'000, 10'000);
ghosts_[1] = new Pinky(board_->get_starting_position_x(symbols::PINKY), board_->get_starting_position_y(symbols::PINKY), 0, 0, 2'000);
ghosts_[2] = new Blinky(board_->get_starting_position_x(symbols::BLINKY), board_->get_starting_position_y(symbols::BLINKY), 100'000, 0, 0);
ghosts_[3] = new Inky(board_->get_starting_position_x(symbols::INKY), board_->get_starting_position_y(symbols::INKY), 0, 100'000, 5'000);
}
void Game::delete_ghosts()
{
for(int i = 0; i < 4; ++i) {
delete ghosts_[i];
}
}
void Game::execute()
{
while(!exit_) {
if(!start_ && !game_over_) {
if(was_reset_) {
render();
was_reset_ = false;
}
//Time for other threads (CPU optimization)
SDL_Delay(10);
input();
} else {
render();
input();
if(!game_over_) {
update();
}
}
}
}
void Game::render()
{
//Black background
SDL_SetRenderDrawColor(renderer_, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer_);
render_maze();
render_pacman();
render_ghosts();
render_manual();
render_scores();
//After above it's time to swap buffer (render new content)
SDL_RenderPresent(renderer_);
}
void Game::render_maze()
{
int size = board_->get_size_of_element();
SDL_Rect view_port;
view_port.w = size;
view_port.h = size;
for(int i = 0; i < board_->get_nr_rows(); ++i) {
for(int j = 0; j < board_->get_nr_cols(); ++j) {
view_port.x = j * size;
view_port.y = i * size;
if(board_->get_element_by_row_col(i, j) == static_cast<char>(symbols::WALL)) {
renderTexture(wall_texture_, renderer_, view_port);
} else if(board_->get_element_by_row_col(i, j) == static_cast<char>(symbols::SCORE) && !board_->is_eaten(view_port.x, view_port.y)) {
renderTexture(score_texture_, renderer_, view_port);
} else if(board_->get_element_by_row_col(i, j) == static_cast<char>(symbols::BOOSTER) && !board_->is_eaten(view_port.x, view_port.y)) {
renderTexture(boost_texture_, renderer_, view_port);
} else if(board_->get_element_by_row_col(i, j) == static_cast<char>(symbols::FRUIT) && board_->is_fruit(view_port.x, view_port.y)) {
switch(board_->get_fruit_type()) {
case object_type::CHERRY:
renderTexture(cherry_texture_, renderer_, view_port);
break;
case object_type::STRAWBERRY:
renderTexture(strawberry_texture_, renderer_, view_port);
break;
case object_type::ORANGE:
renderTexture(orange_texture_, renderer_, view_port);
break;
case object_type::APPLE:
renderTexture(apple_texture_, renderer_, view_port);
break;
case object_type::MELON:
renderTexture(melon_texture_, renderer_, view_port);
break;
case object_type::GALAXIAN:
renderTexture(galaxian_texture_, renderer_, view_port);
break;
case object_type::BELL:
renderTexture(bell_texture_, renderer_, view_port);
break;
case object_type::KEY:
renderTexture(key_texture_, renderer_, view_port);
break;
default:
std::cerr << "Game::render_maze(): " << board_->get_element_by_row_col(i, j) << std::endl;
throw "Game::render_maze() failed! There is not such a fruit!";
}
}
}
}
}
void Game::render_pacman()
{
SDL_Rect view_port;
view_port.w = board_->get_size_of_element();
view_port.h = board_->get_size_of_element();
view_port.y = pacman_->get_y();
view_port.x = pacman_->get_x();
if(pacman_->get_status() == status::BOOST) {
renderTexture(pacman_boost_texture_, renderer_, view_port, rotation_texture_angle());
render_pacman_new_status_ = true;
} else if(pacman_->get_status() == status::OPEN) {
renderTexture(pacman_open_texture_, renderer_, view_port, rotation_texture_angle());
if(time_of_status_change_ < SDL_GetTicks() - snap_velocity_ && pacman_->get_direction() != direction::NONE && render_pacman_new_status_) {
pacman_->set_status(status::CLOSE);
time_of_status_change_ = SDL_GetTicks();
}
} else if(pacman_->get_status() == status::CLOSE) {
renderTexture(pacman_close_texture_, renderer_, view_port, rotation_texture_angle());
if(time_of_status_change_ < SDL_GetTicks() - snap_velocity_ && pacman_->get_direction() != direction::NONE && render_pacman_new_status_) {
pacman_->set_status(status::OPEN);
time_of_status_change_ = SDL_GetTicks();
}
}
}
void Game::render_ghosts()
{
SDL_Rect view_port;
view_port.w = board_->get_size_of_element();
view_port.h = board_->get_size_of_element();
for(int i = 0; i < 4; ++i) {
view_port.x = ghosts_[i]->get_x();
view_port.y = ghosts_[i]->get_y();
if(ghosts_[i]->get_is_dead()) {
renderTexture(eyes_texture_, renderer_, view_port);
} else {
if(ghosts_[i]->get_is_scared()) {
renderTexture(scared_texture_, renderer_, view_port);
} else {
if(i == 0) {
renderTexture(clyde_texture_, renderer_, view_port);
} else if(i == 1) {
renderTexture(pinky_texture_, renderer_, view_port);
} else if(i == 2) {
renderTexture(blinky_texture_, renderer_, view_port);
} else {
renderTexture(inky_texture_, renderer_, view_port);
}
}
}
}
}
double Game::rotation_texture_angle() const
{
switch(static_cast<int>(pacman_->get_direction())) {
case static_cast<int>(direction::UP):
return 270.0;
case static_cast<int>(direction::LEFT):
return 180.0;
case static_cast<int>(direction::DOWN):
return 90.0;
case static_cast<int>(direction::RIGHT):
return 0.0;
case static_cast<int>(direction::NONE):
return 0.0;
default:
std::cerr << "Game::rotation_texture_angle(): " << static_cast<int>(pacman_->get_direction()) << std::endl;
throw "Game::rotation_texture_angle() failed! There is not such a direction";
}
}
void Game::render_manual()
{
SDL_Color font_color = {255, 255, 255, 255};
if(start_) {
int x_position_of_live_image = 585;
int size_of_live_image = 2 * board_->get_size_of_element();
SDL_Rect view_port;
view_port.w = size_of_live_image;
view_port.h = size_of_live_image;
view_port.y = 280;
for(int i = 0; i < lives_; ++i) {
view_port.x = x_position_of_live_image + i * size_of_live_image;
renderTexture(live_texture_, renderer_, view_port);
}
} else {
if(game_over_) {
manual_caption_font_ = renderTextWrapped("It's over! Press space to reset", font_name_, font_color, manual_font_size_, renderer_, 200);
renderTexture(manual_caption_font_, renderer_, 585, 260);
} else if(win_) {
manual_caption_font_ = renderTextWrapped("You won! Press space to start next level", font_name_, font_color, manual_font_size_, renderer_, 200);
renderTexture(manual_caption_font_, renderer_, 585, 260);
} else {
manual_caption_font_ = renderTextWrapped("Press space to start", font_name_, font_color, manual_font_size_, renderer_, 200);
renderTexture(manual_caption_font_, renderer_, 585, 260);
}
}
}
void Game::render_scores()
{
SDL_Color font_color;
font_color = {255, 0, 0, 255};
actual_score_caption_font_ = renderText("SCORE", font_name_, font_color, caption_font_size_, renderer_);
renderTexture(actual_score_caption_font_, renderer_, 585, 40);
if(update_actual_score_) {
font_color = {255, 255, 255, 255};
actual_score_font_ = renderText(std::to_string(score_), font_name_, font_color, score_font_size_, renderer_);
update_actual_score_ = false;
}
renderTexture(actual_score_font_, renderer_, 585, 100);
font_color = {0, 255, 0, 255};
highest_score_caption_font_ = renderText("HIGH.", font_name_, font_color, caption_font_size_, renderer_);
renderTexture(highest_score_caption_font_, renderer_, 585, 150);
if(update_highest_score_) {
font_color = {255, 255, 255, 255};
highest_score_font_ = renderText(std::to_string(highest_score_), font_name_, font_color, score_font_size_, renderer_);
update_highest_score_ = false;
}
renderTexture(highest_score_font_, renderer_, 585, 210);
SDL_DestroyTexture(actual_score_caption_font_);
SDL_DestroyTexture(highest_score_caption_font_);
}