1

Yop,


Depuis un moment, je m'interroge sur la manière dont sont implantés les succès dans les jeux. Exemple, pour être concret : à TF2, il y a une classe Soldat qui obtient un succès si, après un saut auto-propulsé (ie. rocket jump), il tue un adversaire dans les 5 secondes.

Comment programmer ça ? Ca nécessite de loguer le fait qu'il est en train de faire un rocket jump, puis de retenir le moment de son atterissage, de vérifier qu'il y a bien eu un frag dans un délai de 5 secondes, ce qui fait quand même plusieurs choses à loguer/comparer, et ce à différents endroits du code. Comme ça peut se superposer dans le même temps à d'autres succès (ça peut aller de "tuer 1000 connards en face" à d'autres succès jouant sur une demi-douzaine de paramètres), je me demandais comment tout ça fonctionne.

En fait, j'ai du mal à immaginer tout un moteur de jeu bloaté par des centaines de succès. La complexité deviendrait vite monstrueuse... Et à TF2, il y a 400 succès, toutes classes confondues, je vous laisse immaginer le bordel. Donc ça marche comment ce concept de succès ?

edit -> je me pose en fait autant la question pour la gueule du code qui résulte de l'implantation des succès, que pour les performances qui en résultent, avec tout ce qu'il vaut vérifier en permanence, en plus du moteur 3D & co...

2

Je pense que tu sous-estimes grandement la complexité du code des jeux, même sans les succès. Un jeu actuel, c'est un moteur 3D, un moteur audio, un moteur physique, un moteur de scripting, plus plein d'autres trucs, chaque partie étant elle-même relativement complexe (et faites par des équipes différentes voire sous-traitée).

La gestion des succès, à côté de tout ça, ça doit être peanuts.

!call bearbecue
--- Call : bearbecue appelé(e) sur ce topic ...
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

3

hypno

Je suis encore plus curieux ^^

4

Zerosquare (./2) :
La gestion des succès, à côté de tout ça, ça doit être peanuts.


Souvent, c'est directement intégré au scripting...
avatar
Webmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca

5

Justement, je pense que la question, c'est comment ils font pour traiter X données supplémentaires et Y conditions sur ces données à chaque instant pour chaque joueur, X et Y pouvant potentiellement être énormes.
Qu'un jeu soit "déjà complexe", certes, mais c'est orthogonal à la question. Les hauts faits sont gérés sur le serveur pour les jeux multijoueurs (ou pour les jeux mono-joueur en ligne… *tousse* Diablo 3 *tousse*)

