Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: [SFML 1.6] Tile mapping et collisions.  (Lu 3944 fois)

0 Membres et 1 Invité sur ce sujet

Mayt

  • Newbie
  • *
  • Messages: 3
    • Voir le profil
[SFML 1.6] Tile mapping et collisions.
« le: Octobre 26, 2012, 10:29:07 pm »
Bonjour, bonsoir, je sais pas ^^
Bon, alors, j'ai deux trois petites questions. Tout d'abord, j'explique un peu mon projet. Pour le moment, j'essaye d'appliquer ce que j'ai appris en SFML en codant un jeu de plateforme basé sur le Tile Mapping. Je me suis renseigné sur des sites de tutos, et j'ai fini par trouver des cours en SDL. J'ai donc passé quelques (longues) heures à adapter le code en C++ avec SFML, et en le repensant de manière objet. Jusqu'à maintenant, j'ai une carte affichée en Tile Mapping, et un personnage qui se balade dedans sans gravité, mais avec des collisions.

Seulement, quelques problèmes viennent gâcher la fête : Les collisions sont censées être calculées pour les tiles dans lequel se situe le personnage, à savoir, celle qui sont en collisions directes avec le personnage (qui fait 16 * 32, d'ailleurs, puisque vous n'avez pas l'image). Sauf qu'en pratique, les seules collisions calculées sont... les collisions avec le point supérieur gauche du personnage. Résultat, bah.. ça marche pas comme il fait.

L'autre problème, c'est que pour une autre raison tout aussi mystérieuse. La ligne
if (xmin < 0 || ymin < 0 || xmax >= TILEL || ymax >= TILEH)
devrait normalement empêcher le personnage de sortir de l'écran, sauf qu'elle lui permet de sortir d'un tile avant de s'arrêter. Ce qui là non plus n'est pas normal. Sauf que, truc très étrange, si je met la limite à
xmin < 1 || ymin < 1
, le code fait.. exactement ce qu'il devrait, à savoir empêcher le personnage de s'approcher de plus d'un bloc du bord O_o (c'est là que je suis vraiment perdu).

