I created a class for a type of enemy using allegro4 and C++; in this class I have a function that makes move a sprite, like this:
sprite_one(x, y);
sprite_two(x2, y2);
class enemy{
public:
void mov(){
x++;
----
y--;
}
}
};
enemy test_one;
test_one.mov(); // this works because its coordinates are x and y
enemy test_two;
test_two.mov(); // this doesn't work, its coordinates are x2 and y2
The problem is that when I create the object, the first one can move according to the function (updating variable x and y), the others no because they have different way to call the variables of the positions. How can I fix this?
Your enemy class needs to have the x and y coordinates as member variables. This is how you get each actual enemy to have its own coordinates separate from all the others. The following code should get you up and running, at least. You will presumably want to add a public function to print the coordinates, or to draw the enemy onscreen.
class enemy
{
int mx, my; // coordinates of this enemy
public:
enemy(int x, int y)
: mx(x), my(y) // initialize the coordinates
{
// possibly add future initialization here
}
void mov()
{
++mx;
--my;
}
}
Then you can create and move two enemies as before:
enemy test_one(x,y);
test_one.mov();
enemy test_two(x2,y2);
test_two.mov();
Note that x,y,x2,y2 are no longer variables storing the current positions of the enemies, but constants defining their start positions.
Related
I have a 2d physics engine that I've been programming in C++ using SFML; I've implemented a rough collision detection system for all SandboxObjects (the base class for every type of physics object), but I have a dilemma.
I plan to have many different derived classes of SandboxObjects, such as Circles, Rects, and so on, but I want a way to check if the roughHitbox of each SandboxObject collides with another.
When the program starts, it allocates memory for, let's say, 10,000 Circles
int circleCount = 0;//the number of active Circles
constexpr int m_maxNumberOfCircles = 10000;//the greatest number of circles able to be set active
Circle* m_circles = new Circle[m_maxNumberOfCircles];//create an array of circles that aren't active by default
like so.
and every time the user 'spawns' a new Circle, the code runs
(m_circles + circleCount)->setActive();`
circleCount++
Circles that aren't alive essentially do not exist at all; they might have positions and radii, but that info will never be used if that Circle is not active.
Given all this, what I want to do is to loop over all the different arrays of derived classes of SandboxObject because SandboxObject is the base class which implements the rough hitbox stuff, but because there will be many different derived classes, I don't know the best way to go about it.
One approach I did try (with little success) was to have a pointer to a SandboxObject
SandboxObject* m_primaryObjectPointer = nullptr;
this pointer would be null unless there were > 1 SandboxObjects active; with it, I tried using increment and decrement functions that checked if it could point to the next SandboxObject, but I couldn't get that to work properly because a base class pointer to a derived class acts funky. :/
I'm not looking for exact code implementations, just a proven method for working with the base class of many different derived classes.
Let me know if there's anything I should edit in this question or if there's any more info I could provide.
Your problems are caused by your desire to use a polymorphic approach on non-polymorphic containers.
The advantage of a SandboxObject* m_primaryObjectPointer is that it allows you to treat your objects polymorphicaly: m_primaryObjectPointer -> roughtHitBox() will work regardless of the object's real type being Circle, Rectangle, or a Decagon.
But iterating using m_primaryObjectPointer++ will not work as you expect: this iteration assumes that you iterate over contiguous objects in an array of SandboxObject elements (i.e. the compiler will use the base type's memory layout to compute the next address).
Instead, you may consider iterating over a vector (or an array if you really want to deal with extra memory management hassle) of pointers.
vector<SandboxObject*> universe;
populate(universe);
for (auto object:unviverse) {
if (object->isActive()) {
auto hb = object -> roughtHitBox();
// do something with that hitbox
}
}
Now managing the objects in the universe can be painful as well. You may therefore consider using smart pointers instead:
vector<shared_ptr<SandboxObject>> universe;
(little demo)
It's hard to answer this without knowing the requirements but you could have sandbox maintain two vectors of active and inactive objects, and use unique_ptrs of the base class for memory management.
Some code below:
#include <vector>
#include <memory>
#include <iostream>
class sandbox_object {
public:
virtual void do_something() = 0;
};
class circle : public sandbox_object {
private:
float x_, y_, radius_;
public:
circle(float x, float y, float r) :
x_(x), y_(y), radius_(r)
{}
void do_something() override {
std::cout << "i'm a circle.\n";
}
};
class triangle : public sandbox_object {
private:
float x1_, y1_, x2_, y2_, x3_, y3_;
public:
triangle( float x1, float y1, float x2, float y2, float x3, float y3) :
x1_(x1), y1_(y1), x2_(x2), y2_(y2), x3_(x3), y3_(y3)
{}
void do_something() override {
std::cout << "i'm a triangle.\n";
}
};
class sandbox {
using sandbox_iterator = std::vector<std::unique_ptr<sandbox_object>>::iterator;
private:
std::vector<std::unique_ptr<sandbox_object>> active_objects_;
std::vector<std::unique_ptr<sandbox_object>> inactive_objects_;
public:
void insert_circle(float x, float y, float r) {
active_objects_.push_back( std::make_unique<circle>(x, y, r) );
}
void insert_triangle(float x1, float y1, float x2, float y2, float x3, float y3) {
active_objects_.push_back( std::make_unique<triangle>(x1,y1,x2,y2,x3,y3));
}
sandbox_iterator active_objs_begin() {
return active_objects_.begin();
}
sandbox_iterator active_objs_end() {
return active_objects_.end();
}
void make_inactive(sandbox_iterator iter) {
std::unique_ptr<sandbox_object> obj = std::move(*iter);
active_objects_.erase(iter);
inactive_objects_.push_back(std::move(obj));
}
};
int main() {
sandbox sb;
sb.insert_circle(10.0f, 10.0f, 2.0f);
sb.insert_triangle(1.0f, 1.0f, 2.0f, 2.0f, 2.0f, 1.0f);
sb.insert_circle(1.0f, 6.0f, 4.0f);
sb.make_inactive(sb.active_objs_begin());
(*sb.active_objs_begin())->do_something(); // this should be the triangle...
return 0;
}
I've been given a task for my cpp homework, the task is long and has many more functions that this, but I am stuck at the beggining. What I am trying to do here is just write out the point that is given on the screen.
#include <iostream>
using namespace std;
class Point {
public:
double x, y;
Point(){
x=0.0;
y=0.0;
};
Point(double x,double y){
this -> x = x;
this -> y = y;
}
void print() {
cout << "(x,y) = ("<< x <<","<< y <<")"<<endl;
}
};
class Triangle {
public:
Point A;
Triangle(const Point& p1){
A.x = p1.x;
A.y = p1.y;
}
void print1(){
cout << "A(x,y) = ("<< A.x <<","<< A.y <<")"<<endl;
}
};
int main(){
Triangle A{1.0,2.0};
A.print1();
return 0;
}
What my thinking here is, I have a class named Point and it is made of two variables x and y, class Triangle in the task has 3 points, but I am using just one for simplicity, it has a point that is from class Point (so it should have x and y coordinates) and a constructor that has a point from class Point also. I was thinking just to link their x and y coordinates and to print them out. But it doesn't work like that, can you help me. I have more code from the task if you need, and code from our lessons. Thank you.
Triangle(const Point& p1) accepts a const reference to a Point. A reference is an alias to an existing variable. In this case rather than copying in a Point, the Triangle constructor receives the Point itself. The const is important because it is a promise that the Point will not be modified inside by Triangle's constructor. This allows you to pass in a reference to a temporary Point that otherwise would not be around long enough for modification to be meaningful and is rejected by the compiler to prevent possible errors.
Triangle A{1.0,2.0};
will attempt to make Triangle from two floating point values. Triangle needs a reference to a Point, so you must make that Point first.
Triangle A{ {1.0,2.0} };
^ ^
| Construct a temporary Point from 2 floating point numbers
Triangle constructor arguments: one Point
Unrelated improvement: Use the Member Initializer List
Triangle(const Point& p1): A{p1}{
}
EDIT: To initialize the position array m_pos[3] I set all it's values to 0 in the constructor and then I call from the main function another function called SetPos() which only sets the position of the planet in the 3D map:
void SetPos(float x, float z);
void Planet::SetPos(float x, float z)
{
m_pos[0]=x;
m_pos[1]=0;
m_pos[2]=y;
}
Thus, the constructor takes the form:
Planet::Planet()
{
m_pos[0]=0;
m_pos[1]=0;
m_pos[2]=0;
}
Is that a bad way to do it? (by need, i can't set the position directly through the constructor).
ORIGINAL:
I've created a class called Planet which controles a series of planets (Planet object) in a map. Each object has an array pos[3] which stores the coordinates where the planet must be drawn.
The planets also own a function called DrawConnections() which is in charge of drawing lines representing the connections between the actual planet and the other planets. The planets that one planet is connected to are stored in a vector, std::vector<Planet> connections.
Since attributes are encapsulated, there's a function in the Planet class which returns the position of the planet, called GetPos(float* pos), where *pos is a pointer to an array capable of storing the position of the planet.
First things first, those are the prototypes and variable declarations from Planet.h file:
public:
void DrawConnections(float radius);
void GetPos(float* position);
private:
float m_pos[3];
std::vector<Planet> m_connection;
The function DrawConnections() from Planet.cpp looks like this:
void Planet::DrawConnections(float radius) //parameter radius controls width of lines
{
float position[3]={0.0f,0.0f,0.0f}; //array storing the position of the planets
//which we are connecting to
//various OpenGl calls go here
glBegin(GL_LINES); //begins drawing the lines
for(int i=0;i<m_connection.size();i++) //for each planet we are connected to, draw a
//line
{
glVertex3f(m_pos[0],m_pos[1],m_pos[2]); //draws the first point of the line in the
//actual planet
m_connection[i].GetPos(position); //Gets the position of the planet we connect to
glVertex3f(position[0],position[1],position[2]); //draws the second point of the
//in the planet we connect to
}
glEnd(); //ends drawing
//some other OpenGl calls
}
The function GetPos() from Planet.cpp looks like this:
void Planet::GetPos(float* position)
{
position[0]=m_pos[0]; //copies the data from the position array to
position[1]=m_pos[1]; //the given pointer
position[2]=m_pos[2];
}
Any planet has x, neither z, 0 coordinate. Each one of them has a set of (x,y,z) coordinates, with x and z always different to 0.
However, some of the calls to GetPos() return x and z equal to 0, while others work properly.
This results in many lines going from the planets to the bottom left corner of the screen, without representing any connection. From what I've figured out I think the problem is in the GetPos(). However, other similar drawing functions also use GetPos() and work perfectly when they're called before the DrawConnection() function, but seem to be affected when they're called once DrawConnections() has been called It is as if that one was modifying the values of the position array when called and thus disturbing everything else which has to be with the position, including herself.
As an additional information, I'm working with Codeblocks and the MinGW GNU GCC compiler. I appreciate any help that you could give me.
Why not do?
public:
void DrawConnections(float radius);
const std::vector<float>& GetPos() const {return m_pos;};
private:
std::vector<float> m_pos;
std::vector<Planet> m_connection;
I already posted another question regarding structs versus classes. I believe I got good feedback, so I went back to work on my code.
Here is what confused me (maybe it is childish ;) )
I need to Have a class (or struct doesnt really mind) that is called cPoint, and it just defines a Point in space with X, Y coordinates.
from it all shape-classes will derive. So for cRectangle, that is a class for rectangles, the cPoint will be used as a base element.
To instantiate a Rectangle, the caller must provide the coordinates of 2 points, that will be the rectangles UpperLeft & LoowerRight corners respectively.
What I want the cRectangle constructor to do, is to instantiate these two points, as it own private points and use them to define the rectangle, do calculations etc. These two points should not be visible to public scope, so a caller can't change them directly.
Here is an example(wrong obviously) for what I try to do:
class cPoint
{
public:
int X,Y;
cPoint();
cPoint(int x, int y)
{
X=x;
Y=y;
}
};
class cRectangle
{
friend class cPoint;
public:
Rectangle(int x1,int y1,int x2,int y2) //the constructor of cRectangle
{
ul(x1,y1);
dr(x2,y2);
}
unsigned int area()
{
return((dr.X-ul.X) * (dr.Y-ul.Y));//example function that uses ul,dr
}
private:
cPoint ul; //uP lEFT point
cPoint dr; //dOWN Right point
};
The error that i get is " Error 1 no match for call to '(cPoint) (int&, int&)' "
Thank you
/* use initilization list */
Rectangle(int x1,int y1,int x2,int y2) : ul(x1,y1), dr(x2,y2)
{
}
Your code won't compile because here
Rectangle(int x1,int y1,int x2,int y2) //the constructor of cRectangle
{
ul(x1,y1);
dr(x2,y2);
}
you wanted to call operator(int,int) on instances of cPoint class and definition of this operator has been not provided.
Once you enter the body of a constructor, all members are initialized and you can only assign to them and everything else that you can do to a living object.
By the point you attempt this
ul(x1,y1);
dr(x2,y2);
ul and dr have already been default initialized (default constructor is the one that's called if you don't explicitly initializer members - read on). When compiler sees these two lines, it looks like you're trying to call overloaded operator() that doesn't exist, so it naturally reports an error.
To initialize members, use constructor initialization list:
Rectangle(int x1,int y1,int x2,int y2)
: ul(x1,y1), dr(x2,y2) // <-- initialization list
// using cPoint::Cpoint(int, int) constructor
{
// note, empty body
}
I'm designing a robot simulator for a university project and I've hit a big issue for some collision detection. Here is my robot.h header file:
#ifndef robot_h
#define robot_h
#include <vector>
enum direction
{
UP,DOWN,LEFT,RIGHT
};
enum motor
{
STOP,SLOW,FAST
};
class robot
{
public:
robot();
char bot; // The bot onscreen
int getX(); // The X position of robot
int getY(); // The Y position of robot
int dir; // The direction the robot is going
bool touchSensor; // Boolean value if collision
int lightSensor; // light sensor between 10-100
int motorA; // Motor A between 0, 1 and 2
int motorB; // Motor A between 0, 1 and 2
void detection(int x, int y);
void getReturnObject();
bool returnObjectDash;
bool returnObjectLine;
void move(); // Moving the robot
void draw(); // Drawing the robot on screen
void update(); // Updating the robot position
private:
int positionX; // Starting X value
int positionY; // Starting Y value
};
#endif
Basically, I have two boolean values being used:
returnObjectDash;and returnObjectLine. I have this code in my matrix.cpp file:
void matrix::detection(int x, int y)
{
if(vector2D[x][y]=='-')
{
returnObjectDash=true;
system("pause");
}
else
{
returnObjectDash=false;
}
if(vector2D[x][y]=='|')
{
returnObjectLine=true;
}
else
{
returnObjectLine=false;
}
}
Inside my robot.cpp I have this code which gets the two boolean values and then outputs to the console:
void robot::getReturnObject()
{
if(returnObjectDash==true)
{
std::cout<<"Dash\n";
//dir=DOWN;
}
if(returnObjectLine==true)
{
std::cout<<"Line\n";
//dir=DOWN;
}
}
This is my main.cpp
int main()
{
robot r;
while(true)
{
matrix m;
m.robotPosition(r.getX(), r.getY());
m.update(); // vector2D init and draw
m.detection(m.getX(), m.getY());
r.update();
Sleep(250);
}
}
I'm setting the default value of my two boolean variables in my matrix.cpp default constructor to false. When I hit the pause button and debug I seem to be getting two different returns. For my matrix it is returning false, though for my robot it is returning true, it is like my program is making two different variables. If someone could shed some light on this weird behaviour, then please do tell! Thank you
Your program is making two different values because it has two different values. The matrix class apparently has its own Boolean variable, matrix::returnObjectDash, and the robot class has its own variable, robot::returnObjectDash. Setting the variable in one instance of one class has no impact on the variables in any other classes (or any other instances).
You have not provided code to you matrix class, however, judging from void matrix::detection(int x, int y) I assume that you have a method in there, called detection, and that you have declared the same fields returnObjectLine and returnObjectDash.
You are correct in assuming that there are 2 versions of those variables: One of those versions is inside your matrix object, and the other one is inside your robot object.
Not only that, you can (and usually do!) have more than one matrix/robot object. Each of those will have its own separate copy of those variables, and changing one of them will not impact the other ones.