C'est plus un problème indépendant du moteur de jeu utilisé, et j’avoue m'être posé la même question assez récemment. (Je n'ai pas encore creusé car ça ne m'a pas semblé impossible d'y répondre, mais je vais le faire ici tongue)

Le but (enfin, ce qu'on recherche à priori), c'est de pouvoir gérer un maximum de conditions potentiellement complexes de la manière la moins coûteuse possible.
On veut surtout éviter de dégrader les performances du jeu *avec succès* par rapport à la version du jeu *sans succès*.
Et on veut idéalement pouvoir ajouter de nouveaux succès au jeu sans devoir recorder entièrement le moteur physique. (Bon j'exagère, mais disons qu'on ne veut pas y toucher, sauf nécessité absolue)
Les implémentations possibles sont à priori variées (côté client, côté serveur, scripté dans une base de données, scripté en dur, etc.), donc on mettra aussi ça de côté.

Il faut bien concevoir que traiter 500+ conditions à chaque itération du moteur physique, même si ça resterait concevable (ou pas !) en local sur une machine, c'est exclu.
Pour que les choses se produisent de la manière la plus passive possible, il faut retarder la vérification de la condition au plus tard possible. (Au dernier moment, quand on a plus le choix)
Le meilleur moyen pour cela est de procéder de manière évènementielle. (Avec des déclencheurs)
Prenons pour exemple, ce succès
Folco (./1) :
à TF2, il y a une classe Soldat qui obtient un succès si, après un saut auto-propulsé (ie. rocket jump), il tue un adversaire dans les 5 secondes.

Ici, ce qui va déclencher le haut fait (la condition finale, en quelque sorte), c'est tuer un adversaire. (Admettons que tu ne puisses pas tuer tes alliés, comme ça c'est plus simple)
Tant que tu ne tues personnes il ne se passe absolument rien [vis à vis de ce haut fait]. De fait ça ne coûte rien niveau performances. (NB: À priori, "tuer" c'est un truc qui arrive "souvent, mais pas trop quand même", donc c'est idéal comme déclencheur de succès)
Par contre dès que tu tues un méchant, on va effectuer toutes les taches associées à "mort d'un adversaire".
Par exemple, incrémenter ton compteur de victimes. Et aussi, vérifier les succès associés.

Donc pour le succès en question, la condition "générique" suivante est "est-ce que cela s'est produit dans les 5 secondes après X", X étant "atterrissage après un rocket jump".
Cette condition, tu peux la vérifier de manière simple : Quand le joueur atterrit d'un rocket jump, tu stockes le timestamp du dernier atterrissage dans une variable cachée. spécifique au joueur, et interne au jeu.
De là, tu sais si le haut fait est accompli ou non.
Tu peux également optimiser le jeu en activant et désactivant les conditions de haut fait automatiquement pour que cela ne soit effectué que quand cela est nécessaire. (Par exemple, une fois le succès effectué, ce n'est plus la peine de vérifier à chaque fois. Les succès qui ne concernent qu'une classe de personnages n'ont pas besoin d'êtres vérifiés pour les autres, etc.)

Il reste toutefois une question, qui est de savoir comment on détermine l’atterrissage après un rocket jump.
Et bien, cela va se passer de la même manière que pour le haut fait. Un aterrisage quelconque, déclenchera une série de tâches lié à "aterrissage".
Comme par exemple, "stocker le timestamp du dernier atterrissage" (si jamais tu en as besoin pour autre chose), ou "si le dernier atterrissage fait suite à un rocket jump, stocker le timestamp dans la variable cachée adéquate".
Pour savoir si un atterrissage est la conséquence d'un rocket jump, c'est simple, il suffit juste de savoir si le dernier "décollage" provient d'un rocket jump ou pas (saut normal, chute, …).

Bref, tu vas probablement devoir gérer un autre évènement qui est "joueur n'est plus en contact avec le sol", qui stockera probablement un timestamp (si tu veux connaitre la durée du saut, de la chute, etc.) et la raison de ce décollage (rocket jump !).

Au final, le mécanisme de succès revient à stocker tout un tas (ça peut devenir assez énorme) de statistiques sur le jeu dont tu n'avais pas nécessairement besoin avant de gérer le mécanisme de succès. Une partie du travail doit nécessairement être *directement* effectuée par le moteur physique (détecter les évènements, retenir certaines valeurs, …), et une autre partie va se contenter de répondre aux évènements et de réagir en fonction des valeurs retenues, et pourra être totalement scriptée.

Par exemple, pour un haut fait "sauter 10 000 fois", tu auras juste besoin d'une statistique "nombre de sauts effectué (total)", qui sera mise à jour par le moteur de jeu lors de l'évènement "saut effectué", qui, permettra aussi de vérifier la condition du haut fait. (Est-ce que le nombre de sauts total est maintenant [supérieur ou] égal à 10 000)


Gérer des succès te force parfois à retenir énormément de statistiques sur un joueur/personnage, que ce soit de manière statique (données sauvegardées même après la déconnexion) ou de manière dynamique (succès "pendant une seule partie" ou "après que x se soit produit"…)
Ça a nécessairement un coût associé (pas forcément négligeable), mais ça n’impacte pas non plus excessivement les performances de jeu outre mesure, si tu fais attention. (NB: Gérer les évènements a un coût non nul…)


Comme je suis pas sur que ce que j'ai dit ait été très clair, voilà un espèce de pseudo script de comment les choses peuvent se passer.

[Moteur physique] Déclenche évènement [Toto]
[Script] Gère évènement [Toto]
[Script] [Toto] [Action 1] -> Stockage de [Toto.Timestamp] dans [Stat.TotoLastTimestamp], et incrémentation de [Stat.NombreToto]
[Script] [Toto] [Action 2] -> Vérification de la condition [Succès 1] : Si vraie, [Succès 1] réussi, désactiver [Action 2], exécuter [Action Succès 1]; Si faux, ne rien faire.

[Succès 1] = [Stat.TotoLastTimestamp] > 5000
[Action Succès 1] = Activer [Succès 2] (Après validation du succès 1, on a retiré le succès 1 de la liste des conditions à vérifier, et comme action de complétion, on demande d'activer Succès 2, qui est probablement la suite de Succès 1)
avatar
Le scénario de notre univers a été rédigée par un bataillon de singes savants. Tout s'explique enfin.
T'as un problème ? Tu veux un bonbon ?
[CrystalMPQ] C# MPQ Library/Tools - [CrystalBoy] C# GB Emulator - [Monoxide] C# OSX library - M68k Opcodes

6

(je ne sais pas si c'est ce que font les jeux, mais c'est grosso modo la méthode que j'utiliserais aussi si je devais résoudre un problème de ce genre)
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

7

Pour revenir plus particulièrement sur la partie "code bloaté", si ça fonctionne de la façon que décrit Golden (sans avoir jamais non plus creusé la question, il me semble également assez probable que ça fonctionne comme ça), le code n'est pas nécessairement pourri de tests particuliers pour autant.

Le moteur du jeu peut proposer dans son API un système évènementiel pour s'abonner à chaque action effectuée dans le jeu (tuer quelqu'un, sauter, atterrir, etc), sachant que ça peut servir pour plein d'autres choses que les succès, par exemple pour implémenter des missions dans le jeu.

À partir de là, le système qui s'occupe de surveiller certaines actions, de conserver toutes les données temporaires, de réconcilier les conditions pour savoir si un succès a été obtenu et de désactiver les vérifications inutiles peut être un code à part qui ne fait que vérifier les succès (et qui n'a même pas besoin d'utiliser le même langage que le jeu, il peut être scripté intégralement).
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

8

C'est typiquement de la programmation par règle ! Je ne sais pas s'il y a des langages de scripts qui propose ce type de programmation pour les jeux, mais ce serait une bonne idée de procéder ainsi. On écrit des règles en fonction des événements et des états, et un interpréteur de règles s'occupe de gérer le bazar au plus optimal (pour cette événement j'ai telle et telle règle, cette règle là est inutile dans l'état actuel, etc.). Je ne programme pas des jeux, mais l'exemple qui me vient à l'esprit est le système de gestion d’événement udev dans les environnements Linux.

J'avais développé un système de gestion de raid avec : le raid se gérait automatiquement par arrachage/insertion de disque à la main.

J'avais plusieurs règles :

* événement : un volume est arraché
condition : il est situé sur un disque SATA
condition : il fait parti d'un RAID1
action : retirer le volume du raid et déclarer le raid dégradé

* événement : un volume est ajouté
condition : c'est un disque SATA
condition : sa taille est supérieure ou égale au volume RAID1
action : recréer un partitionnement et préparer un volume RAID1

* événement : un volume est ajouté
condition : c'est un volume RAID1
condition : le RAID1 est dégradé
action : reconstruire le miroir avec ce volume

* événement : un volume est arraché
condition : c'est un volume RAID1
condition : un volume RAID1 est prêt et non utilisé
action : reconstruire le miroir avec ce volume

* événement : changement de statut du raid
action : envoyer un mail

On remarque que les actions des événements provoquent d'autres événements :
événement : disque SATA ajouté et de capacité suffisante → action : préparer volume RAID
événement : volume RAID prêt → action : reconstruire le miroir
On remarque que certains événements ne provoquent pas d'actions :
événement : volume RAID surnuméraire prêt → nada
événement : volume ajouté non SATA → nada
événement : volume ajouté trop petit → nada


C'est au gestionnaire d’événement et au processeur de règles de gérer tout ça (sous Debian, on trouve les règles udev dans /lib/udev/rules.d/ (règles statiques) /etc/udev/rules.d/ (règles générées)

Par exemple : une interface Ethernet est disponible (module chargé, matériel présent) :
Si le fichier de règle /etc/udev/rules.d/70-persistent-net.rules existe, nommer l'interface, s'il n'y a pas de règle, /lib/udev/rules.d/75-persistent-net-generator.rules générer un nom et ajouter une règle de nommage.
C'est donc une programmation par règle capable de modifier ses règles (au moins par surcharge).

Si je faisais un jeu et que je devais gérer des succès, j'implémenterai une telle solution si je n'en trouve pas déjà une toute prête. Il existe peut-être déjà un udev-like exprès pour gérer les événements de jeu par règle.

[note : le langage de description de règle d'udev est un langage à goto, ça fait bizarre !]
avatar
† In te confirmátus sum ex útero : de ventre matris meæ tu es protéctor meus.
illwieckz.net ~ Unvanquished ~ gg.illwieckz.net { le frag courtois } ~ NetRadiant

9

Folco (./1) :
Exemple, pour être concret : à TF2, il y a une classe Soldat qui obtient un succès si, après un saut auto-propulsé (ie. rocket jump), il tue un adversaire dans les 5 secondes.

Bah ça c'est trivial hein, en gros checker un succès comme ça c'est quoi ? Mettre une variable à 5.0 en cas de rocket jump, puis la décrémenter de dt (delta temps) à chaque itération de la boucle de jeu, de la mettre à zéro en cas atterrissage, puis en cas de frag regarder cette variable, si elle est >= 0 notifier un haut-fait.

Après évidemment dans le jeu tu vas vouloir soit rendre ça accessible au script (et là t'as diverses manières de le faire), soit à défaut de ça, si le script est hardcodé, externaliser ça dans des classes.

Une manière de faire c'est d'avoir un dispatcher central d'événements. La plupart des objets sont susceptibles de lever un événement, typiquement un trampoline peut lever un "rocket jump" ou quelque chose du style. Le moteur lui même peut vouloir lever un événement, comme par exemple "s'est fait toucher", ou "a fraggé". Tu fais donc un dispatcher dans ton moteur te permettant de t'enregistrer (toi l'objet, ça peut être un ennemi, un haut fait, un élément de l'UI ; bref n'importe quel objet répondant au protocole) dans la liste des objets à être notifiés pour un type d'événement donné. En gros ça veut dire t'ajouter à un std::vector, et quand l'événement est rencontré bah le moteur parcourt le vector et appelle l'événement sur chacun des objets.

Par exemple voici à quoi pourrait ressembler un objet haut fait, qu'on instancierait au démarrage du moteur :

class HautFait_IchBinEinRoxxor: public EventHandler {
    float remainingTime;

public:
    HautFait_IchBinEinRoxxor() {
        remainingTime = 0.0f;
        // Observe les événements qui nous intéressent
        Engine::sharedInstance->registerForEvent(this, Engine::EVENT_BUMP);
        Engine::sharedInstance->registerForEvent(this, Engine::EVENT_FRAG);
        Engine::sharedInstance->registerForEvent(this, Engine::EVENT_LANDED);
        // Demande aussi d'être notifié à chaque frame
        Engine::sharedInstance->registerForUpdate(this);
    }

    // Appelé par le moteur lorsqu'un événement nous concernant est déclenché
    void notifyEvent(Engine::Event *event) {
        switch (event->type) {
        case Engine::EVENT_BUMP:
            remainingTime = 5.0f;
            break;
        case Engine::EVENT_LANDED:
            // Saut fini, haut fait impossible désormais
            remainingTime = 0.0f;
            break;
        case Engine::EVENT_FRAG:
            if (remainingTime > 0.0f)
                Engine::sharedInstance->notifyTrophy(Engine::TROPHY_ROXXOR, "You are a god!");
            break;
    }

    // Appelé par le moteur à chaque frame parce qu'on lui a demandé avec registerForUpdate
    void updateFrame(float deltaT) {
        if (remainingTime > 0.0f)
            remaningTime -= deltaT;
    }
};


A partir de là tu peux en cumuler 1000, puisque comme tu vois ce code n'interfère en rien avec le jeu.
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

10

Pour étayer ma réponse, je dirais qu'on voit ici un élément intéressant de la programmation orientée objet qui simplifie beaucoup de problèmes : le polymorphisme.

Tu auras peut être remarqué que mon objet a une relation d'héritage sur EventHandler, une interface fictive qu'on pourrait définir ainsi :

class EventHandler {
public:
    virtual void notifyEvent(Engine::Event *event) = 0;
    virtual void updateFrame(float deltaT) = 0;
};


Ca signifie que toute classe héritant de EventHandler, s'engage à fournir une implémentation pour répondre à ces deux méthodes. En d'autres termes, si on se trimballe un sous-type de EventHandler, on a forcément un objet qui répond à ces deux méthodes. L'idée c'est donc d'avoir une liste d'EventHandler, dont on ne connait pas la classe réelle (ça peut être un haut fait ou un autre, voire encore autre chose) mais on s'en fiche : on sait juste qu'on peut leur notifier des événements et qu'elles en feront ce que bon leur semble.

Voilà alors comment on pourrait implémenter ça dans le jeu :

extern std::vector<EventHandler*> frameUpdateObservers;

int main(void) {
    // Boucle du jeu
    while (true) {
        // ... (dessin, etc.)

        // Notifie la fin de frame à ceux qui sont enregistrés
        for (unsigned i = 0; i < frameUpdateObservers.size(); i++) {
            // On a des EventHandler, donc ils répondent à updateFrame(float)
            frameUpdateObservers[i]->updateFrame(0.016666f);
        }
    }
    return 0;
}


Et pour enregistrer des objets, aussi simple :

std::vector<EventHandler*> frameUpdateObservers;

void registerForUpdate(EventHandler *observer) {
    frameUpdateObservers.push_back(observer);
}


Avec cette syntaxe, on force quiconque veut enregistrer un objet (registerForUpdate) à fournir un sous-type de EventHandler, donc un objet sachant au moins gérer un appel à updateFrame(float). On pourra donc le faire en toute sécurité. wink
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

11

Brunni (./9) :
Bah ça c'est trivial hein, en gros checker un succès comme ça c'est quoi ? Mettre une variable à 5.0 en cas de rocket jump, puis la décrémenter de dt (delta temps) à chaque itération de la boucle de jeu, de la mettre à zéro en cas atterrissage, puis en cas de frag regarder cette variable, si elle est >= 0 notifier un haut-fait.

Pas si simple au premier abord, car ça fait intervenir des timers, le moteur physique, ça demande d'enregistrer des variables avec des timestamp et compagnie.

Les explications sur le système évènementiel me semblent pas mal en effet, en tout cas pour le côté "propreté du code". Reste la question de la performance. Le script, c'est bien, mais un moteur de script, c'est comme un doberman, ça bouffe.

12

C'est probablement l'héritage "68k" qui veut ça, mais tu sous-estimes à mon avis beaucoup les capacités des PC actuels (et ce qu'on leur demande déjà de faire, qui est au-dessus de ces quelques tests triviaux de plusieurs ordres de grandeur en termes de complexité).

En l'occurrence, le code qu'on va brancher sur les évènements et qui va se charger de vérifier les succès reste très basique. Qu'il soit natif ou qu'il utilise un langage de script, ça ressemblera grosso modo à ce que décrit Brunni (il n'y a pas 50 façons de faire, le modèle qu'il présente est très souvent utilisé pour coder des GUI évènementielles et convient tout à fait ici aussi), et ne bouffera quasiment rien à côté du jeu lui-même smile
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

13

Certainement, j'y connais rien, je ne me rends sûrement pas compte grin

14

cross-edit, mais fais quelques essais avec SDL puisque tu avais l'air d'être parti là-dessus, tu t'en rendras compte rapidement ^^
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

15

Je pencilne Zeph hehe
avatar
Zeroblog

« Tout homme porte sur l'épaule gauche un singe et, sur l'épaule droite, un perroquet. » — Jean Cocteau
« Moi je cherche plus de logique non plus. C'est surement pour cela que j'apprécie les Ataris, ils sont aussi logiques que moi ! » — GT Turbo

16

Zeph (./14) :
cross-edit, mais fais quelques essais avec SDL puisque tu avais l'air d'être parti là-dessus, tu t'en rendras compte rapidement ^^
Folco (./13) :
Certainement, j'y connais rien, je ne me rends sûrement pas compte biggrin.gif



Folco, tu t'occupes du moteur des scripting, on a bob pour la troidé et momotte pour le moteur physique.

Pour le son et la musique, on utilisera la méthode certifiée par Zerosquare.

Pour le marketting viral, on demandera à michou de l'impasse du troc.


Pour ma part je me chargerai d'encaisser les dividendes.
avatar
Webmaster du site Ti-FRv3 (et aussi de DevLynx)
Si moins de monde enculait le système, alors celui ci aurait plus de mal à nous sortir de si grosses merdes !
"L'erreur humaine est humaine"©Nil (2006) // topics/6238-moved-jamais-jaurais-pense-faire-ca

17

Folco (./11) :
Les explications sur le système évènementiel me semblent pas mal en effet, en tout cas pour le côté "propreté du code". Reste la question de la performance. Le script, c'est bien, mais un moteur de script, c'est comme un doberman, ça bouffe.

C'est négligeable. Mais vraiment. tongue
Je sais que tu ne me crois pas, et je pense que tu devrais vraiment une fois essayer pour voir ce qu'a un PC dans le ventre. Je me rappelle quand j'avais reçu mon Pentium 4, je débutais plus ou moins la prog, et je codais un éditeur de maps où je dessinais en soft. Je dessinais plusieurs plans superposés, avec un coefficient de transparence, et un code dégueulasse (je faisais des divisions par 255, des multiplications signées et tout, et ce pour chaque sous couleur RGB de chaque pixel) et pourtant sur les 1280x1024 pixels de mon écran ça ne ramait pas un poil.
Ensuite j'ai implémenté un algo de réduction de couleurs d'image. Le truc était une horreur, j'essayais de déterminer les couleurs les plus proches et j'essayais de fusionner diverses permutations tout en recalculant ensuite à chaque fois une image finale avec les couleurs restantes (en prenant pour chaque pixel la couleur la plus proche), et calculais alors un coefficient d'erreur (à quel point chaque pixel était "faux" par rapport à l'image d'origine) et je prenais l'image minimisant la somme des erreurs. Bref le truc immonde que tu te dis que ça va tourner des années. Bref je lance, et c'est fini. J'y crois pas, je vais vérifier, le fichier est bien là, et a le bon nombre de couleurs...
Plus tard j'ai encore implémenté des algos plus compliqués et là ça commençait à prendre plus long pour de grosses images, mais bon... et puis ça restait ridicule pour le service rendu.
Et ça c'était un bête P4, le truc que je pense que mon smartphone est plus puissant. Un Core i7 ça doit être 30x plus puissant à la louche, donc si tu le faisais maintenant je pense que tu serais encore plus "blazé" que moi.

Tout ça pour dire que ce n'est vraiment pas le plus important, surtout que le gros de la complexité dans ce code repose dans std::vector, et rien n'empêche de remplacer par une autre implém si tu devais avoir à coder sur genre moins puissant que la GBA. Tu pourrais aussi en dernier recours faire directement les appels aux "event handlers" plutôt que passer par une liste, mais pour quelque chose qui sera parcouru moins de 100 fois par seconde, et "gaspillera" une vingtaine de cycles par événement attaché, le jeu n'en vaudra pas la chandelle. Bref après c'est du détail d'implémentation qui dépend de la machine cible, mais si t'es sur PC ça ne vaut pas la peine de refuser une solution sous prétexte qu'elle risque de ne pas tourner très vite sur une NES. Surtout que sur NES genre l'int 32 bits ça n'existe pas... Bref si tu veux coder pour une petite machine il faudra de toute façon réfléchir autrement, donc regarde un peu ce que vaut le PC et fais en fonction wink
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741

18

./2> tl;dr triso
(mais, ouais, c'est peanuts grin)
avatar
HURRRR !

19

À lire le code de Brunni, je me demande… c'est vraiment si peu utilisé que ça la programmation orientée règle?

Parce que là le code mélange rêgle et gestion de rêgle…

Un exemple de règle udev :
SUBSYSTEM!="block", GOTO="end_autoraid_hotplug"
KERNEL!="sd[a-z][0-9]", GOTO="end_autoraid_hotplug"
ACTION=="add", RUN+="/usr/local/sbin/autoraid-hotplug.sh $name"
ACTION=="remove", RUN+="/usr/local/sbin/autoraid-hotunplug.sh $name"
LABEL="end_autoraid_hotplug"


Le code reste descriptif, juste de la logique, des états, des évènements et des actions. les procédures sont ailleurs, et le gestionnaire de règle est un outil dédié à cette tâche et éprouvé.

Je programme peu, je ne connais que les outils et langages que les problématiques que je rencontre me donnent à connaître. Je ne pense donc pas naturellement "objet" pour toutes les solutions. Mais pour gérer des succès je penserai plus naturellement à de la programmation orientée règle plutôt qu'objet.

là une petite liste de paradigmes alternatifs : http://linuxfr.org/users/montaigne/journaux/des-paradigmes-alternatifs
avatar
† In te confirmátus sum ex útero : de ventre matris meæ tu es protéctor meus.
illwieckz.net ~ Unvanquished ~ gg.illwieckz.net { le frag courtois } ~ NetRadiant

20

Dans le cas présent ça pourrait être une solution tout à fait viable, mais pour pouvoir utiliser de la programmation orientée règle il faut déjà se taper un moteur de règle (ou en reprendre un existant et espérer qu'il n'ait aucune limitation imprévue qui pourrait devenir gênante). Il ne faut également pas oublier que contrairement au cas udev, les règles ne sont qu'une (petite) partie de l'environnement du jeu, et introduire un nouveau langage (et même un nouveau paradigme) pour un bénéfice qui n'est pas évident est quelque chose qu'on va plutôt avoir tendance à éviter.

Comme ce genre de code s'écrit à peu près aussi naturellement en évènementiel, et que la simplification automatique des règles (qui aurait été le seul avantage d'un moteur de règles) n'a pas d'intérêt ici puisqu'il n'y a aucun problème de performance, ça me semble apporter plus de complications que ça n'aura de bénéfices.
avatar
All right. Keep doing whatever it is you think you're doing.
------------------------------------------
Besoin d'aide sur le site ? Essayez par ici :)

21

Intéressante discussion smile

Folco, je comprends ta question. Habitué à se débrouiller avec la puissance d'une TI (et d'un 486 pour ma part, sans unité de flottants, alors peut-être un 386 ?), on ne se rend pas compte des progrès énormes qui ont étés faits. Rien qu'un Core i3, pourtant "bas de gamme" (terme qui doit surtout être utilisé par les joueurs, parceque pour Mr Tout-le-monde ca tourne excellement bien (plutôt sur Linux, sans vouloir troller car c'est un constat)), est probablement plus de 2000 fois plus rapide qu'une TI, sur chaque coeur, alors il y a de quoi faire smile
avatar
Un site complet sur lequel vous trouverez des programmes et des jeux pour votre calculatrice TI 89 / Titanium / 92+ / Voyage 200 : www.ti-fr.com.
Quelques idées personnelles ici.

22

illwieckz (./19) :
À lire le code de Brunni, je me demande… c'est vraiment si peu utilisé que ça la programmation orientée règle?
Parce que là le code mélange rêgle et gestion de rêgle…

Disons que pour faire ça, ça ne vaut pas forcément la peine de s'embêter avec un paradigme alternatif (si le même permettait de tout faire... mais là). A mon avis, le plus compliqué qu'on risque de trouver dans ce genre de code c'est une state machine.
avatar
Highway Runners, mon jeu de racing à la Outrun qu'il est sorti le 14 décembre 2016 ! N'hésitez pas à me soutenir :)

https://itunes.apple.com/us/app/highway-runners/id964932741