IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Projets Discussion :

Back to roots


Sujet :

Projets

  1. #101
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Ok, petit silence pendant un moment, le temps de : finaliser le système de combat :-)

    La version 203 du SVN a donc un système de combat !

    On a à présent une nouvelle classe : AIDecisionMaking qui en fait, pour l'instant est simplement une fonction statique qu'appelle CombatViewState.

    Cette fonction gére ce que fait l'IA :
    - Si le dernier perso qu'on a attaqué est encore à porté (dépendant de l'arme), on rattaque
    - Sinon, on trouve le perso le plus proche
    - S'il est à portée, on attaque
    - Sinon on va vers lui (utilisant le code de PathFinder)

    C'est simpliste, mais cela fonctionne bien.

    Histoire de savoir ce qui se passe, j'ai ajouté au début de la gestion de l'IA ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    //Entry point to artificial intelligence handling
    void CombatViewState::handleAI (int diffTime)
    {
        switch (aiState)
        {
            case AI_STATE_WAIT:
                {
                    aiDelayTime += diffTime;
     
                    //Time to go to next state
                    if (aiDelayTime > aiDelayTimeLimit)
                    {
                        aiDelayTime = 0;
                        aiState = AI_STATE_DECIDE;
                    }
                }
                break;
            case AI_STATE_DECIDE:
                {
                    int event = AIDecisionMaking::decide (map, &(playerInfo[currentFocus]), playerInfo, group->getNumCharacters ())
                    handleAIEvent (event);
     
                    //Now check if the game is over
                    int state = getCurrentCombatState ();
     
                    switch (state)
                    {
                        case ALL_PLAYERS_DEAD:
                            //We lost
                            std::cout << "You died... too bad ;-)" << std::endl;
                            exit (0);
                            break;
                        default:
                            break;
                    }
                    //Next player, we did it
                    nextPlayer ();
                }
                break;
            default:
                break;
        }
    }
    Ce code est appelé à la fin de la fonction de mise à jour. On voit qu'on commence dans l'état AI_STATE_WAIT. Si le temps dépasse la limite fixée, alors on passe au stade de décision.

    Cela permet de faire deux choses :
    - Avoir une mini pause pour faire clignoter l'ennemi
    - Donner le temps au joueur de voir ce qui se passe ;-)

    Si vous voyez, si tout le monde meurt, il va falloir que j'ajoute un état : GameOverState ;-)

    Bien entendu, je me suis fait allumé par les gardes, ils ont des bonnes armes et des bonnes armures.

    Pour la gestion des attaques, j'ai bougé du code histoire d'avoir au maximum le même code utilisé par le joueur et par l'IA.

    Pour le moment, on a 4 chances sur 5 de toucher la personne qu'on vise:
    - Si on touche :
    - On demande à l'arme qu'on a quels sont les dégats
    - Ensuite, on demande à l'armure de l'ennemi combien des dégâts sont absorbés
    - Enfin, on vire ces points de vie à l'ennemi
    - S'il est mort, on le vire de la map (en principe, on ajoutera une autre tuile pour dire qu'il est mort ;-))

    Pour l'attaque niveau joueur:
    - On a un système de curseur qui permet de savoir qui on veut attaquer
    - Le système se souvient qui on a attaqué dernièrement et le remet à jour automatiquement si l'ennemi sort de notre portée

    Pour le système de combat:
    - On peut changer nos armes, armures, boire une potion mais seulement du joueur actif
    - On peut bouger/attaquer
    - On peut fuire un combat si : tous les joueurs encore vivants sortent du terrain de combat

    Je pense avoir raconté tout sans rentrer trop dans le code...

    A présent, il faut que je rajoute :
    - Expérience
    - Des objets sur la position ou l'ennemi est mort


    Jc

  2. #102
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Avant, lorsque quelqu'un mourrait, on enlevé la sprite du combat. Mais cela n'est pas logique :
    - Si on veut avoir une ressurection, ben faut savoir où se trouve le joueur et ca fait un peu bizarre.

    Ajout donc d'un vecteur de corps sur une case (et donc après des objets laissés).

    On a donc maintenant un "Death sprite" pour rendre un sprite lorsque le joueur est mort.

    Cela donne les images suivants :

    On a donc ce le début du combat :
    Nom : Screenshot-Back to roots --- Version: 1.21.jpg
Affichages : 107
Taille : 93,1 Ko

    Ensuite on avance et on attaque et on a les "corps" des ennemis :
    Nom : Screenshot-Back to roots --- Version: 1.21-1.jpg
Affichages : 100
Taille : 93,1 Ko

    Dans un autre combat, notre perso "Zeroc" est mort, on voit son corps ;-)
    Nom : Screenshot-Back to roots --- Version: 1.21-2.jpg
