C++ FLTK, creating a rounded box - c++

The problem says:
Draw a box with rounded corners. Define a class Box, consisting of four lines and four arcs.
So I wrote the below code for that exercise:
#include <Simple_window.h>
Simple_window win(Point(100,100), 600,400, "semi-ellipse");
struct Box: Shape{
Box(Point p, int ww, int hh): w(ww), h(hh)
{ add(Point(p.x-ww,p.y-hh)); }
void d_l() const //creating 4 lines
{
Line hrz1 (Point(150,100), Point(400,100));
Line hrz2 (Point(150,300), Point(400,300));
Line ver1 (Point(507,150), Point(507,250));
Line ver2 (Point(41,150), Point(41,250));
win.attach(hrz1);
win.attach(hrz2);
win.attach(ver1);
win.attach(ver2);
}
void draw_lines() const //creating 4 arcs
{
fl_arc(point(0).x,point(0).y,w,h,30,90);
fl_arc(point(0).x,point(0).y,w,h,270,330);
fl_arc(point(0).x,point(0).y,w,h,90,150);
fl_arc(point(0).x,point(0).y,w,h,210,270);
}
private:
int w;
int h;
};
int main()
{
using namespace Graph_lib;
Box b(Point(100,100),100,50);
win.attach(b);
win.wait_for_button();
}
When I ran it I faced this exception:
Unhandled exception at 0x757FE9D7 (ole32.dll) in test.exe: 0xC0000005: Access violation reading location 0x00000004.
I know this refers to declaring Simple_window win(Point(100,100), 600,400, "semi-ellipse"); in global state. But I did that because I had to do it. The problem is that how to attach lines and also object (here b) to Simple_window win in either parts (main() function and also Box struct).

Looks like it is caused by the global creation of win. I have never run an FLTK program where anything graphical is created before main but I'm guessing that sometimes the graphics libs require some things to be in place so it is best to use them after main.
What can you do about it? If win is declared as a pointer and created inside main instead of outside main, then you won't get a crash.
...
Simple_window* win;
struct Box: Shape
{
...
win->...
...
}
int main()
{
win = new Simple_window(Point(100, 100), 600, 400, "semi-ellipse");
Box b ...
win->attach ...
win->wait ...
delete win;
}

You don't need to put anything in global space at all. You want to be passing information to the classes that need them as opposed to needing everything declared in global scope before you do anything with it.
What I write here modifies your Box class so that it also has a private member variable which is a pointer to a Simple_window class. The constructor is modified so that when you construct Box b you have to send it a pointer to the Simple_window in which it will be drawn. When you do this the pointer is assigned the pointer to the then declared Simple_Window win.
#include <Simple_window.h>
struct Box: Shape{
private:
int w;
int h;
Simple_window* window;
public:
Box(Point p, int ww, int hh,Simple_window* win_): w(ww), h(hh),window(win_)
{ add(Point(p.x-ww,p.y-hh)); }
void d_l() const //creating 4 lines
{
Line hrz1 (Point(150,100), Point(400,100));
Line hrz2 (Point(150,300), Point(400,300));
Line ver1 (Point(507,150), Point(507,250));
Line ver2 (Point(41,150), Point(41,250));
window->attach(hrz1);
window->attach(hrz2);
window->attach(ver1);
window->attach(ver2);
}
void draw_lines() const //creating 4 arcs
{
fl_arc(point(0).x,point(0).y,w,h,30,90);
fl_arc(point(0).x,point(0).y,w,h,270,330);
fl_arc(point(0).x,point(0).y,w,h,90,150);
fl_arc(point(0).x,point(0).y,w,h,210,270);
}
};
int main()
{
using namespace Graph_lib;
Simple_window* win = new Simple_window(Point(100,100), 600,400, "semi-ellipse");
Box b(Point(100,100),100,50,win);
win->attach(b);
win->wait_for_button();
}

