My assignment is to derive a new class called Smiley from an existing class called Circle. I am using FLTK & C++.
Circle is:
struct Circle : Shape {
Circle(Point p, int rr) // center and radius
:r(rr) { add(Point(p.x-r,p.y-r)); }
void draw_lines() const;
Point center() const;
void set_radius(int rr) { set_point(0,Point(center().x-rr,center().y-rr)); r=rr; }
int radius() const { return r; }
private:
int r;
};
(The add method is a free method, not part of Circle)
And what I have created for Smiley so far is
class Smiley : public Circle {
public:
Smiley (Point p, int r) : Circle (a, r){
return;
}
};
I'm trying to figure out how to add circular eyes and a semi-circle mouth. I have an extremely vague idea of what the eyes should look like
Circle left_eye(Point(p.x - (r/3), p.y - (r/3)), (r/8)); //left eye
Circle right_eye(Point(p.x + (r/3), p.y - (r/3)), (r/8)); //right eye
But I don't even know how to incorporate it into my Smiley class, or if that's even the proper format. Help would be much appreciated, thanks.
You would push back your eyes onto a Vector_ref along with the mouth and the head and then create a function that draws each element of the vec_ref. Use a for loop in the drawing function (the drawing function should override the draw_lines() function from Circle)
Related
I have the following classes:
//----------------------------------------------------------------------
// CHARACTER CLASS
//----------------------------------------------------------------------
class Character
{
private:
POINT2f char_position;
public:
VECTOR2f char_velocity;
Character();
~Character();
// Mutators
void SetChar_Position(POINT2f p);
void SetChar_Velocity(VECTOR2f v);
// Accessors
POINT2f GetChar_Position();
VECTOR2f GetChar_Velocity();
};
//----------------------------------------------------------------------
// PLAYER CLASS - INHERITED FROM "CHARACTER" CLASS
//----------------------------------------------------------------------
class Player : public Character
{
private:
public:
int health;
Player();
~Player();
void SetPlayer_Health(int h);
int GetPlayer_Health();
};
So essentially the player class inherits from the character class.
The Character class has member function which lets you set the characters position and velocity, which take in a POINT2f and VECTOR2f.
Within my main bit of code I create a player character Player Player1 and than set the balls velocity and position if a button is pressed:
if (ui.isActive('A')) // Check to see if "A" key is pressed
{
// Player Ball
Player1.SetChar_Velocity.x = -12.0;
Player1.SetChar_Position.x += (Player1.GetChar_Velocity.x*dt);
Player1.SetChar_Velocity.x += (acceleration*dt);
}
I'm currently getting errors that say left of .x must have class/struct/union, so I change Player1.SetChar_Velocity.x = -12.0; to Player1.SetChar_Velocity().x = -12.0; which than brings up the error expression must have class type and to few arguments in function call.
Does anyone know of a method that will allow my to only manipulate the x number of the char_velocity only. also I understand that my code to Set the .x velocity isn't correct because I'm not passing in a VECTOR2f value.
In order to achieve what you want to do, you will want the return type of you Get_ methods to be a reference (wiki). Your code will then look like
class Character
{
private:
POINT2f char_position;
public:
VECTOR2f char_velocity;
// Accessors
POINT2f& GetChar_Position() { return char_position; }
VECTOR2f& GetChar_Velocity() { return char_velocity; }
};
Also, it is often advised or required to be able to preserve const-correctness in your code, so you might want to add
const POINT2f& GetChar_Position() const { return char_position; }
const VECTOR2f& GetChar_Velocity() const { return char_velocity; }
This will allow you to do some calls like
POINT2f current_pos = a_char.GetChar_Position(); // const
a_char.GetChar_Velocity().x += 2; // non-const
Please note that it is often advised to pass the structures as const references instead of copies (although this might not hold true depending on your c++ version and your types, you can see this question for clarification), hence change your
void SetChar_Position(POINT2f pos) { char_position = pos; }
void SetChar_Velocity(VECTOR2f vel) { char_velocity = vel; }
to
void SetChar_Position(const POINT2f& pos) { char_position = pos; }
void SetChar_Velocity(const VECTOR2f& vel) { char_velocity = vel; }
I have a vector of Shapes, Shape being a class I wrote. In the keyDown function, I iterate through this vector of Shapes and update the bool property, background, to true. However, it appears not to be persisting this change.
Main class:
vector<Shape> mTrackedShapes;
void CeilingKinectApp::keyDown( KeyEvent event )
{
// remove all background shapes
if (event.getChar() == 'x') {
for (Shape s : mTrackedShapes) {
s.background = true;
}
}
}
Shape.h
#pragma once
#include "CinderOpenCV.h"
class Shape
{
public:
Shape();
int ID;
double area;
float depth;
cv::Point centroid; // center point of the shape
bool matchFound;
bool moving;
bool background;
cinder::Color color;
int stillness;
float motion;
cv::vector<cv::Point> hull; // stores point representing the hull of the shape
int lastFrameSeen;
};
Shape.cpp
#include "Shape.h"
Shape::Shape() :
centroid(cv::Point()),
ID(-1),
lastFrameSeen(-1),
matchFound(false),
moving(false),
background(false),
stillness(0),
motion(0.0f)
{
}
It registers the keyDown event, and correctly iterates through the vector, but the background property remains false. What am I doing wrong?
Try
for (Shape &s : mTrackedShapes)
Your code would make a copy of the object, and you would change the properties on the copy rather than the one in the vector
I am sort of a noob in C++ and I am trying to make a simplegame. This is my problem:
I created class called sprite:
class Sprite
{
private:
Point2D sp_pos;
Point2D sp_vel;
SDL_Surface* sp_img;
Point2D sp_center;
Point2D sp_size;
double sp_radius;
bool sp_animated;
int sp_frames;
int sp_cur_frame;
public:
Sprite() {}
Sprite(Point2D pos, Point2D vel, SDL_Surface *img, ImageInfo info, bool animated = false, int frames = 0);
virtual void draw(SDL_Surface* screen);
virtual void update();
void setInfo (ImageInfo info);
void setPos( Point2D pos ) { sp_pos = pos; }
void setVel( Point2D vel ) { sp_vel = vel; }
void setImg (SDL_Surface* img) { sp_img = img; }
void setNextFrame() { sp_cur_frame++; }
void setFrame( int frame ) { sp_cur_frame = frame; }
void setAnimated(bool animated) { sp_animated = animated; }
void changeVelX (int c) { sp_vel.setX(c);}
void changeVelY (int c) { sp_vel.setY(c);}
void changePosX (int c) { sp_pos.setX(c);}
void changePosY (int c) { sp_pos.setY(c);}
SDL_Surface* getImg() { return sp_img; }
Point2D getPos() { return sp_pos; }
Point2D getVel() { return sp_vel; }
Point2D getCenter() { return sp_center; }
Point2D getSize() { return sp_size; }
double getRadius() { return sp_radius; }
int getCurFrame() { return sp_cur_frame; }
int getFrames() { return sp_frames; }
bool collide(Sprite &another_sprite);
};
Which has a method called "collide", this method detects a collision between two sprites, and works as follows:
bool Sprite::collide(Sprite &another_sprite)
{
double d = getPos().dist(another_sprite.getPos());
if ( d < ( getRadius() + another_sprite.getRadius() ) )
return true;
else
return false;
}
The method works fine. My problem arises with the following, I have implemented different classes that are subclasses of "Sprite" and will represent enemies in my game, so, for instance I would have objects: Class enemy1 : public Sprite, Class enemy2 : public Sprite, etc. They are different because they have different behaviors. I implemented other two helper functions called group_collide and group_group_collide, that work as follows:
bool group_collide(std::list<Sprite> &group, Sprite other_object)
{
bool collision = false;
for (std::list<Sprite>::iterator sprite = group.begin(), end = group.end(); sprite != end; ++sprite)
{
if (sprite->collide(other_object))
{
Sprite exp = Sprite(sprite->getPos(), Point2D(0, 0), exp_image, exp_info, true, 7);
exp_group.push_back(exp);
if( Mix_PlayChannel( -1, explosion, 0 ) == -1 )
{
//abort();
}
sprite = group.erase(sprite);
collision = true;
}
}
return collision;
}
int group_group_collide(std::list<Sprite> &group, std::list<Sprite> &other_group)
{
int scored = 0;
for (std::list<Sprite>::iterator it1 = group.begin(), end1 = group.end(); it1 != end1; ++it1)
{
if (group_collide(other_group, *it1))
{
it1 = group.erase(it1);
scored += 10;
}
}
return scored;
}
So, in fact, group collide will detect collisons between a sprite and a list of sprites, and group_group_collide will detect collisions between group of sprites (two different lists). The problem that arises is: There will be at least 4 types of enemies, and all of them are subclasses of my Sprite class, but I get compilation errors when I create a list of sprites and add elements that are subclasses of sprites. My solution was writing a method group_collide and group_group collide for all types of enemies, but this is quite inelegant. Is there a better way to approach this problem?
EDIT:
Thanks for your suggestions. I defined the list as a pointers list as you have suggested:
std::list<Sprite*> enemy_group;
And for instance, I am adding elements of class "Kamikaze" which is a subclass of sprite, in this way (the method update is different in this class):
enemy_group.push_back(new Kamikaze(enemy_pos, enemy_vel, 0, enemy_image, enemy_info));
However, when iterating over the list:
for (list<Sprite*>::iterator it = enemy_group.begin(), end = enemy_group.end(); it != end; ++it) {
(*it)->draw(screen);
(*it)->update();
if ((*it)->getPos().getY() > SCREEN_HEIGHT + 30)
{
delete *it;
it = enemy_group.erase(it);
}
}
The method update is called from the Sprite class, not Kamikaze class, therefore I also have object slicing problem with this approach, perhaps there is something wrong with what I have done?
I get compilation errors when I create a list of sprites and add elements that are subclasses of sprites.
All derived classes will be 'sliced' in order to fit into an object container like std::list. A std::list<Sprite*> //(Preferably a smart pointer) will avoid this problem, though the actual objects would have to be stored elsewhere.
As given in the answer by Laserbreath, you should replace std::list<Sprite> with std::list<Sprite*>. Currently, any passed subclass will be reduced to Sprite. Using a list of pointers you can avoid that.
You should use virtual functions to get the desired result.
In base class:
//This way you'll have a default collision method for a Sprite...
//...but you'll be able to re-define it in subclasses.
//I don't do THIS ONE often so I'm not sure if you'll have to perform additional steps
virtual bool Sprite::collide(Sprite &another_sprite)
{
...
}
//And this way you are making collied a pure virtual function and Sprite an abstract class...
//...meaning you can't instantiate it, but you can use it with a pointer or reference.
//Every subclass of Sprite must have a body of function collide defined
//you do this only in header of class Sprite
virtual bool virtual bool Sprite::collide(Sprite &another_sprite) = 0;
In sub-class
//if you have made collide pure virtual function, you can do this
//not sure about the first case though
bool SubSprite::collide(Sprite &another_sprite)
{
...
}
So, when collide method is called from a Sprite pointer or reference, the call will be re-directed to the designated function of a subclass.
Same goes for group_collide.
ADDITIONAL EXPLANATION:
//lets assumme you have 2 sprite types, Kamikaze and NotKamikaze
Sprite *sprite1 = new Kamikaze();
Sprite *sprite2 = new NotKamikaze();
//and lets assume collide uses pointer instead, just for this example, so it's shorter
virtual bool Sprite::collide(Sprite *another_sprite) = 0;
bool Kamikaze::collide(Sprite *another_sprite);
bool NotKamikaze::collide(Sprite *another_sprite);
//when you call collide from Sprite*, it **automatically** picks the sub-class collude method
//sprite1 is of type Sprite*, but allocated memory is of Kamikaze
//so the only function called is Kamikaze::collide
sprite1->collide(sprite2);
//sprite2 is of type Sprite*, but allocated memory is of NotKamikaze
//so the only function called is NotKamikaze::collide
sprite2->collide(sprite2);
So whenever a pure virtual function collide is called from pointer or reference, the program automatically selects the right one. If you want it to be different for every sprite type, then this is what you need.
This is where "object slicing" becomes the issue. Sprite can exist as a pointer or reference, but only to a non-abstract sub-class. So Sprite *Sprite sprite1 = new Sprite(); won't work, but Sprite *Sprite sprite1 = new SpriteSubClass(); works.
If you make Sprite::collide not purely virtual, Sprite would no longer be an abstract class, and you could make the method run from Sprite class itself, and you could do Sprite *Sprite sprite1 = new Sprite();. But I highly doubt you'll need that as you're only looking at subclasses.
Whenever a method name is shared, but its behavior differs by subclass, it must be virtual.
I'm currently trying to write a button class. It takes 2 textures, m_texture and m_onHover, and its caption, which should be automatically centered. The function update() takes care of selecting the correct texture.
class button : public sf::Drawable
{
private:
const sf::Texture *m_texture;
const sf::Texture *m_onHover;
sf::Sprite m_sprite;
public:
button();
sf::Text m_caption; // public to allow easy formating, see centerCaption()
bool mouseIsOver() const;
void update();
void setPosition(sf::Vector2f position);
void setPosition(float x, float y);
void centerCaption();
// Access functions
void setTexture(const sf::Texture &texture) { m_texture = &texture; m_sprite.setTexture(*m_texture); }
void setonHoverTexture(const sf::Texture &texture) { m_onHover = &texture; }
void setCaption(sf::String text) { m_caption.setString(text); centerCaption(); }
void setFontSize(unsigned int size) { m_caption.setCharacterSize(size); centerCaption(); }
void setFont(sf::Font& font) { m_caption.setFont(font); }
private:
virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const;
};
bool button::mouseIsOver() const
{
if (m_sprite.getGlobalBounds().contains(sf::Vector2f(sf::Mouse::getPosition()))) // creating a float vector for contains() because getPosition gives int vector
{
return true;
}
else
{
return false;
}
}
Everything seems to be working, but the mouse position at which mouseIsOver() returns true seems to be moved 40 pixels above the sprite. The values in the rect from getGlobalBounds() seem to be correct when printed in the console.
Unluckily I dont have enough reputation to post a screenshot.
The cursor position should be translated to the proper coordinate system. Basically you need to use sf::RenderTarget::mapPixelToCoords (available in sf::Renderwindow by inheritance). For more details, have a look at the documentation and §Coordinates conversions of the official tutorial.
Also, you might want to consider making your button class inherit from sf::Transformable so that you don't have to manage the position/rotation/scale/... yourself. Have a look at Creating a SFML-like entity
I got the classic Shape hierarchy example...
struct Shape { // abstract type
Shape (int x, int y);
int x;
int y;
};
struct Rectangle : public Shape {
Rectangle (int x, int y, int w, int h);
int w;
int h;
};
struct Circle : public Shape {
Circle (int x, int y, int r);
int r;
};
a Shapes container, filled with Rectangles and Circles
std::list<Shape*> container;
and printing functions (in my case, those are collision detection functions)
void print_types (Shape&, Shape&) {
std::cout << "Shape, Shape" << std::endl;
}
void print_types (Rectangle&, Rectangle&) {
std::cout << "Rectangle, Rectangle" << std::endl;
}
void print_types (Rectangle&, Circle&) {
...
Course, when I'm doing this:
std::list<Shape*> it;
Rectangle r (0, 0, 32, 32);
for (it = container.begin(); it != container.end(); it++)
print_types(r, **it);
I don't want to print only "Shape, Shape" lines. I know virtual methods, dynamic_casts and visitors. But is there any elegant way to get out of it without those solutions and keep my external functions ?
You should probably stick with virtual functions and have only one print_types function
void print_types(Shape&)
Then add a virtual PrintName function to the base class and override it in the derived class.
This IS the most elegant way.
The short answer is no, function calls are resolved at compile-time. So there is no way (AFAIK) to do this with your existing free functions.
I believe you will have to invest in a double-dispatch mechanism, or do what #Peter suggests in his answer (which sounds more elegant).
I can't call it elegant, and it has several pitfalls, but the classic way to do this before dynamic_cast was to have a virtual function, say virtual char* name(), in Shape and have each derived class override that function to return the correct name.
The most obvious pitfall is that you must maintain the whole thing by hand.
Responding to the edit of the problem:
The best solution is still to find a virtual method that will deliver what is required. For detecting shape collisions, perhaps you could have a function that converts each shape to a polygon (set of lines) and do the detection on that.
C++ uses the type you declared at compile-time to select which overloaded function to call; it doesn't have the ability to make that selection at run-time. That's why you're seeing "Shape,Shape" as output each time. There's a way to help the compiler out but it's going to be tedious. Try to convert each Shape* to the appropriate type, and if it succeeds you can call a more specific function.
I'm not really advocating this; you can see how it gets out of hand with just two shapes, imagine how ugly it gets as you add more! Still it shows how to do what you were trying to do in C++.
void print_types (Rectangle*, Rectangle*) {
std::cout << "Rectangle, Rectangle" << std::endl;
}
void print_types (Rectangle*, Circle*) {
...
void print_types (Rectangle* left, Shape* right) {
Rectangle* rightRect = dynamic_cast<Rectangle*>(right);
if (rightRect != NULL) {
print_types(left, rightRect);
return;
}
Circle* rightCirc = dynamic_cast<Circle*>(right);
if (rightCirc != NULL) {
print_types(left, rightCirc);
return;
}
throw /* something to indicate invalid shape */;
}
void print_types (Circle* left, Shape* right) {
...
void print_types (Shape* left, Shape* right) {
Rectangle* leftRect = dynamic_cast<Rectangle*>(left);
if (leftRect != NULL) {
print_types(leftRect, right);
return;
}
Circle* leftCirc = dynamic_cast<Circle*>(left);
if (leftCirc != NULL) {
print_types(leftCirc, right);
return;
}
throw /* something to indicate invalid shape */;
}