Affichages : 99
Taille : 93,6 Ko

    Jc

  3. #103
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 858
    Points : 218 577
    Points
    218 577
    Billets dans le blog
    120
    Par défaut
    Bravo,

    Je vais me mettre à parié sur une version jouable ( interessante avec toute fonctionnalités de base mais sans gameplay approfondi ) pour dans une semaine

    Sinon un beau progrès on peut faire la baston
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  4. #104
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Citation Envoyé par LittleWhite Voir le message
    Je vais me mettre à parié sur une version jouable ( interessante avec toute fonctionnalités de base mais sans gameplay approfondi ) pour dans une semaine
    Oui pas sûr, j'ai pas mal de choses à régler avant une version présentable :-)

    Par contre, je viens d'ajouter :

    - Un NPC peut maintenant vous attaquer directement dans la vue générale et le combat commence normalement

    - On récupére de l'expérience maintenant :-)

    Jc

  5. #105
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Vu qu'on approche doucement un stade alpha (on est en pre-alpha pour l'instant), j'ai ajouté à Sourceforge un wikimedia qui va se remplir à mes heures perdues :-)

    Voilà le lien : https://sourceforge.net/apps/mediawi...itle=Main_Page

    Pour le moment, je n'ai mis que les screenshots mais j'ajouterai au fur et à mesure des informations :-)

    Voili voilou,
    Jc

  6. #106
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Après un été rempli de choses et d'autres à faire, d'avoir pas accès à internet ou à mon ordinateur, me voilà de retour et prêt à continuer ;-)

    En attendant, mine de rien les choses ont avancé un tant soit peu entre la dernière mise à jour et maintenant :

    - Les guardes attaquent maintenant si vous attaquez quelqu'un

    - La sauvegarde et chargement est mis en place (automatiquement par contre, je n'ai pas encore mis un système de sauvegarde dans le jeu, tout se fait au début ou à la fin du jeu)

    - Rajout des coffres et des choses qu'on peut récupérer du sol (armes tombés), on peut ouvrir un coffre et voir ce qu'il y a dedans.

    - Gestion des fichiers généraux et fichiers de sauvegarde

    - Début des gestions des monstres et des ennemis en général

    - Ajout d'une aide dans le jeu pour connaître les touches

    Je pense que c'est tout, mais rapidement (aussi rapidement que possible), j'aurai une version alpha jouable sur laquelle on pourra tester différentes choses :-)

    Jc

  7. #107
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Ok, nous voici pas mal ;-)

    On a un combat complet avec expérience, les monstres attaquent, ils laissent des cadeaux une fois mort, etc ;-)

    En image :

    La première montre le monde avec des monstres qui apparaissent et vous attaquent !

    Nom : Screenshot-Back to roots --- Version: 1.22.jpg
Affichages : 75
Taille : 92,9 Ko

    La deuxième montre la scéne de combat au départ. Le nombre d'ennemis est déterminé dépendant du niveau des monstres et du niveau du groupe.

    Nom : Screenshot-Back to roots --- Version: 1.22-1.jpg
Affichages : 62
Taille : 93,8 Ko

    Une fois le combat fini, certains monstres laissent des coffres avec des cadeaux ;-)

    Nom : Screenshot-Back to roots --- Version: 1.22-2.jpg
Affichages : 66
Taille : 98,2 Ko

    A la fin, du combat, on a un coffre vide et on peut quitter le combat pour retourner au monde (petit cookie dans la capture écran vu que le perso clignotte...)

    Nom : Screenshot-Back to roots --- Version: 1.22-4.jpg
Affichages : 52
Taille : 95,9 Ko

    Voili voilou plus ou moins où nous en sommes, je suis au point d'ajouter les sorts et travailler un peu sur l'histoire du jeu. Faut aussi que je me lance dans la retro-compatibilité avec les fichiers originaux, cela permettrait de jouer au jeu de base avec mon moteur :-)

    Jc
    Images attachées Images attachées  

  8. #108
    Membre éclairé
    Avatar de Gregouar
    Profil pro
    Chercheur en mathématiques
    Inscrit en
    Décembre 2007
    Messages
    246
    Détails du profil
    Informations personnelles :
    Âge : 32
    Localisation : Belgique

    Informations professionnelles :
    Activité : Chercheur en mathématiques

    Informations forums :
    Inscription : Décembre 2007
    Messages : 246
    Points : 899
    Points
    899
    Par défaut
    Trop puissant.
    Holyspirit : Hack'n'Slash amateur gratuit !

    www.holyspirit.fr

  9. #109
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Citation Envoyé par Gregouar Voir le message
    Trop puissant.
    Ouai y a encore du boulot mine de rien ;-), mais je commence à être presque à la fin du développement alpha. C'est quand je vais lancer la retro-compatibilité (si j'ose y aller) que je vais m'amuser ;-)

    Jc

  10. #110
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    En regardant un peu pour la retro-compatibilité, j'ai remarqué qu'il manquait certaines choses de base. Donc hier soir, j'ai mis en place:

    - Changement d'ordre des membres du groupe

    - Gros changements niveaux teleportations:
    - Maintenant, on a un nom pour la teleportation
    - Ce n'est plus forcément automatique, du coup, on peut taper sur 'E' pour rentrer dans une ville par exemple

    Ceci m'a permis de nettoyer un peu le code et de le rendre plus robuste.

    Je mets une image montrant le texte maintenant quand on passe de la ville au monde et vice-versa.
    Nom : Screenshot-Back to roots --- Version: 1.22.jpg
Affichages : 68
Taille : 77,1 Ko

    Et une image montrant le changement des joueurs du groupe :
    Nom : Screenshot-Back to roots --- Version: 1.22-1.jpg
