The definitions of Circle and Polygon are here in Graph.h and graph.cpp.
For some exercise I need to have some unnamed shapes which are made using the new keyword. Both Circle and polygon are kinds of Shape.
For example if I have a vector_ref<Circle> vc; I can using this statement add an unnamed Circle into that vector: vc.push_back(new Circle (Point (p), 50)); because I can supply parameters (which are a point and a radius) of a circle when defining it.
But for polygons the subject is different.
For having a polygon I must declare it first, e.g., Polygon poly; then add points to it, this way, poly.add(Point(p));. Now it has caused a problem for me.
Consider I have a vector of polygons, Vector_ref<Polygon> vp; Now how to add (that is push back) a polygon using the new keyword just like I did for circle please?
My code is this:
#include <GUI.h>
using namespace Graph_lib;
//---------------------------------
class Math_shapes : public Window {
public:
Math_shapes(Point, int, int, const string&);
private:
//Widgets
Menu menu;
Button quit_button;
In_box x_coor;
In_box y_coor;
Vector_ref<Circle> vc;
Vector_ref<Graph_lib::Rectangle> vr;
Vector_ref<Graph_lib::Polygon> vt;
Vector_ref<Graph_lib::Polygon> vh;
//Action fucntions
void circle_pressed() {
int x = x_coor.get_int();
int y = y_coor.get_int();
vc.push_back(new Circle (Point(x,y), 50));
attach(vc[vc.size()-1]);
redraw();
}
void square_pressed() {
int x = x_coor.get_int();
int y = y_coor.get_int();
vr.push_back(new Graph_lib::Rectangle (Point(x,y), Point(x+100,y+100)));
attach(vr[vr.size()-1]);
redraw();
}
void triangle_pressed() {
int x = x_coor.get_int();
int y = y_coor.get_int();
vt.push_back(new Graph_lib::Polygon); // Problem is here!!
attach(vt[vt.size()-1]);
redraw();
}
void hexagon_pressed() {
int x = x_coor.get_int();
int y = y_coor.get_int();
Graph_lib::Polygon h;
h.add(Point(x,y)); h.add(Point(x+50,y+50)); h.add(Point(x+50,y+80));
h.add(Point(x,y+100)); h.add(Point(x-50,y+80)); h.add(Point(x-50,y+50));
vh.push_back(h);
attach(vh[vh.size()-1]);
redraw();
}
void quit() { hide(); }
// Call-back functions
static void cb_circle (Address, Address pw) { reference_to<Math_shapes>(pw).circle_pressed(); }
static void cb_square (Address, Address pw) { reference_to<Math_shapes>(pw).square_pressed(); }
static void cb_triangle (Address, Address pw) { reference_to<Math_shapes>(pw).triangle_pressed(); }
static void cb_hexagon (Address, Address pw) { reference_to<Math_shapes>(pw).hexagon_pressed(); }
static void cb_quit (Address, Address pw) { reference_to<Math_shapes>(pw).quit(); }
};
//----------------------------------------------------------------------------------
Math_shapes::Math_shapes(Point xy, int w, int h, const string& title):
Window(xy, w, h, title),
menu (Point(x_max()-150,70),120,30,Menu::vertical, "MathShapes"),
quit_button (Point(x_max()-100, 20), 70,20, "Quit", cb_quit),
x_coor(Point(x_max()-450,30),50,20,"x coordinate: "),
y_coor(Point(x_max()-250,30),50,20,"y coordinate: ")
{
attach(x_coor);
attach(y_coor);
attach(quit_button);
menu.attach(new Button(Point(0,0),0,0,"Circle",cb_circle));
menu.attach(new Button(Point(0,0),0,0,"Square",cb_square));
menu.attach(new Button(Point(0,0),0,0,"Equilateral triangle",cb_triangle));
menu.attach(new Button(Point(0,0),0,0,"Hexagon",cb_hexagon));
attach(menu);
}
//-------------------------------------------
int main()
try {
Math_shapes M_s(Point(100,100), 800, 600, "Math Shapes");
return gui_main();
}
catch(...)
{
return 0;
}
You simply need to hold a pointer to your polygon until you've put it in the conatiner:
Circle* pPoly = new Polygon();
// ...
pPoly->add(Point(p1));
// ...
pPoly->add(Point(p2));
// ...
vc.push_back(pPoly);
you probably want to use smart pointers rather than raw ones as above but this is where you can start.
Have you tried this
void triangle_pressed() {
int x = x_coor.get_int();
int y = y_coor.get_int();
Polygon *poly = new Polygon();
poly.add(Point(x));// add your points, I don't know if these are the right points
poly.add(Point(y));// but have you tried this way? creating it, adding, then calling
vt.push_back(poly); // push back without the move
attach(vt[vt.size()-1]);
redraw();
Well, in order to use the new operator, you would need to create a Polygon constructor that takes vector<Point> or initializer_list<Point> as an argument.
The other way around would be to create a helper function, e.g.
-- note that this is really suboptimal, there may be much better solution using move semantics, etc. (or even variadic template function for the matter)
Polygon* make_polygon(initializer_list<Point>& points)
{
Polygon* poly = new Polygon();
for (auto point : points)
poly->Add(point);
return poly;
}
And then just call vp.push_back(make_polygon({p1, p2, ...});
Obviously you could change the function to work without pointers simply by removing them alongside with the new operator call, but then it wouldn't work with your vector_ref<Polygon> type. You would need to use vector<Polygon> instead, as I assume that vector_ref<T> is just a typedef for vector<T*>
Related
I have a QgraphicsScene which contains many QGraphicsItem. I am reading line, arc and circle's co-ordinates from a file and storing them in a map and when time comes to draw them, I iterate over that map and give those co-ordinates to respective Qt's Api.
But the problem is that, the symbol which is getting generated is not fully selectable.
Means if a symbol is created by let's say 4 lines, 1 arc and 1 circle. Then if I click on a particular line, then only that line gets selected. Or that particular arc gets selected.
But I am expecting, on clicking, the full symbol should be selected.
For that I was suggested to use wrapper class. But not understanding
how to use that ?
Here is my structure:
class mySymbol
{
struct Line {
std::tuple<int, int, int, int> line;
};
struct Arc {
std::tuple<int, int, int, int, int, int> arc;
};
struct Circle {
std::tuple<int, int, int> circle;
};
struct Rect
{
std::vector<Line> allLines;
std::vector<Arc> allArcs;
std::vector<Circle> allCircles;
}
std::map<std::string, Rect> allShapes;
}
DrawShapes.h
class DrawShapes
{
void createSymbol(map<std::string, Rect>);
}
DrawShapes.cpp
void DrawShapes :: createSymbol(map<std::string, Rect> allShapes)
{
QGraphicsItemGroup * parentGroup = new QGraphicsItemGroup;
for (auto iter = allShapes.begin(); iter != allShapes.end(); ++iter)
{
if (iter->second.allLines.size() > 0)
{
for (unsigned int i = 0; i < iter->second.allLines.size(); i++)
{
// getting 4 co-ordinates of line as first,second,third and fourth
myLine* line = new myLine(first,second,third,fourth);
line->DrawLine();
parentGroup->addToGroup(line);
scene->addItem(static_cast<QGraphicsLineItem*>(line));
}
}
// same logic for arc and circle
}
myLine.h
class myLine: public QGraphicsLineItem
{
public:
myLine();
myLine(int x1,int y1,int x2 ,int y2,QGraphicsItem *parent = nullptr)
: QGraphicsLineItem(x1,y1,x2,y2,parent)
{}
void DrawLine();
};
myLine.cpp
void myLine::DrawLine()
{
this->setPen(QPen(QColor("blue"), 1));
this->setFlag(QGraphicsItem::ItemIsSelectable);
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I'm programming a Breakout game in C++. I'm having a HUGE problem that's preventing me from giving the game multi-ball functionality. I think it has something to do with the destructor. Have a look:
for loop for the balls (Driver.cpp):
for (Ball& b : balls) { // Loops over all balls
(...)
// Collision for when you miss
if (b.getYPos() > HEIGHT) { // If the ball falls below the defined height of the screen
balls.erase(balls.begin() + b.getID()); // Wipe the ball out of memory to make room (Troublesome line)
Ball::addToID(-1); // Shift the ball ID to assign to the next ball back one
(...)
}
And I get this error:
Debug Error!
Program: Breakout.exe
abort() has been called
(Press Retry to debug the application)
Do you know why this mysterious crash is happening? Or more importantly, a fix for it?
Here's a replicable piece of code to help:
Driver.cpp:
#include <vector>
#include <allegro5\allegro.h>
#include "Ball.h"
using namespace std;
vector<Ball> balls(0); // Pay attention to this line
const POS WIDTH = 1600, HEIGHT = 900;
int main {
while (running) {
if (al_key_down(&key, ALLEGRO_KEY_SPACE)) { // Spawn the ball
balls.push_back(Ball(WIDTH / 2, 500, 10, 10)); // Spawn the ball
balls[Ball::getIDtoAssign()].setYSpeed(5);
}
for (Ball& b : balls) { // Pay attention to this loop
b.draw(); // This line is what's crashing.
b.move();
(...)
// Collision for when you miss
balls.erase(
remove_if(balls.begin(), balls.end(),
[=](Ball& b) {
// Collision for when you miss
return b.getYPos() > HEIGHT; // If the ball falls below the defined height of the screen, wipe the ball out of memory to make room
}
),
balls.end()
);
}
}
}
}
return 0;
}
Ball.h:
#pragma once
#include <allegro5\allegro_primitives.h>
using namespace std;
class Ball {
public:
Ball();
Ball(float x, float y, float w, float h);
~Ball();
void draw();
void move();
float getYPos();
void setYSpeed(float set);
private:
float xPos; // Horizontal position
float yPos; // Vertical position (upside down)
float width; // Sprite width
float height; // Sprite height
float xSpeed; // Horizontal speed
float ySpeed; // Vertical speed (inverted)
}
Ball.cpp:
#include "Ball.h"
short Ball::ballIDtoAssign = 0;
Ball::Ball() {
this->xPos = 0;
this->yPos = 0;
this->width = 0;
this->height = 0;
this->xSpeed = 0;
this->ySpeed = 0;
}
Ball::Ball(float x, float y, float w, float h) {
this->xPos = x;
this->yPos = y;
this->width = w;
this->height = h;
this->xSpeed = 0;
this->ySpeed = 0;
}
Ball::~Ball() {
// Destructor
}
void Ball::draw() {
al_draw_filled_rectangle(xPos, yPos, xPos + width, yPos + height, al_map_rgb(0xFF, 0xFF, 0xFF));
}
void Ball::move() {
xPos += xSpeed;
yPos += ySpeed;
}
float Ball::getYPos() {
return yPos;
}
void Ball::setYSpeed(float set) {
ySpeed = set;
}
You cannot modify a container while you are iterating through it with a range-for loop. You don't have access to the iterator that the loop uses internally, and erase() will invalidate that iterator.
You can use the container's iterators manually, paying attention to the new iterator that erase() returns, eg:
for(auto iter = balls.begin(); iter != balls.end(); ) { // Loops over all balls
Ball& b = *iter:
...
// Collision for when you miss
if (b.getYPos() > HEIGHT) { // If the ball falls below the defined height of the screen
...
iter = balls.erase(iter); // Wipe the ball out of memory to make room
}
else {
++iter;
}
}
Alternatively, use the erase-remove idiom via std::remove_if() instead:
balls.erase(
std::remove_if(balls.begin(), balls.end(),
[=](Ball &b){
// Collision for when you miss
return b.getYPos() > HEIGHT; // If the ball falls below the defined height of the screen, wipe the ball out of memory to make room
}
),
balls.end()
);
UPDATE: now that you have posted more of your code, it is clear to see that you are trying to use ID numbers as indexes into the vector, but you are not implementing those IDs correctly, and they are completely unnecessary and should be eliminated.
The Ball::ballID member is never being assigned any value, so in this statement:
balls.erase(balls.begin() + b.getID()); // The troublesome line
Trying to erase() the result of balls.begin() + b.getID() causes undefined behavior since the iterator has an indeterminate value, thus you can end up trying to erase the wrong Ball object, or even an invalid Ball object (which is likely the root cause of your runtime crash).
Also, in this section of code:
balls.push_back(Ball(WIDTH / 2, 500, 10, 10)); // Spawn the ball
balls[Ball::getIDtoAssign()].setYSpeed(5);
Ball::addToID(1);
Since you want to access the Ball object you just pushed, that code can be simplified to this:
balls.back().setYSpeed(5);
And I already gave you code further above to show you how to remove balls from the vector without using IDs.
So, there is need for an ID system at all.
With that said, try something more like this:
Driver.cpp:
#include <vector>
...
#include "Ball.h"
using namespace std;
vector<Ball> balls;
const POS WIDTH = 1600, HEIGHT = 900;
int main {
...
while (running) {
...
if (input.type == ALLEGRO_EVENT_TIMER) { // Runs at 60FPS
...
if (al_key_down(&key, ALLEGRO_KEY_SPACE)) { // Spawn the ball
balls.push_back(Ball(WIDTH / 2, 500, 10, 10)); // Spawn the ball
balls.back().setYSpeed(5);
}
for (auto iter = balls.begin(); iter != balls.end(); ) {
Ball &b = *iter;
...
if (b.getYPos() > HEIGHT) { // Collision for when you miss
iter = balls.erase(iter);
}
else {
++iter;
}
}
/* alternatively:
for (Ball& b : balls) {
b.draw();
b.move();
}
balls.erase(
std::remove_if(balls.begin(), balls.end(),
[=](Ball &b){
// Collision for when you miss
return b.getYPos() > HEIGHT; // If the ball falls below the defined height of the screen, wipe the ball out of memory to make room
}
),
balls.end()
);
*/
}
}
return 0;
}
Ball.h:
#pragma once
...
class Ball {
public:
...
// NO ID METHODS!
private:
...
// NO ID MEMBERS!
}
Ball.cpp:
#include "Ball.h"
...
// NO ID MEMBER/METHODS!
OK, so I managed to figure out why the program crashes. It was because I had the erase-remove inside the for loop which can cause all sorts of problems.
I have one class defined as example:
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area (void);
} ;
Suppose that the area calculation is complex an in order to be clean and readable i want to use functions like display_result(); or order_items(int x, int y);. How can i do this ? The general question is how to use functions inside classes in c++.
My particular case:
bool AlphaBetaAI::computeMove (PangScenario *ps, int playerNumber, int *move)
{
int alpha=-Number_MAX_VALUE;
int beta= Number_MAX_VALUE;
float childValue;
int score;
vector<int> legalMovements;
legalMovements.push_back(1); //Move right
legalMovements.push_back(2); //Move left
legalMovements.push_back(3); //stop
legalMovements.push_back(4); //Shoot
vector< pair<float,int> > lista;
PangScenario *pangCopy = new PangScenario(*ps);
//score=myPacman->getPoints(); Si quiero arrastrar los puntos ya conseguidos por pacman antes de tomar decision
score=0; //Si quiero empezar desde 0 a partir del momento que calculo la decisiĆ³n.
lista.clear();
for ( int i=0; i < legalMovements.size();i++)
{
if ( legalMovements[i] != 0)
{
switch (legalMovements[i])
{
case 1: //North
pangCopy->characterPlayerOne->moveRight();
childValue = minimaxAlphaBeta(pangCopy, alpha, beta, score, 1, depth-1, jugador+1);
lista.push_back(make_pair(childValue,1));
break;
case 2: //South
CharactersLocationsMaze[playerRow]=sr+1;
CharactersLocationsMaze[playerColumn]=sc;
childValue= minimaxAlphaBeta(mazeTemp,CharactersLocationsMaze, alpha, beta, score, 2, depth-1, jugador+1);
lista.push_back(make_pair(childValue,2));
break;
case 3: //West
CharactersLocationsMaze[playerRow]=sr;
CharactersLocationsMaze[playerColumn]=sc-1;
childValue= minimaxAlphaBeta(mazeTemp,CharactersLocationsMaze, alpha, beta, score, 3, depth-1, jugador+1);
lista.push_back(make_pair(childValue,3));
break;
case 4: //East
CharactersLocationsMaze[playerRow]=sr;
CharactersLocationsMaze[playerColumn]=sc+1;
childValue = minimaxAlphaBeta(mazeTemp,CharactersLocationsMaze, alpha, beta, score, 4, depth-1, jugador+1);
lista.push_back(make_pair(childValue,4));
break;
}
}
}//for
//more code not relevant to the question
}
I compute the move of some kind of pang game. To calculate the best movement id have to call minimaxAlphabeta recursively using a depth of 5. So i have to declare and define minimaxAlphabeta and use it inside the class computemove.
Thanks in advance
If I understand correctly, your question is not about using methods but about optimizing heavy calculations.
Let take your Rectangle example:
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area (void);
} ;
Supposing that calculating area is not that heavy, it may be done in the method itself and that is a clear, straight and easy example of method. However, if the calculation is complex, we need some optimization.
The simplest solution is to only calculate the area when it make sense, and not always. For this purpose, we could save a boolean indicating the need of updating the value:
class Rectangle {
float width=0.0, height=0.0;
bool area_to_update = true;
float area_last_value = 0.0;
public:
void set_values (float, float);
float area ();
} ;
float Rectangle::area()
{
if (area_to_update)
{
// ... Make complex calculation here, save it to area_last_value
area_to_update = with*height;
// save that the area is now correct.
area_to_update = false;
}
// return the new result
return area_to_update;
}
By default, the value need to be updated, so the first call to area will trigger the calculation, and following calls will just return the same value until an update is required.
When any of the values is changed, the area require to update again:
void Rectangle::set_values(float w, float h)
{
// ... Update values here
bool value_changed = (w!=width || h!=height);
width= w;
height = h;
// Check if the value has really changed, and set area to be updated.
if ( value_changed) area_to_update = true;
}
Using functions in a class is straightforward. Example:
class Foo
{
int x;
public:
void bar();
void baz();
};
void Foo::bar()
{
x = 3;
}
void Foo::baz()
{
bar(); // inside another class function (of same class), you just call it
}
int main()
{
Foo f;
f.baz(); // outside you need an instance, call with dot
}
A note regarding the line
PangScenario *pangCopy = new PangScenario(*ps);
Please don't use new, a regular variable will suffice here,
since pangCopy presumably don't need to outlive AlphaBetaAI::computeMove.
Further, in that function, prefer to take ps by reference.
new here, so be gentle, I'm currently doing my Major Project for my course and, I'm not asking for homework to be done for me, i just can't wrap my head around a strange problem i am having and have not been able to find an answer for it, even on here. I'm using SDL for my Drawing.
I'm doing Object Orientated Programming with my Project or a "state Machine" (which sounds less painful in a newbies mind, believe me), and in the render part of my Class Game1.cpp i am trying to call a Draw Function of my Player Class, but for some unknown reason that i can not fathom, it just skips this function call completely.
I have no errors, i even used breakpoints to find out what was happening, but it just skipped it completely every time, it is drawing the screen black as well without fail. Any help as t why it is skipping this would be really appreciated.
I honestly feel like it's a simple rookie mistake, but any and all scrutiny is welcome of my code, anything i can do to better myself is appreciated.
Game1.cpp:
#include "Game1.h"
#include "PlayerCharacter.h"
Game1::Game1( World * worldObject )
{
//object setup
this->worldObject = worldObject;
setDone (false);
}
Game1::~Game1()
{
}
void Game1::handle_events()
{
//*******************************************
//**//////////////Call Input///////////////**
//*******************************************
//******Check for Keyboard Input*************
//******Check Keyboard Logic*****************
//******Check for Mouse Input****************
//The mouse offsets
x = 0, y = 0;
//If the mouse moved
if (SDL_PollEvent(&worldObject->event))
{
if( worldObject->event.type == SDL_MOUSEMOTION )
{
//Get the mouse offsets
x = worldObject->event.motion.x;
y = worldObject->event.motion.y;
}
}
//******Check Mouse Logic********************
}
void Game1::logic()
{
//*******************************************
//**//////////Collision Detection//////////**
//*******************************************
//******Check Player Bullet Collision Loop***
//Check for collision with enemies
//Check for collision with bitmap mask (walls)
//******Check Enemy Bullet Collision Loop****
//Check for Collision with Player
//Check for collision with bitmap mask (walls)
}
void Game1::render()
{
//*******************************************
//**////////////////Drawing////////////////**
//*******************************************
//******Blit Black Background****************
SDL_FillRect(worldObject->Screen , NULL , 0xff000000);
//******Blit Bitmap Mask*********************
//******Blit Flashlight**********************
//******Blit Map*****************************
//******Blit Pickups*************************
//******Blit Bullets*************************
//******Blit Player**************************
&PlayerCharacter.Draw; // <----- Skips this line completely, no idea why
//******Blit Enemies*************************
//******Blit Blackened Overlay***************
//******Blit HUD*****************************
//******Flip Screen**************************
SDL_Flip(worldObject->Screen);
}
Game1.h
#ifndef __Game1_H_INLUDED__
#define __Game1_H_INLUDED__
#include "GameState.h"
#include "SDL.h"
#include "ImageLoader.h"
using namespace IMGLoader;
class Game1 : public GameState
{
private:
//Menu Image
World * worldObject;
SDL_Rect PauseMenu,Item1Tile,Item2Tile,Item3Tile;
/*bool bPauseMenu, bItem1Tile, bItem2Tile, bItem3Tile;
int ButtonSpace,ButtonSize;
float x,y;
int Alpha1,Alpha2;*/
//Clipping Window
//SDL_Rect sclip,dclip;
public:
//Loads Menu resources
Game1 (World * worldObject);
//Frees Menu resources
~Game1();
//Main loop functions
void handle_events();
void logic();
void render();
};
#endif
PlayerCharacter.cpp
#include "PlayerCharacter.h"
SDL_Rect psclip,pdclip;
PlayerCharacter::PlayerCharacter ( float X, float Y, float dX, float dY, float Angle, float Speed, bool Existance, int Height, int Width, int Health, int Shield, SDL_Surface* Player ):Characters ( X, Y, dX, dY, Angle, Speed, Existance, Height, Width, Health )
{
this->Player = Player;
this->Shield = Shield;
this->Player = load_image("image\Player1.png");
}
void PlayerCharacter::setShield ( int Shield )
{
this->Shield = Shield;
}
int PlayerCharacter::getShield ( void )
{
return Shield;
}
void PlayerCharacter::Draw( )
{
psclip.x = 0; psclip.y = 0; psclip.w = 64; psclip.h = 64;
pdclip.x = 640; pdclip.y = 318; pdclip.w = 64; pdclip.h = 64;
SDL_BlitSurface(Player, &psclip, worldObject->Screen, &pdclip);
}
PlayerCharacter.h
#ifndef __PlayerCharacter_H_INCLUDED__
#define __PlayerCharacter_H_INCLUDED__
#include "Characters.h"
class PlayerCharacter : public Characters
{
private:
int Shield;
SDL_Surface* Player;
World *worldObject;
public:
PlayerCharacter ( float X, float Y, float dX, float dY, float Angle, float Speed, bool Existance, int Height, int Width, int Health, int Shield, SDL_Surface* Player );
void setShield ( int Shield );
int getShield ( void );
void Draw ( );
};
#endif
The line
&PlayerCharacter.Draw; // <----- Skips this line completely, no idea why
is not actually a function call. It's an expression that take the address of the Draw function in the PlayerCharacter class and does nothing with it.
I'm actually kind of surprised it compiles without errors, or at least tons of warnings.
You need to create a PlayerCharacter object, and then call the function in the object.
&PlayerCharacter.Draw is not a function call. PlayerCharacter::Draw() is not a static class method, so you need a PlayerCharacter object to invoke this method on.
You have a class PlayerCharacter, which defines what a PlayerCharacter is and what can be done with it. But as far as I see, you don't have a single PlayerCharacter object, i.e. no player character. If you had one, let's call him pc, then you could draw him with pc.Draw(). For that, you would have to instantiate the class, e.g. via PlayerCharacter pc( ... ), with the ... replaced by some appropriate values for the multitude of constructor parameters you have there. (You really want a default constructor, initializing all those to zero or other appropriate "start" value...)
So I was working on my code, which is designed in a modular way. Now, one of my classes; called Splash has to create a object of another class which is called Emitter. Normally you would just create the object and be done with it, but that doesn't work here, as the Emitter class has a custom constructor. But when I try to create an object, it doesn't work.
As an example;
Emitter has a constructor like so: Emitter::Emitter(int x, int y, int amount); and needs to be created so it can be accessed in the Splash class.
I tried to do this, but it didn't work:
class Splash{
private:
Emitter ps(100, 200, 400, "firstimage.png", "secondimage.png"); // Try to create object, doesn't work.
public:
// Other splash class functions.
}
I also tried this, which didn't work either:
class Splash{
private:
Emitter ps; // Try to create object, doesn't work.
public:
Splash() : ps(100, 200, 400, "firstimage.png", "secondimage.png")
{};
}
Edit: I know the second way is supposed to work, however it doesn't. If I remove the Emitter Section, the code works. but when I do it the second way, no window opens, no application is executed.
So how can I create my Emitter object for use in Splash?
Edit:
Here is my code for the emitter class and header:
Header
// Particle engine for the project
#ifndef _PARTICLE_H_
#define _PARTICLE_H_
#include <vector>
#include <string>
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "image.h"
extern SDL_Surface* gameScreen;
class Particle{
private: // Particle settings
int x, y;
int lifetime;
private: // Particle surface that shall be applied
SDL_Surface* particleScreen;
public: // Constructor and destructor
Particle(int xA, int yA, string particleSprite);
~Particle(){};
public: // Various functions
void show();
bool isDead();
};
class Emitter{
private: // Emitter settings
int x, y;
int xVel, yVel;
private: // The particles for a dot
vector<Particle> particles;
SDL_Surface* emitterScreen;
string particleImg;
public: // Constructor and destructor
Emitter(int amount, int x, int y, string particleImage, string emitterImage);
~Emitter();
public: // Helper functions
void move();
void show();
void showParticles();
};
#endif
and here is the emitter functions:
#include "particle.h"
// The particle class stuff
Particle::Particle(int xA, int yA, string particleSprite){
// Draw the particle in a random location about the emitter within 25 pixels
x = xA - 5 + (rand() % 25);
y = yA - 5 + (rand() % 25);
lifetime = rand() % 6;
particleScreen = Image::loadImage(particleSprite);
}
void Particle::show(){
// Apply surface and age particle
Image::applySurface(x, y, particleScreen, gameScreen);
++lifetime;
}
bool Particle::isDead(){
if(lifetime > 11)
return true;
return false;
}
// The emitter class stuff
Emitter::Emitter(int amount, int x, int y, string particleImage, string emitterImage){
// Seed the time for random emitter
srand(SDL_GetTicks());
// Set up the variables and create the particles
x = y = xVel = yVel = 0;
particles.resize(amount, Particle(x, y, particleImage));
emitterScreen = Image::loadImage(emitterImage);
particleImg = particleImage;
}
Emitter::~Emitter(){
particles.clear();
}
void Emitter::move(){
}
void Emitter::show(){
// Show the dot image.
Image::applySurface(x, y, emitterScreen, gameScreen);
}
void Emitter::showParticles(){
// Go through all the particles
for(vector<Particle>::size_type i = 0; i != particles.size(); i++){
if(particles[i].isDead() == true){
particles.erase(particles.begin() + i);
particles.insert(particles.begin() + i, Particle(x, y, particleImg));
}
}
// And show all the particles
for(vector<Particle>::size_type i = 0; i != particles.size(); i++){
particles[i].show();
}
}
Also here is the Splash Class and the Splash Header.
The second option should work, and I would start looking at compilation errors to see why it doesn't. In fact, please post any compilation errors you have related to this code.
In the meantime, you can do something like this:
class Splash{
private:
Emitter* ps;
public:
Splash() { ps = new Emitter(100,200,400); }
Splash(const Splash& copy_from_me) { //you are now responsible for this }
Splash & operator= (const Splash & other) { //you are now responsible for this}
~Splash() { delete ps; }
};
Well, I managed to fix it, in a hackish way though. What I did was create a default constructor, and move my normal Constructor code into a new function. Then I created the object and called the the new init function to set everything up.