Your lines are hard coded and independent of the constructor parameters. They could be drawn using directly the FLTK library, similarly with the arcs and placed inside the inherited from class Shape and overriden function void draw_lines() const. Then you don't need the window object to be pointer.
A possible implementation is:
Box::Box(Point p, int w, int h)
: width(w), height(h)
{
add(Point(p.x - w, p.y - h));
}
void Box::draw_lines() const
{
// draw lines with reduced length to adapt for the arcs
if (color().visibility())
{
// upper horizontal
fl_line(point(0).x + width/4, point(0).y, point(0).x + (3./4.) * width, point(0).y);
// lower horizontal
fl_line(point(0).x + width/4, point(0).y + height, point(0).x + (3./4.) * width, point(0).y + height);
// left vertical
fl_line(point(0).x, point(0).y + height/4, point(0).x, point(0).y + (3./4.)*height);
// right vertical
fl_line(point(0).x + width, point(0).y + height/4, point(0).x + width, point(0).y + (3./4.) * height);
}
// draw arcs
if(color().visibility())
{
fl_color(fill_color().as_int());
// upper left arc
fl_arc(point(0).x, point(0).y, width/2, height/2, 90, 180);
// upper right arc
fl_arc(point(0).x + width/2, point(0).y, width/2, height/2, 0, 90);
// down right arc
fl_arc(point(0).x + width/2, point(0).y + height/2, width/2, height/2, 270, 0);
// down left arc
fl_arc(point(0).x , point(0).y + height/2, width/2, height/2, 180, 270);
}
}

Related

How do I get a destructor on an object in a vector not to throw a failed assertion? [closed]

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.

Beginner having an issue with classes and functions

I am a beginner programmer working on a program in c++ visual studio 2015 that takes an instance of a class titled rect and passes it to a function within rect that sets a rectangle of random size and position somewhere on a imaginary board in a console window. At the bottom of the code there are full instructions on what the code needs to do. The problem I am having is when the program prints the rectangles, the rectangle of "0's" is not printing but the rectangle of "1's" is. The rectangle rect0 is being passed by reference and the rect1 is being passed by pointer.
/*
iLab2: rectangles
*/
#define NOMINMAX // prevent Windows API from conflicting with "min" and "max"
#include <stdio.h> // C-style output. printf(char*,...), putchar(int)
#include <windows.h> // SetConsoleCursorPosition(HANDLE,COORD)
#include <conio.h> // _getch()
#include <time.h>
/**
* moves the console cursor to the given x/y coordinate
* 0, 0 is the upper-left hand coordinate. Standard consoles are 80x24.
* #param x
* #param y
*/
void moveCursor(int x, int y)
{
COORD c = { x,y };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);
}
struct Vec2
{
short x, y; // variables x and y for storing rectangle coordinates
Vec2() : x(0), y(0) { } // default constructor for vect2 if no parameters are specified
Vec2(int x, int y) : x(x), y(y) { } // default constructor for vect2 if parameters are given
void operator+=(Vec2 v) // function for adding or subtracting (if v is negative) to move the rectangle
{
x += v.x;
y += v.y;
}
};
class Rect
{
Vec2 min, max;
public:
Rect(int minx, int miny, int maxx, int maxy)
:min(minx, miny), max(maxx, maxy)
{}
Rect() {}
void draw(const char letter) const
{
for (int row = min.y; row < max.y; row++)
{
for (int col = min.x; col < max.x; col++)
{
if (row >= 0 && col >= 0)
{
moveCursor(col, row);
putchar(letter);
}
}
}
}
void setMax(int maxx, int maxy)
{
this->max.x = maxx;
this->max.y = maxy;
}
void setMin(int minx, int miny)
{
this->min.x = minx;
this->min.y = miny;
}
bool isOverlapping(Rect const & r) const
{
return !(min.x >= r.max.x || max.x <= r.min.x
|| min.y >= r.max.y || max.y <= r.min.y);
}
void translate(Vec2 const & delta)
{
min+=(delta);
max+=(delta);
}
void setRandom(Rect & r);
void setRandom(Rect* r);
};
void Rect::setRandom(Rect & r)
{
srand(time(NULL)); // added to make the random placement and size of the rect different each time program runs
int pos_x, pos_y, height, width;
pos_x = rand() % 51;
pos_y = rand() % 21;
height = 2 + rand() % 11;
width = 2 + rand() % 11;
height = height / 2;
width = width / 2;
r.min.x = pos_x - width;
r.min.y = pos_y - height;
r.max.x = pos_x + width;
r.max.y = pos_y + height;
}
void Rect::setRandom(Rect * r)
{
srand(time(NULL)); // added to make the random placement and size of the rect different each time program runs
int posX, posY, heightPoint, widthPoint;
posX = rand() % 51;
posY = rand() % 21;
heightPoint = 2 + rand() % 11;
widthPoint = 2 + rand() % 11;
heightPoint = heightPoint / 2;
widthPoint = widthPoint / 2;
this->min.x = posX - widthPoint;
this->min.y = posY - heightPoint;
this->max.x = posX + widthPoint;
this->max.y = posY + heightPoint;
}
int main()
{
// initialization
//Rect userRect(7, 5, 10, 9); // (x-min, y-min, x-max, y-max) x-min how far left the rectange can be
//Rect rect0(10, 2, 14, 4); // (x-min, y-min, x-max, y-max)
//Rect rect1(1, 6, 5, 15); // (x-min, y-min, x-max, y-max)
//Rect userRect;
Rect * userRect;
Rect rect0;
Rect rect1;
const int rectSize = 5;
Rect rect[rectSize];
userRect = new Rect();
// set
rect[0].setRandom(rect[0]);
rect[1].setRandom(& rect[1]);
userRect->setMin(7, 5);
userRect->setMax(10, 9);
//rect0.setMin(10, 2);
//rect0.setMax(14, 4);
//rect1.setMin(1, 6);
//rect1.setMax(5, 15);
int userInput;
do
{
// draw
rect[0].draw('0'); // drawing the 0 rectangle with an x width of 4 and a y height of 2
rect[1].draw('1'); // drawing the 1 rectangle with a x width of 4 and a y height of 9
moveCursor(0, 0); // re-print instructions
printf("move with 'w', 'a', 's', and 'd'");
userRect->draw('#'); // drawing the user rectangle in its starting location with a x width of 3 and a y height of 4
// user input
userInput = _getch();
// update
Vec2 move;
switch (userInput)
{
case 'w': move = Vec2(0, -1); break; // Moves the user Rectangle -y or up on the screen
case 'a': move = Vec2(-1, 0); break; // Moves the user Rectangle -x or left on the screen
case 's': move = Vec2(0, +1); break; // Moves the user Rectangle +y or down on the screen
case 'd': move = Vec2(+1, 0); break; // Moves the user Rectangle +x or right on the screen
}
userRect->draw(' '); // un-draw before moving
userRect->translate(move); // moves the user rectangle to the new location
} while (userInput != 27); // escape key
delete userRect; // delete dynamic object to release memory
return 0;
}
// INSTRUCTIONS
// ------------
// 3) Random rectangles, by reference and by pointer
// a) create a method with the method signature "void setRandom(Rect & r)".
// This function will give the passed-in Rect object a random location.
// The random x should be between 0 and 50 x. The random y should be
// between 0 and 20. Limit the possible width and height to a minimum of 2
// and a maximum of 10.
// b) test "void setRandom(Rect & r)" on the local Rect object "rect0".
// c) create a method with the method signature
// "void setRandomByPointer(Rect * r)", which functions the same as
// "void setRandom(Rect & r)", except that the argument is
// passed-by-pointer.
// d) test "void setRandomByPointer(Rect * r)" on the local Rect object
// "rect1".
// 4) Test and show overlap
// a) Using the existing function "isOverlapping(Rect const &)", test to see
// if userRect collides with any other Rect objects. If userRect is
// overlapping, draw it with '+' instead '#'.
// b) Create a Rect * pointer that points to the address if the Rect object
// that userRect collides with. It should point at NULL if userRect is
// colliding with no other Rect objects.
// c) Print to the screen the width and height of a Rect object that userRect
// collides with. If no collision is happening, print "no collision"
// instead.
// 5) Array of objects
// a) Replace the Rect objects rect0 and rect1 with an array of 2 Rect
// objects, "rect[2]".
// b) Make sure you replace every remaining "rect0" with "rect[0]", and every
// "rect1" with "rect[1]".
// c) Increase the size of the "rect" array to 5. Make sure all 5 Rect
// objects are randomized, drawn to the screen, and tested for collision.
// d) If you have not already done so, replace
// duplicate-code-using-array-elements with a for-loop. For example:
// If you have:
// rect[0].draw('0');
// rect[1].draw('1');
// rect[2].draw('2');
// rect[3].draw('3');
// rect[4].draw('4');
// Replace it with:
// for(int i = 0; i < NUMBER_OF_RECTS; i++)
// {
// rect[i].draw('0'+i);
// }
// Do this where objects are randomized, drawn, and tested for collision
You have two different setRandom() methods with three problems.
Each time either setRandom() gets called, srand() also gets called. srand() should only be called once, when the program starts -- read the first answer to that question, carefully.
Code duplication. The code in both setRandom() is nearly identical. Code duplication is bad. Duplicated code means that if the algorithm needs to be changed in some way, you will have to remember to do it in two places. Or three places. Or four places. Or however many duplicate chunks of code exist in the code. You have to remember them all, and find them. If you miss one, bugs galore.
Same problem as #2, but for the "nearly identical" part. The difference is: the first version of setRandom() takes a reference to another object and modifies another object that's passed by reference. The second version of setRandom() takes a pointer to another object instead of a reference, but ignores it completely, and instead initializes this, instead of the pointed object.
And, as a result of these bugs, we get the results you're seeing.
rect[0].setRandom(rect0);
This ends up initializing rect0. rect[0] is ignored completely, and not initialized at all.
rect[1].setRandom(& rect1);
This ends up initializing rect[1]. rect1 is ignored completely, and not initialized at all.
And that's why the rest of the code fails to draw rect[0]. It does not get initialized at all.
The shown code is completely confused because it has four, and not two, objects. rect0, rect1, and the rect[] array containing two more objects. After they are declared, rect0 and rect1 are completely ignored, except for the misfired initialization, and they serve apparently no purpose whatsoever.
Neither is there any real reason here for setRandom() to take either a pointer or a reference to some other object. The apparent purpose of setRandom() is to initialize an object's dimensions randomly.
So it should simply initialize this's dimensions randomly. Passing some other object, by pointer or reference, makes no sense at all.
Then, after getting rid of rect0 and rect1, and simply calling a single setRandom() method...
rect[0].setRandom();
rect[1].setRandom();
... the rest of the code will proceed and properly draw two randomly-initialized objects.
the code Rect rect[ rectSize ] will create 5 rects to array rect and all of those rects are with min(0,0) max(0,0)(initial state). when you call rect[ 0 ].setRandom( rect0 ) which will update rect0(you pass it by reference) and do nothing to rect[0].when you call rect[ 1 ].setRandom( &rect1 ) you update rect[1] (by this->min.x = posX - some value).so you get difference between rect[0] and rect[1].

How to change the Point coordinates of opengl in the center

I'm working with QT , I will to design a point (0,0) with OPENGL .
the problem is : the point Not in the middle :
http://i.stack.imgur.com/diB33.png
my code :
the header :
#ifndef BRM_H
#define BRM_H
#include <QGLWidget>
#include<qwidget.h>
class brm : public QGLWidget
{
Q_OBJECT
public:
int x , y ;
explicit brm(QWidget *parent = 0);
void initializeGL();
void paintGL();
void resize(int a ,int b);
};
#endif // BRM_H
the class :
#include<brm.h>
#include<qgl.h>
#include <GL/glut.h>
#include <GL/glu.h>
brm::brm(QWidget *parent )
: QGLWidget( parent)
{
}
void
brm::initializeGL(){
glClearColor(0,0,0,1);
}
void brm::paintGL(){
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_POINTS);
glVertex2f(0.0, 0.0);
glEnd();
}
void brm::resize(int a , int b){
}
I will change the point , in the middle like this :
http://i.stack.imgur.com/WRC2e.png
why not define 2 more variables that (if you add these two with your point coordinates, you have your corrected coordinates)
so
const int MIDLLE_X = 1280 / 2; //or whatever your width divided by 2 is
const int MIDDLE_Y = 720 / 2; //or whatever your height divided by 2 is
(make them global if possible)
so (MIDDLE_X, MIDDLE_Y) as a coordinate is in the center
than you can make 2 function
int centerizeX(int x) { // wants the X coordinate
return x + MIDDLE_X;
}
int centerizeY(int y) { // wants the Y coordinate
return y + MIDDLE_X;
}
with that you can still work with your coordinates, they can even go negative. But when you want to render, draw (whatever that has to do with screen) than you should call these 2 functions to, well correct their appereance positions.
Try this:
void brm::resize(int a , int b){
glViewport(-a/2, -b/2, a, b);
}
After that, the [0, 0] position should be always at the center of the widget.