Affichages : 54
Taille : 76,5 Ko

    Je vais passer en revue toutes les commandes du jeu original et je vais voir si j'ai d'autres choses à modifier/mettre à jour,
    Jc

  11. #111
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Retour aux fichiers de configuration d'un niveau/ville/monde


    Comme tout projet qui se crée sans documentation ou cahier de charge digne de ce nom, il y a des changements internes qui arrivent ici et là. Entre mes idées de départ et ce vers quoi nous tendons en ce moment, il y a des petites différences qui sont importantes à noter.

    1) Pourquoi ces changements ?

    La plupart des changements proviennent de deux horizons : la mise en place des sauvegardes cet été et l'ajout de fonctionallités.

    2) Qu'est-ce qui a changé ?

    Revenons à la première version :
    - Un fichier graphique avec des couleurs donnant : les murs, les sprites, les teleportations mais aussi les personnages
    - Un fichier de configuration qui est lié et explique les correspondances couleurs

    Ceci était problématique :

    - Déjà, pour la sauvegarde, cela veut dire que le programme doit regénérer un fichier image lorsque le monde change. En soit, ce n'est pas difficile mais cela veut dire que la sauvegarde doit contenir toutes les images des niveaux différents. Et moi, je trouve cela un peu gros...

    - Ensuite, un souci est survenu lorsque je voulais avoir plusieurs choses sur une case : une épée et une armure sur le sol; un corps et un garde, etc.

    Tout devint un peu bancal et du coup, un nettoyage se produit !


    - Solution au problème :

    1) Le fichier image existe toujours mais maintenant ne montre que les sprites de fond. On a sorti les personnages, les teleporteurs et tout le reste.

    2) Le fichier de configuration contient toutes ces informations:

    Tout d'abord, nous avons les mêmes informations qu'avant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    #Image of the city
    novea.bmp
    #Default sprite sheet
    sprites.bmp
    #Size of one tile
    16 16
    #Size of image
    32 64
    Rien de particulier ici, on lie la ville à son image, on donne l'image des sprites et les tailles respectives des tuiles et de l'image.

    Nouveauté (rien à voir avec ce post vraiment mais présent):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    #Maximum number of monsters in map
    0
    On a un nombre maximum de monstres qui seront générés automatiquement dans la carte (si la valeur est != 0, on met le pourcentage de création d'un monstre).

    Ensuite, nous avons les correspondances des tuiles :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    #Each convention is defined by:
    #   - The color (B,G,R)
    #   - Type of convention
    #       - Not animated (background image) 0
    #       - Animated background 1
    #   - The passage cost (0 for not allowed) (if animated or not)
    #   - Is transparent for visibility or not
    #   - Is it a light source (force of light source)
    #   - Is it a counter (should talking go over or not)
    25
    Grass 0 0 0 0 5 1 1 1 0 0
    Water 0 0 128 1 water_shallow.txt 0 1 0 0
    P 0 20 50 0 15 22 0 1 0 1
    A 0 20 200 0 0 22 0 1 0 1
    E 0 20 255 0 4 22 0 1 0 1
    W 0 60 255 0 6 23 0 1 0 1
    I 0 63 0 0 8 22 0 1 0 1
    F 0 64 0 0 5 22 0 1 0 1
    M 0 100 255 0 12 22 0 1 0 1
    Tree 0 128 0 0 14 3 2 1 0 0
    Bridge 0 128 255 0 11 35 1 1 0 0
    Grass  0 170 0 0 6 1 1 1 0 0
    R 0 200 255 0 1 23 0 1 0 1
    Bridge 0 255 0 0 6 0 1 1 0 0
    O 0 255 255 0 14 22 0 1 0 1
    N 20 100 0 0 13 22 0 1 0 1
    T 50 50 50 0 3 23 0 1 0 1
    L 100 100 100 0 11 22 0 1 0 1
    D 128 0 0 0 3 22 0 1 0 1
    Window 200 0 200 0 10 5 0 1 0 0
    Wall 255 0 255 0 15 5 0 0 0 0
    U 255 50 255 0 4 23 0 1 0 1
    Counter 255 255 0 0 10 23 0 1 0 1
    Lamppost 255 255 255 1 lamppost.txt 0 1 6 0
    Staircase 64 64 64 0 4 13 1 0 0 0
    Rien de nouveau sauf le nom de la tuile (sert à faire un "Look").
    Remarquez bien la disparition des NPCs et de tout autre type.

    Ensuite, nous avons les NPCs:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    #Now NPCs
    11
    28 16 potionSeller.txt
    35 18 toolSeller.txt
    48 20 foodSeller.txt
    51 24 katrina_npc.txt
    8 28 guard.txt
    8 31 guard.txt
    20 30 follower.txt
    25 38 armorSeller.txt
    54 41 guard.txt
    23 46 weaponSeller.txt
    45 57 truelle.txt
    On donne la position de départ et son fichier de configuration.

    Ensuite, on a la définition des teleportations :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    #Teleports
    4
    World 0 163 212 world.txt 1 0 0
    Isle 1 48 6110 0 0
    Mainland 1 54 1910 0 0
    Upstairs 0 7 28 novea_up.txt 0 0 1
    On a aussi un nom pour la teleportation, ensuite les champs sont :
    - Est-ce que c'est local (dans la même carte ou non) ?
    - Destination (x,y) de la teleportation
    - Nom de la carte si non local
    - Est-ce automatique ? (Lorsqu'on arrive sur la case, bim, on est teleporté ?)
    - Est-ce qu'il faudrait entrer dedans ? (pour des villes par exemple)
    - Est-ce qu'il faut descendre/monter ? (pour des escaliers)

    Pour ces deux dernier, je risque de changer cela en une lettre, genre :
    e pour entrer
    c pour monter/descendre

    Mais je ne sais pas si je vais avoir des cas multiples sur la même case... A voir donc.

    Enfin, nous avons la définition des cases spéciales : case de la map qui contient quelque chose (un teleporteur, un objet, etc.)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    66 #Number of special cells
    0 3
    1
    #Objects
    0
    Ici nous avons les coordonnées, ensuite l'indice du teleporteur (0 si aucun). Enfin si des objets sont présents sur la cellule.

    Et si nous avons des objets :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    10 30
    0
    #Objects
    4
    1
    Sword
    1
    Robe
    1000
    Gold
    1
    Chest
    63 30
    1
    On a bien sûr combien d'objets d'un type nous avons.

    Histoire de sourire : j'ai passé pas mal de temps à réfléchir à comment gérer un coffre. En principe, le coffre contient des affaires et nous pouvons y accéder en l'ouvrant.

    Par contre, cela compliquait les choses et surtout ma sauvegarde. Du coup, j'ai triché un peu. Vu que nous pouvons simplement accéder à l'objet le plus haut, j'ai mis le coffre en dernier.

    Ce qui veut dire : il faut l'ouvrir pour accéder aux affaires en dessous !
    Comment cela fonctionne : lorsqu'on ouvre un coffre, l'objet coffre disparaît et on met un objet coffre ouvert au fond de la liste objets.

    Le code qui fait cela se trouve ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    std::string Cell::openObject (void)
    {
        if (objects.size () > 0)
        {
            //Check if it's a chest
            if (objects[objects.size () - 1].object->getName ().compare ("Chest") == 0)
            {
                unsigned int i = 0;
     
                while (i < objects.size ())
                {
                    if (objects[objects.size () - 1].object->getName ().compare ("Open Chest") != 0)
                        break;
                    i++;
                }
     
                //Move object index i to this one
                objects[objects.size () - 1] = objects[i];
     
                //Now put a open chest in position i
                struct sHaveObject sho = {Object_Factory::getObject ("Open Chest"), 1};
                objects[i] = sho;
                return "Chest";
            }
        }
        return "Nothing to open";
    }
    Comme vous voyez, je triche encore plus. Vu que j'ai un vecteur, je cherche d'abord le premier objet qui n'est pas un coffre ouvert. Dès que je le trouve (cela peut être le coffre à la limite s'il est vide), je remplace la case coffre avec la case de l'objet.

    Cela permet d'avoir une case vide pour le coffre ouvert !

    Pour ceux qui ont suivi et se demande s'il n'y a pas de fuites sur ce code, considérez simplement la signature du vecteur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
            std::vector <struct sHaveObject> objects; //Objects on the tile

    Du coup, la sauvegarde est ultra simple à faire, nous pouvons simplement sauvegarder ce que nous devons (et plus les images).

    Jc

  12. #112
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    En continuant les commandes qui existait dans le jeu de base, j'ai ajouté deux hier soir :

    - La recherche
    - Peer


    La recherche:
    - Etait facile à faire. On a des objets, donc là c'est un objet dans la case qui ne s'affiche pas. Il suffit d'ajouter une liste de tels objets et une fonction pour y accéder.

    Tout pour tout, cela a pris 15 minutes.

    Peer:

    - Un peu plus difficile, cela demandait de pouvoir voir une vue globale du jeu. C'est une genre de carte que l'utilisateur peut voir moyennant un objet (une gemme).

    Du coup, il a fallu ajouter un objet "Gem" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Gem
    gem_sprite.txt
    2
    100
    0
    0
    Pas très difficile ;-).

    Ensuite, il faut ajouter la touche 'P' pour activer le mode :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
                case SDLK_p:
                    {
                        SHaveObject *ho = group->getObject ("Gem");
     
                        if (ho != NULL && ho->nbr > 0)
                        {
                            text = "Peer";
                            group->removeObjectFromGroup ("Gem");
                            inState = PEERING_STATE;
                        }
                        else
                        {
                            text = "Peer - with what?";
                        }
                        turn = true;
                    }
                    break;
    Comme vous voyez, c'est ultra simple avec les fonctions déjà existantes. On commence par voir si le groupe a une gemme ou non. Dans le cas non, c'est fini.

    Dans le cas oui, on ajoute le texte "Peer", on enlève une gemme du groupe, et on se met dans l'état PEERING_STATE.

    On demeure dans cet état jusqu'au prochain événement clavier, du coup, la gestion du clavier pour cet état est simpliste aussi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
                    case PEERING_STATE:
                        {
                            inState = DEFAULT_STATE;
                            return true;
                        }
    Pour le rendu, nous avons ajouté un petit paramètre zoomOut qui permet de donner le facteur du zoom. J'ai mis 4 en dur mais cela peut se paramétrer facilement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
            if (map != NULL)
            {
                int zoomOut = 1;
     
                //If PEERING, zoom out a bit
                if (inState == PEERING_STATE)
                    zoomOut = 4;
     
                map->render (10, 10, zoomOut, inState == PEERING_STATE);
            }
    Le petit ajout est aussi le test inState == PEERING_STATE. En effet, on veut tout voir, donc on doit le dire à la carte.

    Et c'est fait, nous avons notre recherche et notre carte disponible ;-)

    Pour le montrer, voici 4 images qui montre le niveau et le monde avant et après l'utilisation de Peer :-)

    Le monde en normal :
    Nom : Screenshot-Back to roots --- Version: 1.22.jpg
