Browse Source

add background parallax. how not to do event & cameraPos delegation

- passing of the gameView instance etcpp should be improved
- event detection has issues, as the state is overidden by last event handler
- idea: create new class ParallaxGrid
master
noerw 2 years ago
parent
commit
73c928d765
7 changed files with 125 additions and 49 deletions
  1. 52
    9
      background.cpp
  2. 9
    3
      background.hpp
  3. 17
    15
      game.cpp
  4. 1
    0
      game.hpp
  5. 25
    5
      main.cpp
  6. 20
    17
      mainmenu.cpp
  7. 1
    0
      mainmenu.hpp

+ 52
- 9
background.cpp View File

@@ -6,21 +6,64 @@
#include "main.hpp"

namespace Proto4 {
void Background::init(sf::Texture bg0, sf::Texture bg1) {
void Background::init(sf::Texture bg0, sf::Texture bg1, sf::View& gameView) {
bg0Tex = bg0;
bg1Tex = bg1;
bg0Tex.setRepeated(true);
bg1Tex.setRepeated(true);
bg0Tex.setSmooth(true);
bg1Tex.setSmooth(true);
bg0Sprite.setTexture(bg0Tex);
bg1Sprite.setTexture(bg1Tex);
bg0Sprite.setTextureRect(sf::IntRect(0, 0, xResolution, yResolution));
bg1Sprite.setTextureRect(sf::IntRect(0, 0, xResolution, yResolution));
bg0Tex.setRepeated(true);
bg1Tex.setRepeated(true);
bg0Tex.setSmooth(true);
bg1Tex.setSmooth(true);

bg0View = bg1View = gameView;
bg0Size = bg0Tex.getSize().x;
bg1Size = bg1Tex.getSize().x;
bg0Sprite.setTextureRect(sf::IntRect(0, 0, xResolution + 2 * bg0Size, yResolution + 2 * bg0Size));
bg1Sprite.setTextureRect(sf::IntRect(0, 0, xResolution + 2 * bg1Size, yResolution + 2 * bg1Size));
// bg0Sprite.setPosition(window.mapPixelToCoords(sf::Vector2i(-bg0Size, -bg0Size), bg0View));
// bg1Sprite.setPosition(window.mapPixelToCoords(sf::Vector2i(-bg1Size, -bg1Size), bg1View));
bg0Sprite.setPosition(gameView.getCenter() - gameView.getSize() * 0.5f);
bg1Sprite.setPosition(gameView.getCenter() - gameView.getSize() * 0.5f);
}

void Background::update(sf::View& gameView, sf::RenderTarget& window) {
//parallax
bg0View.setCenter(gameView.getCenter() / 3.5f);
bg1View.setCenter(gameView.getCenter() / 2.f);

//move endless backgrounds if parallax has moved one -step, to offset parallax-movement
//sf::Vector2f bg0Pos = gameView.getCenter() - bg0View.getCenter(); // alternative solution without coord2pixel transformation? doesnt work currently
sf::Vector2i bg0Pos = window.mapCoordsToPixel(bg0Sprite.getPosition(), bg0View);
if (bg0Pos.x >= 0) bg0Sprite.move(sf::Vector2f(-bg0Size, 0));
else if (bg0Pos.x <= -2 * bg0Size) bg0Sprite.move(sf::Vector2f( bg0Size, 0));
if (bg0Pos.y >= 0) bg0Sprite.move(sf::Vector2f(0,-bg0Size));
else if (bg0Pos.y <= -2 * bg0Size) bg0Sprite.move(sf::Vector2f(0, bg0Size));

sf::Vector2i bg1Pos = window.mapCoordsToPixel(bg1Sprite.getPosition(), bg1View);
if (bg1Pos.x >= 0) bg1Sprite.move(sf::Vector2f(-bg1Size, 0));
else if (bg1Pos.x <= -2 * bg1Size) bg1Sprite.move(sf::Vector2f( bg1Size, 0));
if (bg1Pos.y >= 0) bg1Sprite.move(sf::Vector2f(0,-bg1Size));
else if (bg1Pos.y <= -2 * bg1Size) bg1Sprite.move(sf::Vector2f(0, bg1Size));
}
void Background::update(float x, float y) {}
void Background::draw(sf::RenderTarget& target, sf::RenderStates states) const {
target.setView(bg0View);
target.draw(bg0Sprite);
target.setView(bg1View);
target.draw(bg1Sprite);
}
}

void Background::onEvent(sf::Event& event) {
switch (event.type) {
case sf::Event::Resized:
bg0View.setSize(event.size.width, event.size.height);
bg1View.setSize(event.size.width, event.size.height);
bg0Sprite.setTextureRect(sf::IntRect(0, 0, event.size.width + 2 * bg0Size, event.size.height + 2 * bg0Size));
bg1Sprite.setTextureRect(sf::IntRect(0, 0, event.size.width + 2 * bg1Size, event.size.height + 2 * bg1Size));
break;
default:
break;
}
}
}

+ 9
- 3
background.hpp View File

@@ -9,14 +9,20 @@
namespace Proto4 {
class Background : public sf::Drawable {
public:
void init(sf::Texture bg0, sf::Texture bg1);
void update(float x, float y);
void init(sf::Texture bg0, sf::Texture bg1, sf::View &gameView);
void update(sf::View &gameView, sf::RenderTarget &window);
void onEvent(sf::Event& event);

private:
sf::Sprite bg0Sprite;
sf::Sprite bg1Sprite;
sf::Texture bg0Tex;
sf::Texture bg1Tex;
uint8_t bg0Size;
uint8_t bg1Size;
sf::View bg0View;
sf::View bg1View;

virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
};
}
}

