/* * Application.cpp * * Created on: May 4, 2013 * Author: chibi_000 */ #include "Application.h" #include #include 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: "<game.getScore()<<"\nLevel: "<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(); } }