I am trying to create a function that renders everything in a vector of displayobject objects (on another thread). I am using SDL thread.
Here is the displayobject.h:
class DisplayObject
{
protected:
int width;
int height;
int x;
int y;
SDL_Texture* texture;
SDL_Renderer* renderer;
public:
~DisplayObject();
int getX();
void setX(int x);
int getY();
void setY(int y);
int getWidth();
void setWidth(int width);
int getHeight();
void setHeight(int height);
SDL_Texture* getTexture();
SDL_Renderer* getRenderer();
};
In graphics.h I have these variables:
std::vector<DisplayObject> imgArr;
SDL_Thread* renderThread;
static int renderLoop(void* vectorPointer);
This code is in the graphics constructor:
TextLabel textLabel(graphics->getRenderer(), 300, 80, "Hallo Welt", 50, Color(255, 0, 255), "Xenotron.ttf");
//TextLabel inherits from DisplayObject
imgArr.push_back(textLabel);
renderThread = SDL_CreateThread(Graphics::renderLoop, "renderLoop", &imgArr);
This is the render loop function:
int Graphics::renderLoop(void* param)
{
int counter = 0;
bool rendering = true;
std::vector<DisplayObject>* imgArr = (std::vector<DisplayObject>*)param;
while (rendering)
{
cout << imgArr->size() << endl;
counter++;
if (counter > 600)
{
rendering = false;
}
SDL_Delay(16);
}
return 0;
}
The problem is that it only prints 0's in the console. Why does it do that? It is supposed to write 1 since I pushed on object into it.
When you insert a TextLabel into std::vector<DisplayObject>, what is stored in the vector is not your original TextLabel object, but a DisplayObject copy-constructed from the TextLabel. What you want to do is create your TextLabels with new, store pointers to them, and call delete when you no longer need them.
The best solution would be to use boost::ptr_vector<DisplayObject> instead - it will automatically call delete when you erase objects from it.
http://www.boost.org/doc/libs/1_57_0/libs/ptr_container/doc/ptr_container.html
If you can't use Boost, but can use C++11, you can use std::vector<std::unique_ptr<DisplayObject>>.
Related
I am using an SDL Template and I am trying to implement gravity into my code so I am trying to set a Y as the strength of my gravity in update but when I try to use a pointer to setY I always get an error "a pointer to a bound function may only be used to call the function using a setter" the code below is from my GameScene.cpp
#include "GameScene.h"
GameScene::GameScene()
{
// Register and add game objects on constructor
player = new Player();
this->addGameObject(player);
floor = new Floor();
this->addGameObject(floor);
}
GameScene::~GameScene()
{
delete player;
}
void GameScene::start()
{
Scene::start();
// Initialize any scene logic here
}
void GameScene::draw()
{
Scene::draw();
}
void GameScene::update()
{
Scene::update();
if (player->getOnFloor() == false) {
player->setY -= 1;
}
else {
player->setY = 0;
}
}
This code is from my Player.h where the setters and getters are located
#pragma once
#include "GameObject.h"
#include "common.h"
#include "draw.h"
class Player :
public GameObject
{
public:
void start();
void update();
void draw();
//X Setter
void setX(int x) {
x = x;
}
//X Getter
int getX() {
return x;
}
//Y Setter
void setY(int y) {
y = y;
}
//Y Getter
int getY() {
return y;
}
//Height Setter
void setHeight(int height) {
height = height;
}
//Height Getter
int getHeight() {
return height;
}
//Width Setter
void setWidth(int width) {
width = width;
}
//Width Getter
int getWidth() {
return width;
}
//OnFloor Setter
void setOnFloor(int onFloor) {
onFloor = onFloor;
}
//OnFloor Getter
int getOnFloor() {
return onFloor;
}
private:
SDL_Texture* texture;
int x;
int y;
int height;
int width;
int speed;
bool onFloor;
};
I have tried putting () beside the setY like this
if (player->getOnFloor() == false) {
player->setY() -= 1;
}
else {
player->setY)( = 0;
}
But it still did not work, I was expecting it to make my player fall down but VS studio kept showing me the error
this may be a noobie question but I am still a noobie programmer so please bear with me
EDITED:
The player is now falling upwards, I tried doing -= 1 to make him fall downwards
void GameScene::update()
{
Scene::update();
if (player->getOnFloor() == false) {
player->setY(player->getY() -= 1);
}
else {
player->setY(0);
}
}
but I get an error on player in "player->getY()" saying that expression must be a modifiable lvalue
The error you are getting is because you are trying to use the setY setter function as a variable. In order to use the setter function to set the y property of the player object, you need to call the setY function and pass in the new value for y as an argument. Here is how you would use the setY setter function in your GameScene::update function:
void GameScene::update()
{
Scene::update();
if (player->getOnFloor() == false) {
player->setY(player->getY() + 1);
}
else {
player->setY(0);
}
}
Note that in this example, we are calling the getY getter function to get the current value of y, and then subtracting 1 from it before passing the result to the setY setter function. This will update the y property of the player object and make it fall down by 1 unit each time the update function is called.
I have a sample of code for some framework that I am using. For ease of reading I have separated blocks of code from different files.
Tile.h
class Tile
{
public:
Tile(int row, int column);
~Tile();
void Draw();
void Update(double delta);
void SetValue(int value);
int GetValue();
private:
//Member variables
Label* m_ValueLabel;
int m_Value = 0;
int m_Row;
int m_Column;
float duration = 0.0f;
float xScale = 0;
float yScale = 0;
};
Tile.cpp
void Tile::SetValue(int value)
{
//Set the Tile's value
m_Value = value;
//if (m_Value != EMPTY_TILE)
{
//Update the Tile's Label
m_ValueLabel->SetText(to_string(m_Value));
}
/*else
{
m_ValueLabel->SetText("");
}*/
}
Game.h
class Game
{
public:
Game(); //Constructor
~Game(); //Destructor
void Update(double delta);
void Draw();
void HandleLeftMouseClick(float mouseX, float mouseY);
void HandleRightMouseClick(float mouseX, float mouseY);
void HandleKeyPress(Keyboard::Key key);
bool isBoardFull();
int GetEmptyTileIndex();
void SpawnTile();
void RandomizeSeed();
int RandomRange(int min, int max);
private:
//Member variables should go here
Tile* m_Tiles[NUM_TILES];
bool isTileFull[16] = {};
int TileValueArray[5] = { 2,2,2,4,4 };
};
Game.cpp
void Game::SpawnTile()
{
RandomizeSeed();
int meaningfulVariableName = GetEmptyTileIndex();
if (meaningfulVariableName != -1)
{
int RandomNumber = RandomRange(0,4);
int TileValue = TileValueArray[RandomNumber];
}
else if (meaningfulVariableName == -1)
{
//Does nothing
}
}
What I need to do with this is make it so that the TileValue created in Game.cpp can be passed to the SetValue function in Tile.cpp because the value created is required for m_Value in SetValue.
The majority of code present can probably be ignored, and anything commented out should not effect how I need the code to function at the moment. There is nothing wrong with the framework outside of these files, as I have used it several times before.
I know there are easier ways to do this, but this is how I am required to do it. I would really appreciate if someone could help me with this because anything that I have found online has not helped. If you think that you may need more code for clarification on something, please do not hesitate to ask. Also, in case it helps I am using this to create a 2048 clone.
You have a function Game::GetEmptyTileIndex which will return an index. You can use that index to set Game::m_Tiles by changing the Game::SpawnTile function like so:
// Game.cpp
void Game::SpawnTile()
{
RandomizeSeed();
// Returns a tile index.
int meaningfulVariableName = GetEmptyTileIndex();
if (meaningfulVariableName != -1)
{
int RandomNumber = RandomRange(0,4);
int TileValue = TileValueArray[RandomNumber];
// Set the value for the tile at the required index.
m_Tiles[meaningfulVariableName]->SetValue(TileValue);
}
else if (meaningfulVariableName == -1)
{
//Does nothing
}
}
Hey I am trying to make this space game. Now I have developed my ship, and am able to display it. However I would like to be able to use the class for more than one object. I can do this with a constructor but have no clue how to get a constructor working, what changes would I need to make to my code to make the object take an int value as a constructor and allow me to make multiple ships with the code by calling the object.
Here is my header file.
//
// Ship.hpp
// Zerg_Invasion
//
// Created by Flik Wolf on 11/9/15.
//
//
#ifndef Ship_h
#define Ship_h
#include <stdio.h>
#include "ofMain.h"
class Ship {
public:
// Constructor
Ship();
// Methods
void moveLeft();
void moveRight();
void load();
void draw();
void fire();
void keyPressed();
// Properties
int x;
int y;
ofColor color;
ofImage cat;
};
#endif
and here is my CPP file.
//
// Ship.cpp
// Zerg_Invasion
//
// Created by Flik Wolf on 11/9/15.
//
//
#include "Ship.h"
Ship::Ship() {
// Set the initial color
//color.set( ofRandom(255), ofRandom(255), ofRandom(255));
// Initial x position of the ball
x = 450;
// Initial y position of the ball
y = 200;
}
void Ship::moveLeft() {
x -= 10;
}
void Ship::moveRight() {
x += 10;
}
void Ship::load() {
cat.load("spaceShip.png");
}
void Ship::draw() {
cat.draw(x, y);
// ofCircle(x, y, 30);
}
void Ship::fire() {
ofSetColor(255, 255, 255);
ofCircle(x, 200, 2);
}
Also here is the .h and .cpp files for Openframeworks which I am using for graphics.
#pragma once
#include "ofMain.h"
#include "Ship.h"
class ofApp : public ofBaseApp {
public:
void setup();
void update();
void draw();
void keyPressed(int key);
void keyReleased(int key);
void mouseMoved(int x, int y);
void mouseDragged(int x, int y, int button);
void mousePressed(int x, int y, int button);
void mouseReleased(int x, int y, int button);
void mouseEntered(int x, int y);
void mouseExited(int x, int y);
void windowResized(int w, int h);
void dragEvent(ofDragInfo dragInfo);
void gotMessage(ofMessage msg);
Ship theShip;
};
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup() {
// Smooth edges
ofEnableSmoothing();
// Fixed framerate
ofSetFrameRate(120);
theShip.load();
// No need to define the initial position of the ball
// because the Ball constructor does it for you
}
//--------------------------------------------------------------
void ofApp::update() {
// theShip.move();
}
//--------------------------------------------------------------
void ofApp::draw() {
ofBackground(0);
std::vector <int> nums;
nums.push_back(0);
nums.push_back(1);
nums.push_back(3);
nums.push_back(4);
nums.push_back(5);
nums.push_back(6);
nums.push_back(7);
nums.push_back(8);
cout << nums[0] << endl;
cout << nums[1] << endl;
theShip.draw();
}
//--------------------------------------------------------------
void ofApp::keyPressed(int key) {
if (key == 'a')
{
theShip.moveLeft();
}
if (key == 'd')
{
theShip.moveRight();
}
}
//--------------------------------------------------------------
void ofApp::keyReleased(int key) {
}
//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y) {
}
//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button) {
}
//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button) {
theShip.fire();
}
//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button) {
}
//--------------------------------------------------------------
void ofApp::mouseEntered(int x, int y) {
}
//--------------------------------------------------------------
void ofApp::mouseExited(int x, int y) {
}
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h) {
}
//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg) {
}
//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo) {
}
As mentioned, the constructor in your case should only produce one ship, and this should be the case with all object constructors.
However, it's still easy enough to create and maintain multiple ships (as you've implemented them) if you use a container like std::vector.
Containing multiple ships:
To create a container for your ships, you can use a vector like so:
std::vector<Ship> Ships;
Adding new ships:
To add additional ships to it, you can use std::vector::push_back():
Ships.push_back(Ship()); //Adds a new ship to 'Ships'
Updating the ships:
There are a couple of ways to cycle through your ships:
for (auto& i : Ships)
i.Update(); //Some updating function for each ship
Or, if you need to keep track of the specific position of each ship inside the vector:
for (unsigned int i = 0; i < Ships.size(); ++i)
Ships[i].Update() //The same updating function
How about to get the x and y as constructor argument?
in the .h file:
struct Ship {
// Constructor
Ship(int _x = 450, int _y = 200);
// ...
in the cpp file:
Ship::Ship(int _x, int _y) : x{_x}, y{_y} {
// Set the initial color
//color.set( ofRandom(255), ofRandom(255), ofRandom(255));
}
I have those inheritance classes :
Base Class: Entity
Derived from Entity Classes: Actor, Obj, Enemy
The Base class Entity contains an obj of a user-defined-type that i called "CollisionStuff".
When i run my program the destructor of CollisionStuff is called after every CollisionStuff constructor call and every time game-loop goes on.
so my call is: why is this happening?
As you can see below, i allocate dinamically some arrays in the setRectangle method, the programm calls the destructor, it deletes my data and when i try to use them... it calls "_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));".
Thank you in before
here my code: Entity.h
enum e_Type {tActor = 0, tObj, tEnemy, tBackg};
class Entity
{
public:
Entity(void);
~Entity(void);
float getH();
float getW();
void setWH(float W, float H);
bool CreateSprite(std::string path);
sf::Sprite& getSprite();
void setType(e_Type type);
e_Type getType();
CollisionStuff getColStuff();
static std::list<Entity*> List;
protected:
sf::Sprite m_sprite;
sf::Texture m_texture;
float m_h;
float m_w;
e_Type m_type;
CollisionStuff m_colStuff;
void addToList();
};
CollisionStuff.h
class CollisionStuff
{
public:
CollisionStuff();
~CollisionStuff(void);
void setRectangle(int W, int H);
void followTheSprite(Entity entity);
private:
sf::Vector2f* m_a;
sf::Vector2f* m_b;
sf::Vector2f* m_c;
sf::Vector2f* m_d;
/* this member data are sides of rectangle used
to manage collisions between object throughout the scenario
a
-------------
| |
c | | d
| |
-------------
b
*/
};
CollisionStuff.cpp
CollisionStuff::CollisionStuff()
{
//setRectangle(0, 0);
}
void CollisionStuff::setRectangle(int W, int H)
{
m_a = new sf::Vector2f[W];
m_b = new sf::Vector2f[W];
m_c = new sf::Vector2f[H];
m_d = new sf::Vector2f[H];
}
void CollisionStuff::followTheSprite(Entity entity)
{
entity.getSprite().setOrigin(0, 0);
sf::Vector2f UpLeftVertex = entity.getSprite().getPosition();
for(int i = 0; i < entity.getW(); i++)
{
m_a[i].x = UpLeftVertex.x + i;
m_a[i].y = UpLeftVertex.y;
m_b[i].x = UpLeftVertex.x + i;
m_b[i].y = UpLeftVertex.y + entity.getH();
}
for(int i = 0; i < entity.getH(); i++)
{
m_c[i].x = UpLeftVertex.x;
m_c[i].y = UpLeftVertex.y + i;
m_d[i].x = UpLeftVertex.x + entity.getW();
m_d[i].y = UpLeftVertex.y + i;
}
}
CollisionStuff::~CollisionStuff(void)
{
delete [] m_a;
delete [] m_b;
delete [] m_c;
delete [] m_d;
}
EDIT
Thank you for the answers.
Example of CollisionStuff use
Actor.cpp (it's a derived class of Entity)
Actor::Actor(void)
{
if(!CreateSprite("D://Sprites//MainChar.png"))
{
std::cout << "Impossibile creare sprite" << std::endl;
}
else
{
std::cout << "Creazione sprite riuscita" << std::endl;
m_sprite.setPosition(100.0f, 365.0f);
m_sprite.setOrigin(20, 35);
//m_sprite.setPosition(190.0f, 382.5f); // 200, 400
setWH(40, 70);
m_health = 100;
m_status = Good;
setType(tActor);
m_jCounter = -1;
m_action = Null;
setColStuff();
}
}
void Actor::setColStuff()
{
m_colStuff.setRectangle(m_w, m_h);
}
void Actor::physic()
{
//setColStuff();
m_colStuff.followTheSprite(*this);
}
main.cpp
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "Platform");
std::list<Entity*>::iterator i;
Background BG;
Level1 FirstLev;
Actor Doodle;
while(window.isOpen())
{
sf::Event event;
if(window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
Doodle.inputEvts();
}
Doodle.act(Doodle.getAction());
Doodle.physic();
window.clear();
window.draw(BG.getSprite());
window.draw(Doodle.getSprite());
FirstLev.drawLevel(window);
window.display();
}
return 0;
}
It's really hard to tell from the bit of code that you posted, but if I had to guess I'd say it's probably related to this:
CollisionStuff getColStuff();
you're returning CollisionStuff by value, which means a new copy will be created by whoever is calling this. It'll have the same pointers that the original CollisionStuff object allocated, and it'll delete them when it goes out of scope, leaving the original one with dangling pointers.
You can try returning by reference or by pointer, but either way you should write a copy constructor and override the assignment operator for CollisionStuff (Rule of Three).
Another idea would be to use std::vector<sf::Vector2f> instead of allocating the sf::Vector2f array yourself.
I'm a bit confused with classes was hoping some one could explain.
I have a class I'm making to create buttons for a game menu. There are four variables:
int m_x
int m_y
int m_width
int m_height
I then want to use a render function in the class but Im not understanding how i use the 4 int variables in the class and pass it to the function in the class?
My class is like this:
class Button
{
private:
int m_x, m_y; // coordinates of upper left corner of control
int m_width, m_height; // size of control
public:
Button(int x, int y, int width, int height)
{
m_x = x;
m_y = y;
m_width = width;
m_height = height;
}
void Render(SDL_Surface *source,SDL_Surface *destination,int x, int y)
{
SDL_Rect offset;
offset.x = x;
offset.y = y;
SDL_BlitSurface( source, NULL, destination, &offset );
}
} //end class
Where i am confused is how the values created in public:Button is passed to void render I'm not fully sure I've got this right, if i have its pure luck so far because I'm still a little bit confused.
Maybe an example will help:
#include <iostream>
class Button
{
private:
int m_x, m_y; // coordinates of upper left corner of control
int m_width, m_height; // size of control
public:
Button(int x, int y, int width, int height) :
//This is initialization list syntax. The other way works,
//but is almost always inferior.
m_x(x), m_y(y), m_width(width), m_height(height)
{
}
void MemberFunction()
{
std::cout << m_x << '\n';
std::cout << m_y << '\n';
//etc... use all the members.
}
};
int main() {
//Construct a Button called `button`,
//passing 10,30,100,500 to the constructor
Button button(10,30,100,500);
//Call MemberFunction() on `button`.
//MemberFunction() implicitly has access
//to the m_x, m_y, m_width and m_height
//members of `button`.
button.MemberFunction();
}
You might want to spend some time learning C++ before getting too deep into a complex programming project.
To answer your question, The variables initialized in the constructor (Button) are part of the class instance. So they're available within any class method, including Render.