Faire un match-3 dans Construct 2 Block Movement

Dans la partie précédente de cette série, nous avons apporté des modifications mineures mais importantes à de nombreux systèmes que nous avons créés pour notre jeu Match-3. Avec ces améliorations mises en œuvre, nous allons maintenant nous remettre sur les rails et mettre en œuvre l’un des deux derniers systèmes majeurs du jeu: le système Block Movement..

Ce tutoriel vous guidera à travers tout le développement du système, ce qui permettra aux blocs de s'élever en haut de l'écran et couvrira également la création de tous les systèmes plus petits que nous devrons mettre en œuvre pour prendre en charge le système de mouvement. Bien que les sujets que je couvre dans ce tutoriel ne soient pas trop complexes, il reste encore beaucoup à faire - passons à la question..


Démo finale du jeu

Voici une démonstration du jeu sur lequel nous travaillons tout au long de cette série:




1. Déplacement des blocs

Avant de commencer à déplacer les blocs, nous devons apporter un léger changement aux événements qui génèrent les blocs. Aller au Système> Au début de la mise en page événement et changer le Y pour boucle pour aller de 0 à 3, au lieu de 0 à 7 comme il l'a fait à l'origine.

L'événement devrait maintenant ressembler à ceci:


La raison pour laquelle nous avons effectué ce changement est que nous souhaitons que le jeu commence avec moins de blocs à l'écran, afin qu'il ne se termine pas aussi rapidement lorsque nous ajoutons un Game Over dans le prochain didacticiel..

Ensuite, nous allons créer une variable qui représentera la vitesse des blocs:

Variable globale: Nom = Type de vitesse en cours = Valeur numérique = 0,2

Nous allons maintenant créer l'événement qui déplace réellement les blocs:

Evénement: Condition: Système> Intervalle toutes les X secondes (secondes) = Action CurrentSpeed: Bloquer> Déplacer selon l'angle de l'angle = -90 Distance = 1

L'événement devrait ressembler à ceci:


Si vous lancez le jeu après avoir ajouté cet événement, la première chose que vous devriez voir est que les blocs tombent, en raison de la gravité que nous avons implémentée dans un tutoriel précédent. Après cela, les blocs devraient augmenter lentement jusqu'à ce qu'ils soient dans leur position d'origine, puis retomber. Cela se répètera à l'infini tant que vous ne faites rien aux blocs.

Cela se produit parce que les blocs se déplacent au-delà du point où la gravité est censée entrer en action et découvrent qu’il n’ya pas de blocs sous ceux-ci, ce qui les fait tous tomber. Même s’il s’agit d’un problème, ce n’est pas le premier que je souhaite aborder..


2. Échange de fixation

Lancez le jeu et essayez de faire un échange de toute sorte. Lorsque vous faites cela, vous devriez voir que les blocs commencent à se coincer les uns derrière les autres, à rester coincés dans des positions qui ne sont pas alignées avec la grille et à se comporter généralement mal. Il y a deux raisons à ce problème.

Le premier problème est que, même si nous déplaçons les blocs eux-mêmes, nous ne déplaçons pas le LeftBlock, RightBlock, TopBlock, et BottomBlock objets avec eux, ce qui signifie que les blocs que vous utilisez pour détecter les échanges ne bougent pas avec la grille de blocs - ils sont simplement assis dans la position dans laquelle ils sont définis lorsque vous prenez un bloc pour la première fois.

Ainsi, lorsque vous essayez d'effectuer un échange, les blocs sont déplacés, car ils ne sont pas du tout adaptés à la grille. (C’est aussi la raison du deuxième problème que nous avons, à savoir que nous ne modifions pas les positions que nous avons stockées dans la mémoire. BlockPositions tableau soit.)

Le GIF ci-dessous illustre ce problème:


Comme vous pouvez le voir dans le GIF, les blocs de détection d’échange ne bougent pas, même si les blocs eux-mêmes sont.

Pour résoudre ces deux problèmes, nous allons ajouter quelques actions supplémentaires à l'événement que nous venons de créer:

Action: BottomBlock> Déplacer à l'angle d'angle = -90 Distance = 1 Action: LeftBlock> Déplacer à l'angle d'angle = -90 Distance = 1 Action: Verrou à droite> Déplacer à l'angle d'angle = -90 Distance = 1 Action: TopBlock> Déplacer à l'angle d'angle = -90 Distance = 1 Action: BlockPositions> Définie à XY X = 0 Y = 1 Valeur = BlockPositions.At (0,1) - 1 Action: BlockPositions> Définie à XY X = 1 Y = 1 Valeur = BlockPositions.At ( 1,1) - 1

