I'm designing a simple Connect 4 game. So far, I have 4 underlying classes:
Colour - responsible for representing colours (RGBA). Includes conversion operators.
Player - represents a player of the game. Each Player has a Colour and a name.
Board - represents the playing board. It contains dimensions, as well as a 2D vector of Tiles with those dimensions.
Tile - a nested class within Board. Represents one space on the board. Each Tile has a Colour and an std::unique_ptr to the owner of that tile. The owner starts as nullptr and can be changed once to a Player. The colour starts as a transparent black.
I've tested my Colour class and it appears to be working fine. My Player class is in tip-top shape as well. However, I'm having some problems with the Board/Tile classes.
My test consisted of creating two players, and a board. These executed normally. Next, I loop through the dimensions of the board, once for each tile. I then call
board.tile (j, i).claimBy (p2);
The loop goes through rows with i and columns with j, the way you'd expect to print it.
tile (j, i) retrieves the tile I'm working with. It works as expected.
Chain of Events Leading to the Crash:
claimBy (p2) sets the tile to become claimed by player 2. It is implemented as follows:
bool Board::Tile::claimBy (const Player &owner)
{
if (!_owner)
{
*_owner = owner;
_colour = owner.colour();
return true;
}
return false;
}
_owner is my std::unique_ptr<Player>. It first checks whether the owner of the tile has been set before (i.e. is not nullptr). If not, it sets the Player inside to the one passed in. It then updates the tile's colour and returns true. If the tile has been previously claimed, it returns false.
Following the debugger, the crash occurs in the line *_owner = owner;. Stepping in takes me to the line struct Player (my declaration of the Player class), which I take to be the implicit copy constructor (remember the class only has a Colour _colour and a std::string _name).
Stepping in again leads me to Colour::operator= (which makes sense for a copy constructor to call). Here's the definition:
Colour &Colour::operator= (const Colour &rhs)
{
if (*this != rhs)
{
_red = rhs.red();
_green = rhs.green();
_blue = rhs.blue();
_alpha = rhs.alpha();
}
return *this;
}
The path turns into *this != rhs. This is just a reverse call to operator==, which is:
return red() == rhs.red()
&& green() == rhs.green()
&& blue() == rhs.blue()
&& alpha() == rhs.alpha();
The first comparison here red() == rhs.red() has red() which is just return _red;. This is the point at which the program crashes. The debugger states that this (this->_red) is 0x0.
I'm clueless about why this is happening. My best guess is that I'm using the smart pointer wrongly. I've never actually used one before, but it should be pretty similar to normal pointers, and I didn't think release would accomplish anything if the pointer is nullptr.
What could be the cause of this being 0x0?
Edit:
I'm sure everything is initialized, as I do so in each constructor, in member initializers (e.g. Board::Tile::Tile() : _colour (Colours::NONE), _owner (nullptr){}), where NONE is a transparent black.
I'm also not too proficient with a debugger, as I haven't used it that much over printing debugging values.
The line
*_owner = owner;
means "make a copy of the owner object, and store it at the place that _owner points to." The problem is that _owner doesn't point to anything yet; it's still null.
If you really want to make a copy of the Player object in each tile that the player controls, you'd need to do
_owner.reset(new Player(owner));
But making copies of the Player object is a strange thing to do. Consider using shared_ptr instead — you can have both owner and _owner be shared_ptrs, and just assign one to the other in the usual way.
You start off with a default initialized std::unique_ptr<Player>. That is to say, the equivalent of a NULL pointer with some cleanup semantics. Then you try to dereference it in the statement *_owner=owner; so that you can assign to it.
Thus the statement *_owner=owner; is basically equivalent to ((Player*)NULL)->operator=(owner);, calling the implicit assignment operator. The first thing this does is then equivalent to ((Player*)NULL)->_colour=owner._colour; Finding this==NULL is not surprising here; indeed, it's expected.
The fix depends on what you actually want to happen. Should each Board::Tile be given a completely new copy of its owner? Then you want to instead say _owner.reset(new Player(owner)). Do you just want each tile to hold a reference to an already existing player? Can you guarantee that the Player object owner will outlive the Board::Tile object? Then you want a raw pointer: (in declaration of Board::Tile) Player const *_owner; (in implementation) _owner=&owner;.
Related
Im using SFML to make a simple fighting game.
I have a class called Fighter that I use to make two objects.
In main:
Fighter fighterOne;
Fighter fighterTwo;
Both fighters modify the same variables, mainly isLow() and isGuarded().
To check collision between the two fighters I call checkHit() in updateFighter() (basically if the fighter updates a move, check if it hit) I check the collision in my collision.h class
Note: I chane which fighter is currently being updated with a bool called isRight. if its true, it modifies the 2nd fighter, else, it modifies the first one.
void Fighter::updateFighter(Sprite& fighter, Sprite& otherFighter, bool isRight)
{
if (Keyboard:isKeyPressed(attack)
{
//animates the attack
collision.checkHit(fighter, otherFighter, isLow, isGuarded, lowAttack, isRight);
}
}
Problem is, with the above, Im trying to check the value of isLow of the opposite fighter object (fighterTwo). But when i call it like this, it goes off the currently being used isLow, which belongs to fighterOne. How do I pass fighterTwo's isLow value to checkHit instead of fighterOne's?
I am currently taking an intermediate c++ class with my university, and we've just done classes/polymorphism and so I decided to work on a little project of my own. This is not homework, figured I'd get that out of the way.
So I'm using SFML to make a little "idle" game. This consists of an entity class, with a class for a weapon and a class for an armor. I have 2 entities, being the player and "other", or the enemy. Everything has been good so far, but I am running into trouble when I am trying to invoke a member function on the entity class with an argument as another entity.
Here are the two functions
/*
Simulates the entity attacking another entity
*/
void Entity::attackEntity(Entity other) {
other.decreaseHP(5);
if (other.getCurrentHP() <= 0) {
killEntity(other);
}
}
/*
Simulates main entity defeating another
*/
void Entity::killEntity(Entity other) {
if (other.getEntityType() == "Enemy") {
other.setXP(rand() % (other.getRequiredXP() / 9) + 1);
addXP(other.getXP());
//addXP(rand() % (rand() % (getRequiredXP() / 10) + 1) + getEntityLevel()); // testing
addGold(rand() % getEntityLevel() + getEntityLevel());
// Increment the level of the entity to give them better armor/weapon
other.incrementLevel();
// Regenerate a weapon and armor for the enemy
other.setWeapon(other.getWeapon().generateRandomWeapon(other.getEntityLevel()));
other.setArmor(other.getArmor().generateRandomArmor(other.getEntityLevel()));
}
else if (other.getEntityType() == "Player") {
other.setXP(other.getXP() / 10);
other.setCurrentHP(other.getMaxHP());
other.refreshEntityInfo();
}
}
Currently, in the main program, I am calling it as
if (clock.getElapsedTime().asSeconds() >= 1.0f) {
player.attackEntity(enemy);
clock.restart();
}
What I want the code to do is every 1 second, the player will "attack" the other entity, being enemy. This will decrease the health points of the other entity by 5, and when the other entity's health points drop below 1, it will "kill" the entity, granting the player experience and resetting the other entity's armor and weapon, which will give it new stats.
However, what is happening, is nothing. Health points do not decrease.
Obviously I am doing something wrong here as it is not working.
I tested just calling the decreaseHP() method alone in the time loop and that works:
if (clock.getElapsedTime().asSeconds() >= 1.0f) {
//player.attackEntity(enemy);
player.decreaseHP(5);
clock.restart();
}
but the way I supplied before using the attackEntity() method does not.
Here is the decreaseHP() method.
/*
Decreases the entity's current health by amount
*/
void Entity::decreaseHP(int amount) {
setCurrentHP(getCurrentHP() - amount);
}
Do I need to pass the other entity object as reference? Am I going about these functions in a poor way? How should I be approaching this?
Edit -- So I know I just posted this, but I changed the parameters for both the attackEntity() function and killEntity() function so it takes the entity object by reference, and that seemed to solve the solution.
/*
Simulates main entity defeating another
*/
void Entity::killEntity(Entity &other) {
if (other.getEntityType() == "Enemy") {
other.setXP(rand() % (other.getRequiredXP() / 9) + 1);
addXP(other.getXP());
//addXP(rand() % (rand() % (getRequiredXP() / 10) + 1) + getEntityLevel()); // testing
addGold(rand() % getEntityLevel() + getEntityLevel());
// Increment the level of the entity to give them better armor/weapon
other.incrementLevel();
// Regenerate a weapon and armor for the enemy
other.setWeapon(other.getWeapon().generateRandomWeapon(other.getEntityLevel()));
other.setArmor(other.getArmor().generateRandomArmor(other.getEntityLevel()));
}
else if (other.getEntityType() == "Player") {
other.setXP(other.getXP() / 10);
other.setCurrentHP(other.getMaxHP());
other.refreshEntityInfo();
}
}
/*
Simulates the entity attacking another entity
*/
void Entity::attackEntity(Entity &other) {
other.decreaseHP(5);
if (other.getCurrentHP() <= 0) {
killEntity(other);
}
}
However, my last questions still stand: am I going about this the right way?
The signature void Entity::attackEntity(Entity other) causes other to be a copy of the entity. Any changes made to other are local to the attackEntity function.
If you need the changes to persist from the source item, the most straight forward way is to pass other in by reference, changing the signature to: void Entity::attackEntity(Entity& other)
Given this...
void Entity::attackEntity(Entity other) {
... then this code
Entity x;
foo.attackEntity(x);
... will create a COPY of X, pass that to attackEntity, which modifies the local copy that's immediately discarded. So x stays unchanged.
In this case, use pass by reference.
void Entity::attackEntity(Entity &other)
If the method isn't meant to modify x, use pass by const reference instead:
bool Entity::isWithinRange(const Entitiy &other)
Following from your edit, yes, references are absolutely the correct way of handling this. Passing objects by value (or as pointers) is often a code 'smell'.
Check your use of the equality operator, "==". C++ doesn't treat strings the way Java and C# do. Quoted strings (e.g. "Enemy") decompose into pointers, so the comparison becomes "does this pointer point to the same address as the other pointer does," the answer to which will pretty much always be "no."
You can try using the std::string type, which defines a compare() method, but in general, C++ strings are only slightly friendlier than C strings.
You should probably be using the old-fashioned C string comparison functions such as strcmp().
I'm an absolute beginner in OOP (and C++). Trying to teach myself using resources my university offers for students of higher years, and a bunch of internet stuff I can find to clear things up.
I know basic things about OOP - I get the whole point of abstracting stuff into classes and using them to create objects, I know how inheritance works (at least, probably the basics), I know how to create operator functions (although as far as I can see that only helps in code readability in a sense that it becomes more standard, more language like), templates, and stuff like that.
So I've tried my first "project": to code Minesweeper (in command line, I never created a GUI before). Took me a few hours to create the program, and it works as desired, but I feel like I'm missing a huge point of OOP in there.
I've got a class "Field" with two attributes, a Boolean mine and a character forShow. I've defined the default constructor for it to initialize an instance as an empty field (mine is false), and forShowis . (indicating a not yet opened filed). I've got some simple inline functions such as isMine, addMine, removeMine, setForShow, getForShow, etc.
Then I've got the class Minesweeper. Its attributes are numberOfColumns, ~ofRows, numberOfMines, a pointer ptrGrid of type Mine*, and numberOfOpenedFields. I've got some obvious methods such as generateGrid, printGrid, printMines (for testing purposes).
The main thingy about it is a function openFiled which writes the number of mines surrounding the opened field, and another function clickField which recursively calls itself for surrounding fields if the field which is currently being opened has 0 neighbor mines. However, those two functions take an argument -- the index of the field in question. That kinda misses the point of OOP, if I understand it correctly.
For example, to call the function for the field right to the current one, I have to call it with argument i+1. The moment I noticed this, I wanted to make a function in my Field class which would return a pointer to the number right to it... but for the class Field itself, there is no matrix, so I can't do it!
Is it even possible to do it, is it too hard for my current knowledge? Or is there another more OOP-ish way to implement it?
TLDR version:
It's a noob's implemetation of Minesweeper game using C++. I got a class Minesweeper and Field. Minesweeper has a pointer to matrix of Fields, but the navigation through fields (going one up, down, wherever) doesn't seem OOP-ishly.
I want to do something like the following:
game->(ptrMatrix + i)->field.down().open(); // this
game->(ptrMatrix + i + game.numberOfColumns).open(); // instead of this
game->(ptrMatrix + i)->field.up().right().open(); // this
game->(ptrMatrix + i + 1 - game.numberOfColumns).open(); // instead of this
There are a couple of ways that you could do this in an OOP-ish manner. #Peter Schneider has provided one such way: have each cell know about its neighbours.
The real root of the problem is that you're using a dictionary (mapping exact coordinates to objects), when you want both dictionary-style lookups as well as neighbouring lookups. I personally wouldn't use "plain" OOP in this situation, I'd use templates.
/* Wrapper class. Instead of passing around (x,y) pairs everywhere as two
separate arguments, make this into a single index. */
class Position {
private:
int m_x, m_y;
public:
Position(int x, int y) : m_x(x), m_y(y) {}
// Getters and setters -- what could possibly be more OOPy?
int x() const { return m_x; }
int y() const { return m_y; }
};
// Stubbed, but these are the objects that we're querying for.
class Field {
public:
// don't have to use an operator here, in fact you probably shouldn't . . .
// ... I just did it because I felt like it. No justification here, move along.
operator Position() const {
// ... however you want to get the position
// Probably want the Fields to "know" their own location.
return Position(-1,-1);
}
};
// This is another kind of query. For obvious reasons, we want to be able to query for
// fields by Position (the user clicked on some grid), but we also would like to look
// things up by relative position (is the cell to the lower left revealed/a mine?)
// This represents a Position with respect to a new origin (a Field).
class RelativePosition {
private:
Field *m_to;
int m_xd, m_yd;
public:
RelativePosition(Field *to, int xd, int yd) : m_to(to), m_xd(xd),
m_yd(yd) {}
Field *to() const { return m_to; }
int xd() const { return m_xd; }
int yd() const { return m_yd; }
};
// The ultimate storage/owner of all Fields, that will be manipulated externally by
// querying its contents.
class Minefield {
private:
Field **m_field;
public:
Minefield(int w, int h) {
m_field = new Field*[w];
for(int x = 0; x < w; x ++) {
m_field[w] = new Field[h];
}
}
~Minefield() {
// cleanup
}
Field *get(int x, int y) const {
// TODO: check bounds etc.
// NOTE: equivalent to &m_field[x][y], but cleaner IMO.
return m_field[x] + y;
}
};
// The Query class! This is where the interesting stuff happens.
class Query {
public:
// Generic function that will be instantiated in a bit.
template<typename Param>
static Field *lookup(const Minefield &field, const Param ¶m);
};
// This one's straightforwards . . .
template<>
Field *Query::lookup<Position>(const Minefield &field, const Position &pos) {
return field.get(pos.x(), pos.y());
}
// This one, on the other hand, needs some precomputation.
template<>
Field *Query::lookup<RelativePosition>(const Minefield &field,
const RelativePosition &pos) {
Position base = *pos.to();
return field.get(
base.x() + pos.xd(),
base.y() + pos.yd());
}
int main() {
Minefield field(5,5);
Field *f1 = Query::lookup(field, Position(1,1));
Field *f0 = Query::lookup(field, RelativePosition(f1, -1, -1));
return 0;
}
There are a couple of reasons why you might want to do it this way, even if it is complicated.
Decoupling the whole "get by position" idea from the "get neighbour" idea. As mentioned, these are fundamentally different, so expose a different interface.
Doing it in this manner gives you the opportunity to expand later with more Query types in a straightforwards fashion.
You get the advantage of being able to "store" a Query for later use. Perhaps to be executed in a different thread if it's a really expensive query, or in an event loop to be processed after other events, or . . . lots of reasons why you might want to do this.
You end up with something like this: (C++11 ahead, be warned!)
std::function<Field *()> f = std::bind(Query::lookup<RelativePosition>,
field, RelativePosition(f1, -1, -1));
. . . wait, what?
Well, what we essentially want to do here is "delay" an execution of Query::lookup(field, RelativePosition(f1, -1, -1)) for later. Or, rather, we want to "set up" such a call, but not actually execute it.
Let's start with f. What is f? Well, by staring at the type signature, it appears to be a function of some sort, with signature Field *(). How can a variable be a function? Well, it's actually more like a function pointer. (There are good reasons why not to call it a function pointer, but that's getting ahead of ourselves here.)
In fact, f can be assigned to anything that, when called, produces a Field * -- not just a function. If you overload the operator () on a class, that's a perfectly valid thing for it to accept as well.
Why do we want to produce a Field * with no arguments? Well, that's an execution of the query, isn't it? But the function Query::lookup<RelativePosition> takes two arguments, right?
That's where std::bind comes in. std::bind essentially takes an n-argument function and turns it into an m-argument function, with m <= n. So the std::bind call takes in a two-place function (in this case), and then fixes its first two arguments, leaving us with . . .
. . . a zero-argument function, that returns a Field *.
And so we can pass around this "function pointer" to a different thread to be executed there, store it for later use, or even just repeatedly call it for kicks, and if the Position of Fields was to magically change for some reason (not applicable in this situation), the result of calling f() will dynamically update.
So now that I've turned a 2D array lookup into a mess of templates . . . we have to ask a question: is it worth it? I know this is a learning exercise and all, but my response: sometimes, an array is really just an array.
You can link the four neighbours to the cell via pointers or references. That would likely happen after the playing field has been created. Whether that's good or bad design I'm not sure (I see the same charme though that you see). For large fields it would increase the memory footprint substantially, because a cell probably doesn't hold that much data besides these pointers:
class Cell
{
// "real" data
Cell *left, *right, *upper, *lower;
// and diagonals? Perhaps name them N, NE, E, SE, S...
};
void init()
{
// allocate etc...
// pseudo code
foreach r: row
{
foreach c: column
{
// bounds check ok
cells[r][c].upper = &cells[r-1][c];
cells[r][c].left = &cells[r][c-1];
// etc.
}
}
// other stuff
}
I'm planning to extend the CCSprite class in order to create a Block class, which are the basic building blocks of my game. There may be a number of "archblocks" - prototypes on which individual blocks are to be based. In particular, I want to create a palette, from which the user can pick her building blocks which are to be placed on the game board. Once placed on the board, the building blocks takes on an identity of it's own.
Here's what I have so far:
class Block : public CCSprite {
private:
int _id = 0;
int _type = 0;
public:
Block* CopyBlock();
}
Once a user selects a Block and drops it on the game board, CopyBlock is going to be invoked and the prototype be safely returned to the palette, leaving the newly minted Block living a life of its own on the game board.
I've noticed that CCObject "implements" a Copy method, but as far as I can tell this just refers to a CopyWithZone(0) for CCObject that isn't implemented. The Copy method isn't virtual, though, so I'm a little unsure if I'm able to override this. (I'm not super strong in C++ but I do have a good grasp on OOP, so I'm up for the details if anyone care to share.)
Question:
1) Does this design make sense? Should I go with overriding Copy and/or CopyWithZone instead?
2) How can I implement CopyBlock (or Copy and/or CopyWithZone) so that both CCSprite stuff and members like _type are copied to the new Block?
Thanks!
Unless your block sprite contains children. You can easily create a copy constructor, creating the same sprite and copying the block's attributes (and maybe some needed sprite attributes) by yourself :
class Block : public CCSprite {
private:
int _id = 0;
int _type = 0;
public:
Block (Block &otherBlock);
}
Implementation file :
Block::Block (Block &otherBlock) {
this->initWithTexture(otherBlock.getTexture());
// If your sprite contains children then this is the place to iterate all children
// sprites, create and add them to this block. (do not forget to copy their position as well.)
this->_id = otherBlock._id;
this->_type = otherBlock._type;
}
Note that since initWithTexture does not copy the texture, if you tweak the texture it will be visible on all copies of blocks but if you don't have texture tweaking needs then this should work for you.
First of all let me prefix this question with the following points:
1) I have searched Stackexchange for this issue, most of the code presented was difficult enough for me to follow in order to warrant Asking a new Question/Opening a new Thread about this. The closest i could find was this Creating multiple class objects with the same name? c++ and unfortunately this is way past my scope of understanding
2) http://www.cplusplus.com/doc/tutorial/classes/ has not really discussed this or i have missed it.
Now that this is out of the way:
Rectangle Class code:
class Rectangle {
private:
int lineNumber;
float valueMax;
float valueMin;
public:
Rectangle(SCStudyInterfaceRef sc, int lineNumber, float valueMax, float valueMin);
int getLineNumber(); // member function of class
float getValueMax(); // member function of class Rectangle
float getValueMin(); // member function of class Rectangle
};
Rectangle::Rectangle(SCStudyInterfaceRef sc, int lineNumber0, float value1, float value2) {
lineNumber = lineNumber0;
int value2_greater_than_value1 = sc.FormattedEvaluate(value2, sc.BaseGraphValueFormat, GREATER_OPERATOR, value1, sc.BaseGraphValueFormat);
if (value2_greater_than_value1 == 1) {
valueMax = value2;
valueMin = value1;
} else {
valueMax = value1;
valueMin = value2;
}
}
int Rectangle::getLineNumber() {
return lineNumber;
}
float Rectangle::getValueMax() {
return valueMax;
}
float Rectangle::getValueMin() {
return valueMin;
}
And here is the more important part, this code is running pretty much in a loop and will repeat everytime a certain event triggers it:
bool xxx = Conditions here
if (xxx) {
// Draw new rectangle using plattforms code
code here
// Save rectangle information in the list:
Rectangle rect(sc, linenumbr + indexvalue, high, low);
(*p_LowRectanglesList).push_back(rect);
}
bool yyy = conditions here
if (Short) {
// Draw new rectangle using plattforms code
code here
// Save rectangle information in the list:
Rectangle rect(sc, linenumber + indexvalue, high, low);
(*p_HighRectanglesList).push_back(rect);
}
So the question is the following:
Since this is looped everytime an event triggers the second part of the code is going to be run, the bool condition is going to be checked, if its true its going to use plattform integrated code to draw a rectangle. Once it has drawn it this information is going to be passed to a new rectangle object/instance based on the Rectangle Class in the first part of the code using the: Rectangle rect(sc, linenumber + indexvalue, high, low); part and then save that information in a list which is in a different part of the code for now and irrelevant.
What exactly happens when there is a new Bool = True condition and the code gets executed after it has already been executed? Will the old rectangle object be simply replaced with a new rectangle object with the same name and using the new parameters (since they change on every instance due to the way the code is written)? Or are there now two objects of the Rectangle Class using the same name "rect" ?
It's technically speaking not even that important to me since the information of the parameters should be pushed into a list anyways using the (*p_HighRectanglesList).push_back(rect); part of the code
So TL;DR:
Does "rect" get destroyed/overwritten or are there now potentially limitless amounts of Rectangle Objects/Instances called "rect" floating around?
My Apologies for the wall of text but being a complete noob i thought it would be best to outline my thought process so that it will be easier for you to correct me on where I'm wrong.
Kind regards,
Orbital
Yes, rect is destroyed and recreated every loop. In C++, the scope of any variable declared in a block (in this case an if() statement) is limited to that block. Every time your program iterates, you get a new rect, and the old rect is gone.
To add, whenever you call NEW, you are basically allocating memory and creating Rectangle objects. NEW will allocate address to each instance. The pointer *rect will be pointing to the current memory address, and when you call rect with NEW again, now rect will be pointing to the new memory address the previous address becomes a NULL reference. However in C++ you have to worry about memory leaks unlike Java where you have a garbage collector.