Si vous pouviez m'aider, je vous en serez reconnaissant :)
D'ailleurs, si jamais il y a d'autres erreurs (je n'en au pas vu, mais bon), je suis preneur aussi.

Voilà le code (inutile de vous pencher sur la partie ou je définis les SubRect : c'est compliqué et c'est normal ^^)

// main.cpp

#include <SFML/Graphics.hpp>
#include <iostream>
#include <cstdlib>
#include <sstream>

#include "map.hpp"


using namespace sf;

int main()
{
    RenderWindow app(VideoMode(LARGEUR_SCREEN, HAUTEUR_SCREEN, 32), "It works !");
    app.SetFramerateLimit(80);

    Carte carte(app, "tileset.bmp", "level3.bmp");

    while (app.IsOpened())
    {
        Event event;
        while(app.GetEvent(event))
        {
            switch(event.Type)
            {
                case Event::Closed : // Croix de fermeture
                    app.Close();
                    break;

                case Event::KeyPressed : // Appui sur une touche
                {
                    switch(event.Key.Code)
                    {
                        case Key::Escape : // Touche echap
                            app.Close();
                            break;
                        default:
                            break;
                    }
                }
                    break;
                default :
                    break;
            }
        }
        carte.Afficher();
    }
    return 0;
}

//map.hpp

#ifndef MAP_HPP_INCLUDED
#define MAP_HPP_INCLUDED

#include <SFML/Graphics.hpp>
#include <iostream>
#include <ostream>
#include <cstdlib>
#include <sstream>

#define LARGEUR_TILE 16  // hauteur et largeur des tiles.
#define HAUTEUR_TILE 16
#define HAUTEUR_SCREEN 300
#define LARGEUR_SCREEN 400
#define TILEL 127
#define TILEH 39
#define LARGEUR_MAP (TILEL*LARGEUR_TILE)
#define HAUTEUR_MAP (TILEH*HAUTEUR_TILE)
#define VITESSE 100

#include "perso.hpp"


class Perso;

class Carte
{
public:
    Carte(sf::RenderWindow&, std::string, std::string);
    ~Carte();
    void Afficher();
    void Scroll(float, float);
    int GetBlocCarte(int, int);
    void AfficherPerso(sf::Sprite&);
private:
    sf::RenderWindow &app;
    Perso *joueur;
    float m_xscroll;
    float m_yscroll;
    sf::Event event;
    sf::Image i_tileset;
    sf::Sprite s_tileset;
    sf::Image i_map;
    int blocCarte[TILEL][TILEH];

    void ChargerTileset();
};

#endif // MAP_HPP_INCLUDED

//map.cpp

#include "map.hpp"


using namespace sf;
using namespace std;

Carte::Carte(RenderWindow& app, string tileset, string map) : app(app), m_xscroll(0), m_yscroll(0)
{
    if (!i_tileset.LoadFromFile(tileset)) // Si le chargement du fichier a échoué
        cerr << "Erreur durant le chargement du tileset" << endl;
    else // Si le chargement de l'image a réussi
    {
        i_tileset.SetSmooth(false);
        s_tileset.SetImage(i_tileset);
    }
    if (!i_map.LoadFromFile(map)) // Si le chargement du fichier a échoué
        cerr << "Erreur durant le chargement de la carte" << endl;
    else
        i_tileset.SetSmooth(false);

    ChargerTileset();
    joueur = new Perso(app, "test.bmp", *this);
}

Carte::~Carte()
{
    delete joueur;
}

void Carte::AfficherPerso(Sprite& personnage)
{
    app.Draw(personnage);
}

void Carte::Scroll(float xscroll, float yscroll)
{
    m_xscroll += xscroll * app.GetFrameTime();
    m_yscroll += yscroll * app.GetFrameTime();

    if (m_xscroll < 0)
        m_xscroll = 0;
    else if (m_xscroll > LARGEUR_MAP - LARGEUR_SCREEN)
        m_xscroll =  LARGEUR_MAP - LARGEUR_SCREEN;

    if (m_yscroll < 0)
        m_yscroll = 0;
    else if (m_yscroll > HAUTEUR_MAP - HAUTEUR_SCREEN)
        m_yscroll = HAUTEUR_MAP - HAUTEUR_SCREEN;
}

void Carte::Afficher()
{
    app.Clear();

    int minx = (int)m_xscroll / LARGEUR_TILE;
    int miny = (int)m_yscroll / HAUTEUR_TILE;
    int maxx = ((int)m_xscroll + LARGEUR_SCREEN)/LARGEUR_TILE;
    int maxy = ((int)m_yscroll + HAUTEUR_SCREEN)/HAUTEUR_TILE;

    for(int i = minx; i <= maxx; i++)
    {
        for(int j = miny; j <= maxy; j++)
        {
            switch (blocCarte[i][j])
            {
                case(1):
                    s_tileset.SetSubRect(IntRect(1, 1, 17, 17));
                    break;
                case(2):
                    s_tileset.SetSubRect(IntRect(2, 0, 18, 16));
                    break;
                case(3):
                    s_tileset.SetSubRect(IntRect(0, 0, 16, 16));
                    break;
                case(4):
                    s_tileset.SetSubRect(IntRect(0, 2, 16, 18));
                    break;
                case(5):
                    s_tileset.SetSubRect(IntRect(2, 2, 18, 18));
                    break;
                case(6):
                    s_tileset.SetSubRect(IntRect(1, 0, 17, 16));
                    break;
                case(7):
                    s_tileset.SetSubRect(IntRect(0, 1, 16, 17));
                    break;
                case(8):
                    s_tileset.SetSubRect(IntRect(1, 2, 17, 18));
                    break;
                case(9):
                    s_tileset.SetSubRect(IntRect(2, 1, 18, 17));
                    break;
                case(10):
                    s_tileset.SetSubRect(IntRect(19, 1, 35, 17));
                    break;
                case(11):
                    s_tileset.SetSubRect(IntRect(20, 0, 36, 16));
                    break;
                case(12):
                    s_tileset.SetSubRect(IntRect(18, 0, 34, 16));
                    break;
                case(13):
                    s_tileset.SetSubRect(IntRect(18, 2, 34, 18));
                    break;
                case(14):
                    s_tileset.SetSubRect(IntRect(20, 2, 36, 18));
                    break;
                case(15):
                    s_tileset.SetSubRect(IntRect(19, 0, 35, 16));
                    break;
                case(16):
                    s_tileset.SetSubRect(IntRect(18, 1, 34, 17));
                    break;
                case(17):
                    s_tileset.SetSubRect(IntRect(19, 2, 35, 18));
                    break;
                case(18):
                    s_tileset.SetSubRect(IntRect(20, 1, 36, 17));
                    break;
                case(19):
                    s_tileset.SetSubRect(IntRect(37, 1, 53, 17));
                    break;
                case(20):
                    s_tileset.SetSubRect(IntRect(38, 0, 54, 16));
                    break;
                case(21):
                    s_tileset.SetSubRect(IntRect(36, 0, 52, 16));
                    break;
                case(22):
                    s_tileset.SetSubRect(IntRect(36, 2, 52, 18));
                    break;
                case(23):
                    s_tileset.SetSubRect(IntRect(38, 2, 54, 18));
                    break;
                case(24):
                    s_tileset.SetSubRect(IntRect(37, 0, 53, 16));
                    break;
                case(25):
                    s_tileset.SetSubRect(IntRect(36, 1, 52, 17));
                    break;
                case(26):
                    s_tileset.SetSubRect(IntRect(37, 2, 53, 18));
                    break;
                case(27):
                    s_tileset.SetSubRect(IntRect(38, 1, 54, 17));
                    break;
                default:
                    s_tileset.SetSubRect(IntRect(1, 1, 17, 17));
                    break;
            }

            s_tileset.SetPosition((i * LARGEUR_TILE) - m_xscroll, (j * HAUTEUR_TILE) - m_yscroll);
            app.Draw(s_tileset);
        }
    }

    joueur->Evolue(app.GetFrameTime());
    joueur->Afficher();

    app.Display();
}

int Carte::GetBlocCarte(int a, int b)
{
    return blocCarte[a][b];
}

void Carte::ChargerTileset()
{
    Color FondF1(96,117,200);

    Color CoinHDF1(112,112,112);
    Color CoinHGF1(0,255,102);
    Color CoinBGF1(200,194,96);
    Color CoinBDF1(219,219,219);


    Color CoteHF1(255,0,108);
    Color CoteGF1(96,200,118);
    Color CoteBF1(186,66,255);
    Color CoteDF1(47,47,47);


    Color FondB1(48,0,255);

    Color CoinHDB1(106,68,85);
    Color CoinHGB1(255,204,0);
    Color CoinBGB1(255,102,0);
    Color CoinBDB1(116,2,53);

    Color CoteHB1(255,0,0);
    Color CoteGB1(0,85,40);
    Color CoteBB1(255,164,136);
    Color CoteDB1(0,0,0);


    Color FondB2(9,99,7);

    Color CoinHDB2(0,255,198);
    Color CoinHGB2(255,255,255);
    Color CoinBGB2(255,157,255);
    Color CoinBDB2(96,0,118);

    Color CoteHB2(253,255,86);
    Color CoteGB2(162,157,255);
    Color CoteBB2(126,74,0);
    Color CoteDB2(0,104,81);

    int i = 0,j = 0;

    for(i = 0; i < TILEL; i++)
    {
        for(j = 0; j < TILEH; j++)
        {
            if(i_map.GetPixel(i,j) == FondF1)
                blocCarte[i][j] = 1;
            else if (i_map.GetPixel(i,j) == CoinHDF1)
                blocCarte[i][j] = 2;
            else if (i_map.GetPixel(i,j) == CoinHGF1)
                blocCarte[i][j] = 3;
            else if (i_map.GetPixel(i,j) == CoinBGF1)
                blocCarte[i][j] = 4;
            else if (i_map.GetPixel(i,j) == CoinBDF1)
                blocCarte[i][j] = 5;
            else if (i_map.GetPixel(i,j) == CoteHF1)
                blocCarte[i][j] = 6;
            else if (i_map.GetPixel(i,j) == CoteGF1)
                blocCarte[i][j] = 7;
            else if (i_map.GetPixel(i,j) == CoteBF1)
                blocCarte[i][j] = 8;
            else if (i_map.GetPixel(i,j) == CoteDF1)
                blocCarte[i][j] = 9;
            else if (i_map.GetPixel(i,j) == FondB1)
                blocCarte[i][j] = 10;
            else if (i_map.GetPixel(i,j) == CoinHDB1)
                blocCarte[i][j] = 11;
            else if (i_map.GetPixel(i,j) == CoinHGB1)
                blocCarte[i][j] = 12;
            else if (i_map.GetPixel(i,j) == CoinBGB1)
                blocCarte[i][j] = 13;
            else if (i_map.GetPixel(i,j) == CoinBDB1)
                blocCarte[i][j] = 14;
            else if (i_map.GetPixel(i,j) == CoteHB1)
                blocCarte[i][j] = 15;
            else if (i_map.GetPixel(i,j) == CoteGB1)
                blocCarte[i][j] = 16;
            else if (i_map.GetPixel(i,j) == CoteBB1)
                blocCarte[i][j] = 17;
            else if (i_map.GetPixel(i,j) == CoteDB1)
                blocCarte[i][j] = 18;
            else if (i_map.GetPixel(i,j) == FondB2)
                blocCarte[i][j] = 19;
            else if (i_map.GetPixel(i,j) == CoinHDB2)
                blocCarte[i][j] = 20;
            else if (i_map.GetPixel(i,j) == CoinHGB2)
                blocCarte[i][j] = 21;
            else if (i_map.GetPixel(i,j) == CoinBGB2)
                blocCarte[i][j] = 22;
            else if (i_map.GetPixel(i,j) == CoinBDB2)
                blocCarte[i][j] = 23;
            else if (i_map.GetPixel(i,j) == CoteHB2)
                blocCarte[i][j] = 24;
            else if (i_map.GetPixel(i,j) == CoteGB2)
                blocCarte[i][j] = 25;
            else if (i_map.GetPixel(i,j) == CoteBB2)
                blocCarte[i][j] = 26;
            else if (i_map.GetPixel(i,j) == CoteDB2)
                blocCarte[i][j] = 27;
            else
                blocCarte[i][j] = 0;
       }
    }
}

//perso.hpp

#ifndef PERSO_HPP_INCLUDED
#define PERSO_HPP_INCLUDED

#define ABS(X) ((((X)<0)?(-(X)):(X)))
#define SGN(X) (((X)==0)?(0):(((X)<0)?(-1):(1)))

#include "map.hpp"


class Carte;

class Perso
{
public:
    Perso(sf::RenderWindow&, std::string, Carte&);
    void Evolue(float);
    void Afficher();
private:
    Carte& carte;
    sf::RenderWindow& app;
    const sf::Input& input;
    sf::Image i_perso;
    sf::Sprite s_perso;
    float posx;
    float posy;
    int l;
    int h;
    float vx;
    float vy;

    bool CollisionDecor(float, float);
    void Evenements(float);
    void Deplace();
    bool EssaiDeplace(float, float);
};

#endif // PERSO_HPP_INCLUDED

//perso.cpp

#include "perso.hpp"


using namespace sf;
using namespace std;

Perso::Perso(RenderWindow& app, std::string personnage, Carte& map) : carte(map), app(app), input(app.GetInput()), posx(10), posy(10), l(s_perso.GetSize().x), h(s_perso.GetSize().y), vx(0), vy(0)
{
    if (!i_perso.LoadFromFile(personnage)) // Si le chargement du fichier a échoué
        cerr << "Erreur durant le chargement du personnage" << endl;
    else // Si le chargement de l'image a réussi
    {
        i_perso.SetSmooth(false);
        s_perso.SetImage(i_perso);
    }
    s_perso.SetPosition(posx, posy);
    Afficher();
}

void Perso::Afficher()
{
    app.Draw(s_perso);
}

void Perso::Evolue(float time)
{
    Evenements(time);
    Deplace();
    s_perso.SetPosition(posx, posy);
}

void Perso::Evenements(float time)
{
    vx = 0; vy = 0;
    if (input.IsKeyDown(sf::Key::Left))
    {
        vx = -VITESSE * time;
    }

    if (input.IsKeyDown(sf::Key::Right))
    {
        vx = VITESSE * time;
    }

    if (input.IsKeyDown(sf::Key::Up))
    {
        vy = -VITESSE * time;
    }

    if (input.IsKeyDown(sf::Key::Down))
    {
        vy = VITESSE * time;
    }
}

void Perso::Deplace()
{
    int i;
    if (vx>=LARGEUR_TILE || vy>=HAUTEUR_TILE)
        {
            vx /= 2;
            vy /= 2;
                Deplace();
                Deplace();
                return;
    }

        if (EssaiDeplace(vx, vy)==true)
                return;

    for(i=0;i<ABS(vx);i++)
        {

                if (EssaiDeplace(SGN(vx),0)==false)
                        break;

        }
        for(i=0;i<ABS(vy);i++)
        {

                if (EssaiDeplace(0,SGN(vy))==false)
                        break;

        }
}

bool Perso::EssaiDeplace(float vxx, float vyy)
{
    float posxx = posx + vxx, posyy = posy + vyy;
    if (CollisionDecor(posxx, posyy)==false)
        {
                posx = posxx;
                posy = posyy;
                return true;
        }
        return false;
}

bool Perso::CollisionDecor(float nposx,float nposy)
{
        int xmin, xmax, ymin, ymax, i, j, type;
        xmin = nposx / LARGEUR_TILE;
        ymin = nposy / HAUTEUR_TILE;
        xmax = (nposx + l - 1) / LARGEUR_TILE;
        ymax = (nposy + h - 1) / HAUTEUR_TILE;
        if (xmin < 0 || ymin < 0 || xmax >= TILEL || ymax >= TILEH)
                return true;
        for(i = xmin ; i <= xmax ; i++)
        {
                for(j = ymin ; j <= ymax ; j++)
                {
                        type = carte.GetBlocCarte(i, j);
                        if (type >= 10)
                                return true;
        }
        }
        return false;
}


PS : Il y a des fonctions qui servent à rien, mais c'est pour plus tard dans le développement, donc c'est normal ^^
« Modifié: Octobre 30, 2012, 11:52:48 am par Mayt »

Koryushin

  • Jr. Member
  • **
  • Messages: 93
    • Voir le profil
Re : [SFML 1.6] Tile mapping et collisions.
« Réponse #1 le: Octobre 30, 2012, 01:04:32 pm »
Coucou, je pense qu'il y a un peu trop de code pour que l'on puisse le tester. (perso ca me donne pas envie  ;D )

Ensuite une petite remarque, je suis pas trop fan de ton block switch dans la fonction afficher(). Pourquoi ne pas utiliser directement un tableau/vector de sprite et faire la manipe avec les switch une seule fois dans une fonction inti(). ça coute pas grand chose.

En tout cas je pense qu'il y a plus simple en utilisant la puissance du c++.
Bonne continuation

Mayt

  • Newbie
  • *
  • Messages: 3
    • Voir le profil
Re : [SFML 1.6] Tile mapping et collisions.
« Réponse #2 le: Octobre 30, 2012, 01:20:28 pm »
L'avantage de faire ça, c'est qu'on ne stocke qu'un seul sprite. Avec un tableau, ça va prendre beaucoup de place non ?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : [SFML 1.6] Tile mapping et collisions.
« Réponse #3 le: Octobre 30, 2012, 01:44:08 pm »
Et tu penses qu'un sprite occupe combien de mémoire, au juste ? ;)

Là tu fais du code compliqué et inefficace basé sur des hypothèses non-vérifiées ("les sprites ça prend beaucoup de mémoire"). Prends plutôt le temps de comprendre ce qu'impliquent les différentes options que tu as à ta disposition. Et à défaut de maîtriser tous les détails d'implémentation de SFML, écris le code le plus simple -- il est toujours temps de changer plus tard si tu constates un problème.

Bref, fais un tableau de sprite. Le sprite n'est pas une function de dessin (sinon j'en aurais fait une fonction...), c'est une entité qui est prévue pour représenter un "truc" que tu dessines.
« Modifié: Octobre 30, 2012, 01:48:46 pm par Laurent »
Laurent Gomila - SFML developer

Mayt

  • Newbie
  • *
  • Messages: 3
    • Voir le profil
Re : [SFML 1.6] Tile mapping et collisions.
« Réponse #4 le: Novembre 04, 2012, 05:46:51 pm »
Merci pour ces conseils, je vais essayer de faire évoluer le code en ce sens ^^