422 lines
9.8 KiB
C++
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();
|
||
|
}
|
||
|
}
|