Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Platform game / tile permeability / Box2D  (Read 3801 times)

0 Members and 1 Guest are viewing this topic.

Vitis

  • Newbie
  • *
  • Posts: 10
    • View Profile
Platform game / tile permeability / Box2D
« on: June 27, 2014, 05:03:49 am »
Greeting SFML community!

I'm very new to SFML and game programming.  I've been using SFML for about three weeks.  So far, I've programmed a rudimentary fighting game using a primitive physics engine and a collision detection system I coded from scratch.  Like most fighting games, there aren't any tiles, just a background, two animated character sprites, and sprites for lifebars.

For my next project, I want to create a basic, tile-based platform game.  I have already created a program that maps tiles over a background and displays a movable character sprite; however, I could use some advice from more experienced programmers before I proceed further. (Keep in mind that my goal in this new project is not to make a great platform game, but to learn more about game programming in general.)

I have not yet developed a system to keep track of the permeability characteristics of each individual tile.

My questions are:

1) What is an efficient way to handle character sprite/tile interaction to be consistent with normative platform gameplay mechanics?  (By "player sprite/tile interaction" I mean that some (transparent) tiles should  be completely permeable to the character sprite, some tiles should be completely impermeable to the character sprite, and some should be permeable in only one direction, i.e. a the player should be able to pass through the tile/platform from below but not from above.)