L'événement devrait maintenant ressembler à ceci:


Les quatre premières actions que nous venons d'ajouter ont ajusté les positions du LeftBlock, TopBlock, RightBlock, et BottomBlock objets afin qu'ils restent alignés avec la grille de bloc. Les deux autres événements ajustent les valeurs Y que nous avons stockées dans BlockPositions tableau de sorte qu'ils restent également en ligne avec la grille de blocs.

Si vous testez à nouveau le jeu à ce stade, la permutation devrait être généralement résolue.

À ce stade, il reste un autre problème à résoudre pour que l’échange fonctionne correctement. Lancez le jeu et essayez d'effectuer un échange vers le bas avec l'un des blocs de la rangée du bas, alors que cette rangée se situe partiellement sous la zone du bas du champ de jeu:

Effectuez le swap lorsque les blocs sont derrière la bordure, comme ceux surlignés dans l'image ci-dessus.

Si vous avez fait cela correctement, vous devriez voir que rien ne s'est passé et les blocs ne sont pas échangés. Si vous avez attendu trop longtemps, les blocs ont peut-être été échangés car ils sont à nouveau passés au-dessus de la limite du terrain de jeu. Si cela se produit, réessayez une fois qu'ils tombent et vous devriez voir le problème se produire..

Ce problème est plutôt simple à résoudre et à comprendre. Si vous examinez le code pour les échanges vers le bas, vous devriez trouver l'événement que nous avons ajouté au didacticiel précédent, qui empêche le joueur d'effectuer des échanges vers le bas qui font que le bloc tombe du bas du champ de jeu. Depuis cette déclaration empêche le joueur de faire des échanges vers le bas lorsque le BottomBlock l'objet est plus bas que la position Y initiale du bloc, il empêche les blocs d'être échangés une fois qu'ils sont tombés et ne vous permet de les échanger qu'une fois qu'ils ont dépassé leur position d'origine.

Pour corriger cette affirmation, nous allons apporter une petite modification à la condition:

Condition: BottomBlock> Comparaison Y Comparaison = Coordonnée Y inférieure ou égale = SPAWNY + ((Block.Width + 2) / 2)

La condition devrait maintenant ressembler à ceci:


Cette modification signifie qu'un échange à la baisse ne peut avoir lieu que lorsque le BottomBlock l'objet commence au plus un demi-bloc sous la position Y. Cela signifie également que, une fois que nous commencerons à créer de nouvelles rangées de blocs et à les pousser sur l'écran à partir du bas, ces blocs ne pourront plus être échangés. De cette façon, une fois au moins la moitié du bloc est visible.

Nous allons également imposer une restriction similaire à tous nos événements de permutation pour nous assurer qu’ils deviennent tous utilisables en même temps et qu’un bloc ne peut pas être échangé du tout jusqu’à ce qu’au moins la moitié de celui-ci soit visible. Encore une fois, cela nous aidera également lorsque nous intégrerons le système qui générera de nouvelles rangées de blocs. Pour ce faire, nous allons ajouter une nouvelle condition à chacun des trois événements d'échange restants..

Les conditions que nous ajoutons seront exactement les mêmes que celle que nous venons de modifier dans BottomBlock événement, sauf qu'ils feront référence à la TopBlock, RightBlock, et LeftBlock objets au lieu de BottomBlock objet, en fonction de l'événement, il est en.

La nouvelle condition pour la TopBlock L'événement devrait être:

Condition: TopBlock> Comparaison Y Comparaison = coordonnée Y inférieure ou égale = SPAWNY + ((Block.Width + 2) / 2)

La nouvelle condition pour la LeftBlock L'événement devrait être:

Condition: LeftBlock> Comparaison Y Comparaison = coordonnée Y inférieure ou égale = SPAWNY + ((Block.Width + 2) / 2)

La nouvelle condition pour la RightBlock L'événement devrait être:

Condition: RightBlock> Comparaison Y Comparaison = coordonnée Y inférieure ou égale = SPAWNY + ((Block.Width + 2) / 2)

Votre ensemble Drop DragDrop L'événement devrait maintenant ressembler à ceci:


Avec ces nouvelles conditions en place, nous avons corrigé nos mécanismes d’échange et commencé à préparer les systèmes existants pour le prochain système que nous ajoutons: celui qui générera de nouvelles rangées de blocs..