Affichages : 66
Taille : 93,3 Ko

    Le monde en grande vue :
    Nom : Screenshot-Back to roots --- Version: 1.22-1.jpg
Affichages : 63
Taille : 111,2 Ko

    Le ville en normal :
    Nom : Screenshot-Back to roots --- Version: 1.22-2.jpg
Affichages : 63
Taille : 73,5 Ko

    La ville en grande vue :
    Nom : Screenshot-Back to roots --- Version: 1.22-3.jpg
Affichages : 73
Taille : 110,1 Ko


    Jc

  13. #113
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Bien le bonjour,

    Le jeu continue de bon train. Je me suis mis à attaquer les sorts, ce qui représente un bon troncon du travail...

    Ceci passe donc par les étapes suivantes :

    - Pouvoir créer un sort
    - Pouvoir lancer un sort


    - Créer un sort :

    Dans le monde d'Ultima, les sorts sont créés en mélangeant des ingrédients. Il a donc fallu ajouter un code pour gérer cela. Chaque sort contient dans sa définition les ingrédients nécessaire.

    Il suffit donc de récupérer le nom du sort que le joueur veut tenter de faire, les ingrédients et ensuite on fait une comparaison. Si c'est bon, le sort est créé !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
                            if (internalMixSpell->checkMix (mix))
                            {
                                appendText ("done !");
                                sendText ("Spell created !");
                                group->addObjectToGroup (internalMixSpell);
                            }
                            else
                            {
                                appendText ("fizzle !");
                            }
    C'est aussi simple que cela ;-)

    - Mais comment savoir les ingrédients pour un sort ?

    On passe par un fichier qui définit un sort. Par contre, vu qu'un sort est un objet aussi, d'abord il y a une entrée dans le fichier objets :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    Heal
    NULL
    5
    0
    spells/heal.txt
    Ce fichier spells/heal.txt définit le sort de guérison :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    #Letter codes (can be multiple (as for Ultima V))
    h
    #Reagents
    2
    Ginseng
    Sulfurous Ash
    #In combat, out of combat
    1 1
    #Direction/Target/Global/For player/For caster
    0 1 0 1 0
    #Minimum level/Mana
    1 10
    #State removed from the target
    0
    #Length of state change
    0
    #Damage
    0
    #Healing target/caster
    100 0
    #Type of ennemies affected (nbr of types first)
    0
    #Scares/Sleeps/Charm
    0 0 0
    #Special treatment required
    0
    #Extra parameters
    0
    On a donc le nom court du sort (Sert pour les raccourcis), les ingrédients nécessaires, et ensuite, les commentaires doivent être explicites.

    Special treatment permet de mettre le code pour faire les sorts plus compliqués, du genre téléportation, etc.

    Pour le moment, 8 des 26 sorts sont déjà en place. Il faut simplement que j'ajoute le code et que je vérifie si tout va bien :-)

    Jc

  14. #114
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Il est intéressant de voir comment avance un projet, autant dans la logique du code que dans l'évolution et les migrations de bouts de code.

    Lorsque j'ai commencé à faire la gestion des sorts, je me suis vite appercu que la gestion des sorts même pour un jeu de 1985 avait tout d'une complexité importante.

    Le jeu de base avait 26 sorts et certains vraiment ont un effet important sur la logique du moteur.

    Pour information, avant on avait une classe mère GameState dont tout le monde dérivé. On avait trois classes filles : le départ, le jeu de base et les combats.

    Nom : classGameState-before.png