+ 17
- 15
game.cpp View File

@@ -10,26 +10,28 @@ namespace Proto4 {
return true;
}

AppState Game::update(sf::RenderWindow &window, sf::Time timestep) {
sf::Event event;

while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
} else if (event.type == sf::Event::Resized) {
// resize the views, so everything is still displayed
// proportionally
//view.setSize(event.size.width, event.size.height);
//view.setCenter(event.size.width / 2, event.size.height / 2);
} else if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::Q)
return AppState::MainMenu;
}
AppState Game::onEvent(sf::Event& event) {
switch (event.type) {
case sf::Event::Resized:
// resize the views, so everything is still displayed
// proportionally
//view.setSize(event.size.width, event.size.height);
//view.setCenter(event.size.width / 2, event.size.height / 2);
break;
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::Q) return AppState::MainMenu;
break;
default:
break;
}

return AppState::Game;
}

AppState Game::update(sf::RenderWindow &window, sf::Time timestep) {
return AppState::Game;
}

void Game::draw(sf::RenderTarget &window, sf::RenderStates states) const {
}


+ 1
- 0
game.hpp View File

@@ -14,6 +14,7 @@ namespace Proto4 {
public:
virtual void draw(sf::RenderTarget &window, sf::RenderStates states) const;
AppState update(sf::RenderWindow &window, sf::Time timestep);
AppState onEvent(sf::Event& event);

bool init();


+ 25
- 5
main.cpp View File

@@ -1,5 +1,6 @@
#include <iostream>
#include <string>
#include <cmath>

#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
@@ -19,6 +20,7 @@ namespace Proto4 {
MainMenu menu{};
Game game{};
Background background{};
sf::View gameView;
sf::Texture bg0, bg1;
sf::Font font;

@@ -34,8 +36,12 @@ namespace Proto4 {
std::cout << "Unable to load background images. Aborting execution.";
return false;
}
background.init(bg0, bg1);

gameView.setCenter(middleX, middleY);
gameView.setSize(xResolution, yResolution);
gameView.setViewport(sf::FloatRect(0, 0, 1, 1));

background.init(bg0, bg1, gameView);

if (
!menu.init(font) ||
@@ -65,9 +71,22 @@ namespace Proto4 {
return true;
}

void update(sf::Time timestep) {
void update(sf::Time timestep, sf::Time currentTime) {

// poll for events and pass them to components
sf::Event event;
while (window.pollEvent(event)) {
background.onEvent(event);
state = menu.onEvent(event);
game.onEvent(event);
}

background.update(1.0f, 1.0f);
// (temporary!) move camera to show off parallax background
gameView.setCenter(sf::Vector2f(
gameView.getCenter().x + timestep.asSeconds() * 100 * std::sin(currentTime.asSeconds()),
gameView.getCenter().y + timestep.asSeconds() * 100
));
background.update(gameView, window);

switch (state) {
case AppState::Game:
@@ -94,6 +113,7 @@ namespace Proto4 {

window.clear(sf::Color::Black);
window.draw(background);
window.setView(gameView);

switch (state) {
case AppState::Game:
@@ -126,7 +146,7 @@ namespace Proto4 {
lagTime += elapsedTime;

while (lagTime >= updateTimestep) {
update(updateTimestep);
update(updateTimestep, clock.getElapsedTime());
lagTime -= updateTimestep;
}
draw(lagTime);

+ 20
- 17
mainmenu.cpp View File

@@ -30,28 +30,31 @@ namespace Proto4 {
return true;
}

AppState MainMenu::update(sf::RenderWindow &window, sf::Time timestep) {
sf::Event event;

while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed) {
window.close();
} else if (event.type == sf::Event::Resized) {
// resize the views, so everything is still displayed
// proportionally
view.setSize(event.size.width, event.size.height);
view.setCenter(event.size.width / 2, event.size.height / 2);
} else if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::Q)
return AppState::Exit;
if (event.key.code == sf::Keyboard::S)
return AppState::Game;
}
AppState MainMenu::onEvent(sf::Event& event) {
switch (event.type) {
case sf::Event::Resized:
// resize the views, so everything is still displayed
// proportionally
view.setSize(event.size.width, event.size.height);
view.setCenter(event.size.width / 2, event.size.height / 2);
break;
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::Q)
return AppState::Exit;
if (event.key.code == sf::Keyboard::S)
return AppState::Game;
break;
default:
break;
}

return AppState::MainMenu;
}

AppState MainMenu::update(sf::RenderWindow &window, sf::Time timestep) {
return AppState::MainMenu;
}

void MainMenu::draw(sf::RenderTarget &window, sf::RenderStates states) const {
window.setView(view);
window.draw(mainLine);

+ 1
- 0
mainmenu.hpp View File

@@ -13,6 +13,7 @@ namespace Proto4 {
bool init(sf::Font &font);
AppState update(sf::RenderWindow &window, sf::Time timestep);
virtual void draw(sf::RenderTarget &window, sf::RenderStates states) const;
AppState onEvent(sf::Event& event);

private:
sf::View view{};

Loading…
Cancel
Save