Aventura, le Royaume Poudingue... Un long projet !
Posté le 06/07/2016 23:44
Aventura, Le Royaume Poudingue est un RPG en Basic Casio (monochrome) entamé en 2016 et repris en 2018. Projet très ambitieux, ce dernier tend à s'emparer des meilleures techniques de Basic Casio pour offrir une expérience de jeu dépassant les attentes du joueur. Il aura fallu deux années complètes pour que la première version complète du jeu sorte enfin ! Ouf !
Le jeu est enfin disponible ! Cliquez ici !
Le projet en 2016
Cliquer pour enrouler
[...]
En réalité, je projette de concevoir un RPG en recommençant absolument tout de zéro. En errant sur ce forum, j'ai amassé une quantité satisfaisante de savoirs nouveaux en ce qui concerne le basic ! Toutes les techniques et les jeux que j'ai entraperçu ou étudié sur ce forum ont fait germer tout un tas de petites idées en moi !
Je vous expose le plan : l'idée n'est qu'à l'état embryonnaire, mais je compte la faire évoluer par débats et expositions d'idées. Pour l'histoire, le scénario, je n'ai pas de problème. J'ai l'imagination qu'il faut pour pondre des trucs farfelus. Ce dont j'ai besoin, c'est d'approfondir le système du jeu et tenter de construire un programme cohérent, très optimisé et performant. Procédons à tout cela par étape, je relèverai chacune de mes interrogations par la suite.
La map : Résolu
Cliquer pour enrouler
C'est ce qui me fait me poser le plus de questions. Voici ce que j'ai décidé : sur une picture sera enregistrée une sidebar qui sera visible pareillement sur le mapmonde et en combat. J'ai pour ambition d'adopter un système de tiles pour générer les maps (qui seront statiques, comme le fameux Zelda PC de Remiweb, et pas de map scrolling). Pour commencer, je projette de concevoir un système de sauvegarde provisoire des maps. Voici un schéma pourri fait à l'arrache :
Lorsque le joueur est sur la map 1, le décor de cette map est enregistrée en picture 1 (par exemple). Arrivé sur la map 2, celle-ci est enregistrée en picture 2. Sur la map 3, elle est enregistrée en picture 3. Lorsque le joueur veut retourner sur la map 2, la picture 2 est directement affichée plutôt que de la redessiner. En passant sur la map 4, la map 1 sur la picture 1 est effacée pour laisser place à la map 4. Ainsi, le personnage peut se ballader entre les map 2, 3 et 4 sans temps de chargement !
Ensuite :Résolu
Cliquer pour enrouler
je vais rencontrer de nombreuses problématiques concernant le dessin d'une map. Pour une map, je vais rentrer dans une matrice les ID de chaque case. Admettons que j'ai un programme "lecteur de matrice" qui dessine chaque case en fonction de l'ID. Il est évident que je vais essayer de dessiner d'une traite tous les tiles identiques avant de passer aux tiles suivants, plutôt que de faire :
For 1→A To 6
For 1→B To 11
Mat A[A;B]=1⇒{1,2,3→List 1
etc.
Next
Next
Drawstat
C'est-à-dire lire chaque case, une à une, même si elle est vide, pour dessiner une tile. après avoir entré dans la liste les coordonnées. Bref. C'est long, sale et un peu bulldozer.
Un génie de Naheulbeuk a écrit :
Baston !
J'avais prévu de faire entrer toutes les données chiffrées dans une chaîne (Str 1) plutôt que dans une matrice(qui est d'ailleurs lourde) pour pouvoir exploiter les fonctions StrSrch, StrMid, etc. Il est tout à fait possible de passer d'une chaîne à une expression numérique, donc ce point ne pose pas problème. Qu'en pensez-vous ? L'idée peut-elle être exploitée ou est-elle incohérente ?
Les tiles en eux-mêmes :Résolu
Cliquer pour enrouler
Je cherche le bonne taille de tiles à prendre. J'avais pensé à utiliser des tiles de 10*10. Chacune de mes maps feraient alors 6*11 cases. Y a-t-il une taille préférable à 10*10 ? Qu'en pensez-vous ? Je ne sais quoi en penser. Je vais rencontrer un autre problème : le stockage de données. Avec les listes, je me demandais si une seule liste avec des coordonnées complexes est plus légère que deux listes pour les abscisses et ordonnées séparées. La différence est-elle notable ? Si oui, ça m'arrangerait bien pour ce que je pensais faire :
Il serait possible que j'exploite la technique Augment( pour dessiner tout d'une traite avec le Graph(X ; Y)=. Cette technique étant très gourmande en mémoire sur l'instant, je pourrais effectuer l'opération plusieurs fois. Mais ça serait assez confortable de pouvoir mettre :
Dim List 1→Tθmax
Graph(X;Y)=(ReP List 1[T];ImP List 1[T
J'aimerais votre avis là-dessus !
Le moteur de combat :
Alors là, j'ai pas mal réfléchi. Sur le modèle de fonctionnement Poule/Renard/Épervier, ou Feu/Eau/Plante dans Pokémon, j'ai l'intention de créer trois types d'attaque :
Puissance ,
Dextérité et
Vitesse.
Le personnage aura trois attaques pour chacun de ces types. Donc une animation différente pour chacun d'entre elle. Il maîtrisera en plus une capacité de soin, et peut-être une capacité secrète.
Il n'y aura pas de niveau à proprement dire : Selon les attaques qu'on emploie, la maîtrise dans la branche correspondante augmente et améliore les capacités du personnage : Force, Défense, Nombre de coups, précision, Esquive, etc.
Bon. Le souci, c'est que je vais devoir à dessiner des monstres et risque d'être limité sur ce point là.
Le personnage est en fait personnalisable. Au début du jeu, vous pourrez choisir une arme et une coiffe (lunettes de soleil, chapeau en pointe...) La machine génère alors sur plusieurs listes trois positions du personnage : une statique, une en tenant l'arme en l'air, une troisième en donnant le coup. Pour cela, je fais tourner l'arme, comme je l'ai évoqué dans ce
topic. ce point précis est résolu. C'est grâce à ses trois dessins pré-enregistrés que je ferai les animations. Une question se pose : comment faire des animations pour les monstres potables et peu spacio-phages ?
Voici à quoi ils ressemblent !
(photos expirées)
Pour le menu :
Pas encore d'idée, si ce n'est un truc enregistré sur une autre picture qui sera beau graphiquement parlant. On y verra l'état du personnage et son niveau de maîtrise dans chaque branche.
Pour l'interaction avec des pnj :
Résolu
Cliquer pour enrouler
Je projette de concevoir un sous-programme "lecteur de texte", si je puis dire. Sur la map, le programme dessinera une boîte de dialogue dans laquelle s'écriront les paroles d personnage. Pour ce point, je compte beaucoup m'inspirer des travaux de Remiweb sur son Zelda PC. J'ai trouvé ce point absolument remarquable et incroyablement bien fait.
Voici la tronche du projet. J'aimerais vraiment avoir vos avis, savoir ce que vous en pensez, avoir de vos précieux conseils et surtout engager le débat pour progresser. Je vous remercie d'avance, et vous remercie aussi de m'avoir lu jusque là.
État des lieux du projet
modifié le 20 09 2018
À ce jour, voici ce qui est fait et ce qui reste à faire pour l'ensemble du programme de jeu.
Graphismes (personnages, monstres, background, carte du monde, title screen...)
Comme vous pouvez le voir, il reste beaucoup de travail.
Le plus difficile sera de faire tenir tout le jeu en ~ 60 000 octets. Seulement, je ne parle pas du programme seul : à présent, il ne fait que 6772 octets. Toutefois, les Pictures prennent déjà 11404 octets (avec y compris les 6072 octets des trois pictures du mon système de sauvegarde de map, et les list peuvent atteindre les 7000 octets. Actuellement, il me reste quelque chose comme 36 000 octets de libres pour faire TOUT LE RESTE.
Le jeu en quelques questions
modifié le 08 06 2018
Que sont les Poudingues ?
Les poudingues sont des petites créatures sans bras ni jambe, au corps semblable à un mélange entre une balle d'arme à feu et un pudding. Leur visage est expressif et ils déterminent généralement leur appartenance sociale par leur couvre-chef.
Quel est le but du jeu ?
Vous incarnez un de ces fameux Poudingues, vivant au sein d'un royaume dirigé par un monarque Poudingue. En tant qu'Explorateur, vous êtes convoqué par le roi lui-même pour vous confier une mission : localiser le repaire des poudingues anti-royalistes qui semblent préparer une révolte dans l'ombre...
Quel type de jeu ?
Aventura, le royaume poudingue est un RPG / jeu d'exploration. Vous devrez, pour une partie du jeu, explorer des terrains, trouver les pnj à qui parler pour faire avancer l'histoire, etc. Durant le jeu, vous devrez aussi affronter les monstres sauvages ou bien les opposants qui se dresseront sur votre chemin ! Au fil des luttes, vous affinerez votre style de combat, renforcerez vos spécialités et augmenterez votre niveau et vos caractéristiques.
Quelles caractéristiques et quel système de combat ?
Le système de combat est à priori un système au tour à tour, en un contre un de profil sur l'écran.
Un poudingue possède trois caractéristiques, avec un niveau de maîtrise pour chacune d'entre elle : Puissance, Technique, Vitesse. En fonction des attaques employées par le poudingue, ses niveaux de maîtrise correspondant augmentent. Lors d'une montée de niveau, chaque caractéristique augmente proportionnellement à son niveau de maîtrise. Utilisez beaucoup de fois l'attaque « Cogne » et votre puissance avancera davantage ! Votre type est ensuite déterminé par la valeur la plus élevée des trois caractéristiques : type Puissance, type Technique, type Vitesse, ou bien Neutre si vos caractéristiques sont équilibrées.
Ces trois types fonctionnent selon une règle similaire au jeu Pierre-Feuille-Ciseaux. Le type Puissance a l'avantage face au type Vitesse, le type Vitesse a l'ascendant sur le type Technique et le type Technique est plus efficace contre le type Puissance. Ce rapport de force se détermine dans le calcul des dégâts infligés, qui sont en pourcentage. Autrement dit, le joueur a 100% de vitalité et meurt s'il tombe à 0%. Le nombre maximal de vitalité ne change pas, il est de 100% pour tout le monde.
À priori, le niveau maximal atteignable serait de 100. Le système de calcul d'expérience n'est pas encore établi.
Les trois caractéristiques interviennent donc dans le calcul des dégâts en fonction du type de l'attaque. La caractéristique du lanceur correspondant au type de l'attaque et la caractéristique de la cible correspondant au type ayant l'ascendant sur celui de l'attaque sont pris en compte dans le calcul des dommages. Exemple : le joueur utilise une attaque Vitesse sur une cible de type Technique. La caractéristique Vitesse du joueur et la caractéristique Puissance de la cible seront pris en compte. Un facteur de dégâts accru s'appliquera sur les dommages totaux puisque le type Technique est faible face aux attaques Vitesse. Au final, si le lanceur a beaucoup de Vitesse et la cible peu de Puissance, l'attaque infligera de lourds dégâts.
Les niveaux de maîtrise augmentent aussi l'efficacité des attaques suivantes : Cogne, Estoc, Rafale. À partir de certains seuil, les niveaux de maîtrise donnent de nouveaux effets / bonus à ces attaques. Il peut donc sembler intéressant de se spécialiser dans un type pour améliorer ses attaques.
Les sorts, quant à eux, n'augmentent pas les niveaux de maîtrise lors de leur utilisation. Si un sort peut s'avérer plus efficace qu'une attaque classique, il ne permettra pas à son utilisateur de bien progresser sur le long terme.
Un aperçu du moteur de combat, le 09 07 2018 (V - 0.21)
Un aperçu du moteur de dialogue, le 21 07 2018 (V - 0.22)
L'Éditeur de mappemonde, 08/2018.Un autre aperçu du moteur de combat, le 08 08 2018 (V - 0.24)
Phase 1 : Écriture. Cette étape consiste à coucher sur le papier ce que je projette de faire, le gameplay et les composants du jeu, dans un idéal. Je ne m'occupe pas tant de savoir si ça tiendra dans le code, ni de savoir si j'aurais le temps et/ou la motivation d'en faire autant. J'essaye d'en écrire le plus possible, dont le scénario avec le plus de détails possible, les personnages, etc.
Phase 2 : Architecture générale. Il s'agit de hiérarchiser les sous-programmes, menus, et les chemins qui s'opèrent entre chaque. Dans cette partie, on ne s'occupe pas du code dans les détails, mais plutôt de « blocs » en tant qu'ensembles de fonctions. Par exemple, j'aurai un bloc « Title screen », un bloc « dessin map », un bloc « dialogue », etc. Il s'agira de définir avec une certaine précision les blocs qui interviendront pour le fonctionnement du jeu, d'estimer si possible leur taille et de les positionner les uns par rapport aux autres, les cheminements de sous-programmes à sous-programmes – sachant qu'on ne peut pas avoir plus de 10 sous-programmes qui tournent à la fois.
Phase 3 : Code. Écriture du code à l'intérieur de chaque bloc, avec seulement quelques données à titre d'exemple. Il ne s'agira pas de faire du bô graphisme ou bien pleins de sprites et de pictures différentes. L'objectif ici est de fabriquer rapidement quelques éléments de dialogue et de graphisme pour pouvoir écrire tout le code qui fera fonctionner le jeu et qui agira comme un squelette. De beaux graphismes sont inutiles si le code sous-jacent n'est pas fonctionnel. J'ai eu tort de commencer à faire des maps et des pictures, mais elles sont là et je ne vais pas les gâcher.
Il me faudra alors écrire de façon individuelle et séparée chaque « bloc » ou « fonction » pour m'assurer que leur fonctionnement propre est opérationnel. C'est aussi l'occasion de revoir certaines ambitions à la baisse si elles demandent trop de place dans le code. Cette partie ne constitue pas l'intégralité de l'écriture du code, loin de là. La phase 4 y occupera une place importante aussi.
Phase 4 : Mise en relation et assemblage des blocs. Cette partie sera délicate, mais aura été largement anticipée avec la phase 2. Il s'agit non plus de faire fonctionner des pièces détachées, mais de les assembler et de penser avec ingéniosité leur articulation pour que le jeu devienne une seule entité. Cette phase comprendra vraisemblablement des modifications à l'intérieur même de chaque bloc pour d'éventuelles optimisations. Il y aura naturellement de nombreux tests et essais quant au bon fonctionnement de l'ensemble de la structure.
Phase 5 : Travail de « remplissage ». Si le squelette du jeu est tout à fait opérationnel et ne présente pas de bug, on passe à cette phase qui consiste à remplir le jeu de son contenu : les graphismes, les maps, les dialogues. C'est donc à ce moment que je m’attellerai activement à la conception des graphismes du jeu et à ses dialogues. Cette phase porte bien son nom puisqu'elle devra également être modulée en fonction de la place restante en mémoire dans la calculatrice.
Phase 6 : Optimisations, essais et tests du jeu intensifs. Cette phase vise à repérer les éventuels défauts dans le code du jeu, mais aussi dans le gameplay. C'est une phase très importante car elle vise à rendre le jeu jouable, appréciable et source de plaisir (oh yeah baby), mais aussi cohérent dans son ensemble. Elle contiendra donc beaucoup de recorrections et peut-être même de frustration chez le concepteur (moi) qui constatera que son jeu est tout pourri.
Phase 7 : Publication. Une fois que les corrections, tests, optimisations et finitions sont finis, il ne me reste plus qu'à publier une version 1.0 (ou Bêta) du jeu et attendre des retours de la communauté, qui sera sans doute enthousiaste de voir un jeu sortir après plus de deux années d'attente, lôl. En fonctions des retours, des finitions et des ajouts auront peut-être lieu pour donner suite à une version 1.1, 1.2, etc. L'objectif sera donc de corriger les éventuels bugs qui seraient passés inaperçus, et prendre en compte des suggestions pour améliorer l'expérience de jeu.
Phase 8 : Supplication. Demander à ce que le jeu jouisse du label de qualité Casio. C'est mon rêve. Je le veux. Au moins une fois dans ma vie !
Les suggestions de sorts par les membres de la communauté :
Lephenixnoir : « Pistole, Assaut, Regard perçant, Empalement, Illusion, Barrage, Retour de l'Hirondelle, Contournement, Vorpal, Survol, Coup ascendant, Berserk, Flèche ? »
Shadow15510 : « Boule de Feu (T) ». Woaw. Incroyable.
Membres ayant manifesté leur volonté d'apparaître dans le jeu :
Lightmare
Shadow15510
Cakeisalie5
Massena
Totoyo
Lephenixnoir
Math680
Git du projet : Soyez au plus près du code et des avancées des versions !
https://gitea.planet-casio.com/PlaneteCasio/Le_Royaume_Poudingue
Mis à jour le : 31/10/2018
Fichier joint
Citer : Posté le 25/06/2018 23:38 | #
Nemhardy, Zezombye, merci de vos réactions.
En fait, tous les objets n'ont pas forcément de propriété. Il n'y en a que quelques uns, à savoir ceux que je veux faire se déplacer avec l'appui d'un interrupteur.Dans un donjon, ça peut être une statue. Dans une forêt, un arbre. Etc.
L'idée de ZZ n'est pas bête. Un pnj a forcément un ID, donc à partir de là.... Le seul truc qui m'embête, c'est la vérification de la condition. En gros, tous les pnj sont regroupés, genre du tile numéro 32 au tile numéro 37 ou je ne sais plus quoi. Quand j'ai une parenthèse, c'est facile à vérifier. Quand je dois vérifier que j'ai à faire à un pnj, c'est moins simple. ça donne ça... (Avec Str 2 la chaîne de caractère contenant la map)
If StrSrc ( Str 2, "(" )
Then //gna gna gna
//Si je dois vérifier que c'est un pnj :
If StrCmp ( Str 2, "V-" ) = 1 And StrCmp ( Str 2, "b-" ) = -1
Then // gna gna gna
Après, sur un assez grand nombre de pnj, ça devient rentable, je pense.
Citer : Posté le 26/06/2018 12:37 | #
salut Drak ! j'ai pas mal joué à ton jeu ( qui est davantage un projet comme tu le dis )
... et il me plaît ! J'ai aussi vu que tu faisais une liste de membres de PC qui voudraient apparaître dans le jeu, comme elle est vide au moment où j'écris ce commentaire et que l'idée me plait ( ), j'aimerais bien avoir un personnage à mon nom ( tu le fais comme tu veux ).
Dijkstra - The Witcher
Citer : Posté le 26/06/2018 12:45 | #
Wouhou ! Ça fait plaisir, Lightmare ! Merci !
Je verrai comment je t'intègrerai au jeu. Il est fortement probable qu'un pnj porte ton nom. Je t'ajoute de ce pas dans la liste !
Citer : Posté le 26/06/2018 13:27 | #
Je suis également d'accord pour que mon pseudo figure dans ton jeu (enlève le "15510" : garde que Shadow )
Citer : Posté le 26/06/2018 13:32 | #
Hmmmmm............
Tu es juste "d'accord" ou tu le veux vraiment ?
Citer : Posté le 26/06/2018 13:36 | #
...
... Bon ok je le veux vraiment
Citer : Posté le 26/06/2018 13:41 | #
Très bien ! Je t'ai rajouté dans la liste !
Oh, et, petite précision...
J'AI MILLE POINTS !!! WOOOUUHHHH!!!
Citer : Posté le 26/06/2018 13:43 | #
J'avais pas vu... BRAVO
Attends moi j'y arrive
Citer : Posté le 26/06/2018 23:29 | #
Ben moi j'en ai 741. Et j'en fais pas un fromage. Râpé.
C'était le message utile de la journée.
Citer : Posté le 27/06/2018 15:05 | #
J'ai besoin de votre avis sur autre chose. Comment feriez-vous pour stocker les informations sur les attaques en combat ?
Je m'explique. Ce que j'envisage vaguement, pour le moment, c'est d'avoir une variable (un booléen) du genre Joueur, qui m'indique si c'est le joueur qui attaque ou si c'est le monstre. Ensuite, il y aurait un ID pour définir l'attaque utilisée. C'est l'idée que j'ai :
If A = 1 //Attaque "Poing danlaggle"
Then "Poing danlaggle"→Str 5
// Animation prenant en compte le booléen Joueur
// Calculs prenant en compte le même booléen
IfEnd
If A = 2
Then //Attaque "GNU is not ta mère"
Etc.
Text 1, 8, "Machin lance " + Str 5 + " !"
Auriez-vous moyen de m'aiguiller un peu ?
Citer : Posté le 27/06/2018 17:25 | #
Pour le text 1,8
je mettrai plutôt :
//au début de ton programme
"Bisounous"→Str 1
//Tu met les noms des monstres dans des chaînes de caractères
//Quand le monstre Bisounours attaque tu met juste
Text 1,8,Str 1+"lance"→Str1
Pour chaque monstre tu peux utiliser une matrice
Chaque colonne représente un monstre
Mat A [1,1]=1 C'est un monstre
Mat A [1,1]=0 Ce n'est pas un monstre (mais un ennemis quand même)
Mat A [1,1]=2 C'est un PNJ
Mat A [2,1] Ça pourrait être l'ID de l'attaque
Citer : Posté le 01/07/2018 15:30 | #
@Shadow : Ouaip, je pensais à la même chose pour l'histoire des Str.
Pour la matrice je n'en vois pas trop l'intérêt. Peut-être ne l'as-tu pas compris : J'ai prévu de n'avoir que du Un contre un. Autrement dit, il n'y aura toujours qu'un seul monstre !
Autrement, j'ai un souci que je peine à résoudre. Si vous avez du temps à perdre, vous êtes la bienvenue.
Voici un bout de code :
"" -> Str 5
For 0 -> A To 8
Not MOD(A, 3 => RanInt#(1, 3 -> B
Dsz B
StrJoin(Str 5, "□") -> Str 5
Not B => StrJoin(Str 5, "■") -> Str 5
Locate 9 + MOD(A, 3), 5 - Int (A / 3), StrMid(Str 5, A + 1, 1)
Next
1 -> P
For 400 -> A To 1 Step -1
Locate 1, 1, A
GetKey
If Ans : Then -.1Ans + 2 + 31Frac (.1Ans -> B
B > 9 Or B < 1 => Break
If StrCmp(StrMid(Str 5, B, 1), "□") : Then StrLeft(Str 5, B - 1) + "□" + StrRight(Str 5, 9 - B) -> Str 5
Locate 9 + MOD(B - 1, 3), 5 - Int ((B - 1) / 3), "□"
Isz P
Else
Break
IfEnd
IfEnd
Locate 1, 6, Not StrSrc(Str 5, "■")
If Not StrSrc(Str 5, "■") :Then
Break
IfEnd // s'écrit en une ligne mais c'est pas grave
Next
Locate 8, 7, Str 5◢
IfEnd
Laissez-moi vous expliquer. Ce bout de code est un genre de mini game où le joueur doit appuyer sur trois des neuf touches numériques de la calculatrice. En gros, l'écran affiche quelque chose comme ceci :
□□■
□□■
Et, le plus rapidement possible, le joueur doit appuyer sur les touches correspondant aux carrés noirs, qui redeviennent blancs à l'appui d'une touche. Dans cette situation, le joueur devra appuyer sur les touches 3, 6 et 7. S'il se trompe, on sort de la boucle et l'attaque foire.
Le truc, c'est que dès que j'appuie sur une touche correcte, on sort quand même de la boucle et ça m'arrache les fesses parce que je peine à trouver pourquoi. Je vous mets le même code ci dessous, commenté.
"" -> Str 5
For 0 -> A To 8 // cette boucle sert à remplir Str5 de 6 carrés blancs et 3 carrés noirs. Remarquez la finesse de l'utilisation du Dsz B.
Not MOD(A, 3 => RanInt#(1, 3 -> B
Dsz B
StrJoin(Str 5, "□") -> Str 5
Not B => StrJoin(Str 5, "■") -> Str 5
Locate 9 + MOD(A, 3), 5 - Int (A / 3), StrMid(Str 5, A + 1, 1) // J'affiche chaque carré pour avoir un "tableau" de 3 * 3 cases
Next
1 -> P // la variable dont je me sers pour définir la puissance finale de l'attaque
For 400 -> A To 1 Step -1
Locate 1, 1, A // A me sert de "timer"
GetKey
If Ans : Then -.1Ans + 2 + 31Frac (.1Ans -> B // Cette ligne un peu barbarre récupère la valeur des touches pressées de 1 à 9 à partir du Getkey.
B > 9 Or B < 1 => Break // si le joueur a appuyé sur d'autres touches, on sort plutôt que de provoquer une erreur.
If StrCmp(StrMid(Str 5, B, 1), "□") : Then StrLeft(Str 5, B - 1) + "□" + StrRight(Str 5, 9 - B) -> Str 5
Locate 9 + MOD(B - 1, 3), 5 - Int ((B - 1) / 3), "□"
Isz P // le joueur a appuyé sur une touche correcte ; P augmente et on continue.
Else
Break // Le joueur a fait de la merde et la case correspondante était déjà blanche. On sort.
IfEnd
IfEnd
Locate 1, 6, Not StrSrc(Str 5, "■") // Ligne qui me sert pour le debug. S'il n'y a plus de carré noir, égale zéro.
If Not StrSrc(Str 5, "■") :Then // le joueur a appuyé sur les trois touches correspondant aux carrés noirs.
Break
IfEnd // s'écrit en une ligne mais c'est pas grave
Next
Locate 8, 7, Str 5◢ // pour le debug également.
IfEnd
Donc, le délire, c'est que quand j'appuie sur une touche dont la case correspondante est noire, ça sort direct de la boucle sans demander son reste. Et ce n'est pas ce que je veux.
Citer : Posté le 01/07/2018 15:36 | #
Je vous rappelle que les strings peuvent contenir jusqu'à 255 caractères, donc une méthode très optimisée consiste à les utiliser comme ceci :
// On met les nom des monstres (ou attaques)
"BulbizarrePikachuRatata"→ Str 1
"Boule de feuTonnerre"→Str 2
// On indique dans des listes (ou une matrice, à voir) les positions des noms dans la chaine
{1, 11, 18, 25} → List 1
{1, 13, 21} → List 2
// Utilisation
3→A // ID du monstre
1→B // ID de l'attaque
// On utilise StrMid pour récupérer ce qui nous intéresse
StrMid(Str 1, List 1[A], List 1[A+1]-List 1[A]) + " lance " + StrMid(Str 2, List 2[B], List 2[B+1]-List 1[B])→Str 3
// On affiche
Text 1, 1, Str 3
Je sais plus comment sont calculés les X caractères à récupérer avec StrMid, y'a peut-être un +1 ou -1 à ajouter au calcul de la longueur de chaine.
C'est un peu lourd au niveau de la syntaxe, mais ça permet de stocker beaucoup de noms dans peu d'espace, et d'éviter les successions de If dues à l'usage des strings.
Ajouté le 01/07/2018 à 15:45 :
Là t'as le coup classique de la boucle qui va trop vite. C'est même écrit dans les commentaires : // Le joueur a fait de la merde et la case correspondante était déjà blanche. On sort.
Mets une variable mémoire pour éviter le comportement : If Ans And Ans ≠ Old
Ajouté le 01/07/2018 à 15:50 :
Le code corrigé :
"" -> Str 5
For 0 -> A To 8 // cette boucle sert à remplir Str5 de 6 carrés blancs et 3 carrés noirs. Remarquez la finesse de l'utilisation du Dsz B.
Not MOD(A, 3 => RanInt#(1, 3 -> B
Dsz B
StrJoin(Str 5, "□") -> Str 5
Not B => StrJoin(Str 5, "■") -> Str 5
Locate 9 + MOD(A, 3), 5 - Int (A / 3), StrMid(Str 5, A + 1, 1) // J'affiche chaque carré pour avoir un "tableau" de 3 * 3 cases
Next
1 -> P // la variable dont je me sers pour définir la puissance finale de l'attaque
For 400 -> A To 1 Step -1
Locate 1, 1, A // A me sert de "timer"
GetKey→G
// Si on a un Getkey et qu'il est différent du dernier
If G And G≠O : Then -.1G + 2 + 31Frac (.1G -> B // Cette ligne un peu barbarre récupère la valeur des touches pressées de 1 à 9 à partir du Getkey.
B > 9 Or B < 1 => Break // si le joueur a appuyé sur d'autres touches, on sort plutôt que de provoquer une erreur.
If StrCmp(StrMid(Str 5, B, 1), "□") : Then StrLeft(Str 5, B - 1) + "□" + StrRight(Str 5, 9 - B) -> Str 5
Locate 9 + MOD(B - 1, 3), 5 - Int ((B - 1) / 3), "□"
Isz P // le joueur a appuyé sur une touche correcte ; P augmente et on continue.
Else
Break // Le joueur a fait de la merde et la case correspondante était déjà blanche. On sort.
IfEnd
IfEnd
Locate 1, 6, Not StrSrc(Str 5, "■") // Ligne qui me sert pour le debug. S'il n'y a plus de carré noir, égale zéro.
If Not StrSrc(Str 5, "■") :Then // le joueur a appuyé sur les trois touches correspondant aux carrés noirs.
Break
IfEnd // s'écrit en une ligne mais c'est pas grave
G→O // On récupère la dernière valeur du Getkey en mémoire
Next
Locate 8, 7, Str 5◢ // pour le debug également.
IfEnd
Citer : Posté le 01/07/2018 15:53 | #
Super idée, DS ! Mais je suis sûr qu'on peut se simplifier la tâche si on utilise des séparateur et qu'on se sert de la fonction StrSrc.
Voici ton code :
// On met les nom des monstres (ou attaques)
"BulbizarrePikachuRatata"→ Str 1
"Boule de feuTonnerre"→Str 2
// On indique dans des listes (ou une matrice, à voir) les positions des noms dans la chaine
{1, 11, 18, 25} → List 1
{1, 13, 21} → List 2
// Utilisation
3→A // ID du monstre
1→B // ID de l'attaque
// On utilise StrMid pour récupérer ce qui nous intéresse
StrMid(Str 1, List 1[A], List 1[A+1]-List 1[A]) + " lance " + StrMid(Str 2, List 2[B], List 2[B+1]-List 1[B])→Str 3
Je pense qu'on peut donc s'épargner l'utilisation de listes.
"Boule de feu_Tonnerre_GNU is not ta mere"→Str 2
Ensuite, l'utilisation est différente. Sachant que le StrSrc ne s'arrête qu'à la première occurrence trouvée, on peut peut-être...
"Boule de feu_Tonnerre_GNU is not ta mere"→Str 2
3→A // ID du monstre
4→B // ID de l'attaque
For 0 → C To A // pour le nom du monstre
StrShift(Str 1,StrSrc(Str 1, "_")) → Str 1
Next
//même principe pour les attaques.
Citer : Posté le 01/07/2018 15:55 | #
Le fait d'utiliser des listes permet d'avoir une complexité en O(1) et non en O(N). Si tes strings n'ont pas plus de 5 ou 6 noms ça ira vite, mais si tu montes à ~25 (pour des noms de 10 caractères), là ça risque de ramer un peu. À voir selon tes besoins
Ajouté le 01/07/2018 à 16:00 :
Sinon t'as la solution intermédiaire, en O(1) :
"Bulbizarre-Pikachu_Ratata×Salameche÷"→ Str 1
"Boule de feu-Tonnerre_"→Str 2
StrSrc(Str 1, StrMid(Str 20, A, 1)) → P // La position du début de chaine
StrSrc(Str 1, StrMid(Str 20, A+1, 1)) - P → L // La longueur de la chaine
StrMid(Str 1, P, L) → Str 3
Ça demande du débug, j'ai pas fait gaffe à l'ID n°1, aux ±1 de position et longueur, mais l'idée est là.
Citer : Posté le 01/07/2018 17:12 | #
Toute petite curiosité : est-ce que la syntaxe suivante :
est correcte ?
Ajouté le 01/07/2018 à 18:04 :
Edit : Non, ce n'est pas correct. Ne faites pas ça les enfants !
Alors, j'ai fait des essais de performances sur ma technique, celle avec les séparateurs.
Avec un total de 30 séparateurs contenus dans une Str, avec des noms qui font chacun 7 caractères, il faut entre 0.6 et 0.7 secondes pour aller chercher la dernière occurrence et afficher le texte à l'écran. Acceptable ? Reste à voir combien de temps ça va mettre avec les calculs en plus.
Pour afficher la 10ème occurrence, l'exécution est encore très rapide.
Ajouté le 01/07/2018 à 21:18 :
Je viens d'ouvrir le Git du projet. C'est une première pour moi !
Vous pourrez, je l'espère, y accéder ici : https://git.planet-casio.com/Drak/Le_Royaume_Poudingue
Citer : Posté le 01/07/2018 21:49 | #
Excellent le dépôt
Par contre, GG à BIDE, c'est sûr que ça change la vie
Citer : Posté le 01/07/2018 21:50 | #
Je n'aurais jamais fait ça sans BIDE ! Parfois j'ai l'impression de ne parler que de ça, mais franchement, c'est un super truc.
Citer : Posté le 02/07/2018 00:30 | #
Je m'en suis rendu compte en lisant le code sur la forge
Citer : Posté le 02/07/2018 01:40 | #
J'avance, j'avance, même à 1h30 du mat.
Je vous incite à jeter un œil au Git rajouté dans le topic. Beaucoup d'indications précises s'y trouvent.
Ensuite, j'en suis au point où je réfléchis à comment stocker les données des monstres. Les monstres ont chacun un ID (on pourrait même dire un UID ! ) et plusieurs caractéristique : une valeur de Puissance "ADN", Technique ADN, Vitesse ADN, ainsi qu'un niveau et un panel d'attaques utilisables. Les valeurs "ADN" sont en fait des valeurs qui définissent les caractéristiques finales en fonction du niveau. Ce sont les valeur de base, que je surnomme "ADN". Voici ce que j'ai imaginé :
If D = 0 : Then
{.1,5.03,2.08,10.08,12.15 -> List 6 //le sprite du monstre Dander
"Dander_675" -> Str 5 // Dans l'ordre : son Nom, puis les caractéristiques ADN de la Puissance, Technique et Vitesse.
IfEnd
If D = 1 : Then
// autre sprite -> List 6
"Epee hantee_ABC" -> Str 5 //Ici, Puissance ADN = 10 ; T ADN = 11... bref.
IfEnd
StrLeft( Str 5 , StrSrc( Str 5, "_")) -> Str 4 // le nom
//'Le calcul des caractéristiques est à définir.'
For 1->A To 3
StrSrc( Str 3, StrMid( Str 5, StrSrc( Str 5, "_") + A, 1 )) * List 7 [2-> List 7 [2 + A
Next
Citer : Posté le 02/07/2018 23:31 | #
Si tes nombres sont des entiers, tu peux les compresser dans une unique valeur
Typiquement 05071003→List 1[1], avec le monstre n°1 qui a pour caractéristiques 5, 7, 10, et 3. Je te laisse trouver et adapter l'algo selon tes besoin, c'est juste une histoire de divisions successives.