I'm trying to make a 2D platform based game (in SFML) for my university work. I'm not asking for anyone to write some code for me but if anyone could offer some pointers I'd be extremely grateful :)
At present I have around 13 classes, including:
BaseEntity (Most game objects derive from this)
Player (Inherits from BE)
Beetle (Inherits from BE - the game is called 'Beetle Dodger' so there will be moving beetles as a threat to the player)
Gem
MagicGem (players needs these to advance through the levels)
Platform
SolidBlock (inherits from Platform)
DownBlock (inherits from Platform - player can fall through but not jump up through this block)
UpBlock (as above but vice versa)
GameSound
Game (The game manager)
I've built most of the games 'building blocks' so to speak - every class has its own update function which is called in Game::Update. The same applies to each object's Draw() function. Every class holds a pointer to the game window so it can achieve these things and they're also passed a number of variables from Game, such as what key is currently being pressed and also the elapsed time (for movement calcs).
All seemed fine and dandy up to here - then I met collisions. Whilst I understand the basis of how they work, I've tried two or three different approaches to implementing them. At first I began with just having the Player class hold a bunch of functions such as CollidesWith( Beetle& b ) and CollidesWith( Platform& plat ). Obviously this is extremely strenuous when testing against every object in my level (including gems of course) and I began to consider how to implement broad phase collision detection. I then tried using an AABB class defined by 2 2DVectors (SFML's built in class). And this is where I got slightly stuck and decided to come and ask for help here. I went back to testing collisions using purely the size of the sprites (as they are defined by a box - the same as AABB's, right?) but I'm not sure this is/was a wise path to take.
Before I make a serious mess up of what're the good foundations of a game, can anyone offer some friendly advice on a good way to implement broad phase and narrow phase collision detection? I had narrow working quite well at one stage and then I realised that a player could still move through the side of a platform, heh.
Should I create a dedicated class for collisions? Or should I continue as I was, using the size of the sprites of each object (each object has it's own sprite and image - in fact I'll show an example):
class BaseEntity
{
public:
// Constructors
BaseEntity();
BaseEntity(sf::RenderWindow* gameWin, string imgPath, sf::Vector2f position = sf::Vector2f(0,0), sf::Vector2f velocity = sf::Vector2f(0,0));
virtual ~BaseEntity();
// Setters
void SetCurrentPos(sf::Vector2f newPos); // Set the current position
void SetPreviousPos(sf::Vector2f newPrevPos); // Shouldn't be needed but there may be rare circumstances
void SetCurrentVel(sf::Vector2f newVel); // Set the velocity
// Getters
sf::Vector2f GetCurrentPos(); // Returns the current position values
sf::Vector2f GetPreviousPos(); // Returns the previous position values
sf::Vector2f GetCurrentVel(); // Returns the current velocity values
void virtual SetSprite(string imgPath); // Set up the images for the sprite
void virtual Update(float elapsedTime); // The function that handles the updating of movement
void virtual Draw(); // The function that handles the 'Draw' aspect of this object
protected:
sf::RenderWindow* p_GameWin; // A pointer to the game window (used for drawing)
sf::Vector2f currentPos;
sf::Vector2f previousPos;
sf::Vector2f currentVel;
sf::Sprite mySprite; // This objects sprite
sf::Image myImage; // This objects image
};
The player class inherits from this and has a few extra functions such as CheckBoundaries, CollidesWith, Jump and also holds a few variables - bool isColliding may be of interest in this scenario.
Cheers guys, and sorry for the essay!
As you have found out solving the collision cannot be considered just at the level of a single game object. You need an object that can keep track of all the objects that participate in collision, and can read from them all the properties that affect collision. If this is done then it can solve collision globally for all the objects once every game update tick.
What I recommend is creating an interface through which you can get all the information required to process the collision detection. All objects that participate in collision will need to inherit from this. The interface will allow you to smoothly transition from the per object case and the global case.
This is just an example to help you understand. You need to adapt it to your own code.
class ICollidable
{
public:
// we use these function to retrieve collision relevant information
// (can be optimised)
virtual sf::Vector2f GetPosition() = 0; // objects have position
virtual sf::Vector2f GetSize() = 0; // objects have a size
// using this function, we notify the object that it collided with something else
virtual void ProcessCollision(ICollidable* other) = 0;
// if you use virtual methods, you need a virtual destructor
virtual ~ICollidable{};
};
Now you can create a collision system. A collision system would hold a list of ICollidable objects that can interact with each other. You can even choose some objects to not participate in collisions at all. This will be responsible to solving the collision at the global level.
class CollisionSystem
{
private:
// hold all objects that participate in collision
std::vector<ICollidable*> objectList;
public:
void AddToCollisionList(ICollidable* obj);
void RemoveFromCollisionList(ICollidable* obj);
void ProcessCollisionList();
}
The CollisionSystem::ProcessCollisionList(); contains the implementation of the collision checking algorithm. It will get the position and size of each object. Base on that information it will decide that two objects collide and call ICollidable::ProcessCollision(ICollidable& other); for each object that collides. This method will be overriden by subclasses to provide class specific functionality.
Inside CollisionSystem, you can use data structures like quad trees or binary trees to speed up the time it takes to solve all collisions. As a first step I recommend just sorting on X axis. By keeping the list sorted you only have to check the neighbors that are not further away than the size of you object.
If the requirements for your game change, you can update with better collision checking algorithm, you can add more attributes to ICollidable. In general you also need to process physics, you could also provide the functionality for that through ICollidable.
And as a tip, if two objects collide, I recommend immediately moving them away from each other so that they don't collide in the next game tick.
Depending on the amount of entities you are dealing with, just checking collision for every object in the game might have a huge cost, in terms of memory and/or in terms of performance.
You might want to pre-treat your objects to classify them by an axis, like increasing x coordinate, to simplify the collision checking. It could be even better to prepare all your objects and sort them before the game even starts, as an initiation to a level for example. I think that would be the way i'd choose to do it, for a first try.
Related
I have 3 classes in my program:
class GameObject{
private:
std::pair<int, int> position;
}
class World{
private:
std::vector<GameObject*> gameObjects;
int gravity;
}
class MovingObject : public GameObject{
private:
int velocity;
bool isSensitiveToGravity;
unsigned mass;
}
I am using a vector of GameObject* in the World class because I want to put in there every object that is in the game, and some objects are not MovingObject instances.
But I see a problem there: during the game, I will need to loop on world.gameObjects in order to check if an object is sensitive to gravity to drag it down if it is the case, but how should I do this?
My first idea was to add a pure virtual method in the GameObject class that would be implemented in the MovingObject class and return whether an object is sensitive to gravity or not, but isn't this a weird design?
The other idea is of course to use dynamic_cast on every object, check for (sub)class of MovingObject, and then check for the isSensitiveToGravity field, but I read a lot that dynamic_cast should be avoided and is almost always a sign of bad design, so where is my error here?
Thank you!
When you think in terms of functionality in OOP you should think in terms of interfaces and not structs of data. This is exactly the case so you should create an interface with a function interactWithGravity and use it. In case this is an object that does not interact with gravity simply do nothing.
To emphasize why this it the correct solution let's consider the other alternative, having a parameter determining if it's moveable by gravity or not. This has the following cons:
If you'll have more parameters the affects how certain objects are interact with gravity means adding another property to the common struct (although it's only relevant to some).
The previous example also suggests you'll need to expend you're cases in the main function that goes over the objects and make the code more complex and harder to expend.
Perhapse you'll find it easier to do the "gravity calculations" in polar coordinates. This means changing all the calculation and coordinates in the different objects.
Holding different lists may be reasonable if you need to do some optimizations but otherwise it will be less reusable and expendable from similar reasons.
The list goes on and on with other concepts like ISP but you get the general idea.
I've this situation:
class Shape{};
class Triangle : public Shape{};
class Rectangle : public Shape{};
class Square : public Rectangle{};
I want to implement a virtual collideWith method in the base class that works this way:
Shape *square = new Square();
Shape *triangle = new Triangle();
bool test = square.collideWith(triangle);
Is there a way to implement this method in order to work with base class without explitit casting do derived classes?
I've thinked to create a namespace that do it:
namespace Collision {
bool isCollisionBetween(const Triangle &triangle, const Square &square) {/* calculus */}
bool isCollisionBetween(const Rectangle &rect, const Square &square) {/* calculus */}
// and so on for all combination
}
But then I don't know how I can apply this when I have something like
std::set<Shape*> shapesSet;
and I want to calculate all collision for this set.
Is it possible or it's always necessary to explicity cast Shape class to the right inherited one?
In general you would solve a problem like this as follows:
Give Shape an abstract function describing the shape, that each subclass must implement.
Each subclass implements this function based on the specific type it is.
A collideWith() function in Shape uses the abstract function of two types to determine the property.
This way when a shape is added, none of the other shapes need to be changed and you don't have to add a function to compare it with each other shape. Only the new shape has to provide functions for all required properties.
Now the difficult part is to decide what property each shape can provide. And in your case it might be difficult to provide it with an efficient implementation.
Examples of properties you can use to provide a collision detection are:
polygonRepresentation()
asVectorGrahpic()
convertToBitMap()
As you can imagine, in your problem, it might be difficult to find a proper representation suitable for each item. Then you probably have to revert to comparisons that know all the elements. But this is really an anti Object Oriented pattern, and will lead to trouble when the amount of shapes or properties increases.
ok, my comment was a little bit missleading you. What I meant was:
To create the collisionInformation make something like a "BroadPhase" (This is optional but very helpful). Consider it as a precheck if potential shapes are colliding. Google therefore "Binary Space Partition". Forget about Quad- or Octtrees at this time. This phase will create a potential contact and their information. Ask your self: which shapes are colliding? which collision resolve function am i calling? Should I use polymorphism or function pointers? (i.e calling a function pointer to a static bool CollisionResolver::handle( Box b, Circle c ); which can be retrieved/called through collisoinInformation ). What callback am I calling if there is a collision? Save all this info to this collisoinInformation object
Create your different collision handle functions to treat collisions between different shapes. Iterate your i.e std::vector saving your collisionInformation and call ( a now imaginary function) colIter->resolve() which is calling the right implementation of your collision handle functions. If you found a collision ask yourself: Which functions will I call? What information could I provide? i.e stuff additional information into your collisoinInformation or maybe create a new object collisionPair etc... You could save collision point, normal, the shapes....
Collision detection was successfully an is calling "saved" callbacks to your final gameObjects. i.e you could call GameObject::OnCollision( const ContactPair& p );
Hope this helps you a little bit more than my previously added comment
ps: A good tip for starters: Look behind the scenes of current open source implementation. i.e ODE or PhysX
I'm developing a base for a 2D game. My general design is something like this:
class Entity:
Every object class (like a wall, an enemy, floor etc.) derives
from this class. Most of the functions are pure virtual. There is
a hitbox as well.
class Scene:
Contains pointers to Entity-objects. When an Entity-pointer is added,
it will be given a Scene-pointer to its parent so it may access that.
Scene also has a collision-detecting function:
getIntersections<T> (Entity *)
getIntersections<T...> (Entity *)
(both return a std::vector<Entity *>)
This basically gets all Entity *s intersecting the parameter-Entity * (by checking the hitbox) and then tries to dynamic_cast<T *> them. All matching Entity *s (not the casted ones) are then returned. The variadic template is used for checking for more then one intersecting class.
My basic idea behind that was, if I had a Player-class (which represents the player obviously), and some other classes like Enemy, Wall, etc., it would be an easy task to check if a Player-object was colliding with one(or more) of these:
// (inside Player::tick(); quick and dirty)
{
if ( (this->parentScene->getIntersections<Wall>(this)).empty() )
// player does not collide with a wall, just move.
else
// player does collide with a wall, do whatever.
}
However, I have got two questions on that:
Does my (general) design show up flaws for the need of dynamic_cast<T *> as replacement for instanceof (like there is in Java for example)
Is it a performant solution on the task? Since for every collision check, Scene basically loops through every Entity * it contains, checks if it collides with the given Entity * and finally casts it to check if it derives from another given class. If that is not performant, what changes were to make in my design to make it performant?
On the performance part it would be better to separate entities in separate vectors by primitive type. Not only you can specifically test a plane vs a sphere for example it eliminates the need to have dynamic_cast entirely ( -> extra speedup ). Also since you already separated the types in vectors you can just ignore the virtual functions and go for non virtual call providing additional performance improvement;
So your scene would look something like this:
class scene
{
std::vector<PlaneEntity> m_planes;
std::vector<CircleEntity> m_circles;
};
And regarding the design of this it is much easier to select the right algorithm when intersecting primities:
This is an example on how a basic collision checking would look based on this design:
void colide(const PlaneEntity & e)
{
for each plane
call plane vs plane collision
for each circle
call plane vs circle collision;
};
void colide(const CircleEntity & e)
{
for each plane
call plane vs circle collision;
for each circle
call circle vs circle collision;
};
So to answer your question:
1: it is not a rule weather to use or not dynamic_cast, it is known that not using it is better for performance.
2: The design described above is not performant at all. Also your design with dynamic cast is even slower. To improve this you need to look into accelerations structures (this is huge topic so i can't explaing everything here) to speed up collision detection. They basically reduce the number of collision check for each primitive giving a massive improvement in performance. Basic structures are KD-Tree, Quad-Trees, Spacial-Hash , Grid, etc. You can find lots of code for each just by googleing them.
Hope this helps,
Raxvan.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I have one more question hopefully summerizing my thoughts.
Suppose I have the following 3 classes:
class Player:
class Player {
private:
int positionX, positionY;
public:
void move(Board& b) {
// player changes its position on the board(move)
b.removeCharFromBoard(positionX, positionY);
positionX++;
positionY++;
// 'P' indicates a Player in the Board....
b.insertCharToBoard(positionX, positionY, 'P');
}
};
class Board:
class Board {
private:
// BOARD_C and BOARD_R are both "#define ..." for some integer number.
char board[BOARD_C][BOARD_R];
};
class GameEngine:
class GameEngine {
private:
Board* board;
public:
void playTurn(const Player& p) {
p.move(board);
}
};
is it seem reasonable to you that the GameBoard's playTurn function will call the Player's move function with the parameter "board"?
I need to do it in order to mark in the board data member that the Player has changed his position.
Is it keep the OOP basic rules?
Thank you all,
Syndicator!
Yes, in this case it seems to be reasonable (by "in this case" I mean "considering what I can guess about the semantics of your GameEngine and Board classes and the nature of their association/aggregation relationship"):
Rather use a smart pointer than a raw pointer to hold the Board object in GameEngine. unique_ptr is probably what you want in this case, because all other aliases seems to be just observers and the lifetime of the board object is bound to the one of the GameEngine object. However, if shared ownership is needed, opt for shared_ptr. Just try not to use raw pointers, new, and delete, because they lead to buggy code;
You still need to provide public functions on the interface of the Board class to modify the board, because Player won't be able to access its private member variables (and board happens to be one).
Rather than #defines, use constexpr values for the sizes of the board (if you are using C++11). You might also want to consider Boost.MultiArray for creating safe bi-dimensional C-style arrays.
Your approach is fine. GameEngine will be used as some kind of controller of your game. Thanks to it you can for example filter player movements, check if this kind of move is even possible or do other kind of stuff in case of specific player operations.
Secondly, thnks to this solution you don't have to connect player to specific board, which expands your possibilites of other options like easy transfering players between boards. I think you are on a good way :)
You must think of how your application will change, and what features you would like to introduce. From this code it kind of looks ok, but will it look like that when you will introduce new features?
Other solution is to put into player only moving logic, it will update its positions, then your GameEngine will update board entries basing on all your players current positions. Imaging that with some time you will want to implement collision detection, then after each player has updated its positions or movements, collision detection would take place and correct those movements, and only later on your board would be correctly updated.
Many things have already been said, but if I may to add something.
Passing the Board (be it private or not) to the Player is not bad per se, and such design is used in several architectures (code taken from SFML 2.0):
void Sprite::draw(RenderTarget& target, RenderStates states) const
{
if (m_texture)
{
states.transform *= getTransform();
states.texture = m_texture;
target.draw(m_vertices, 4, Quads, states);
}
}
RenderTarget is your Board. This thing to understand here that you will operate on Board only using its public interface (to which you have access to). In above code, draw() is the method which is used on target to force it to draw something.
This whole idea of passing an inner object to a higher level class (like Player) can be interpreted as bridge OO pattern, where there can be several implementations of interface Board and several classes can implement IBoardManipulator (or something like this).
That said, I would say it's much better to follow the general idea of the game engine which is:
Register entities of the game (in this case the player)
Capture the player input
Digest & react to the player input (request moving the player)
Process game logic (check if the player can move to a given location, and if yes - move him)
For every registered entity GameEngine will call draw() passing Board as the target which the entities can use.
Repeat from step 2
I am not saying that for a simple architecture this is needed, but in the longer run it is much easier to manage than to deal with nasty things that each of the Player-like classes can do to the Board.
I've got a game engine where I'm splitting off the physics simulation from the game object functionality. So I've got a pure virtual class for a physical body
class Body
from which I'll be deriving various implementations of a physics simulation. My game object class then looks like
class GameObject {
public:
// ...
private:
Body *m_pBody;
};
and I can plug in whatever implementation I need for that particular game. But I may need access to all of the Body functions when I've only got a GameObject. So I've found myself writing tons of things like
Vector GameObject::GetPosition() const { return m_pBody->GetPosition(); }
I'm tempted to scratch all of them and just do stuff like
pObject->GetBody()->GetPosition();
but this seems wrong (i.e. violates the Law of Demeter). Plus, it simply pushes the verbosity from the implementation to the usage. So I'm looking for a different way of doing this.
The idea of the law of Demeter is that your GameObject isn't supposed to have functions like GetPosition(). Instead it's supposed to have MoveForward(int) or TurnLeft() functions that may call GetPosition() (along with other functions) internally. Essentially they translate one interface into another.
If your logic requires a GetPosition() function, then it makes sense turn that into an interface a la Ates Goral. Otherwise you'll need to rethink why you're grabbing so deeply into an object to call methods on its subobjects.
One approach you could take is to split the Body interface into multiple interfaces, each with a different purpose and give GameObject ownership of only the interfaces that it would have to expose.
class Positionable;
class Movable;
class Collidable;
//etc.
The concrete Body implementations would probably implement all interfaces but a GameObject that only needs to expose its position would only reference (through dependency injection) a Positionable interface:
class BodyA : public Positionable, Movable, Collidable {
// ...
};
class GameObjectA {
private:
Positionable *m_p;
public:
GameObjectA(Positionable *p) { m_p = p; }
Positionable *getPosition() { return m_p; }
};
BodyA bodyA;
GameObjectA objA(&bodyA);
objA->getPosition()->getX();
Game hierarchies should not involve a lot of inheritance. I can't point you to any web pages, but that is the feeling I've gather from the several sources, most notably the game gem series.
You can have hierarchies like ship->tie_fighter, ship->x_wing. But not PlaysSound->tie_fighter. Your tie_fighter class should be composed of the objects it needs to represent itself. A physics part, a graphics part, etc. You should provide a minimal interface for interacting with your game objects. Implement as much physics logic in the engine or in the physic piece.
With this approach your game objects become collections of more basic game components.
All that said, you will want to be able to set a game objects physical state during game events. So you'll end up with problem you described for setting the various pieces of state. It's just icky but that is best solution I've found so far.
I've recently tried to make higher level state functions, using ideas from Box2D. Have a function SetXForm for setting positions etc. Another for SetDXForm for velocities and angular velocity. These functions take proxy objects as parameters that represent the various parts of the physical state. Using methods like these you could reduce the number of methods you'd need to set state but in the end you'd probably still end up implementing the finer grained ones, and the proxy objects would be more work than you would save by skipping out on a few methods.
So, I didn't help that much. This was more a rebuttal of the previous answer.
In summary, I would recommend you stick with the many method approach. There may not always be a simple one to 1 relationship between game objects and physic objects. We ran into that where it was much simpler to have one game object represent all of the particles from an explosion. If we had given in and just exposed a body pointer, we would not have been able to simplify the problem.
Do I understand correctly that you're separating the physics of something from it's game representation?
i.e, would you see something like this:
class CompanionCube
{
private:
Body* m_pPhysicsBody;
};
?
If so, that smells wrong to me. Technically your 'GameObject' is a physics object, so it should derive from Body.
It sounds like you're planning on swapping physics models around and that's why you're attempting to do it via aggregation, and if that's the case, I'd ask: "Do you plan on swapping physics types at runtime, or compile time?".
If compile time is your answer, I'd derive your game objects from Body, and make Body a typedef to whichever physics body you want to have be the default.
If it's runtime, you'd have to write a 'Body' class that does that switching internally, which might not be a bad idea if your goal is to play around with different physics.
Alternatively, you'll probably find you'll have different 'parent' classes for Body depending on the type of game object (water, rigid body, etc), so you could just make that explicit in your derivation.
Anyhow, I'll stop rambling since this answer is based on a lot of guesswork. ;) Let me know if I'm off base, and I'll delete my answer.