Affichages : 47
Taille : 784 octets

    Par contre, rapidement dans la gestion des sorts, je me suis appercu que du code était en commun entre le combat et la vue générale.

    Du coup, j'étais face à un dilemne : en pleine implémentation est-ce qu'on modifie la structure de GameState et on ajoute le code en commun (très logique en terme d'héritage) ou est-ce qu'on trouve une autre solution.

    Mon souci est de terminer avec un code propre, même si cela me coûte un peu de temps à certains moment de "nettoyage".

    J'ai donc créé assez rapidement une classe HelperView qui en fait est une classe statique qui ne contient que des fonctions statiques.

    Quel est l'avantage de ne pas mettre dans GameState : pour moi, GameState est une classe générique qui ne doit pas se spécialiser et cela n'était vraiment pas encore clair quels bouts de code allait rester tel quel, quel code se stabiliserait, etc.

    Depuis presque 3 semaines, cette classe a beaucoup évoluté et contenait beaucoup de choses.

    Hier soir, lorsque j'étais en train de vouloir avancer sur finir les sorts, je me suis apercu qu'il était enfin temps de migrer le code vers quelque chose de plus propre.

    HelperView est devenu PlayingGameState et est devenue la fille de GameState. GeneralViewState et CombatViewState sont devenus les filles de PlayingGameState.

    Nom : classGameState.png
Affichages : 43
Taille : 1,0 Ko

    Ceci, maintenant que le code est stable a demandé un peu de travail, j'ai factorisé le code, remonté certaines informations, membres communs, etc.

    Au final, bien que j'avais pensé à cette solution au départ, je n'étais pas persuadé de sa force structurelle ou si elle était nécessaire.

    Maintenant, après avoir laissé le code de HelperView devenir ce qu'il était devenu, ce choix était essentiel. Quelques changements et une heure plus tard les modifications étaient en place. Je ne dis pas que cela est facile à faire, au contraire, mais cela était nécessaire.

    A ce changement sont apparus deux classes annexes : CastInformation et CursorInformation, qui serviront de placement d'information pour les sorts et les curseurs.

    Voilà pour le post sur comment et pourquoi il est bon de ne pas trop réfléchir avant de coder et simplement y aller. Ensuite, on peut faire quelques passes de remodélisation et de nettoyage.

    Il me reste encore quelques concepts et mes 26 sorts initiaux seront intégrés au jeu.

    Jc

  15. #115
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Petite information de la journée : j'ai commencé à faire un doxygen du projet et je pense que je vais faire en alternance documentation/implémentation jusqu'à ce que la documentation soit bien faite.

    Du coup, je vous donne la page pour le doxygen :
    http://backtoroots.sourceforge.net/d...functions.html

    Bonne découverte,
    Jc

  16. #116
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 858
    Points : 218 577
    Points
    218 577
    Billets dans le blog
    120
    Par défaut
    Je reviens, et j'ai lu tout ce que j'ai manqué.

    D'abors, je voulais savoir quel éditeur vous avez utiliser ... car souvent la factorisation n'est pas automatisé ... et si vous en connaissiez un où elle est bien intégré je suis interessé.

    Après, pour la documentation en alternance, je doute ... disons que des fois, je n'ai pas vraiment la motivation de la faire
    Du coup je la fais, en plein partie de codage comme ça elle est faite :p

    Sinon, bah déjà, bravo pour tout les progrès ça sent la fin ( ok, je dis ça depuis le début )

    Et si j'avais d'autres trucs à dire, j'ai du oublié ... dans tout les cas, bravo pour l'avancement :clap:
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  17. #117
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Bon ben, dix jours plus tard, j'ai enfin terminé ma première passe à la documentation :

    http://backtoroots.sourceforge.net/doc/html/index.html

    Oui c'est la même adresse qu'avant mais toutes les classes sont commentées !

    Je peux enfin continuer à programmer le jeu maintenant que j'ai repris en main la documentation.

    Bientôt, j'aurai l'API pour les sorts terminés,
    Jc

  18. #118
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Après un petit silence, la programmation a repris. Et comme je l'ai remarqué avec les premiers sorts, implémenter les effets d'un sort est vraiment quelque chose d'intéressant car cela retouche le moteur, lance des nouvelles problématiques, etc.

    Du coup, actuellement, il me manque encore 9 sorts implémentés:
    - 3 sont pour les donjons
    - Un est pour la téléportation
    - 5 pour le combat

    Au final, je garde ces sorts sous la main pour passer à quelque chose d'autre pour l'instant :

    - Charger de la mémoire les fichiers d'origine du jeu...

    Cela va être aussi un travail de longue haleine mais cela en vaudra le coup ;-)

    Pour la petite histoire, je vais revenir un peu sur les fichiers actuels sorts pour présenter les "energy fields".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    #Letter codes (can be multiple (as for Ultima V))
    e
    #Reagents
    3
    Black Pearl
    Sulfurous Ash
    Spider Silk
    #In combat, out of combat
    1 1
    #Preprocessing
    1
    #Direction/Target/Global/For player/For caster
    0 1 0 0 0
    #Minimum level/Mana
    1 10
    #State removed from the target
    0
    #Length of state change
    0
    #Damage
    0
    #Range
    5
    #Healing target/caster
    0 0
    #Type of ennemies affected (nbr of types first)
    0
    #Scares/Sleeps/Charm
    0 0 0
    #Special treatment required
    1
    #Extra parameters
    0
    Comme on le voit, le fichier sort est relativement auto-explicatif.

    On a:
    • les ingrédients nécessaires pour la création du sort
    • est-ce que le sort est autorisé en combat/hors du combat
    • est-ce que le sort nécessite du preprocessing
    • des flags d'informations
    • le niveau minimum et le coût en mana
    • les dégats, les effets du sort
    • la portée du sort
    • les soins
    • le type d'ennemi affecté (ou tous si 0)
    • les effets supplémentaires
    • a-t-on besoin d'un traitement post?
    • les paramètres en plus du sort


    Cela permet de commencer le lancement du sort qui passe dans la classe PlayingGameState. Comme d'habitude tout se passe par une machine d'état pour déterminer ce qu'on doit faire.

    Cela est défini par un enum:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    enum CastingState {INIT_CASTING, SELECT_PLAYER, SELECT_SPELL, SELECT_TARGET_PLAYER, SELECT_TARGET, SELECT_DIRECTION,
                       PREPROCESSING};
    Souvent c'est un code relativement simple par état (voir si un joueur est séléctionné), etc.

    Dans le cas du Preprocessing, on a besoin de lancer du code particulier, du coup cela devient :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
            case PREPROCESSING:
                {
                    Spell *internalCastingSpell = information.getSpell ();
                    assert (internalCastingSpell);
                    void *info = NULL;
     
                    bool res = internalCastingSpell->handlePreprocessing (ev, info, textarea);
                    if (res == true)
                    {
                        information.setInformation (info);
                        chooseNextStep (outOfCombat, spellCast);
                    }
                }
                break;
    On récupére le sort, et ensuite on passe l'événement à la fonction handlePreprocessing qui s'occupera du sort.

    Gestion du texte

    Pour récupérer le texte du preprocessing, en fait, on passe de toute facon par une fonction de CastInformation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    void CastInformation::updateText (void)
    {
        switch (state)
        {
            case INIT_CASTING:
                text = "Casting !";
                break;
            case SELECT_PLAYER:
            case SELECT_TARGET_PLAYER:
                text = "Select player:";
                break;
            case SELECT_SPELL:
                text = "Select spell:";
                break;
            case SELECT_TARGET:
                text = "Select target:";
                break;
            case SELECT_DIRECTION:
                text = "Select direction:";
                break;
            case PREPROCESSING:
                assert (spell);
                text = spell->getPreText ();
                break;
            default:
                assert (0);
                break;
        }
    }
    C'est à la fonction getPreText de nous donner le texte spécialisé à cet effet. Cela permet d'afficher n'importe quel texte voulu par le sort.

    handlePreProcessing

    Cela commence avec récupérer l'index du sort:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
        unsigned int idx;
        assert (getSpellIndex (idx));
    Ceci permet de passer du nom du sort en nombre unique. En fait, lorsque j'aurai 2 secondes, cette association se fera une seule fois après le chargement du sort. Mais, ce n'est pas la priorité.

    Ensuite, on peut passer au travail de gérer le preprocessing :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
     
    switch (idx)
        {
            case ENERGY_INDEX: //ENERGY
                {
                    std::string name;
     
                    switch (ev.key.keysym.sym)
                    {
                        case SDLK_f:
                            name = "Fire Field";
                            break;
                        case SDLK_p:
                            name = "Poison Field";
                            break;
                        case SDLK_e:
                            name = "Energy Field";
                            break;
                        case SDLK_s:
                            name = "Sleep Field";
                            break;
                        default:
                            text->appendText ("wrong value");
                            return false;
                    }
    D'abord, on passe de ce que l'utilisateur nous a rendu comme touche et on met à jour la variable name. Si jamais c'est une mauvaise touche, on retourne false, ce qui permettra d'attendre le prochain choix.

    Ensuite, dans notre cas, si nous avons la bonne touche, on peut ajouter à l'information du sort :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
                    //Now create a pointer for this
                    std::string *res = new std::string (name);
                    information = static_cast <void*> (res);
                    text->appendText (name);
                    return true;
                }
                break;
            default:
                assert (0);
                break;
        }
    Ceci sera géré par le sort. Cela nous permet de créer l'objet. Où cela ? Ben dans le postprocessing (Donc quand le sort est effectivement lancé !)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
            case ENERGY_INDEX:
                {
                    std::string *s = static_cast<std::string *> (information);
                    assert (s);
                    Object *obj = Object_Factory::getObject (*s);
                    delete s, s = NULL;
                    cell->setEnergyField (obj);
                }
                break;
    Voilà où on crée le energy field et où l'on permet de l'ajouter à la destination.
    Remarquez qu'on aurait pu récupérer l'objet du factory au preprocessing et utiliser. Cela revient un peu au même sauf que cette recherche est mise ici pour un peu d'optimisation (Quoi que, cela ouvre une conversation...)

    Mais donc maintenant, où voyons nous les effets de ces champs d'énergie ?

    En fait, lorsqu'on marche sur une case, on regarde si un champs est présent, si oui, alors on applique l'effet associé.

    Petite image avec les champs en place ;-)
    Nom : Screenshot-Back to roots --- Version: 1.24.jpg
