Avez-vous déjà entendu parler de Vampus? Quelle que soit la réponse - bienvenue dans son mandat!Dans cet article, je veux vous raconter mon histoire de création d'un jeu pour Android. Selon la compétence du lecteur, l'expérience, les réflexions et les décisions que je transmets seront plus ou moins utiles. Cependant, j'espère que mon histoire, au moins, sera intéressante.
Table des matières
1.
Introduction2.
Choix des fonds3.
L'idée du projet4.
JE SENTE UN WUMPUS5.
La base des bases - la structure du projet6.
Génération du labyrinthe de Vampus et travail avec lui7.
Stockage des messages du jeu et de leur sortie pour le joueur8.
Le premier résultat9.
Même les petits jeux sont dignes de l'histoire.10. La
transformation Vampus et le résultat final11.
Conclusion1. Introduction
Table des matièresTout d'abord, quelques mots sur vous. La programmation, malheureusement, n'est pas mon activité principale, mais je suis heureuse d'y consacrer mon temps libre.
Pour une raison quelconque, j'ai choisi la façon de créer des jeux mobiles. Mes projets précédents pour les appareils mobiles ont été créés dans l'environnement Qt en conjonction avec les langages QML et C ++. J'ai beaucoup apprécié ce trio, mais en analysant mes idées, j'ai réalisé qu'à l'avenir, il faudrait trop de temps et d'efforts pour résoudre certains problèmes avec les moyens que je connaissais. Par conséquent, en réfléchissant au prochain projet, j'ai décidé de trouver de nouveaux outils de développement plus adaptés et d'acquérir de l'expérience avec eux.
2. Choix des fonds
Table des matièresAuparavant, je ne faisais attention qu'à Android, et dans le nouveau projet, j'ai décidé de me concentrer sur ce système d'exploitation, de me familiariser avec Android Studio, qui en est originaire, d'essayer de nouveau Java pour moi-même (et à l'avenir, si vous l'aimez, promettant également Kotlin).
Je n'ai jamais utilisé AS ou Java auparavant, et j'ai été confronté à un gigantesque front de travail avec de nombreuses nouvelles tâches, et j'étais prêt à me lancer dans la bataille, il ne restait plus qu'à proposer un projet.
3. L'idée du projet
Table des matièresOn sait que le mieux, c'est que la formation se déroule sur des tâches réelles, et surtout celles qui l'intéressent. Pour moi, un tel projet de formation devait être un jeu pour lequel je formais un certain nombre d'exigences:
- Rejouer la valeur.
- La simplicité des mécaniques de jeu.
- Utilisation minimale des graphiques.
- Le gameplay devrait obliger le joueur à réfléchir.
- La partie de jeu ne devrait pas être longue.
- Mise en œuvre rapide du projet (2 mois).
- Simplicité et facilité de l'interface utilisateur.
Après avoir trié de nombreuses options et évalué objectivement mes forces, en me rappelant que peu importe le temps et les ressources alloués au début, en fait, beaucoup plus sera nécessaire, je suis arrivé à la conclusion qu'il vaut mieux prendre les classiques testés comme base de formation que d'inventer quelque chose qui leur est propre. Je ne voulais absolument pas créer un serpent conditionnel et j'ai commencé à étudier les vieux jeux. J'ai donc découvert le curieux Hunt the Wumpus.
4. JE SENTE UN WUMPUS
Table des matièresVampus Hunting est un jeu de texte classique inventé par Gregory Yob en 1972. La même année, il a reçu une description du jeu et du code source dans un article de magazine.
L'essence du jeu est l'étude par le joueur du labyrinthe de dodécaèdre, qui est la maison du vampire maléfique, et tente de deviner, sur la base des messages indicateurs affichés dans le journal de jeu, qui se trouvent dans les salles supérieures. En plus de Vampus lui-même (dégage une odeur désagréable), il y a des chauves-souris (du bruit est entendu) transportant le joueur dans une pièce aléatoire, et des piqûres (pénètre), frappées dans lesquelles mène à la fin de la partie. Le but du jeu est de tuer le Vampus, pour lequel le joueur a 5 flèches qui peuvent voler de 1 à 5 pièces à la fois (le joueur décide lui-même quel type de "force" pour faire le coup). Ainsi, le joueur a deux actions: tirer de l'arc, aller dans la salle. Le résultat dépendra de la part de chance et du degré de conscience.
En général, j'ai aimé la mécanique: c'est simple, mais en même temps avec des éléments de risque. Il n'y avait pas de jeux intéressants sur Vampus sur Google Play (sauf un nouveau jeu à cette époque dans le monde Lovecraft, dans lequel, comme je l'ai découvert plus tard, il était basé sur les mêmes mécanismes Vampus. Mais cet
article concerne la création d'un jeu sur Habré), il a donc été accepté la décision de prendre Vampus comme base. Je me suis fixé comme objectif de conserver le jeu classique, mais je le mets légèrement à jour et j'ajoute de nouvelles fonctionnalités.
5. La base des bases - la structure du projet
Table des matièresTout d'abord, j'ai appris les règles du jeu classique et me suis familiarisé avec diverses implémentations de Vampus. Ensuite, j'ai fait un schéma avec la logique du jeu (cliquable):
Au début, le schéma était utile, car Autorisé à analyser les mécanismes du jeu, à éliminer les défauts et à créer quelque chose qui leur est propre. De plus, ce schéma a été utile lorsque j'ai travaillé plus tard avec l'artiste pour expliquer l'essence du jeu.
J'ai divisé le projet en 4 parties, dans chacune desquelles différentes tâches ont été résolues. Je n'en donnerai que quelques-uns.
1. Mécanique du jeu- Sous quelle forme les informations sur le donjon seront-elles stockées?
- De quel type et de combien de variables avez-vous besoin?
- Écriture d'algorithmes: formation d'un donjon, vol de flèche, vérification du résultat du tir, vol de flèche avec une séquence de pièces incorrectement sélectionnée, déplacement d'un joueur, vérification d'une pièce lors du déplacement, déplacement d'un joueur avec des chauves-souris, etc.
- Comment afficher les informations dans le journal de jeu et dans quel ordre?
- Dans quel ordre vérifier la chambre?
2. UI- Quelles activités devraient figurer dans l'application? À quoi devraient-ils ressembler et quels éléments devraient y figurer?
- Quels paramètres peuvent être modifiés dans les paramètres?
- Ai-je besoin d'images dans le jeu?
- Quel devrait être en général le style de l'application (couleurs, ambiance, style de message)?
- Quelles polices utiliser?
3. Autre- Connectez-vous aux services Google Play
- Travailler avec des fichiers XML
- Quelles polices utiliser?
4. Écrire du texte pour le jeu- Messages du jeu
- Les règles
- Description du jeu pour Google Play
Il est plutôt inutile, plutôt qu'impossible, de tout décrire, donc je ne me concentrerai que sur certains points, après quoi je montrerai le premier résultat obtenu.
6. Génération du labyrinthe de Vampus et travail avec lui
Table des matièresLe Labyrinthe de Vampus est un dodécaèdre, qui peut être représenté comme une matrice
G de dimension 20x20. Nous numérotons les sommets de 0 à 19. Si l'élément de matrice est 1, il y a un passage entre les sommets (chambres), sinon, non.
Nous introduisons également la matrice
N de dimension 20x3, qui stocke les indices de voisins pour chaque pièce. Cette matrice accélérera le travail avec
G.Les matrices
G et
N sont cousues dans le code du jeu et ne changent pas (bien sûr, le stockage de
G est inutile, car vous ne pouvez travailler qu'avec
N , mais pour le moment, laissons cela de cette façon). Ce sont les «vrais» indices de sommet d'un dodécaèdre donné une fois pour toutes. Pour le joueur, des indices «jeu» sont formés, qui sont une sorte de masque des «vrais», en un vecteur
V de dimension 20 comme suit:
Ainsi, l'image suivante est obtenue:
Le vecteur V est formé à chaque nouveau jeu, ce qui donne au joueur un "nouveau" donjon.
Pour établir la correspondance entre l'index de salle «vrai» et «jeu», la méthode de conversion
indByNmb est utilisée:
public byte indByNmb(int room) { byte ind = -1; for (byte i = 0; i < V.length; i++) { if (V[i] == room) { ind = i; break; } } return ind; }
En entrée, la méthode
indByNmb obtient l'index "jeu" de la salle
room , et en sortie, elle donne l'
ind "true".
Après avoir généré la structure du donjon, nous plaçons: 2 troupeaux de chauves-souris, 2 trous, un Vampus et un joueur:
byte[] randomRooms = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; for (int i = 0; i < 20; i++) { int tmpRand = random.nextInt(20); byte tmpVar = randomRooms[i]; randomRooms[i] = randomRooms[tmpRand]; randomRooms[tmpRand] = tmpVar; } P = randomRooms[0]; W = randomRooms[1]; Pits[0] = randomRooms[2]; Pits[1] = randomRooms[3]; Bats[0] = randomRooms[4]; Bats[1] = randomRooms[5];
Un tel placement garantit qu'il n'y aura pas deux habitants dans une pièce et que le joueur ne sera pas jeté dans la pièce vers le Vampus dès le début.
La génération complète du donjon est la suivante:
Vous pouvez maintenant implémenter tous les algorithmes de la mécanique de jeu. Ainsi, par exemple, la sortie des salles voisines se produit lorsqu'un joueur
entre dans la salle avec l'index
currentRoom :
public void printNearRooms(byte currentRoom) { byte ind = indByNmb(currentRoom); appendText(V[N[ind][0]], V[N[ind][1]], V[N[ind][2]]); }
En entrée, la méthode
printNearRooms obtient l'index «jeu» actuel de la salle
currentRoom .
Considérez la mécanique d'un exemple. Laissez le joueur se déplacer dans une nouvelle salle et un message apparaît: "Maintenant, je suis dans la salle 8". Le nombre 8 est un indice de jeu. L'indice de pièce «vrai» est 6 (voir les captures d'écran ci-dessus). Le code fonctionne spécifiquement avec le «vrai» index, c'est-à-dire 6. Pour 6, les indices des «vrais» voisins sont déterminés: 2, 5, 7. Les «jeux», respectivement, seront: 10, 0, 7. Nous montrons le joueur dans le journal: «Je peux aller dans les salles 10, 0, 7».
Ainsi, en formant à chaque nouveau jeu le vecteur
V et en travaillant avec les index "vrai" et "jeu" du graphe du labyrinthe, l'apparence du fait que chaque jeu est unique est créée.
Grâce à la fonction
appendText, les messages sont affichés à un intervalle spécifié. Nous la rencontrerons plus tard.
Voici un exemple de vérification de la proximité de souris dans la pièce:
public boolean isBatsNear() { boolean answer = false; byte indP = indByNmb(P); for (int i = 0; i < 3; i++) { if ((V[N[indP][i]] == Bats[0]) || (V[N[indP][i]] == Bats[1])) { answer = true; break; } } return answer; }
7. Stockage des messages du jeu et de leur sortie pour le joueur
Table des matièresLe jeu classique était un processus d'interaction entre le joueur et la console, c'est-à-dire le jeu était purement textuel. Je voulais enregistrer cette fonctionnalité pour laquelle j'ai divisé tous les messages du jeu en blocs, par exemple:
- Le premier message du nouveau jeu.
- Un message quand un joueur bouge.
- Message à proximité des stands.
- Message lors du déplacement de Vampus.
- Message en tombant dans un trou.
Le texte est stocké dans un fichier XML. Chaque bloc a plusieurs options de message pour une variété de gameplay.
Un exemple de bloc de message qui s'affiche s'il y a un trou dans l'une des pièces voisines:
<string name="g_pitsNear_1">— \n</string> <string name="g_pitsNear_2">— \n</string> <string name="g_pitsNear_3">— \n</string> <string name="g_pitsNear_4">— , \n</string> <string name="g_pitsNear_5">— \n</string> <string-array name="g_pitsNear"> <item>@string/g_pitsNear_1</item> <item>@string/g_pitsNear_2</item> <item>@string/g_pitsNear_3</item> <item>@string/g_pitsNear_4</item> <item>@string/g_pitsNear_5</item> </string-array>
Avec cette structure, vous pouvez facilement modifier les messages existants ou ajouter de nouveaux messages sans affecter le code Java.
Si, par exemple, lors de la vérification de la salle, la méthode
isBatsNear présentée précédemment a renvoyé
true , nous obtenons le bloc de message requis à partir de XML, puis en prenons un au hasard comme argument pour
appendText :
if (isBatsNear()) { String[] g_batsNear = getResources().getStringArray(R.array.g_batsNear); appendText(g_batsNear[random.nextInt(g_batsNear.length)]); }
Les messages du jeu sont envoyés à la console, qui est un objet
TextView . Regardons la méthode
appendText .
public void appendText(final String str) { msgBuffer.add(str); if (!isTimerGameMsgWork) { mTimerGameMsg.run(); isTimerGameMsgWork = true; } }
Lorsqu'il devient nécessaire d'afficher un message de jeu, la méthode
appendText est
appelée , qui la prend comme argument. Dans la méthode elle-même, une ligne est d'abord ajoutée au tampon
msgBuffer . Ceci est suivi de la vérification de la variable booléenne
isTimerGameMsgWork . Il accepte
vrai dans les cas où le minuteur
mTimerGameMsg est
démarré . Lorsque cette minuterie fonctionne, puis à partir du tampon
msgBuffer, selon le principe FIFO (First In First Out), les messages sont
reçus à un intervalle spécifié
mIntervalGameMsg et ajoutés au journal du jeu -
txtViewGameLog .
Le code de sortie du message complet:
Code ArrayList<String> msgBuffer = new ArrayList<>(); Handler mHandlerGameMsg; private int mIntervalGameMsg = 1000; boolean isTimerGameMsgWork = false; public void appendText(final String str) { msgBuffer.add(str); if (!isTimerGameMsgWork) { mTimerGameMsg.run(); isTimerGameMsgWork = true; } } final Runnable mTimerGameMsg = new Runnable() { @Override public void run() { if (msgBuffer.size() == 0) { mHandlerGameMsg.removeCallbacks(mTimerGameMsg); isTimerGameMsgWork = false; } else { txtViewGameLog.append(msgBuffer.get(0)); msgBuffer.remove(0); mHandlerGameMsg.postDelayed(mTimerGameMsg, mIntervalGameMsg); } } };
8. Le premier résultat
Table des matièresAprès un mois de développement, la première version jouable du jeu avec des fonctionnalités entièrement implémentées a été reçue. Je joins des captures d'écran:
Captures d'écran de la première version du jeu Sur les captures d'écran présentées, vous pouvez voir: le menu principal, la fenêtre des règles, la fenêtre des paramètres, la fenêtre du jeu.
Bien sûr, j'ai compris que le résultat était complètement inintéressant. L'essentiel est que j'ai acquis une expérience pratique en AS et Java, ce qui était la première tâche.
Le joueur, comme dans le jeu classique, devait interagir via la console: saisir le numéro de la pièce à déplacer ou l'itinéraire de la flèche pour voler. Dans les paramètres, j'ai permis de changer la taille de la police et la transparence de l'arrière-plan. J'ai supposé que pour chaque fenêtre de jeu, il y aurait son propre fond d'image (afin de diversifier légèrement le gameplay, ha!).
Ensuite, j'ai prévu de remplacer les images existantes (que j'ai prises sans scrupule sur Internet) par celles que l'artiste dessinerait. Ensuite, je publierais le jeu sur le marché du jeu et l'oublierais en toute sécurité, en appliquant l'expérience acquise à de nouveaux projets. Et puis je ne pouvais pas imaginer combien Vampus pouvait changer ...
9. Même les petits jeux sont dignes de l'histoire.
Table des matièresQuand une personne vient travailler avec l'âme, le projet n'en profite que. J'ai eu la chance que l'artiste,
Anastasia Frolikova , se soit avérée être une telle personne. C'est-à-dire au lieu de simplement dessiner ce dont j'avais besoin, elle s'est intéressée au monde du jeu et voulait comprendre comment cela fonctionne. Et soudain, il s'est avéré que, dans l'ensemble, il n'y avait pas de paix! Qui est ce vampus? Et pourquoi un joueur devrait-il le tuer? À quoi ressemblent les salles Vampus? Et ainsi de suite, ainsi de suite, auquel je ne pensais pas et que je n'avais pas l'intention de dire au joueur. En conséquence, nous avons convenu que même un jeu aussi petit devrait avoir sa propre histoire. Et elle est apparue.
Selon notre légende, le Vampus, bien qu'ancien, mais pas une créature mythique maléfique qui aime se moquer des gens. Oui, il vit dans un labyrinthe, mais ce labyrinthe n'est pas sous la forme d'un donjon sombre classique, mais sous la forme d'une maison inimaginable composée d'un tas de pièces, dont le contenu caractérise Vampus. Ainsi, par exemple, dans une des salles il y a un cinéma, sur les murs duquel se trouvent des affiches de ses films préférés, et dans l'autre il y a son placard, où il prépare ses "farces".
Le joueur d'un chasseur sans nom est devenu un habitué du forum cryptozoologique qui veut prouver l'existence de Vampus. Nous avons remplacé l'arc et la flèche classiques par un appareil photo et un film, et le but du jeu n'était pas de tuer Vampus, mais d'obtenir sa photo. Soit dit en passant, le menu principal a été refait pour un forum où les gens discutent de Vampus, et à partir de la discussion, le joueur peut en apprendre davantage.
La première version du menu principal, réalisée sous forme de forum Quant aux autres aspects, ils sont restés quasiment inchangés: les souris agissent de la même manière, et entrer dans le trou a commencé à entraîner un crash, une panne de caméra et la fin du jeu (et non la mort du joueur).
Un autre moment sur la caméra. Dans le jeu classique, le joueur pouvait tirer une flèche dans une plage de 1 à 5 pièces et cela semblait logique. Nous avons un appareil photo au lieu d'un arc (prenant des photos de 1 à 3 pièces à la fois, mais fonctionnant comme une flèche classique qui frappe Vampus). Et ça ... ça a l'air bizarre, non? Il y avait une idée de réduire la portée de la caméra à 1 pièce afin que vous puissiez prendre des photos de la seule voisine, mais cela, d'une part, complique le jeu, et d'autre part, des situations peuvent être obtenues où le jeu ne peut pas être gagné, ce qui est faux. En général, c'est le moment qui me hante toujours personnellement, mais je n'ai pas encore trouvé de solution.
En ce qui concerne le style et l'humeur du jeu. Presque tous les jeux sur Vampus sont faits dans des tons gris ennuyeux, et les actions se déroulent dans des endroits sombres des donjons. Par conséquent, nous avons décidé que notre jeu devrait être différent de tout cela et être fait avec humour et dans des couleurs vives.
10. La transformation Vampus et le résultat final
Table des matièresEnsuite, 2 autres mois de travail sur le jeu nous attendaient. Puisque Vampus dispose de 20 chambres, chacune a son propre intérieur. De plus, des icônes de réalisations, des icônes du jeu ont été dessinées, des décisions sur la conception en général et l'interface utilisateur ont été prises. Le texte complet du jeu a également été ajouté, le code a été complété et optimisé, de nouvelles fonctions ont été ajoutées (par exemple, un bloc-notes est apparu pour enregistrer des informations pendant le jeu). En général, le Vampus a subi des changements majeurs.
Les salles, par exemple, ont été créées comme suit:

Il y a 20 salles, toutes uniques, et le joueur reçoit un "nouveau" labyrinthe à chaque partie. Comment rendre chaque nouvelle photo de jeu attachée à de nouvelles salles? La plus simple consiste à utiliser la même approche d'index "vrai" et "jeu":
public void changeImgOfRoom() { ImageView img = findViewById(R.id.imgRoom); int ind = indByNmb(P); String imgName = "room_" + ind; int id = getResources().getIdentifier(imgName, "drawable", this.getPackageName()); Glide.with(this) .load(id) .transition(DrawableTransitionOptions.withCrossFade()) .into(img); }
Les images de format carré (pour réduire la distorsion lors de la visualisation sur différents écrans) sont stockées dans des ressources portant les noms [room_0; room_1; ..., chambre_19]. Et ils sont, en fait, associés aux «vrais» indices du dodécaèdre, mais pour le joueur, chaque nouveau jeu pour la même pièce aura des images différentes. Pourquoi est-ce nécessaire? Afin de donner la possibilité dans une partie de jeu spécifique de corréler des informations textuelles avec l'image d'une pièce particulière ("ouais, je me souviens que dans la salle X, qui était le salon, il y avait un brouillon") et que cela n'a pas fonctionné "pourquoi est-ce toujours dans ma chambre X est la même image? " Tout pour la variété et aider le joueur (cependant, comme l'expérience l'a montré, il n'y a pas d'aide de la mémorisation visuelle, il est plus efficace de travailler avec du texte).
Finalement, nous avons eu une nouvelle version du jeu. Et tu sais quoi? Le vampus est devenu sacrément attrayant, et surtout, c'est toujours le même Vampus classique, mais dans une nouvelle maison confortable!
Captures d'écran de la deuxième version du jeu Sur les captures d'écran: le menu principal, la fenêtre des règles, la fenêtre des paramètres, la fenêtre du jeu.
En ce qui concerne la mécanique, elle n'est que légèrement modifiée et renommée (enfin, en fait, y a-t-il une différence: un appareil photo ou un arc, si vous avez besoin de faire la même chose?). Le changement le plus notable dans la mécanique est de simplifier le processus d'interaction entre le joueur et le jeu - l'entrée classique des numéros de pièce à l'aide du clavier a été supprimée. Maintenant, pour basculer entre les pièces, vous devez sélectionner 1 numéro sur 3 dans la fenêtre pop-up, et pour former le «parcours» pour la photographie, faites simplement défiler les roues du tambour:
Dans la vidéo ci-dessous, vous pouvez voir le résultat final:
11. Conclusion
Table des matièresLa première version du jeu a été reçue par moi dans un mois de développement, allouant 1 à 2 heures après le travail. En même temps, ni AS ni Java ne m'étaient auparavant familiers. La deuxième version du jeu a pris encore 2 mois. Ainsi, seulement 3 mois de travail tranquille.
Bien sûr, sous cette forme, le jeu n'est pas pour un large éventail, car cela peut sembler compliqué et pas excitant pour un joueur moderne, mais plus important encore, probablement, en gardant l'esprit des jeux classiques, ne trouvez-vous pas?
Suis-je satisfait du résultat? Certainement oui. J'ai acquis beaucoup d'expérience à la fois en programmation et en travail d'équipe. J'aime à la fois la mécanique résultante du jeu et sa composante visuelle. Y a-t-il quelque chose que j'aimerais changer? Bien sûr, il n'y a pas de limites à la perfection et vous pouvez toujours ajouter / améliorer quelque chose, mais vous ne pouvez pas le faire pour toujours!
Ce jeu est-il intéressant? Eh bien, ce n'est pas à moi de décider. Mais que Vampus soit à l'aise dans la maison que nous lui avons construite avec beaucoup d'amour et d'attention.
Je vous souhaite du succès!
Merci et attention à Vampus!
PS Les tâches qui surgissent constamment et la joie de les résoudre sont exactement ce que j'aime programmer. J'espère que vous n'obtiendrez pas moins de plaisir.