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'm trying to represent a 2 dimensional map of objects. So I have a two-dimensional array of "MapItems":
MapItem* world_map[10][10];
In my specific situation, these MapItems are going to be used to represent Drones, Static Objects (like trees or any obstruction that doesn't move), or empty positions (these objects will be subclasses of MapItem):
class Drone : public MapItem {
int droneId;
...
}
class StaticObject : public MapItem {
...
}
class EmptyPosition : public MapItem {
int amount_of_time_unoccupied;
...
}
Is it a good idea to have an instance variable on the MapItem class that tells what specific type of item it is, and then cast it the proper type based on that? For example:
enum ItemType = {DRONE, STATIC_OBSTRUCTION, EMPTY};
class MapItem {
ItemType type;
...
}
And then when I want to know what is at a position in the map, I do:
MapItem *item = world_map[3][3];
if (item->type == DRONE) {
Drone *drone = dynamic_cast<Drone*>(item);
// Now do drone specific things with drone
...
} else if (item->type == STATIC_OBSTRUCTION) {
StaticObject *object = dynamic_case<StaticObject*>(item);
// Static object specific stuff
...
} else {
...
}
I have not actually tried this, but I assume it's possible. What I'm really asking is this a good design pattern? Or is there a better way to do this?
A "switch on type" indicates a design problem much more often than not.
What you usually want to do is define and implement some virtual functions for the behaviors you care about. For example, you might care about flying into one of the spaces. If so, you might have a function to see if it allows entry. That will return true if a drone is trying fly into open air, or false if it's trying to fly into a tree.
As an aside, if you're going to have derived objects, you need to define the array as container pointers, not actual objects of the base class. Otherwise, when you try to put a derived object into the array, it'll get "sliced" to become an object of the base class.
I'm learning C++ by programming a game. I'm using SDL to display my objects and a factory structure to keep it all organised.
I separated the first object (a car), the controls (keyboard) and the display (monitor).
In my main class I call the monitor class to display a window where I should draw the images. If a key is pressed, the car should react to that by redrawing the image.
The problem here is that I initialized the monitor in the main class and I can't access it in my car class..
I tried a variety of things, but nothing seems to do the trick.
So here is the main class
Game::Game(GuiFactory* factory) {
bool is_running = true;
Car* car = factory->createCar();
car->drawCar();
// create factory specific window
Monitor* monitor = factory->createMonitor();
// create factory specific keyboard
Keyboard* keyboard = factory->createKeyboard();
while (is_running) {
// keyboard input
string key_input = keyboard->getKeys();
if (key_input == "quit") {
is_running = false;
} else if (key_input != "") {
if(key_input == "right"){
car->turnRight(monitor);
}
}
}
}
I have a main car class and an SDLCar class, which inherits car.
class Car {
public:
Car();
virtual ~Car();
virtual void drawCar() = 0;
virtual void turnRight() = 0;
};
Here is where I'm confused:
class SDLCar : public Car {
public:
SDLCar();
virtual ~SDLCar();
void drawCar();
void turnRight(SDLMonitor& monitor);
// ^^^^^^^^^^^^^^^^^^^
};
Could someone please explain?
In your base class Car you have declared the method turnRight which takes no parameters.
In your derived class SDLCar you have declared a completely different method with the same name. The reason why it's a different method and not a function override is that its takes a parameter. It should be parameterless to override Car::turnRight.
And because it's not a function override, the rules of polymorphism don't apply. Thus you can't call SDLCar::turnRight(SDLMonitor&) from a Car pointer.
Right now is an excellent time to start using the override keyword. It prevents specifically these kind of programming errors. By marking a function with override:
void turnRight(SDLMonitor& monitor) override;
the compiler will automatically check that it actually overrides a function from the base class.
E.g. with the above declaration, the compiler would give you an error (or a warning at least). This would've helped you find your error right away and prevented more erroneous code such as car->turnRight(monitor).
So now that the error is found, you need to find a way to fix it. Either declare the base class turnRight to take a SDLMonitor& as well, or think of something else if that's not how it should behave.
IMO having to pass the game window to a method like turnRight seems weird. Why would turning a car need a window? I think turnRight should do just what it says on the tin: turn the car right. Nothing else.
I don't know why you're passing a window to the method but if it's for drawing, shouldn't the drawCar method handle that? I don't know your code, so I'll leave it up to you.
The following syntax is from cocos2d
-(void) setLevelScene:(Class)klass
{
[[CCDirector sharedDirector] replaceScene: [CCTransitionFade transitionWithDuration:1 scene:[klass scene]]];
}
i want to change above cocos2d code to Cocos2dx, as i know there is no type such as Class in COCOS2DX.
How can i change the code particularly Class class type or any alternative type in cocos2dx?
Can you assist me to change the above code?
C++ doesn't have mechanism like isKindOf or class "that contain class name".
If you want to check that object is an instance of a class you can use dynamic cast.
dynamic_cast< Class* >(object) <- this line will return null if object isn't an instance of Class
Another way is to use virtual method like ClassName();
which you override in your every class and return a string with ClassName, for example:
std::string MainLayer::ClassName(){
return "MainLayer";
}
edit:
In your example I would write something like this
void setLevel(CCScene* scene){
CCDirector::sharedDirector->replaceScene(CCTransitionFade::create(1.0f, scene);
}
and call like that
setLevel(MainLayer::scene());
In this case you don't need any information about class in setLevel function. If you have many levels in your project good idea is use the Factory Method pattern.
void className:: setLevelScene(className* klass)
{
CCDirector::sharedDirector()->replaceScene(CCTransitionFade::create(1, klass));
}
I'm in a bit of a pickle: say I'm making a simple, 2D, Zelda-like game.
When two Objects collide, each should have a resulting action. However, when the main character collides with something, his reaction depends solely on the type of the object with which he collided. If it's a monster, he should bounce back, if it's a wall, nothing should happen, if it's a magical blue box with ribbons, he should heal, etc. (these are just examples).
I should also note that BOTH things are part of the collision, that is, collision events should happen for both the character AND the monster, not just one or the other.
How would you write code like this? I can think of a number of incredibly inelegant ways, for instance, having virtual functions in the global WorldObject class, to identify attributes - for instance, a GetObjectType() function (returns ints, char*s, anything that identifies the object as Monster, Box, or Wall), then in classes with more attributes, say Monster, there could be more virtual functions, say GetSpecies().
However, this becomes annoying to maintain, and leads to a large cascading switch (or If) statement in the collision handler
MainCharacter::Handler(Object& obj)
{
switch(obj.GetType())
{
case MONSTER:
switch((*(Monster*)&obj)->GetSpecies())
{
case EVILSCARYDOG:
...
...
}
...
}
}
There's also the option of using files, and the files would have things like:
Object=Monster
Species=EvilScaryDog
Subspecies=Boss
And then the code can retrieve the attributes without the need for virtual functions cluttering everything up. This doesn't solve the cascading If problem, however.
And THEN there's the option of having a function for each case, say CollideWall(), CollideMonster(), CollideHealingThingy(). This is personally my least favourite (although they're all far from likeable), because it seems the most cumbersome to maintain.
Could somebody please give some insight into more elegant solutions to this problem?
Thanks for any and all help!
I would do it vice versa - because if the character collides with an object, an object collides with the character as well. Thus you can have a base class Object, like this:
class Object {
virtual void collideWithCharacter(MainCharacter&) = 0;
};
class Monster : public Object {
virtual void collideWithCharacter(MainCharacter&) { /* Monster collision handler */ }
};
// etc. for each object
Generally in OOP design virtual functions are the only "correct" solution for cases like this:
switch (obj.getType()) {
case A: /* ... */ break;
case B: /* ... */ break;
}
EDIT:
After your clarification, you will need to adjust the above a bit. The MainCharacter should have overloaded methods for each of the objects it can collide with:
class MainCharacter {
void collideWith(Monster&) { /* ... */ }
void collideWith(EvilScaryDog&) { /* ... */ }
void collideWith(Boss&) { /* ... */ }
/* etc. for each object */
};
class Object {
virtual void collideWithCharacter(MainCharacter&) = 0;
};
class Monster : public Object {
virtual void collideWithCharacter(MainCharacter& c)
{
c.collideWith(*this); // Tell the main character it collided with us
/* ... */
}
};
/* So on for each object */
This way you notify the main character about the collision and it can take appropriate actions. Also if you need an object that should not notify the main character about the collision, you can just remove the notification call in that particular class.
This approach is called a double dispatch.
I would also consider making the MainCharacter itself an Object, move the overloads to Object and use collideWith instead of collideWithCharacter.
How about deriving all collidable objects from one common abstract class (let's call it Collidable). That class could contain all properties that can be changed by a collission and one HandleCollision function. When two objects collide, you just call HandleCollision on each object with the other object as the argument. Each object manipulates the other to handle the collision. Neither object needs to know what other object type it just bounced into and you have no big switch statements.
Make all colidable entities implement an interface (lets say "Collidable") with a collideWith(Collidable) method.
Then, on you collision detection algorithm, if you detect that A collides with B, you would call:
A->collideWith((Collidable)B);
B->collideWith((Collidable)A);
Assume that A is the MainCharacter and B a monster and both implement the Collidable interface.
A->collideWith(B);
Would call the following:
MainCharacter::collideWith(Collidable& obj)
{
//switch(obj.GetType()){
// case MONSTER:
// ...
//instead of this switch you were doing, dispatch it to another function
obj->collideWith(this); //Note that "this", in this context is evaluated to the
//something of type MainCharacter.
}
This would in turn call the Monster::collideWith(MainCharacter) method and you can implement all monster-character behaviour there:
Monster::CollideWith(MainCharacter mc){
//take the life of character and make it bounce back
mc->takeDamage(this.attackPower);
mc->bounceBack(20/*e.g.*/);
}
More info: Single Dispatch
Hope it helps.
What you call "an annoying switch statement" i would call "a great game" so you are on the right track.
Having a function for every interaction/game rule is exactly what I would suggest. It makes it easy to find, debug, change and add new functionality:
void PlayerCollidesWithWall(player, wall) {
player.velocity = 0;
}
void PlayerCollidesWithHPPotion(player, hpPoition) {
player.hp = player.maxHp;
Destroy(hpPoition);
}
...
So the question is really how to detect each of these cases. Assuming you have some sort of collision detection that results in X and Y collide (as simple as N^2 overlap tests (hey, it works for plants vs zombies, and that's got a lot going on!) or as complicated as sweep and prune + gjk)
void DoCollision(x, y) {
if (x.IsPlayer() && y.IsWall()) { // need reverse too, y.IsPlayer, x.IsWall
PlayerCollidesWithWall(x, y); // unless you have somehow sorted them...
return;
}
if (x.IsPlayer() && y.IsPotion() { ... }
...
This style, while verbose is
easy to debug
easy to add cases
shows you when you have
logical/design inconsistencies or
omissions "oh what if a X is both a
player and a wall due to the
"PosessWall" ability, what then!?!"
(and then lets you simply add cases
to handle those)
Spore's cell stage uses exactly this style and has approximately 100 checks resulting in about 70 different outcomes (not counting the param reversals). It's only a ten minute game, that's 1 new interaction every 6 seconds for the whole stage - now that's gameplay value!
If I am getting your problem correctly, I would sth like
Class EventManager {
// some members/methods
handleCollisionEvent(ObjectType1 o1, ObjectType2 o2);
// and do overloading for every type of unique behavior with different type of objects.
// can have default behavior as well for unhandled object types
}