Affichages : 53
Taille : 85,7 Ko
    Jc

  19. #119
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    En mettant de côté le reste des sorts pour l'instant, je me suis attaqué à gérer les fichiers du jeu de base. J'ai choisi le 4 parce qu'il est plus simple et donc me permet de ne pas avoir une tonne de choses à faire pour l'intégrer dans le moteur (déjà qu'il y aura une tonne de choses à gérer ;-)).

    Bref, je me suis attaqué à la police du jeu qui était défini dans un fichier séparé.

    Je me suis aussi attardé à faire des répertoires, car avec 60 fichiers sources et 60 fichiers d'en-tête, cela devenait vite compliqué...

    Donc on a maintenant Core qui est le moteur et Versions qui auront les codes spécifiques.

    Je vais aussi faire que le tout soit modulaire, par exemple, vous allez voir, que la police peut-être changée dépendant de ce que défini un fichier de configuration.

    Si le fichier de texte contient :
    None
    On obtient le rendu de base que je vous montre depuis un moment.
    Nom : Screenshot-Back to roots --- Version: 1.26.jpg
Affichages : 44
Taille : 70,1 Ko

    Par contre, si nous avons :
    #Here are the lines for the original U4 font
    U4
    ../ULTIMA4/CHARSET.EGA
    Nous obtenons la police de base:

    Nom : Screenshot-Back to roots --- Version: 1.26-1.jpg
Affichages : 50
Taille : 85,9 Ko

    Enfin, si vous faites :
    #Type of font : U4VGA
    U4VGA
    ../ULTIMA4VGA/charset.vga
    ../ULTIMA4VGA/u4vga.pal
    Vous obtenez la police version VGA:
    Nom : Screenshot-Back to roots --- Version: 1.26-2.jpg
Affichages : 45
Taille : 87,2 Ko

    Ceci est possible de facon transparente puisque j'utilise l'héritage :

    Nom : classTextRenderer__inherit__graph.png
Affichages : 36
Taille : 6,8 Ko

    Du coup, au chargement du jeu, on peut vérifier quel est le choix de l'utilisateur et faire quelque chose comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
        //Get version name
        std::string name = lp.getNextLine ();
     
        try {
            if (name.compare ("U4VGA") == 0)
            {
                std::string fileName = lp.getNextLine ();
                std::string palette = lp.getNextLine ();
                //For the moment, we load the original, it either will redefine how to render things
                ourInst = new TextRendererU4VGA (fileName, palette, verbose);
            }
            else
            {
                if (name.compare ("U4") == 0)
                {
                    std::string fileName = lp.getNextLine ();
     
                    //For the moment, we load the original, it either will redefine how to render things
                    ourInst = new TextRendererU4 (fileName, verbose);
                }
                else
                {
                    //Problem
                    throw 1;
                }
            }
        }
        catch (int exception)
        {
            ourInst = new TextRendererCustom ();
        }
    Ce qui permet, à la volée, de choisir le rendu et, pour le reste du jeu, cela est entièrement transparent. Si jamais il y a un souci, on léve une exception et on utilise ma version de base qui utilise Glut.

    Il faut que je corrige un peu le rendu des versions de base. OpenGL n'aime pas trop comment j'ai créé ma texture. Mais cela peut attendre.

    Je vais faire quelque chose de similaire pour les tuiles du jeu et cela va en fait être intéressant puisque cela va me permettre de mélanger tuiles et polices de facon transparente au moteur du jeu.

    Jc

  20. #120
    Expert éminent sénior

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Points : 11 877
    Points
    11 877
    Par défaut
    Me voilà contre un mur ;-)

    J'ai finalement fini une première version du chargement des tuiles de base et je me retrouve contre un souci :

    - Déjà, je remarque que si je veux juste garder les images du jeu de base, mon moteur fait beaucoup plus que ce que le jeu autorisé. Par exemple, je n'ai pas de texture des armes, sorts, etc. Cela a apparu dans le jeu suivant.

    Du coup, je vais sûrement faire quelque chose où je mets un

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    if (jeu.supporteJeterDesObjets ())
      jeu.jetteObjet ();
    Et parsemé un peu le code avec des tests pour restreindre le moteur dépendant du jeu lancé. Cela ne pose pas trop trop de souci.

    Par contre, plus embêtant, mes fichiers de bases en fait utilise un sprite sheet différent du jeu de base. Donc, forcément, lorsque je dis que je veux la tuile (5,4) avec mon sprite sheet, cela donne quelque chose de différent sur le sprite sheet du jeu d'origine.

    Une solution serait d'avoir une association <nombre unique> sprite qu'on veut avoir et faire l'association comme cela... Mais cela limite le moteur, du coup, je pense qu'on ne pourra pas passer de facon aussi transparente entre les différents styles graphiques si les fichiers de configuration ne sont pas compatibles.

    Autre effet de bord, dans mes fichiers de configuration, je donne le nombre de tuiles de la sprite sheet. Alors forcément, dans mon fichier de base, j'avais 32 * 64 tuiles. Dans le jeu de base, il y en a 16 * 16

    Du coup, considérez la scéne du jeu avec mes fichiers :
    Nom : Screenshot-Back to roots --- Version: 1.26-1.jpg
