My code is for a simple "cart-creation" class and sample use in SFML. The Cart
class inherits sf::RectangleShape
and will end up having more member functions (isFull
, numberOfWheels
, etc.) There will also be a conveyor belt class in the transvac
folder. Currently, though, the Cart
class is really just a special sort of sf::RectangleShape
.
I have had very little experience with design patterns and I would like to know how I can use them in general to make the Cart class more effective. I think the Cart class may be a Decorator, but I'm not sure.
Also, the other important things that I would like to look at are: use of header files, OOP, source tree layout, and general best practices.
Compile with:
g++ -I ./include -Wall -Wextra -Werror -std=c++11 -c ./include/transvac/cart.cpp -o ./obj/cart.o
g++ -I ./include ./src/main.cpp -Wall -Wextra -Werror -std=c++11 -lsfml-graphics -lsfml-window -lsfml-system ./obj/cart.o -o ./bin/cart-mover
Directory tree:
/cart-mover
/bin
cart-mover
/include
/transvac
cart.hpp
cart.cpp
/obj
cart.o
/src
main.cpp
cart.hpp:
// cart.hpp
#include <SFML/Graphics.hpp>
#ifndef __CART_HPP_INCLUDED__
#define __CART_HPP_INCLUDED__
enum Orientation {VERTICAL, HORIZONTAL};
// TransVac namespace
namespace tvc {
class Cart : public sf::Drawable {
// The Cart class is basically a glorified sf::RectangleShape.
public:
// Constructor- create with position, color, and orientation.
Cart(const sf::Vector2f& cart_pos_, sf::Color cart_color_ = sf::Color::Black, Orientation cart_or_ = VERTICAL);
// The Position and FillColor setters and getters are just wrappers for sf::RectangleShape member methods.
void setPosition(const sf::Vector2f& cart_pos_);
const sf::Vector2f& getPosition();
void setFillColor(sf::Color cart_color_);
sf::Color getFillColor();
// Not related to sf::RectangleShape member methods.
void setOrientation(Orientation cart_or_);
Orientation getOrientation();
private:
// Virtual method needed for proper drawing in a RenderWindow. Overrides inherited Drawable member method.
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
// The heart of the Cart.
sf::RectangleShape display_rect;
Orientation cart_or;
static const int CART_WIDTH = 28.5; // inches
static const int CART_HEIGHT = 48; // inches
};
}
#endif // __CART_HPP_INCLUDED__
cart.cpp:
// cart.cpp
#include "cart.hpp"
namespace tvc {
// Everything in here pans out into the setter member methods.
// Again, much of this is just a wrapper for sf::RectangleShape.
Cart::Cart(const sf::Vector2f& cart_pos_, sf::Color cart_color_, Orientation cart_or_) {
if(cart_or_ == VERTICAL)
display_rect.setSize(sf::Vector2f(CART_WIDTH, CART_HEIGHT));
else
display_rect.setSize(sf::Vector2f(CART_HEIGHT, CART_WIDTH));
display_rect.setPosition(cart_pos_);
display_rect.setFillColor(cart_color_);
// These lines are needed to construct a cart every time:
display_rect.setOutlineThickness(-1); // Outline goes inside cart boundary
display_rect.setOutlineColor(sf::Color::Black);
}
void Cart::setPosition(const sf::Vector2f& cart_pos_) {
display_rect.setPosition(cart_pos_);
return;
}
const sf::Vector2f& Cart::getPosition() {
return display_rect.getPosition();
}
void Cart::setFillColor(sf::Color cart_color_) {
display_rect.setFillColor(cart_color_);
return;
}
sf::Color Cart::getFillColor() {
return display_rect.getFillColor();
}
void Cart::setOrientation(Orientation cart_or_) {
if(cart_or_ == VERTICAL)
display_rect.setSize(sf::Vector2f(CART_WIDTH, CART_HEIGHT));
else
display_rect.setSize(sf::Vector2f(CART_HEIGHT, CART_WIDTH));
return;
}
Orientation Cart::getOrientation() {
return cart_or;
}
// Virtual method- overrides inherited method from sf::Drawable.
void Cart::draw(sf::RenderTarget& target, sf::RenderStates states) const {
target.draw(display_rect, states);
return;
}
}
main.cpp:
// main.cpp
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
#include <random>
#include "transvac/cart.hpp"
const int WIN_HEIGHT = 600; // pixels
const int WIN_WIDTH = 800; // pixels
// This program creates a randomly colored cart onscreen that can be moved with the arrow keys.
// The program can be closed with "ESC", or the "X" button.
int main() {
// Set up the window and put it in the upper left corner
sf::RenderWindow main_window(sf::VideoMode(WIN_WIDTH, WIN_HEIGHT), "Cart Mover", sf::Style::Titlebar | sf::Style::Close);
main_window.setPosition(sf::Vector2i(0, 0));
// Make a cart in the middle of the screen and paint it a random color.
std::default_random_engine generator;
std::random_device rd;
generator.seed(rd());
std::uniform_real_distribution<float> norm_dist(0.0, 255.0);
tvc::Cart main_cart(sf::Vector2f((WIN_WIDTH - 28.5)/2, (WIN_HEIGHT - 48)/2), \
sf::Color(norm_dist(generator), norm_dist(generator), norm_dist(generator)), \
VERTICAL);
// Main processing loop
while (main_window.isOpen()) {
sf::Event event;
// Event processing loop
while (main_window.pollEvent(event)) {
switch (event.type) {
// Close the window if there is an "sf::Event::Closed" event
case sf::Event::Closed:
main_window.close();
break;
// Close the window if the ESC key is pressed
case sf::Event::KeyPressed:
if (event.key.code == sf::Keyboard::Escape)
main_window.close();
break;
// No other events are processed
default:
break;
}
}
// Clear background to light grey
main_window.clear(sf::Color(160, 160, 160));
main_window.draw(main_cart);
// If the "right" arrow key is pressed... move the cart right.
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) {
main_cart.setPosition(sf::Vector2f(main_cart.getPosition().x+1,main_cart.getPosition().y));
}
// If the "left" arrow key is pressed... move the cart left.
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) {
main_cart.setPosition(sf::Vector2f(main_cart.getPosition().x-1,main_cart.getPosition().y));
}
// If the "up" arrow key is pressed... move the cart up.
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up)) {
main_cart.setPosition(sf::Vector2f(main_cart.getPosition().x,main_cart.getPosition().y-1));
}
// If the "down" arrow key is pressed... move the cart down.
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down)) {
main_cart.setPosition(sf::Vector2f(main_cart.getPosition().x,main_cart.getPosition().y+1));
}
main_window.display();
}
return 0;
}