2) Should I use a physics engine like Box2D, or should I handle physics with code I create from scratch?
    (I'm leaning towards the latter option because I want this project to be didactic.)

Regards,
-Vitis
 


Mutoh

  • Newbie
  • *
  • Posts: 31
    • View Profile
Re: Platform game / tile permeability / Box2D
« Reply #1 on: June 27, 2014, 06:42:38 am »
Interesting, I've been dealing with this "permeability" concept just recently in my own game (with some personal success). :) Here's what I've been doing:

My tiles are all represented by a "Tile" base class that has "dislodgeX" and "dislodgeY" methods, a hitbox and any flags I want within it.

Every time I move an entity, I do an equivalent to the following:

void Entity::move (const sf::Vector2f& delta) {
    moveHitbox(delta.x, 0);
   
    for (Tile& tile: getStage().tiles)
        tile.dislodgeX(*this, delta.x);
       
        moveHitbox(0, delta.y);
   
    for (Tile& tile: getStage().tiles)
        tile.dislodgeY(*this, delta.y);
}

And a Tile's ::dislodgeX method, for example, looks somewhat like the following:

void Tile::dislodgeX (Entity& ent, float delta) const {
        if (!ent.getHitbox().intersects(this->getHitbox())) return;
        // ---
       
        if (delta < 0) {
                // Entity is moving left. [T]<-[E]
               
                ent.setHitboxLeft(this->getHitbox().left + this->getHitbox().width);
                // A similar method to the above makes it so that the entity and the tile's
                // hitboxes are now perfectly adjacent. [T|E]
        }
        else if (delta != 0) {
                // Entity is moving right [E]->[T]
               
                ent.setHitboxLeft(this->getHitbox().left - ent.getHitbox().width);
                // [E|T]
        }
}

How could we implement permeability? What I did is somewhat complex or very simple, it depends on how you look at it. My "Entities" have two std::set<const Tile*>'s within them that keeps track of the impermeable tiles in which they are inside (one set is for the previous tick, and another is for the new tick), and here is how make the Tiles use these sets:

struct Entity {
        std::set<const Tile*> tilesInside, prevTilesInside;
       
        /* ... */
       
        void move (const sf::Vector2f&);
        bool wasInside (const Tile&) const;
};

void Entity::move (const sf::Vector2f& delta) {
    prevTilesInside = tilesInside;
        tilesInside.clear();
        /* Alternatively: prevTilesInside = std::move(tilesInside); */
       
        // ---
       
        moveHitbox(delta.x, 0);
   
    for (Tile& tile: getStage().tiles)
        tile.dislodgeX(*this, delta.x);
       
        moveHitbox(0, delta.y);
   
    for (Tile& tile: getStage().tiles)
        tile.dislodgeY(*this, delta.y);
}

bool Entity::wasInside (const Tile& tile) const {
        return prevTilesInside.find(&tile) != prevTilesInside.end()
                || tilesInside.find(&tile) != tilesInside.end();
}

/*
        ...
*/


void Tile::dislodgeX (Entity& ent, float delta) const {
        if (!ent.getHitbox().intersects(this->getHitbox())) return;
        // ---
       
        if (delta < 0) {
                if (!this->allowsEnteringLeft && !ent.wasInside(*this)) {
                        ent.setHitboxLeft(this->getHitbox().left + this->getHitbox().width);
                }
                else ent.tilesInside.insert(this);
        }
        else if (delta != 0) {
                if (!this->allowsEnteringRight && !ent.wasInside(*this)) {
                        ent.setHitboxLeft(this->getHitbox().left - ent.getHitbox().width);
                }
                else ent.tilesInside.insert(this);
        }
}

I tried many methods before this one, each more convoluted than the other, but this was what worked best. It's effective. And why sets instead of a single pointer, you may ask? The entity can always be inside more than one tile at once. ;)

Good luck with your project! I wouldn't recommend using physics engines, indeed, at least not for a platformer that requires tight controls - or, mainly, for learning. As long as you keep your game timestep-fixed (constant framerates) and you stick to using AABB rectangles for collision, you won't need them. But it's not like you won't have some work to do, mainly when dealing with accelerations and gravity. It's either "stick to a engine and cut off work" or "write it up yourself and have complete control over the physics". :)
« Last Edit: July 01, 2014, 02:30:48 am by Mutoh »

Vitis

  • Newbie
  • *
  • Posts: 10
    • View Profile
Re: Platform game / tile permeability / Box2D
« Reply #2 on: June 27, 2014, 07:17:27 am »
Mutoh,

Thanks for the advice, and thanks for sharing your method and code.

Indeed, my game loop does have a fixed time step.  I am currently using 60 FPS for the platform game project, just like in my fighting game, but I might lower it to 30 FPS in the future.

I'm going to try your method for dealing with tile permeability, and I'll take your advice and avoid using a physics engine.

Maybe, if this project goes well, I'll post it as open source on GitHub so others can learn from our experiences.

Regards,
-Vitis



eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
AW: Platform game / tile permeability / Box2D
« Reply #3 on: June 27, 2014, 08:39:51 am »
One thing to keep in mind is that the graphical and logical representation of the tile map should be separated.

As such you'd have to run a check for the collision type within the collision response fubction, unless you can fully pass through, then there shpuldn't be a collision at sll. If a collision happens you need to check if you have to reset the position (collision) or from which direction the player collided and if necessary let it pass.

Physics libraries can help you quite a bit, since you won't have to deal with special physics cases and the collision system is rather flexible (Box2D supports such one-way platforms out of the box and a lot more), but you'll be spending quite a bit time on tweaking the parameters to get a controls that feel good.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Platform game / tile permeability / Box2D
« Reply #4 on: June 27, 2014, 02:22:54 pm »
Quote
Box2D supports such one-way platforms out of the box
Does it really? Since which version?
Back to C++ gamedev with SFML in May 2023

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Platform game / tile permeability / Box2D
« Reply #5 on: June 27, 2014, 02:40:28 pm »
Does it really? Since which version?
I guess "supports" can be interpreted differently, but it seems that it's possible to easily do so since version 2.1a.
Personally I haven't worked much with Box2D, but I knew it was possible, since I've played around with it in the testbed.

Ah as for the topic, slops and irregular collisions are also more of less easily handled by Box2D and can be quite a challenge if you try implementing them yourself. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Mutoh

  • Newbie
  • *
  • Posts: 31
    • View Profile
Re: Platform game / tile permeability / Box2D
« Reply #6 on: June 27, 2014, 03:00:46 pm »
Absolutely right, slopes are hell. ;D