Affichages : 55
Taille : 80,7 Ko

    Et bien, avec les données du jeu de base cela donne :
    Nom : Screenshot-Back to roots --- Version: 1.26.jpg
Affichages : 51
Taille : 84,1 Ko



    Ironiquement, vous voyez que les tuiles de texte sont nickels car, par pure chance, ils tombent sur les mêmes cases !

    Bref, je vais devoir faire des choix et probablement laisser tomber l'idée de l'interchange transparente des tuiles si les sprites sheet ne sont pas compatibles. Ce qui, n'est pas forcément une grande limitation.

    D'ailleurs, comme d'habitude, ce changement de chargement se fait bien sûr via un fichier de configuration et non une recompilation ;-)

    [Edit] Je viens de remarquer que je n'ai pas mis la version de base :
    Nom : Screenshot-Back to roots --- Version: 1.26-2.png
Affichages : 53
Taille : 198,1 Ko

    Vous remarquez donc qu'on obtient la même chose (en terme de type de tuile) que la version VGA ;-)

    [/Edit]
    Jc

Discussions similaires

  1. [phpMyAdmin] [phpMyAdmin] Problème mot de passe Root !
    Par StouffR dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 7
    Dernier message: 26/09/2014, 11h59
  2. IDE vs programmation "roots" ?
    Par yoloosis dans le forum Débats sur le développement - Le Best Of
    Réponses: 44
    Dernier message: 27/01/2005, 00h37
  3. Comment change l'utilisateur root de mysql?
    Par silvermoon dans le forum Installation
    Réponses: 3
    Dernier message: 29/10/2003, 11h25
  4. probleme identification et mot de passe root
    Par freums dans le forum Débuter
    Réponses: 5
    Dernier message: 19/09/2003, 17h09
  5. Password root perdu !!
    Par Va(l)ve dans le forum Administration système
    Réponses: 8
    Dernier message: 18/08/2003, 22h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo