I have an stl set with objects of Cell class
class Cell
{
public:
//Ctor/Dtor
Cell(size_t cellId=0,int x =0,int y = 0,size_t t = 0):m_cellId(cellId),m_x(x),m_y(y),m_t(t),m_color(WHITE),m_pCellId(0),m_regNum(0){}
////////////////////
// Mutators //
////////////////////
void schedNode(size_t t,int nodeId){m_sched[t] = nodeId;}
void setColor(color c){m_color = c;}
void setParentId(size_t pId){m_pCellId = pId;}
//.....
}
Each Cell has m_x and m_y (member) coordinates + additional data members(m_t,m_color,m_pCellId,m_regNum)
comapareCells class is used to find the cell only based on its actual m_x and m_y coordinates:
class comapareCells
{
public:
bool operator()(const Cell& lCell,const Cell& rCell)
{
if(lCell.getX() < rCell.getX())
return true;
else if(lCell.getX() == rCell.getX())
return (lCell.getY() < rCell.getY());
else
return false;
}
};
I run the following in order to find "actual cell":
c is a cell which has only needed cell coordinates. It is used to find the actual cell, contained in the cet, having given coordinates and try to make some operations on the actual cell:
set<Cell,comapareCells>::iterator itCell;
if((itCell = m_cells.find(c)) == m_cells.end())
return;
if(itCell->getColor() != WHITE)
return;
itCell->setColor(GRAY);
itCell->setParentId(cIdFrom);
I get compilation error/s foritCell->setColor(GRAY); itCell->setParentId(cIdFrom);:
cannot convert 'this' pointer from 'const Cell' to 'Cell &'
How can it be solved?
It is not legal to change the value of a set's elements through an iterator because the set has no way of knowing what you have changed and would invalidate it. If you want to change it like that you would have to remove it and reinsert it with your changes.
Cell newCell(*itCell);
newCell.setColor(GRAY);
m_cells.erase(itCell);
m_cells.insert(newCell);
Related
I have a class called Child that holds a name and a list of string items. Different child objects are stored in a separate list, sort of as a nested list. The representation is:
List<"Child"> [Child1(name, List<"string">), Child2(name, List<"string">), etc.]
My objective is to create two functions: insertChild() and insertPresent(). The first one works, where the idea is to insert a child object into List(Child) with a specified name and List<"string">. Where I'm having trouble is with insertPresent(), where it is supposed to search List<"Child"> given a name and, once there's a match, add a present (string) to that Child object's List<"string">.
The problem appears to be I'm accessing a local copy of the List<"string"> when calling getList(), which explains why there appears to be no errors and the original list remains untouched after calling insertPresent(). How do I implement the changes to access the original list and not the copy? Here's the code:
ArrayList.h:
template<class ItemType>
class ArrayList
{
private:
static const int DEFAULT_CAPACITY = 5; // Small capacity to test for a full list
ItemType items[DEFAULT_CAPACITY]; // Array of list items
protected:
int itemCount; // Current count of list items
int maxItems; // Maximum capacity of the list
public:
ArrayList();
// Copy constructor and destructor are supplied by compiler
bool isEmpty() const;
int getLength() const;
bool insert(int newPosition, const ItemType& newEntry);
bool remove(int position);
void clear();
/** #throw PrecondViolatedExcep if position < 1 or
position > getLength(). */
ItemType getEntry(int position) const throw(PrecondViolatedExcep);
/** #throw PrecondViolatedExcep if position < 1 or
position > getLength(). */
void setEntry(int position, const ItemType& newEntry) throw(PrecondViolatedExcep);
}; // end ArrayList
template<class ItemType>
ArrayList<ItemType>::ArrayList() : itemCount(0), maxItems(DEFAULT_CAPACITY)
{
} // end default constructor
template<class ItemType>
bool ArrayList<ItemType>::isEmpty() const
{
return itemCount == 0;
} // end isEmpty
template<class ItemType>
int ArrayList<ItemType>::getLength() const
{
return itemCount;
} // end getLength
template<class ItemType>
bool ArrayList<ItemType>::insert(int newPosition, const ItemType& newEntry)
{
bool ableToInsert = (newPosition >= 1) && (newPosition <= itemCount + 1) &&
(itemCount < maxItems);
if (ableToInsert)
{
// Make room for new entry by shifting all entries at
// positions >= newPosition toward the end of the array
// (no shift if newPosition == itemCount + 1)
for (int pos = itemCount; pos >= newPosition; pos--)
items[pos] = items[pos - 1];
// Insert new entry
items[newPosition - 1] = newEntry;
itemCount++; // Increase count of entries
} // end if
return ableToInsert;
} // end insert
template<class ItemType>
bool ArrayList<ItemType>::remove(int position)
{
bool ableToRemove = (position >= 1) && (position <= itemCount);
if (ableToRemove)
{
// Remove entry by shifting all entries after the one at
// position toward the beginning of the array
// (no shift if position == itemCount)
for (int fromIndex = position, toIndex = fromIndex - 1; fromIndex < itemCount;
fromIndex++, toIndex++)
items[toIndex] = items[fromIndex];
itemCount--; // Decrease count of entries
} // end if
return ableToRemove;
} // end remove
template<class ItemType>
void ArrayList<ItemType>::clear()
{
itemCount = 0;
} // end clear
template<class ItemType>
ItemType ArrayList<ItemType>::getEntry(int position) const throw(PrecondViolatedExcep)
{
// Enforce precondition
bool ableToGet = (position >= 1) && (position <= itemCount);
if (ableToGet)
return items[position - 1];
else
{
string message = "getEntry() called with an empty list or ";
message = message + "invalid position.";
throw(PrecondViolatedExcep(message));
} // end if
} // end getEntry
template<class ItemType>
void ArrayList<ItemType>::setEntry(int position, const ItemType& newEntry) throw(PrecondViolatedExcep)
{
// Enforce precondition
bool ableToSet = (position >= 1) && (position <= itemCount);
if (ableToSet)
items[position - 1] = newEntry;
else
{
string message = "setEntry() called with an empty list or ";
message = message + "invalid position.";
throw(PrecondViolatedExcep(message));
} // end if
} // end setEntry
Child.h:
#include "ArrayList.h"
class Child
{
private:
string name;
ArrayList<string> presents;
public:
string getName() const;
ArrayList<string> getList() const;
void setName(string name);
void setList(ArrayList<string> aList);
};
string Child::getName() const {
return name;
}
ArrayList<string> Child::getList() const {
return presents;
}
void Child::setName(string name) {
this->name = name;
}
void Child::setList(ArrayList<string> aList) {
this->presents = aList;
}
NiceArrayList.h: List<"Child">
#include <string>
#include "Child.h"
using namespace std;
template<class ItemType>
class NiceArrayList : public ArrayList<ItemType>
{
public:
/** Inserts an object containing name and aList into this list at a given position.
#pre None.
#post If 1 <= position <= getLength() + 1 and the insertion is
successful, name and aList is at the given position in the nice list,
other entries are renumbered accordingly, and the returned
value is true.
#param position The list position at which to insert the object.
#param name The string assigned to the object inserted into this list.
#param aList The list assigned to the object inserted into this list.
#return True if insertion is successful, or false if not. */
bool insertChild(int position, string name, const ArrayList<string>& aList);
/** Inserts a new entry to the gift list inside an object from this
list given a name.
#pre The parameter name must be in an object in this list.
#post If 1 <= position <= getLength() + 1 and the insertion is
successful, newEntry is at the given position in the gift list,
other entries are renumbered accordingly, and the returned
value is true.
#param position Theobject list position at which to insert the new entry.
#param name The string used to identify the object in this list.
#param newEntry The entry to insert into the object's list.
#return True if removal is successful, or false if not. */
bool insertPresent(string name, string newEntry);
};
template<class ItemType>
bool NiceArrayList<ItemType>::insertChild(int position, string name, const ArrayList<string>& aList) {
bool ableToInsert = false;
Child aChild;
aChild.setName(name);
aChild.setList(aList);
ableToInsert = this->insert(position, aChild);
return ableToInsert;
}
template<class ItemType>
bool NiceArrayList<ItemType>::insertPresent(string name, string newEntry) {
bool ableToInsert = false;
int length = this->getLength();
int position = 0;
for (int i = 1; i <= length; i++) {
position++;
if (this->getEntry(i).getName() == name) {
break;
}
}
//THE PROBLEM APPEARS TO BE HERE! THE INSERT DOES NOT UPDATE THE LIST!
ableToInsert = this->getEntry(position).getList().insert(1, newEntry);
return ableToInsert;
}
Sample main to test:
#include <iostream>
#include "NiceArrayList.h"
int main() {
ArrayList<string> aList1;
aList1.insert(1, "PS4");
aList1.insert(2, "PS5");
aList1.insert(3, "Toy Car");
NiceArrayList<Child> nice;
nice.insertChild(1, "John", aList1);
nice.insertPresent("John", "Phone");
return 0;
}
Your problem is here
ArrayList<string> Child::getList() const {
return presents;
}
This is returning a copy of presents, So thios line only updates the copy
ableToInsert = this->getEntry(position).getList().insert(1, newEntry);
You need
ArrayList<string> & Child::getList() {
return presents;
}
Note the removal of the const too
and here
ArrayList<string> &getList() ;
same for getEntry on ArrayList, same fix
The API you defined for ArrayList does provide the basic operations of adding items, removing items, and changing items. However, the paradigm you chose for changing items can be awkward to use and – as you discovered – easy to mess up. It is not wrong, per se, since it is a good choice in some situations, but it does not appear to bring any of its benefits to your situation.
Since it is a valid approach, I will go over how to fix the code using the existing paradigm before going over an alternative paradigm.
Your way
Under your approach, changing an element of a list requires calling setEntry(). You are not allowed to directly change an element, but must make a copy (obtained via getEntry()), modify the copy, then update the list with setEntry().
Let us look at the line where you try to make your change.
ableToInsert = this->getEntry(position).getList().insert(1, newEntry);
This follows two of the three steps for making a change. There is a call to this->getEntry(position) to make a copy of the Child object. Then there is a change made to that copy (via .getList().insert(1, newEntry)), but the changed object is never given to the NiceArrayList as an update.
To update an element with your paradigm, you need to add a call to setEntry(). Given how your API is configured, this necessitates defining additional variables to help out. (Note, though, that even if this was not necessary, defining at least one of these variables would probably be a good idea style-wise, since this line is already quite long, and we intend to add code.)
// The first three lines split the existing line into pieces.
ItemType toChange = this->getEntry(position);
auto theList = toChange.getList();
ableToInsert = theList.insert(1, newEntry);
// The next lines update the child and list.
toChange.setList(theList);
this->setEntry(position, toChange);
Inserting an element into the presents list (a.k.a. getList()) is a change to that list, which in turn is a change to the Child object (a.k.a. ItemType). This new call to setEntry() replaces the object in the list with the changed copy.
Alternative way
The line of code you used to try to update the presents list would be correct if you adopt a different paradigm for changing a list. Instead of requiring a get/set pair of function calls, you could allow direct access to the elements of an ArrayList, similar to how [] allows direct access to the elements of an array. Instead of having getEntry() return a copy of an entry, it could return a reference to the entry.
If you adopt this paradigm, you could replace the setEntry() function with a non-const version of getEntry(). This would change code that changes entries in an ArrayList from something like setEntry(i, object); to something like getEntry(i) = object;. In more complex cases, you could modify an entry directly, much like you attempted to do in your version of insertPresent().
The new signature of your "get" function would look like the following.
const ItemType & getEntry(int position) const throw(PrecondViolatedExcep);
// ^^^^^ ^
Other than this change to the return type, the implementation would remain the same. (Well, you might want to get rid of throw(PrecondViolatedExcep), as that syntax was deprecated in C++11 and removed in C++17.)
The non-const version of this function could piggy-back on the const version's functionality.
ItemType & getEntry(int position) {
// Trick to invoke the const version of this function:
auto constThis = const_cast<const ArrayList *>(this);
return const_cast<ItemType &>(constThis->getEntry(position));
}
(Don't forget that you can remove setEntry() once this is defined. This can be a net reduction in lines of code.) This approach tends to be more intuitive to work with and less prone to bugs when used.
A similar change should be made to Child::getList() and Child::setList(). With these changes, your version of insertPresent() should work as-is, and you may find that working with these "get" functions is more intuitive than your original approach.
getList() was returning a copy of the sublist, so I turned the presents attribute into a pointer of the list array and made getList() return a reference to the array. Updated Child class:
Child.h:
#include "ArrayList.h"
class Child
{
private:
string name;
ArrayList<string>* presents;
public:
string getName() const;
ArrayList<string>& getList() const;
void setName(string name);
void setList(ArrayList<string>& aList);
};
string Child::getName() const {
return name;
}
ArrayList<string>& Child::getList() const{
return *presents;
}
void Child::setName(string name) {
this->name = name;
}
void Child::setList(ArrayList<string>& aList) {
this->presents = &aList;
}
I'm currently trying for a game project to get rid of a dangling reference when a plane crashes before reaching the terminal it was booked to reach.
I would like to go through <algorithm> functions only to better understand how they work.
At the moment I've tried going through the map that contains all the planes associated with a terminal, comparing it with the list of all the planes and checking if a plane that is in the map is no longer in the vector then delete it from the map to free the associated terminal.
void remove_crashed_aircraft(std::unordered_map<const Aircraft*, size_t>& reserved_terminals, std::vector<std::unique_ptr<Aircraft>>& aircrafts)
{
auto it = std::all_of(reserved_terminals.begin(), reserved_terminals.end(),
[aircrafts](const Aircraft* a1){ return std::find_if(aircrafts.begin(), aircrafts.end(),
[a1](std::unique_ptr<Aircraft> a2){ return a1==a2.get();});});
reserved_terminals.erase(it);
}
And this is my Aircraft class:
class Aircraft : public GL::Displayable, public GL::DynamicObject
{
private:
const AircraftType& type;
const std::string flight_number;
Point3D pos, speed; // note: the speed should always be normalized to length 'speed'
WaypointQueue waypoints = {};
Tower& control;
bool landing_gear_deployed = false; // is the landing gear deployed?
bool is_at_terminal = false;
int fuel = 0;
// turn the aircraft to arrive at the next waypoint
// try to facilitate reaching the waypoint after the next by facing the
// right way to this end, we try to face the point Z on the line spanned by
// the next two waypoints such that Z's distance to the next waypoint is
// half our distance so: |w1 - pos| = d and [w1 - w2].normalize() = W and Z
// = w1 + W*d/2
void turn_to_waypoint();
void turn(Point3D direction);
// select the correct tile in the plane texture (series of 8 sprites facing
// [North, NW, W, SW, S, SE, E, NE])
unsigned int get_speed_octant() const;
// when we arrive at a terminal, signal the tower
void arrive_at_terminal();
// deploy and retract landing gear depending on next waypoints
void operate_landing_gear();
void add_waypoint(const Waypoint& wp, const bool front);
bool is_on_ground() const { return pos.z() < DISTANCE_THRESHOLD; }
float max_speed() const { return is_on_ground() ? type.max_ground_speed : type.max_air_speed; }
bool is_paused = false;
Aircraft(const Aircraft&) = delete;
Aircraft& operator=(const Aircraft&) = delete;
public:
Aircraft(const AircraftType& type_, const std::string_view& flight_number_, const Point3D& pos_,
const Point3D& speed_, Tower& control_, int fuel_) :
GL::Displayable { pos_.x() + pos_.y() },
type { type_ },
flight_number { flight_number_ },
pos { pos_ },
speed { speed_ },
control { control_ },
fuel { fuel_ }
{
speed.cap_length(max_speed());
}
const std::string& get_flight_num() const { return flight_number; }
float distance_to(const Point3D& p) const { return pos.distance_to(p); }
bool is_circling() const
{
if (!has_terminal() && !is_at_terminal)
{
return true;
}
return false;
}
bool has_terminal() const
{
if (waypoints.empty())
{
return false;
}
else
{
return waypoints.back().type == wp_terminal;
}
}
bool is_low_on_fuel() const
{
if (fuel<200)
{
return true;
}
else
{
return false;
}
}
void display() const override;
bool move() override;
void refill(int& fuel_stock);
friend class Tower;
friend class AircraftManager;
};
The code of the function generates errors that I can't understand unfortunately.
use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Aircraft; _Dp = std::default_delete<Aircraft>]’
static assertion failed: result type must be constructible from value type of input range
If anyone has an idea of how I can achieve this, I would be very grateful!
First, you have to use std::remove_if, because std::all_of returns bool, not iterator. But std::remove_if does what you want, it removes all instances that match bool predicate.
Second, your compile errors appear because you pass by value everywhere, so instead of (std::unique_ptr<Aircraft> a2) pass reference (std::unique_ptr<Aircraft> const & a2), instead [aircrafts] and [a1] pass [&aircrafts] and [&a1].
Third, inner predicate should not just return result of std::find_if (which returns iterator) but return bool, i.e. compare result of find_if to aircrafts.end().
Speed-wise your algorithm can be optimized if needed, for that you have to convert std::vector to std::unordered_set and then iterate through first map and check containment inside second set. If you don't have too many elements and speed is not of much importance then your algorithm is alright.
Final working code below:
void remove_crashed_aircraft(
std::unordered_map<const Aircraft*, size_t>& reserved_terminals,
std::vector<std::unique_ptr<Aircraft>>& aircrafts
) {
std::remove_if(reserved_terminals.begin(), reserved_terminals.end(),
[&aircrafts](auto const & a1){
return std::find_if(aircrafts.begin(), aircrafts.end(),
[&a1](auto const & a2){ return a1.first == a2.get(); })
== aircrafts.end();
}
);
}
Sorry, but I have to repeat the same question as I asked before "C++, Adding conditions in class vars".
I am using SDL2 here.
In obj.h: (excluding preprocessor commands)
class obj {
public:
SDL_Rect clip;
void addCollideWith( SDL_Rect rect );
void hasCollide();
void clearCollideWith();
private:
std::list<bool *> collideWith;
};
In obj.cpp: (excluding preprocessor commands)
void obj::addCollideWith( SDL_Rect rect )
{
collideWith.push_back(SDL_HasIntersection(obj.clip, rect));
}
void obj::hasCollide()
{
bool retval = true;
for (std::list<bool *>::iterator it = collideWith.begin(); it != collideWith.end(); it++)
{
retval = retval && **it;
}
return retval;
}
void clearCollideWith()
{
collideWith.clear();
}
Inside main function, I am saying that the object moves by one pixel and every time when it moves by one pixel, it checks for collision with other objects. I cleared the pointer thing '*' as I am not putting in variables as you can see: collideWith.push_back(SDL_HasIntersection(obj.clip, rect));. What I do is to make it move a pixel, clear collideWith and add collideWith condition again for updating whether it is true or false.
Now, whats the problem?
Its making the program really really slow! If I remove collideWith thing and then, starts the program, it gets a lot more smoother. Now, what I want, is to store the statement rather than true or false. std::list takes:
collideWith.pushBack(true /*OR*/ false);
But what I want is:
collideWith.pushBack(/*statement determining whether it is true or false*/ var1 > var2);
Please do complain if context is missing or the question is somehow, not understandable!
(NOTE: Context related to moving the object and declaring obj clip sub-vars is not mentioned as they are not a part of question.)
You could try to replace
std::list<bool *> collideWith;
with
std::list<SDL_Rect> collideWith;
in order to track of the rectangles that you want to considere.
The implementation could be :
void obj::addCollideWith( SDL_Rect rect )
{
collideWith.push_back(rect);
}
// to test if it collides with at least one rectangle
bool obj::hasCollide()
{
bool retval = false;
for (std::list<SDL_Rect>::iterator it = collideWith.begin(); it != collideWith.end(); it++)
{
retval = retval || SDL_HasIntersection(obj.clip, *it);
}
return retval;
}
// to test if it collides with all rectangles
/* bool obj::hasCollide()
{
bool retval = true;
for (std::list<SDL_Rect>::iterator it = collideWith.begin(); it != collideWith.end(); it++)
{
retval = retval && SDL_HasIntersection(obj.clip, *it);
}
return retval;
} */
I have a few classes set up for a game, with XMapObject as the base, and XEntity, XEnviron, and XItem inheriting it.
MapObjects have a number of flags, one of them being MAPOBJECT_SOLID. My problem is that XEntity is the only class that correctly detects MAPOBJECT_SOLID. Both Items are Environs are always considered solid by the game, regardless of the flag's state. What is important is that Environs and Item should almost never be solid.
Each class has a very basic preliminary constructor, just initializing all varibles to zero or NULL. During the CreateX() phase, Objects are linked into the map, set into a linked linked list.
Both XItem and XEnviron are a tad sloppy. They are both new, and in the middle or my debugging attempts.
Here are the relevent code samples:
XMapObject:
#define MAPOBJECT_ACTIVE 1
#define MAPOBJECT_RENDER 2
#define MAPOBJECT_SOLID 4
class XMapObject : public XObject
{
public:
Uint8 MapObjectType,Location[2],MapObjectFlags;
XMapObject *NextMapObject,*PrevMapObject;
XMapObject();
void CreateMapObject(Uint8 MapObjectType);
void SpawnMapObject(Uint8 MapObjectLocation[2]);
void RemoveMapObject();
void DeleteMapObject();
void MapObjectSetLocation(Uint8 Y,Uint8 X);
void MapObjectMapLink();
void MapObjectMapUnlink();
};
XMapObject::XMapObject()
{
MapObjectType = 0;
Location[0] = 0;
Location[1] = 1;
NextMapObject = NULL;
PrevMapObject = NULL;
}
void XMapObject::CreateMapObject(Uint8 Type)
{
MapObjectType = Type;
}
void XMapObject::SpawnMapObject(Uint8 MapObjectLocation[2])
{
if(!(MapObjectFlags & MAPOBJECT_ACTIVE)) { MapObjectFlags += MAPOBJECT_ACTIVE; }
Location[0] = MapObjectLocation[0];
Location[1] = MapObjectLocation[1];
MapObjectMapLink();
}
XEntity:
XEntity *StartEntity = NULL,*EndEntity = NULL;
class XEntity : public XMapObject
{
public:
Uint8 Health,EntityFlags;
float Speed,Time;
XEntity *NextEntity,*PrevEntity;
XItem *IventoryList;
XEntity();
void CreateEntity(Uint8 EntityType,Uint8 EntityLocation[2]);
void DeleteEntity();
void EntityLink();
void EntityUnlink();
Uint8 MoveEntity(Uint8 YOffset,Uint8 XOffset);
};
XEntity::XEntity()
{
Health = 0;
Speed = 0;
Time = 1.0;
EntityFlags = 0;
NextEntity = NULL;
PrevEntity = NULL;
IventoryList = NULL;
}
void XEntity::CreateEntity(Uint8 EntityType,Uint8 EntityLocation[2])
{
CreateMapObject(EntityType);
SpawnMapObject(EntityLocation);
if(!(MapObjectFlags & MAPOBJECT_SOLID) { MapObjectFlags += MAPOBJECT_SOLID; }
EntityFlags = ENTITY_CLIPPING;
Time = 1.0;
Speed = 1.0;
EntityLink();
}
void XEntity::EntityLink()
{
if(StartEntity == NULL)
{
StartEntity = this;
PrevEntity = NULL;
NextEntity = NULL;
}
else
{
EndEntity->NextEntity = this;
}
EndEntity = this;
}
XEnviron:
class XEnviron : public XMapObject
{
public:
Uint8 Effect,TimeOut;
void CreateEnviron(Uint8 Type,Uint8 Y,Uint8 X,Uint8 TimeOut);
};
void XEnviron::CreateEnviron(Uint8 EnvironType,Uint8 Y,Uint8 X,Uint8 TimeOut)
{
CreateMapObject(EnvironType);
Location[0] = Y;
Location[1] = X;
SpawnMapObject(Location);
XTile *Tile = GetTile(Y,X);
Tile->Environ = this;
MapObjectFlags = MAPOBJECT_ACTIVE + MAPOBJECT_SOLID;
printf("%i\n",MapObjectFlags);
}
XItem:
class XItem : public XMapObject
{
public:
void CreateItem(Uint8 Type,Uint8 Y,Uint8 X);
};
void XItem::CreateItem(Uint8 Type,Uint8 Y,Uint8 X)
{
CreateMapObject(Type);
Location[0] = Y;
Location[1] = X;
SpawnMapObject(Location);
}
And lastly, the entity move code. Only entities are capable of moving themselves.
Uint8 XEntity::MoveEntity(Uint8 YOffset,Uint8 XOffset)
{
Uint8
NewY = Location[0] + YOffset,
NewX = Location[1] + XOffset;
if((NewY >= 0 && NewY < MAPY) && (NewX >= 0 && NewX < MAPX))
{
XTile *Tile = GetTile(NewY,NewX);
if(Tile->MapList != NULL)
{
XMapObject *MapObject = Tile->MapList;
while(MapObject != NULL)
{
if(MapObject->MapObjectFlags & MAPOBJECT_SOLID)
{
printf("solid\n");
return 0;
}
MapObject = MapObject->NextMapObject;
}
}
if(Tile->Flags & TILE_SOLID && EntityFlags & ENTITY_CLIPPING)
{
return 0;
}
this->MapObjectSetLocation(NewY,NewX);
return 1;
}
return 0;
}
What is wierd, is that the bitwise operator always returns true when the MapObject is an Environ or an Item, but it works correctly for Entities. For debug I am using the printf "Solid", and also a printf containing the value of the flag for both Environs and Items.
Any help is greatly appreciated, as this is a major bug for the small game I am working on. I am also very new at Object Oriented programming, anything tips, suggestions and/or criticism are also welcome.
Your problem appears to be that you never initialize MapObjectFlags in any classes other than XEnviron so, as a basic type, it will have an unspecified value in XItem, XEntity and other XMapObject derived objects. I suggest that, as a member of XMapObject you explicitly initialize it to a known value.
As a rule, it is generally a good idea to ensure that all members of basic type are explicitly initialized in the initializer list of every constructor that you define.
e.g.
XMapObject()
: MapObjectFlags(0)
, // ... other initializers
{
// Other initializations
}
You can't (legally) be calling XEntity::MoveEntity on a MapObject or Environ because they don't have such a method. If you're using static_cast to change your object pointer into an XEntity so you can call MoveEntity on it, then you really have no guarantees about how the bit operation will work. In some implementations, things may appear to work in MoveEntity, but what's actually happening is it's interpreting the other object's memory as an XEntity. When it tries to access the offset where it believes MapObjectFlags exists, it's not actually there and always has that bit set to 1.
I figured out the problem earlier today - It didn't have any relation to OO programming, inheritance, or bitwise; it was a simple scope error.
The problem was in the fact that during my quick test to get an Environ in game, I declared the new variable inside of the control switch sequence, so the next time any control was used, the Environ would act in unpredictable ways.
switch(Event.key.keysym.sym)
{
...
case SDLK_c: { XEnviron Environ; Environ.InitEnviron(...); }
...
}
i have what i hope is a quick question about some code i am building out.. basically i want to compare the variables amongst two instances of a class (goldfish) to see if one is inside the territory of another. they both have territory clases which in turn use a point clase made up of an x and y data-point.
now i was curious to know why the below doesnt work please:
(this bit of code compares two points: a & b, each with two points, a north-east (ne) and south-west (sw) and their x and y plots)
if ((a->x_ne <= b->x_ne && a->y_ne <= b-> ne) &&
(a->x_sw => b->x_sw && a->y_sw => b-> sw)) {
return true;
} else return false;
I can think of a work around (for instance, by having a get location method), and using a function in the main body to compare, but im curious to know --as a budding c++ programmer -- why the above, or a similar implementation doesnt appear to work.
and also, what would be the CLEANEST and most elegant way to accomplish the above? have a friend function perhaps?
many thanks
edit: added some comments to (hopefully make the variables clearer)
// class point {
// public:
// float x;
// float y;
// point(float x_in, float y_in) { //the 2 arg constructor
// x = x_in;
// y = y_in;
// }
// };
// class territory {
// private:
// point ne, sw;
// public:
// territory(float x_ne, float y_ne, float x_sw, float y_sw)
// : ne(x_ne, y_ne), sw(x_sw,y_sw) {
// }
// bool contain_check(territory a, territory b) {
// //checks if a is contained in b (in THAT order!)
// if ((a->x_ne <= b->x_ne && a->y_ne <= b-> ne) &&
// (a->x_sw => b->x_sw && a->y_sw => b-> sw)) {
// return true;
// } else return false;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// };
// class goldfish {
// protected:
// float size;
// point pos;
// territory terr;
// public:
// goldfish(float x, float y) : pos(x,y), terr(x-1,y-1,x+1,y+1) { //constructor
// size = 2.3;
// }
// void retreat() { //what happens in the case of loss in attack
// /*
// if(goldfish.size[1] - goldfish.size[2] <= 1 && goldfish.size[1] - goldfish.size[2] > 0) {
// size = size - 0.2;
// }
// */
// }
// void triumph() {
// }
// void attack() {
// }
// // void goldfish()
// };
On first glance: There isn't a => operator. It's called >=
Assuming that your territories are rectangles and your are detecting overlap by comparing the corners of the two classes (ne and nw) you are only checking the northwest and northeast corners which have a region of a line. As #Éric Malenfant mentioned, you have structures as the class members which are accessed by the '.' operator. Those members are ne and sw so to reference them would be: "a.ne.x"
So starting with this:
if ((a->x_ne <= b->x_ne && a->y_ne <= b-> ne) &&
(a->x_nw => b->x_nw && a->y_nw => b-> nw)) {
return true;
} else return false;
Change it to:
return ( (a.ne.x <= b.ne.x && a.ne.y <= b.ne.y)
&& (a.sw.x >= b.sw.x && a.sw.y >= b.sw.y));
What do you mean by "doesnt work"? I does not compile?
If contain_check is written as shown in your post, a problem is that you are using the arrow operator on non-pointers. Use dot instead:
if ((a.x_ne <= b.x_ne && a.y_ne <= b.ne) //etc.
I noticed two possible problems right off (note: not a C++ expert):
You use => for "greater than or equal to", where it should be >=.
Also, I think b->ne should be b->y_ne.
bool contain_check(territory a, territory b)
You're passing in two territory objects, not pointers to territory objects. Consequently, you'll want to use the . operator to access members instead of the -> operator. Something like:
a.ne
Additionally, you've declared the ne and sw members private, which means that they won't be accessible to unrelated functions. They would need to be public for the contain_check() function to access them.
sorry, i was clearly (very) confused. thanks guys! below works:
if ((a.ne.x <= b.ne.x && a.ne.y <= b.ne.y) &&
(a.sw.x >= b.sw.x && a.sw.y >= b.sw.y)) {
return true;
} else return false;
}
the method bool territory::contain_check(const territory &a, const territory &b); should be declared as static. it makes sense.
or, better, write it as standalone function, because it has nothing to do with the class territory; it checks some kind of relation between two instances, right?