3. Générer plus de blocs

Maintenant que les blocs avancent à un rythme constant, nous devons faire apparaître les nouvelles rangées de blocs au bon moment et permettre au joueur de continuer à jouer aussi longtemps qu'il le souhaite. Nous allons utiliser une fonction pour générer les nouvelles lignes de blocs, et nous allons utiliser un événement qui détecte quand les blocs sont alignés avec SPAWNY pour déclencher cette fonction.

Alors tout d'abord, faisons la fonction elle-même.

Événement: Condition: Fonction> Fonction activée Nom = "SpawnNewBlocks" Condition: Système> Pour Nom = "X" Début Index = 0 Fin Index = 7 Action: Système> Créer un objet Objet = Bloc Calque = 1 X = SPAWNX + (loopIndex ( "X")) * (Block.Width + 2) Y = SPAWNY + (Block.Width + 2) Action: Bloquer> Définir la valeur Instance Variable = Couleur Valeur = floor (Aléatoire (1,7)) Action: Système> Ajouter to Variable = NumBlocks Value = 1

Votre nouvel événement devrait ressembler à ceci:


Lorsqu'elle est utilisée, cette fonction créera une rangée de blocs sous la dernière rangée de blocs dans le champ de jeu. Dans l'état actuel des choses, nous n'utilisons cette fonction à aucun moment. Nous allons donc créer l'événement qui le fait:

Événement: Condition: Système> Toutes les X secondes Intervalle (secondes) = CurrentSpeed ​​Condition: Bloc> Comparaison Y Comparaison = Égal à Y = SPAWNY Condition: Inverser: Bloc> Fait glisser Action: Fonction> Appel fonction Name = "SpawnNewBlocks"

Votre nouvel événement devrait ressembler à ceci:


L'événement que nous venons de créer vérifie la position Y des blocs à chaque fois qu'ils sont déplacés. S'il trouve des blocs en ligne avec SPAWNY, il déclenche la SpawnNewBlocks () fonctionner comme nous avons discuté plus tôt. Il vérifie également que le bloc trouvé n'est pas celui que le joueur fait glisser..

Si vous testez votre jeu à ce stade, cela fonctionnera, mais vous devriez remarquer un problème étrange. Dès que vous commencerez le jeu, vos blocs tomberont comme s’il n’y avait pas de blocs en dessous d’eux, mais après cela tout fonctionnait parfaitement et de nouveaux blocs apparaissaient à tout moment..

Cela se produit parce que, lorsque le jeu démarre pour la première fois, il traite le code de gravité avant le code qui génère de nouvelles lignes de blocs. Pour résoudre ce problème, nous allons apporter un petit ajustement au code qui génère le groupe initial de blocs afin qu'ils soient générés en dessous du point où une nouvelle ligne serait nécessaire. Cela lui permet d'éviter d'exécuter le code de gravité immédiatement et de créer la nouvelle rangée de blocs une fois que les blocs existants sont au bon endroit..

Accédez à l'événement qui génère le groupe de blocs initial et modifiez l'action qui crée le bloc. Changez l'action en ceci:

Action: Système> Créer un objet Objet = Bloc Couche = 1 X = SPAWNX + (loopIndex ("X")) * * (Block.Width + 2) Y = SPAWNY - (loopIndex ("Y")) * (Block.Width + 2) + 5

L'événement devrait maintenant ressembler à ceci:


Cette modification signifie que les blocs apparaîtront cinq pixels plus bas. SPAWNY. Cela signifie que les blocs devront en fait monter cinq fois avant qu'une nouvelle ligne apparaisse et résolve notre problème..


4. Un peu d'animation

À ce stade, nos blocs se déplacent et de nouvelles lignes sont créées. De plus, rappelez-vous que nous avions précédemment empêché le joueur d'utiliser un bloc jusqu'à ce qu'au moins la moitié du bloc soit visible. Bien que ce soit une fonctionnalité intéressante, le joueur peut ne pas comprendre pourquoi un bloc ne peut pas être utilisé immédiatement lorsqu'il devient visible, même si une grande partie de celui-ci n'est pas visible à ce moment-là..

En raison de ce problème potentiel d'interface utilisateur, nous allons faire en sorte que chaque bloc utilise l'image-objet de bloc gris (au début des images d'animation du bloc) lorsqu'il est dans cet état inutilisable. Cela indiquera clairement au joueur quand un bloc deviendra utilisable, et cela nous donnera une chance d'utiliser enfin notre dernier bloc d'image..

Vous pouvez voir un exemple de ce à quoi ressemblera une fois les blocs inactifs, puis actifs dans le GIF ci-dessous:


L'événement que nous créons comportera également une deuxième condition qui vérifie que le bloc en question n'est pas déplacé. Cette condition nous permet de nous assurer que lorsque le joueur glisse un bloc en dessous du point où il devient utilisable, il ne changera pas d'image en gris, et restera la couleur qu'il est censé être..

Pour que cette animation fonctionne, nous devons d’abord ajouter un nouvel événement:

Événement: Condition: Bloc> Comparaison Y Comparaison = Supérieur à Y = SPAWNY + ((Block.Width + 2) / 2) Condition: Inverser: Bloc> Is Dragging Action: Bloc> Définir le cadre Numéro du cadre = 0

Le nouvel événement devrait ressembler à ceci:


Vous devriez maintenant pouvoir tester votre jeu et vous devriez voir que les blocs utilisent l'image grise lorsqu'ils se trouvent en dessous du point où ils deviennent utilisables..


5. Activer et désactiver le glisser / déposer

Si vous lancez le jeu maintenant, vous remarquerez que même si les blocs ne peuvent pas être échangés lorsqu'ils sont en gris, ils peuvent toujours être déplacés et manipulés. C’est parce que nous n’avons jamais désactivé les fonctionnalités de glisser / déposer du bloc lorsque nous avons empêché le lecteur d’échanger avec eux..

Pour éviter que les blocs gris ne puissent être déplacés, nous allons modifier l'événement que nous avons créé dans la section précédente. Nous allons d’abord ajouter une nouvelle action qui désactive le glissement lorsque le bloc est en dessous du point où il devient utilisable..

Ajoutez cette action à l'événement que nous avons créé précédemment:

Action: Bloquer (DragDrop)> Définir activé State = Disabled

Nous allons également ajouter une instruction Else pour cet événement, qui permet de déplacer le bloc à nouveau une fois qu'il est au-dessus du point où il devient utilisable:

Evénement: Condition: Autre Action: Bloquer (DragDrop)> Définir activé State = Enabled

Avec ces deux modifications, l'événement devrait ressembler à ceci:


Si vous testez le jeu à ce stade, les blocs ne devraient plus être utilisables quand ils sont gris, et devraient fonctionner de la même façon qu’ils le sont toujours quand ils ne le sont pas..


6. Changements de vitesse

La dernière chose que je veux aborder dans cet article est le système qui nous permettra de changer la vitesse du jeu au fil du temps. Plus précisément, c'est le système qui accélérera le déplacement des blocs à mesure que le joueur en éliminera plus.

Le système que nous allons créer est relativement simple: chaque fois que le joueur obtient un nombre de points, la vitesse du jeu augmente en fonction du modificateur que nous allons créer et du nombre de points que le joueur doit obtenir. la prochaine augmentation de vitesse changera en fonction d'un deuxième modificateur.

Avant de pouvoir commencer à créer les événements pour ce système, nous allons créer deux variables globales pour gérer les nouvelles fonctionnalités:

Variable globale: SPEEDMOD Type = Nombre Valeur initiale = 0,8 Constante = Oui Variable globale: PointsForSpeedUp Type = Nombre Valeur initiale = 400 Constante = Non Variable globale: PointsBetweenSpeedUps Type = Nombre Valeur initiale = 400 Constante = Non Variable globale: POINTSFORSPEEDUPMOD Type = Numéro initial valeur = 1,4 constante = oui

Vos nouvelles variables devraient ressembler à ceci:


Maintenant que nous avons les variables en place, je vais expliquer ce que chacun fait.

  • SPEEDMOD est la variable sur laquelle nous allons multiplier la vitesse pour la modifier chaque fois que le joueur atteint le nombre de points dont il a besoin pour provoquer une augmentation de sa vitesse.
  • PointsForSpeedUp est le nombre de points dont le joueur a besoin pour atteindre la prochaine vitesse.
  • PointsEntreSpeedUps représente combien le PointsForSpeedUp variable augmentera lorsque le joueur aura atteint une vitesse supérieure, pour l'ajuster de sorte que la vitesse suivante prenne encore plus de points. En ce moment il est 400, comme PointsForSpeedUp, mais lorsque le joueur obtient réellement une vitesse, il sera multiplié par POINTSFORSPEEDUPMOD avant qu'il soit ajouté à PointsForSpeedUp.
  • finalement, POINTSFORSPEEDUPMOD est la variable que nous allons utiliser pour modifier le nombre de points que le joueur doit obtenir pour augmenter sa vitesse une fois de plus que celui qu’il a obtenu récemment.

En plus de configurer les variables, nous devons également créer un nouvel objet sprite qui servira d’alerte pour le joueur lorsque la vitesse augmente..

Aller à Disposition 1 et suivez ces étapes pour créer le nouveau sprite:

  1. Insérer un nouveau Lutin objet sur Disposition 1.
  2. Avec l'éditeur d'animation, ouvrez l'image SpeedIncImage.png.
    1. Met le prénom à SpeedIncreaseIndicator.
    2. Met le Couche à Terrain de jeu.
    3. Met le Position à 188, 329.
    4. Ensemble Visibilité initiale à Invisible.
      1. Ajouter un Fondu Comportement au Sprite.
      2. Ensemble Actif au début à Non.
      3. Met le Temps de fondu à 2,5.
      4. Ensemble Détruire à Non.

Votre mise en page devrait maintenant ressembler à ceci:


Nous allons maintenant créer l’événement qui modifie la vitesse:

Événement: Condition: Fonction> Fonction activée Nom = "CheckForSpeedUp" Condition: Système> Variable de comparaison Variable = Comparaison de scores = Valeur égale ou supérieure = Valeur de PointsForSpeedUp: SpeedIncreaseIndicator> Définir la visibilité visible = Visible Action: SpeedIncreaseIndicator> Démarrer le fade Action Système> Définir la valeur Variable = CurrentSpeed ​​Valeur = CurrentSpeed ​​* Action SPEEDMOD Système> Valeur définie Variable = PointsBetweenSpeedUp Valeur = PointsBetweenSpeedUp * POINTSFORSPEEDUPMOD Action: Système> Ajouter à la variable = PointsForSpeedUp Valeur = PointsBetweenSpeedUp

Votre événement devrait ressembler à ceci:


Lorsque cette fonction est appelée, il vérifie si le joueur a marqué suffisamment de points pour justifier une augmentation de sa vitesse. Si oui, alors:

  • il active le sprite qui indique au joueur que la vitesse a augmenté en le rendant visible et en démarrant le fondu
  • il augmente la vitesse en le multipliant par le modificateur
  • il détermine le nombre de points nécessaires avant la prochaine accélération, et
  • il ajoute cette valeur au nombre total de points que le joueur devra avoir avant que la vitesse n'augmente à nouveau.

Avec cette fonction terminée, nous devons simplement nous assurer qu’elle est appelée. Aller au Give Points () fonction et ajoutez cette action à la fin de l'événement primaire et du sous-événement:

Action: Fonction> Appeler la fonction Nom = "CheckForSpeedUp"

le Give Points () la fonction devrait maintenant ressembler à ceci:


Une fois cet événement terminé, vous devriez pouvoir tester votre jeu et voir le système d'accélération en action..

Pointe: Tandis que je jouais plus avec elle, j'ai trouvé que ces valeurs étaient un peu décalées. Je vous suggère donc de prendre le temps de tester le système et de trouver les valeurs avec lesquelles vous vous sentez le plus à l'aise..


Conclusion

Nous avons abordé de nombreux sujets dans cet article, mais tout ce que nous avons traité était directement ou indirectement lié au fait que le système de circulation fonctionne comme nous le souhaitions. Cela a pris un certain temps et nous a obligés à créer plus de systèmes que nous ne l'aurions anticipé au début, mais le gain en valait la peine et nous avons finalement abouti à un système très fort..

En raison de tout ce que nous avons déjà couvert, je pense que c’est un bon endroit pour terminer cet article. Le prochain article devrait être le dernier tutoriel de cette série et nous allons couvrir beaucoup de sujets plus petits, mais la chose la plus importante que nous couvrons est sans aucun doute l’élimination des correspondances préparées à l’avance..

Si vous voulez commencer à essayer de trouver comment nous allons les éliminer, regardez comment nous détectons les correspondances pour commencer. Le système que nous créons sera très similaire à ce système, à la différence qu’il utilisera les correspondances qu’il trouve de manière différente. Commencez à y penser et voyez ce que vous pouvez imaginer. Je vous reverrai ici la prochaine fois pour le dernier tutoriel majeur de la série..