tetris/Application.cpp

422 lines
9.8 KiB
C++

/*
* Application.cpp
*
* Created on: May 4, 2013
* Author: chibi_000
*/
#include "Application.h"
#include <iostream>
#include <sstream>
const unsigned char pcols[][4] = {
{0xf0, 0xf0, 0xf0, 0xa0}, // finished line
{0xf0, 0xf0, 0xf0, 0x05}, // empty block
{0x00, 0xf0, 0xf0, 0xa0}, // line block
{0xf0, 0xa5, 0x00, 0xa0}, // L block
{0x40, 0x40, 0xf0, 0xa0}, // reverse L block
{0xf0, 0x40, 0xf0, 0xa0}, // T block
{0xf0, 0x00, 0x00, 0xa0}, // 2 block
{0x00, 0xf0, 0x00, 0xa0}, // S block
{0xf0, 0xf0, 0x00, 0xa0} // O block
};
/***********************************
* Constructor *
***********************************/
Application::Application()
{
this->stop_flag = false;
this->paused = false;
}
/***********************************
* Initialize, dispose *
***********************************/
bool Application::initialize()
{
// Load images
background_texture.loadFromFile("Assets/background.tga");
background_texture.setSmooth(true);
// Load font
font.loadFromFile("Assets/OptimusPrinceps.ttf");
// Load window
this->mainWindow.create(sf::VideoMode(100, 100), "Tetris");
this->mainWindow.setSize(sf::Vector2u(640, 480));
return true;
}
void Application::onStart()
{
}
void Application::dispose()
{
}
/***********************************
* Main loop (run) *
***********************************/
int Application::run()
{
// Initialize
if (!this->initialize())
{
this->dispose();
return -1;
}
sf::Clock clock;
// Before start handler
this->onStart();
// Main loop
while (!this->stop_flag)
{
// Get elapsed time
sf::Time elapsed = clock.restart();
// Handle events
sf::Event event;
while (this->mainWindow.pollEvent(event))
this->onMainWindowEvent(event);
// Update logic
onLogicUpdate(elapsed);
// Update graphics
onRender(elapsed);
}
// Cleanup
this->dispose();
return 0;
}
void Application::stop()
{
this->mainWindow.close();
this->stop_flag = true;
}
/***********************************
* Event handler *
***********************************/
void Application::onMainWindowEvent(sf::Event& e)
{
switch (e.type)
{
case sf::Event::Closed :
this->stop();
break;
case sf::Event::KeyPressed:
this->onKeyDown(e);
break;
case sf::Event::Resized:
this->onResized(e);
break;
default:
break;
}
}
void Application::onKeyDown(sf::Event& e)
{
switch(e.key.code)
{
case sf::Keyboard::R:
this->game = TetrisGame();
break;
case sf::Keyboard::Left:
this->game.moveLeft();
break;
case sf::Keyboard::Right:
this->game.moveRight();
break;
case sf::Keyboard::Down:
this->game.moveDown();
break;
case sf::Keyboard::Up:
this->game.rotate();
break;
case sf::Keyboard::Escape:
this->stop();
break;
case sf::Keyboard::T:
this->game.tick();
break;
case sf::Keyboard::P:
this->paused = !this->paused;
break;
default:
break;
}
}
void Application::onResized(sf::Event& e)
{
sf::Vector2f center(e.size.width / 2, e.size.height / 2);
sf::Vector2f size(e.size.width, e.size.height);
sf::View view(center, size);
this->mainWindow.setView(view);
}
/***********************************
* Renderer *
***********************************/
void Application::onRender(sf::Time& elapsed)
{
mainWindow.clear(sf::Color::Black);
// Render game
this->drawBackground();
this->drawTetrisGridBackground();
this->drawTetrisGrid();
this->drawNextPieceBackground();
this->drawNextPiece();
this->drawText();
// Render ui
// this->ui.render(mainWindow);
mainWindow.display();
}
void Application::drawBackground()
{
// Create sprite
sf::Sprite back(background_texture);
// Calculate scale
sf::Vector2u img_size = this->background_texture.getSize();
sf::Vector2f scr_size = this->mainWindow.getView().getSize();
float rap_x = scr_size.x / (float)(img_size.x);
float rap_y = scr_size.y / (float)(img_size.y);
back.setScale(std::max(rap_x, rap_y), std::max(rap_x, rap_y));
// Draw
this->mainWindow.draw(back);
}
void Application::drawTetrisGridBackground()
{
// Calculate size
sf::Vector2f scr_size = this->mainWindow.getView().getSize();
sf::Vector2f rect_size((scr_size.y - 10) * 0.6f, scr_size.y - 10);
sf::Vector2f marginrect_size = rect_size + sf::Vector2f(4, 4);
// Calculate position
sf::Vector2f marginrect_pos = 0.5f * (scr_size - marginrect_size);
sf::Vector2f rect_pos = 0.5f * (scr_size - rect_size);
// Create margin rectangle
sf::RectangleShape margin (marginrect_size);
margin.setPosition(marginrect_pos);
margin.setFillColor(sf::Color(0x00, 0x00, 0x00, 0x40));
// Create rectangle
sf::RectangleShape rect (rect_size);
rect.setPosition(rect_pos);
rect.setFillColor(sf::Color(0x02, 0x0a, 0x1a, 0x77));
// Draw
this->mainWindow.draw(margin);
this->mainWindow.draw(rect);
}
void Application::drawTetrisGrid()
{
// Calculate positions, sizes
sf::Vector2f scr_size = this->mainWindow.getView().getSize();
sf::Vector2f container_size((scr_size.y - 10) * 0.6f - 10, scr_size.y - 20);
sf::Vector2f container_pos = 0.5f * (scr_size - container_size);
sf::Vector2f block_margin_size (container_size.x / 10, container_size.y / 20);
sf::Vector2f block_size = block_margin_size - sf::Vector2f(2, 2);
// Draw every block
for (int i = 0; i < 20; i++)
for (int j = 0; j < 10; j++)
{
// Get block
int val = this->game.get(j, i);
// Calculate position
float x = container_pos.x + block_margin_size.x * j + 1;
float y = container_pos.y + block_margin_size.y * i + 1;
// Create block shape
sf::RectangleShape shape(block_size);
shape.setFillColor(sf::Color(pcols[val+1][0], pcols[val+1][1], pcols[val+1][2], pcols[val+1][3]));
shape.setPosition(x, y);
// Draw block
this->mainWindow.draw(shape);
}
}
void Application::drawNextPieceBackground()
{
// Calculate position
sf::Vector2f scr_size = this->mainWindow.getView().getSize();
sf::Vector2f tetris_grid_size((scr_size.y - 10) * 0.6f, scr_size.y - 10);
sf::Vector2f tetris_grid_pos = 0.5f * (scr_size - tetris_grid_size);
sf::Vector2f block_margin_size (tetris_grid_size.x / 10, tetris_grid_size.y / 20);
sf::Vector2f next_text_pos = tetris_grid_pos + sf::Vector2f(tetris_grid_size.x + 10, 0);
sf::Vector2f next_grid_pos = next_text_pos + sf::Vector2f(0, 50);
sf::Vector2f next_grid_size = 5.0f * block_margin_size + sf::Vector2f(4, 4);
// Draw text
sf::Text txt;
txt.setString("Next piece");
txt.setFont(this->font);
txt.setCharacterSize(25);
txt.setColor(sf::Color::White);
txt.setPosition(next_text_pos);
mainWindow.draw(txt);
// Draw next piece border
sf::RectangleShape rect;
rect.setPosition(next_grid_pos);
rect.setSize(next_grid_size);
rect.setFillColor(sf::Color(0x00, 0x00, 0x00, 0x40));
mainWindow.draw(rect);
// Draw next piece background
sf::RectangleShape rect2;
rect2.setPosition(next_grid_pos + sf::Vector2f(2, 2));
rect2.setSize(next_grid_size - sf::Vector2f(4, 4));
rect2.setFillColor(sf::Color(0x02, 0x0a, 0x1a, 0x77));
mainWindow.draw(rect2);
}
void Application::drawNextPiece()
{
// Calculate position
sf::Vector2f scr_size = this->mainWindow.getView().getSize();
sf::Vector2f tetris_grid_size((scr_size.y - 10) * 0.6f, scr_size.y - 10);
sf::Vector2f tetris_grid_pos = 0.5f * (scr_size - tetris_grid_size);
sf::Vector2f block_margin_size (tetris_grid_size.x / 10, tetris_grid_size.y / 20);
sf::Vector2f block_size = block_margin_size - sf::Vector2f(2, 2);
sf::Vector2f next_text_pos = tetris_grid_pos + sf::Vector2f(tetris_grid_size.x + 10, 0);
sf::Vector2f next_grid_pos = next_text_pos + sf::Vector2f(2, 52);
Piece p = this->game.getNextPiece();
// Draw every block
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
{
// Get block
int val;
if (i < p.getHeight() && j < p.getWidth())
val = p.get(j, i);
else val = 0;
// Calculate position
float x = next_grid_pos.x + block_margin_size.x * j + 1;
float y = next_grid_pos.y + block_margin_size.y * i + 1;
// Create block shape
sf::RectangleShape shape(block_size);
shape.setFillColor(sf::Color(pcols[val+1][0], pcols[val+1][1], pcols[val+1][2], pcols[val+1][3]));
shape.setPosition(x, y);
// Draw block
this->mainWindow.draw(shape);
}
}
void Application::drawText()
{
// Calculate position
sf::Vector2f scr_size = this->mainWindow.getView().getSize();
sf::Vector2f tetris_grid_size((scr_size.y - 10) * 0.6f, scr_size.y - 10);
sf::Vector2f tetris_grid_pos = 0.5f * (scr_size - tetris_grid_size);
sf::Vector2f score_pos = tetris_grid_pos - sf::Vector2f(150, 0);
// Get score string
std::stringstream str;
str<<"Score: "<<this->game.getScore()<<"\nLevel: "<<this->game.getLevel();
// Draw score
sf::Text txt;
txt.setString(str.str());
txt.setFont(this->font);
txt.setCharacterSize(25);
txt.setColor(sf::Color::White);
txt.setPosition(score_pos);
mainWindow.draw(txt);
// Draw if game is over
if (this->game.isGameOver())
{
sf::Text txt2;
txt2.setString("Game over!");
txt2.setFont(this->font);
txt2.setCharacterSize(50);
txt2.setColor(sf::Color::White);
// Set position
sf::FloatRect size = txt2.getLocalBounds();
txt2.setPosition(0.5f * (scr_size - sf::Vector2f(size.width, size.height)));
mainWindow.draw(txt2);
}
else if (this->paused)
{
sf::Text txt2;
txt2.setString("Paused");
txt2.setFont(this->font);
txt2.setCharacterSize(50);
txt2.setColor(sf::Color::White);
sf::FloatRect size = txt2.getLocalBounds();
txt2.setPosition(0.5f * (scr_size - sf::Vector2f(size.width, size.height)));
mainWindow.draw(txt2);
}
}
/***********************************
* Game logic *
***********************************/
void Application::onLogicUpdate(sf::Time& elapsed)
{
this->elapsed += elapsed;
if (this->elapsed.asMilliseconds() > this->game.getTickTime())
{
this->elapsed = sf::Time();
if (!this->paused)
this->game.tick();
}
}