C calling a class function inside of another Class that is currently an Object

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...)

Animating an array of child class objects

I am trying to create a parent class "Shape" with child classes "Circle", "Triangle", "Rectangle". The parent class holds the x pos, y pos, and fill color or all the "shapes" and then each child class holds info specific to that shape. Would anyone mind looking over my code and see why im getting the error "Shapes does not have a member 'setRadius'" when trying to set the radius in the array of objects...
P.S. right now I only have the child class "Circle" until i get it working. Then I will add the other two classes.
Also, if anyone sees any other errors in my code, I would appreciate them being pointed out.
Thanks in advance
#include <allegro.h>
#include <cstdlib>
using namespace std;
#define scrX 640
#define scrY 400
#define WHITE makecol(255,255,255)
#define GRAY makecol(60,60,60)
#define BLUE makecol(17,30,214)
int random(int low, int high);
const int numCircles = random(1,50);
class Shape{
public:
Shape(){x = scrX / 2; y = scrY / 2; fill = WHITE;}
protected:
int x, y, fill;
};
class Circle : public Shape{
public:
Circle(){radius = 0;}
Circle(int r){radius = r;}
void setRadius(int r){radius = r;}
protected:
int radius;
};
int main()
{
// Program Initialization
allegro_init();
install_keyboard();
set_color_depth(32);
set_gfx_mode(GFX_AUTODETECT_WINDOWED, scrX, scrY, 0, 0);
// Create and clear the buffer for initial use
BITMAP *buffer = create_bitmap(scrX, scrY);
clear_to_color(buffer, GRAY);
// Set title and create label text in window
set_window_title("Bouncing Balls Ver 1.0");
textout_ex(buffer, font, "Bouncing Balls Ver 1.0", 10, 20, WHITE, GRAY);
// Draw a background box
rectfill(buffer, 50, 50, scrX-50, scrY-50, BLUE);
// Create circles
Shape **GCir;
GCir = new Shape *[numCircles];
for(int i=0;i<numCircles;i++){
GCir[i] = new Circle;
GCir[i]->setRadius(random(1,25)); // THIS IS THE ERROR
}
while(!key[KEY_ESC]){
blit(buffer, screen, 0, 0, 0, 0, scrX, scrY);
}
destroy_bitmap(buffer);
return 0;
}
END_OF_MAIN();
int random(int low, int high)
{
return rand() % (high - low) + low;
}
The type of GCir[i] is Shape* and the Shape class doesn't have a setRadius method, Circle does. So either call setRadius on the Circle object before assign it to GCir[i] or just construct the Circle with the proper radius: GCir[i] = new Circle(random(1,25));
hammer fix :
GCir[i]->setRadius(random(1,25));
should be changed to
((Circle*)GCir[i])->setRadius(random(1,25));
Deeper problems:
you need virtual destructor on BaseClass
a better way to do it is to take the radius in the Circle class constructor.
then either use Shape::draw() as a virtual function to specify shape drawing or implement Shape::getType() and use a switch case to determine drawing logic after proper casting.
Compiler said it. You have an array of Shapes on which you try to call setRadius which is only defined for Circles. You can only call shape methods without casting Shape poonter to circle.