Catégories
LEGO Microgame Unity

Personnaliser sa minifig • LEGO Microgame

Le template LEGO Microgame propose 4 minifigures pour créer votre mini-jeu. Vous trouverez une astronaute, un aventurier, une pirate et un pizza boy.

Présentation des quatre minifigures de base proposé par LEGO Microgame

Ces personnages iconiques vous inspireront peut-être pour créer votre propre jeu LEGO, mais si vous aviez une idée précise en tête, il est possible qu’ils ne correspondent pas du tout au thème que vous imaginiez.

Dans cet article, je vous propose quelques solutions pour rendre votre mini-jeu unique à votre image !

Utiliser les add-ons

Pour avoir d’autres minifigures thématiques, le plus simple est d’utiliser les contenus additionnels proposés sur l’asset store de Unity. Peut-être que certaines correspondent déjà parfaitement à votre idée, ou s’en rapprochent assez…

Unity et LEGO proposent une variété de contenus additionnels basés sur les thèmes de la marque danoise :

Notez que certains de ces contenus se débloquent en réalisant les tutoriels Unity ou en publiant un jeu LEGO Microgame. Aussi, tous ces assets sont présents dans le template de base, les add-ons ne fournissant que des prefabs prêts à l’emploi. Vous pouvez donc reproduire les personnages cités sans télécharger ces packs comme nous verrons plus tard dans cet article.

Modifer les matériaux existants

Une autre manière rapide pour modifier l’apparence de votre minifigure est de modifier ses matériaux. Vous aimez la spationaute mais vous la voudriez en rose ? Même si LEGO et Unity cachent les objets composant votre minifig, vous pouvez retrouver dans les assets du projet les matériaux utilisés, afin de les éditer.

Ces matériaux se trouvent dans le dossier LEGO Data/Materials/Bodies. Le plus simple à trouver sera le torse, cherchez torso t:Material, vous devriez pouvoir reconnaitre celui qui vous intéresse. Autrement, essayez de deviner grâce au nom ou en modifiant sa couleur pour voir s’il s’agit bien du matériau de votre personnage.

Recherche "torso t:Material" dans le panel projet

Dans le cas de la spationaute, une fois le torse changé de couleur, cherchez white t:Material et modifiez la dizaine de matériaux blanc affichés, il correspondent aux bras et jambes.

Animation de différentes modifications de l'astronaute

Un premier soucis avec cette méthode est que nous n’avons plus la spationaute d’origine et qu’il n’est pas possible d’avoir plusieurs couleurs pour le même torse.

Aussi dans notre cas, en modifiant des matériaux blanc, nous avons modifié d’autres minifigures qui partageaient cette couleur. Ce qui peut être gênant pour réaliser plusieurs niveaux avec des thèmes différents.

Plusieurs personnages affecté par le changement de couleur de l'astronaute
D’autres personnages avaient des pièces blanches

Éditer sa minifig pièce par pièce

Mais alors comment personnaliser ma propre minifigure, sans altérer les autres ?

La première difficulté, qui peut être étonnante si vous connaissez déjà Unity, c’est qu’il n’y a aucun objet visible comportant le design dans nos personnages.

L'objet minifig avec ses objets enfant cachés
Minifig avec ses objets enfants cachés

En effet, LEGO cache pas mal d’éléments pour simplifier l’utilisation de son système, ou pour contrôler ce qui est édité. Pour autant, il n’y a pas de magie et, avec un peu d’expérience sur Unity, on se doute qu’il y a quelque part des objets représentant la ou les différentes formes de la minifigure. Mais encore faut-il pouvoir y accéder pour les éditer…

Script révélateur

Ces objets sont cachés grâce à la propriété Object.hideFlags. Voici un petit script qui va nous permettre simplement de réafficher les gameobjects :

using UnityEngine;
public class MinifigRevealer : MonoBehaviour
{
    private void Reset()
    {
        Reveal();
    }
    
    [ContextMenu("Reveal")]
    public void Reveal()
    {
        RecursiveUnhide(transform);
    }
    
    protected void RecursiveUnhide(Transform _transform)
    {
        _transform.gameObject.hideFlags = HideFlags.None;
        foreach (Transform child in _transform)
            RecursiveUnhide(child);
    }
}

Placez le script sur la minifig, et hop ! Tous les objets composant notre personnage sont visibles ! Vous pouvez désormais les sélectionner et modifier leurs matériaux, ou leur maillage (mesh) pour les cheveux et chapeaux.

L'objet minifig avec ses objets enfants visibles
Minifig avec les objets enfants visible

De temps en temps les objets re disparaissent, utilisez simplement le menu contextuel du composant et l’action Reveal.

Vous pouvez désormais retrouver les principaux éléments visuels de la minifigure dans l’objet Geo_grp, comme la tête, le torse, les jambes… Quand aux cheveux et chapeaux, vous les retrouverez dans le « squelette » du personnage, dans l’objet hat_loc.

Pour trouver des matériaux adaptés à la pièce que vous modifiez, vous pouvez suivre la nomenclature des assets :

TêteBrasTorseTailleJambes
HeadArm_L_Front
Arm_L_Main

Arm_R_Front
Arm_R_Main
Torso_Main
Torso_Front
Torso_Back
Hip_Main
Hip_Crotch
Hip_Front
Leg_L_Main
Leg_L_Foot
Leg_L_Front
Leg_L_Side

Leg_R_Main
Leg_R_Foot
Leg_R_Front
Leg_R_Side
Préfixe des matériaux des minifig, suivis par le nom de la couleur.

Pas de nom particulier pour retrouver les faces, mais elles sont placées dans un sous-dossier particulier LEGO Data/Materials/Faces. Elle porte en nom d’identifiant de l’imprimé.

Vous verrez en parcourant les matériaux présents qu’il y a toutes les minifigs des add-ons. Voici par exemple le classic police man de l’extension Island Adventure.

Si vous souhaitez donner de toutes nouvelles couleurs à votre personnage, dupliquez un matériau adapté à votre pièce et assignez la. De cette façon, vous êtes certain de ne pas modifier une autre minifigure par erreur.

Minifigures astronaute et classic space de différentes couleurs

Création d’un nouveau sticker

Maintenant que vous savez modifier chaque élément, il ne reste qu’un pas avant de confectionner le personnage parfait pour votre jeu. Il s’agit de créer un stickers personnalisé pour le torse de votre personnage.

Comme objectif pour cette nouvelle texture nous allons essayer de reproduire les minifigs offerte lors de la Jam.

Image de présentation de la minifigure offerte dans le cadre du concours LEGO Microgame

On commence par récupérer le logo Unity. Ce dernier a changé depuis le concours d’ailleurs comme on peut le voir sur le site de la marque. Pour l’ancien logo, il est possible de le retrouver sur wikipédia.

Nous pouvons donc faire deux minifigures à l’effigie de Unity avec chacun des logos.

Le patron

En partant des textures proposés par LEGO Microgame, j’essaye de définir la map de base pour le torse frontal. Une première petite surprise, il y a (actuellement) 3 formats de textures:

  • Les minifigs d’add-ons on un format carré, ce qui donne une très légère déformation.
  • Les minifig principales ont un format rectangulaire qui n’est pas déformé sur le modèle.
  • Le dernier add-on Ninjago a un format rectangulaire mais plus grand.

On va se baser sur les textures principales qui semblent les plus correctes, car pas de déformation et moins lourde.

De là il est très simple de reproduire le torse avec le logo Unity. Seul détail, il n’est pas possible d’utiliser le decal sur ce matériau. Il n’est donc pas possible de créer des variations de couleur sans faire plusieurs textures.

Je cherche ensuite des formes de cheveux similaires à ceux offerts lors de la Jam, malheureusement la coupe féminine n’est pas disponible.

Minifig personnalisées avec le logo Unity

Un autre exemple pour le plaisir. Après avoir récupéré les sprites de LEGO Island, je peux rapidement reproduire Infomaniac sur LEGO Microgame !

LEGO Island – Infomaniac

Et ensuite ?

Les principaux éléments de notre minifigure sont maintenant personnalisés, mais il reste quelques accessoires qu’il pourrait être intéressant d’utiliser.

Catégories
LEGO Microgame Unity

Un premier niveau • LEGO Microgame

Plutôt que des salles de test inspirés du jeu Portal, je pense désormais faire différents niveaux courts inspiré des Mario 64 ou Mario Sunshine auxquels j’ai eu l’occasion de jouer dernièrement. Ses niveaux, basés sur des thèmes différents, pourrait avoir plusieurs déclinaisons à débloquer.

L’objectif

Pour ce niveau je compte donc réaliser :

  • Un petit monde de plaine/ferme.
  • Des animaux amicaux qu’il faudra sauver, des moutons, cochons…
  • Un boss qui aura capturé des animaux et créera des enemies. Il aura un niveau de vie et sera attaquable par moment, après avoir détruit un certain nombre d’enemies.
  • Des enemies qui se baladent aléatoirement et nous suivent s’il on est proche. On pourra les tuer en sautant sur leur tête.
  • Une petite scénette avec des explication de la quête.

Ce micro-jeu comportera plusieurs étapes :

  1. Sauver des animaux pris dans des petites cages. Débloque la zone du boss.
  2. Détruire les enemies qui protègent le boss. Il se met donc à en créer.
  3. Le boss surchauffe de plus en plus en créant des enemies. Il fini par passer en mode repos. A ce moment là on peut atteindre son point faible pour lui retirer de la vie.

Les ennemies

Je vais commencer par prototyper les ennemies qui seront utilisés un peu partout sur la carte. Ils ont ces caractéristiques :

  • Vivant (Brique Alive)
  • Intouchable / mortel (Brique Hazard)
  • En mouvement aléatoire
    • Tourne irrégulièrement (Briques Random trigger + Rotate)
    • Avance (Brique Move)
  • En alerte si le joueur est près (Brique Nearby Trigger)
    • Regarde le joueur (Brique Look At)

Pour simplifier la logique, je pense utiliser une variable pour gérer le mode alerte des enemies. Ils partageront une même variable et se mettront tous en mode alerte en même temps si l’un d’entre eux est approché. On pourra utiliser plusieurs variables pour créer des groupes d’ennemies.

Prototype d’ennemi

Et voilà à quoi ressemble notre premier ennemi avec toutes ses briques logiques. Même s’il ressemble vaguement à quelque chose, ce n’est pas vraiment le visuel final que j’ai en tête… Mais utiliser les brique m’a permit de tester rapidement la faisabilité du concept initial.

Un détail est apparu lors des tests. En effet, je veux pouvoir tuer mon ennemi en sautant dessus et à la fois qu’il me tue s’il me touche. Initialement j’ai utilisé la brique Touch pour détecter le saut sur l’ennemie, sauf qu’en touchant la brique mon personnage était tué également. J’ai donc changé se comportement par une brique de détection de distance. Ainsi la sensation reste la même, mais en réalité l’ennemi est tué si l’on s’approche assez près du haut de son… dos ?

Donnons maintenant à cette ennemi un air plus mignon-méchant ! Je pars sur une idée de mini-loup. C’est parti sur BrickLink Studio pour le design de notre personnage en brique.

A présent il faut réattribuer les différents comportements. Cette fois je n’utilise pas les briques mais directement les scripts. C’est un peu plus compliquer pour lier correctement les déclencheurs avec les bonnes actions. Je décide donc de simplifier la logique. Les loups serons statiques en attendant le joueur. J’enlève également le comportement qui anime le modèle car cela crée des décalages et les loups se mettent à voler…

Voilà pour nos ennemis, passons aux animaux à sauver à présent et à leur cages.

Amis en cage…

Je commence par prototyper la partie logique du concept. J’ai besoin d’ajouter un objectif qui est de sauver les animaux en cages. Pour cela chaque cage sera gardée par quelques loups qu’il faudra éliminer. Une fois toutes le cages ouvertes l’objectif est rempli.

Lorsque l’on récolte les trois cristaux, la barrière explose et l’on peut atteindre l’objectif final. C’est la version la plus simple du niveau. Je veux maintenant que les cristaux apparaissent si un groupe de loup est battu. J’ajoute quelques ennemis, autour des cristaux, auxquels j’ajoute des variables pour chaque groupe. Je place également un compteur déclencheur sur chaque cristal, afin qu’ils n’apparaissent qu’une fois les meutes battues.

La mécanique du mini-jeu est faite, c’est parti pour un petit tour sur BrinkLink Studio afin de donner vie à ce petit monde !

A présent il est temps de décorer la scène pour rendre tout ça plus immersif ! Mais aussi de créer un chemin à suivre…

Après avoir ajouté quelques détails et testé le niveau à plusieurs reprises, il semble manquer d’un second type d’ennemi. En effet le nombre de loups croissant ne suffit pas et cela reste répétitif.

Plus d’ennemis !

J’ai en tête deux types d’ennemis. L’un à distance lançant des projectiles. L’autre très rapide fonçant sur notre joueur. Commençons par prototyper ces ennemis afin de valider la pertinence.

Pour le premier j’utilise donc une brique de tire, une brique de ciblage et un détecteur de proximité pour l’attaque. Et pour détruire cette ennemi je place un détecteur de proximité avec une courte distance qui le fera exploser « de peur ». J’ajoute une petite bulle de discussion pour qu’il exprime son étonnement.

Le second doit simplement être intouchable et foncer sur notre joueur lorsqu’il passe devant. Je commence donc par le construire à partir d’une brique de danger, une de déplacement, et un détecteur de distance. Cependant mon ennemi fonce même si je ne suis pas du tout devant lui. Ce qui le rend nettement moins surprenant…

Dans un premier temps je vais le laisser comme tel et essayer de la placer stratégiquement dans le niveau. Par la suite il pourrait être intéressant de créer un déclencheur « champ de vision ». En attendant durant l’implémentation dans le niveau j’utilise les extra conditions pour ne déclencher les nouveaux ennemis que lorsque le groupe lié est en alerte. Cela évite notamment que mes attaquants à distance tirent derrière eux.

Je vais réutiliser le premier design de loup pour l’ennemi à distance. Quant au coureur je luis design un model plus élancé pour suivre son mouvement.

Une pause avant le boss !

Finalement ce niveau m’aura pris beaucoup plus de temps que je ne l’aurai imaginé. Je décide de faire une petite mise à jour du menu de défaite avant d’attaquer la partie du niveau avec le boss. Pour donner plus de vie à ce menu je réalise une petit scénette reprenant mon personnage animé et quelques loups. La camera tourne autour pour animer le tout.

A suivre…

Le boss restant une partie conséquente, je traiterai son implémentation dans un second article. En attendant je réalise tout de même un build que je publie sur Unity Play afin de valider le travail effectué.

A bientôt pour le développement du boss de fin de niveau !

Catégories
LEGO Microgame Unity

Les variables • LEGO Microgame

Le compteur doit être actionné par une autre brique, et sera configuré pour une certaine opération tel que l’addition, la soustraction, etc… Le déclencheur lui se voit configuré une condition, par exemple « si le score égale 3 ».

Si vous n’êtes pas familier avec la programmation informatique, une variable est un symbole que associe un nom à une valeur. Généralement la valeur est amenée à changer au cours du temps. Par exemple: on peut avoir la vie du joueur (nom) qui est à 42 (valeur). Si il mange un donut, on ajoutera +8 à la vie du joueur qui vaudra maintenant 50.

Ces deux briques ouvrent beaucoup de possibilités, à noter que l’on peut désormais ajouter des conditions sur tous les déclencheurs. On peut donc combiner des interactions et l’état d’une variable. Cependant si l’on change de scène la variable est réinitialisée, or j’aurais besoin de valeurs persistées entres les différences salles de mon jeu.

Comment ça marche ?

Ouvrons les scripts pour comprendre le fonctionnement qui a été choisi pour ces briques de comportement. On trouve 4 Scripts relatifs à au système:

  • CounterAction.cs : LEGOBehaviour d’action, c’est lui qui déclare la variable au lancement de la scène, puis demande à la modifier lorsqu’il est activé.
  • CounterTrigger.cs : LEGOBehaviour de déclenchement, il lit à chaque rafraichissement la valeur de la variable qu’il suit et test sa ou ses conditions. Je note aussi qu’il ne détient aucune logique spécifique, mais se base entièrement sur les conditions propres aux déclencheurs.
  • Variable.cs : ScriptableObject servant à la configuration de la variable. Avec un nom pour l’identifier, une valeur initiale, mais aussi l’interface utilisateur à utiliser pour afficher la variable en jeu si voulu.
  • VariableManager.cs : La classe statique qui garde en mémoire les valeurs des variables, utilisé par les briques de comportement pour lire et modifier les variables.

En l’état mes variables ne devraient s’initialiser qu’à l’apparition d’une brique d’action comportant une nouvelle variable, lors du chargement d’une scène. Le script statique garde les valeurs durant toute l’éxécution du jeu. La raison pour laquelle mes valeurs sont perdues entre les scènes est en fait extérieur. C’est le manager de jeu qui commande la réinitialisation au lancement d’une scène :

public class GameFlowManager : MonoBehaviour
{
  void Start()
  {
    // ...
    VariableManager.Reset();
  }
}

On va donc pouvoir obtenir des variables partagées entre les scènes sans trop de difficultés. Il me suffit de commencer mon script de gestion de partie personnalisé.

Let’s code !

Première mésaventure, je ne peux pas étendre la classe GameFlowManager fournie. Trop d’éléments sont déclarés privé et m’empêche de reprendre le code existant correctement. Je part donc sur une copie brute de la classe. De toute façon j’ai d’autres modifications en tête, elle était vouée à changer…

Je n’exclue pas la possibilité de réinitialiser les variables au lancement d’une scène, j’ajoute simplement un champ me permettant d’activer ou non cette fonction :

public class MyGameFlowManager : MonoBehaviour
{
  [SerializeField, Tooltip("Does the variables must be reset when the scene is loaded ?")]
  bool m_resetVariablesOnStart = true;
  protected void Start()
  {
    // ...
    if (m_resetVariablesOnStart)
      VariableManager.Reset();
  }
  // ...
}

Je modifie le prefab Game Manager avec mon script. J’oublie une première fois de décocher ma variable, classique ! Et finalement je peux voir que cela fonctionne, à un détail prêt, l’affichage des variables ne se fait plus après un changement de scène.

On y était presque ! Malheureusement le code fourni se montre toujours compliqué à étendre. Le manager de variable statique est appelé directement par les briques, et je n’ai pas envie de modifier un script susceptible d’être mis à jour par Unity. Or l’interface attend de ce manager l’indication qu’une variable a été ajouté pour afficher cette dernière.

Je suis obligé de ruser pour arranger ce comportement. Le manager de variable ne propose pas de méthode donnant les variables enregistrées. J’ajoute donc un tableau de variable à surveiller dans mon manager de jeu, et quelques ruses :

public class MyGameFlowManager : MonoBehaviour
{
  [SerializeField, Tooltip("Does the variables must be reset when the scene is loaded ?")]
  bool m_resetVariablesOnStart = true;
  [SerializeField, Tooltip("The variables to watch when the scene load.")]
  Variable[] m_VariablesToWatchAtStart = new Variable[0];
  protected void Start()
  {
    // ...
    HandleVariableManagement();
  }
  protected void HandleVariableManagement()
  {
    if (m_resetVariablesOnStart) {
      VariableManager.Reset();
      return;
    }
    foreach (Variable variable in m_VariablesToWatchAtStart) {
      if (!VariableManager.IsVariableRegistered(variable)) {
        continue;
      }
      VariableAdded evt = Events.VariableAddedEvent;
      evt.Variable = variable;
      EventManager.Broadcast(evt);
      // Force value update, as HUD init with initialValue
      VariableManager.SetValue(variable, VariableManager.GetValue(variable));
    }
  }
}

Ça y est ! Les valeurs de mes variables sont gardées d’une scène à l’autres comme escompté. Je regrette tout de même que les scripts ne soient pas plus ouverts.

Je réarrange mon code pour simplifier l’utilisation. Je considère désormais une liste de variable à conserver entre les scènes, au lieu du couple garder les variable + variables à vérifier :

public class MyGameFlowManager : MonoBehaviour
{
  [SerializeField, Tooltip("The variables to keep when the scene load.")]
  Variable[] m_VariablesToKeepBetweenScenes = new Variable[0];
  protected void HandleVariableManagement()
  {
    // Keep value before reset
    Dictionary<Variable, int> currentValues = m_VariablesToKeepBetweenScenes
      .Where(VariableManager.IsVariableRegistered)
      .ToDictionary(_v => _v, VariableManager.GetValue);
    // Reset all variables
    VariableManager.Reset();
    // Set the variable we want to keep between scenes
    foreach (KeyValuePair<Variable,int> value in currentValues) {
      VariableManager.SetValue(value.Key, value.Value);
    }
  }
  // ...
}

Où est mon record ?

Pour aller plus loin sur les variables je souhaite ajouter un comportement qui me permette de sauvegarder des scores sur plusieurs sessions. Pour ça je vais utiliser la class PlayerPref de Unity, qui se charge de gérer la méthode de sauvegarde selon la plateforme. Je pars du script existant que je duplique faute d’attributs accessibles, auquel j’ajoute la sauvegarde persistante. Et voilà, prêt à battre des records !

Vous pouvez retrouver les modification cités dans cette article sur mon repository GitLab.

À suivre

Les comportements manquants étant résolus, nous allons pouvoir nous atteler au level design. À très vite pour de nouveaux défis !

Catégories
LEGO Microgame Unity

Scene loader • LEGO Microgame

Une première chose que j’aimerais tester est la création d’une brique de comportement qui chargera une scène lorsqu’elle est activée. Le template proposé ne gère de base qu’une scène en cas de victoire, et une en cas d’échec. Or, pour mon projet j’aimerais un hub où le joueur sélectionne les niveaux en déplaçant son personnage, inspiré des jeux Lego.

Let’s code !

Je pars donc d’un comportement d’action, qui doit être déclenché par un trigger. Je prends pour exemple l’AudioAction. Très simple, cette classe qui déclenche simplement un clip audio fait une bonne base pour implémenter notre comportement.

J’observe que le comportement d’action utilise simplement la variable m_Active de la classe parente durant la boucle d’update. La modification de cette variable et l’animation « flash » de la brique lors d’un déclenchement sont entièrement gérées par la classe mère.

public class SceneAction : Action
{
    [SerializeField]
    string m_Scene = "";
    
    bool m_IsLoading;

    protected void Update()
    {
        if (!m_Active || m_IsLoading)
            return;

        SceneManager.LoadSceneAsync(m_Scene);
        m_IsLoading = true;
    }
}

Je reprends l’un des prefabs du projet. Je remplace le script d’action par le mien. Ma nouvelle brique est prête à l’emploi !

Cette première implémentation me permet rapidement de charger une scène à la volée grâce à une brique de déclenchement. C’est assez brut, le chargement se fait sans transition, mais la scène est correctement chargée.

Et voilà, j’ajoute quelques briques pour un premier système de portes menant aux salles et le tour est joué !

Le premier point de logique de mon projet est fonctionnel. Il reste à peaufiner le rendu, avec un fondu de transition par exemple, mais je pourrais d’ores et déjà créer mon hub principal menant à mes différentes scènes.

Vous pouvez retrouver les modification cités dans cette article sur mon repository GitLab.

Et ensuite ?

Le prochain point que je compte aborder est la gestion de variables globales. En effet, un système de variable est présent mais il semble que la valeur soit initialisée au lancement de la scène. J’aimerais avoir un compteur général de pièces et un système de déblocage de niveaux. C’est pourquoi il me faut éclaircir ce point rapidement. Il serait aussi intéressant de voir pour utiliser les PlayerPrefs de Unity pour garder des variables sur plusieurs sessions.

Catégories
LEGO Microgame Unity

LEGO Microgame • C’est parti !

J’avais déjà essayé ce modèle proposé par Unity et LEGO il y a quelques mois. On y retrouve de très bonnes idées pour aborder la création d’un micro-jeu.

En se basant sur le moteur Unity, LEGO propose un système de briques qui s’imbriquent, comme on pourrait le faire en vrai, et auxquelles ils ajoutent des comportements. Il est possible de combiner les effets très simplement en assemblant les briques entre elles.

À l’occasion d’une mise à jour de leur modèle, Unity et LEGO propose un nouveau challenge. Ce qui me semble être une très bonne occasion.

l’Idée

L’idée pour ce mini-jeu sera de faire un ensemble de salles avec des défis d’entraînement, inspiré du jeu Portal. Elles présenteront chacune des mécaniques de jeu en utilisant les briques de comportement proposées par LEGO Microgame. Ces salles devront être débloquées une après l’autre, jusqu’à l’ultime défis, la course sans fin !

Portal 2: Test Chamber Creator

Ces activités seront accessibles depuis un hub 3D inspiré de Lego Island et des derniers jeux Lego, notamment Lego Star Wars.

LEGO Island / LEGO Star Wars : Complete Saga

Pour la course infinie je tenterais de créer des ensembles

Lien du challenge: https://ideas.lego.com/challenges/6811cf30-f944-4dfa-8714-9b38be6fbb52
Lien du template: https://store.unity.com/fr/lego-microgame

Journal du développement :

Catégories
Tower Defense Pixel Unity

Tower Defense Pixel /log3

image

Voici le résultat de ce week-end, productif cette fois-ci. Pas de détails sur le processus, j’ai beaucoup de mal à faire les deux, ce sera juste un résumé.

J’ai donc travaillé sur l’éditeur de carte. Après avoir créé des belles cases sur MagicaVoxel, j’ai mis en place la gestion d’une carte. Le manager stock les données de la carte bien sûr, instancie les Prefabs qu’il faut au bon endroit. Il est aussi possible de modifier une case.

Autour de ça, le premier outils d’édition, une sorte de crayon à terrain. Et également la possibilité de sauvegarder et de charger une carte. On va donc pouvoir commencer à mieux tester le gameplay.

Après tout ça un coup de re-factorisation sera peut-être de mise. Aussi il faut maintenant ajouter les bâtiments dans l’edition et la gestion des cases adjacentes.

Voici quelques preview des différentes case, réalisées avec MagicaVoxel. Bonne semaine, et j’espère au week-end prochain !

image
image
image
Catégories
Tower Defense Pixel Unity

Tower Defense Pixel /log2

Aujourd’hui, comme dit dans le précédent billet, je m’attaque au terrain. Les joueurs vont avoir besoin de placer leurs tours, murs et autres bâtiments pendant la partie. Il faut donc que le NavMesh se mette à jour en temps réel. Heureusement Unity Technologies propose maintenant des NavMeshComponents qui permettent cela. L’ayant déjà testé je sais que j’aurais à faire face à un petit détail non-bloquant au début. Lorsqu’un build est fait durant le jeu, tout les agents marquent un court arrêt. Cela se comprend mais si à chaque fois qu’un joueur pose un bâtiment les unités s’arrêtent, le gameplay risque d’être frustrant.

Avant de partir dans le développement, un petit rappel de l’objectif :

  • La carte est une grille de cases carrées
  • Il y a plusieurs types de terrain. Par dessus desquels il sera possible ou non de construire un bâtiment. La terraformation n’est pas prévue, mais les cases type forêt on des chances de ce voir transformée en plaine lors d’une construction. A voir donc…
  • Le terrain et les bâtiments affectent le path finding

Pour les différents types de terrain j’ai en tête un jeu de mon enfance orienté stratégie. Il s’agit de Advance Wars. Comme j’ai besoin de murs je vais chercher les sprite du second opus qui en possédait. Ci dessous donc tout les types dont nous allons avoir besoins, et même plus.

image

Pour commencer simplement je vais m’occuper des types principaux :

  1. Plaine (Case neutre)
  2. Forêt (Déplacement plus lent)
  3. Montagne (Déplacement très lent, pour l’instant)
  4. Mer (Déplacement impossible, pour l’instant)
  5. Route (Déplacement plus rapide)

Je vais partir sur une solution simple, mais peut-être pas la plus optimisée dans un premier temps. Je vais faire une série de prefabs qui représenteront chaque case, et qui comporteront un component NavMeshModifier.

image

Lors de la configuration, il est apparu que le système de NavMesh proposé risque de ne pas être complètement adapté à ce cas. En effet il y aura plusieurs types d’unités, qui réagiront différemment selon le terrain. Il faudra donc certainement dupliquer les Areas pour chaque type d’unité, mais pour l’instant ça ne gène pas.

Il est temps de créer une petite carte pour tester les réactions des unités. Sans éditeur de carte c’est un peu laborieux, il faudra rapidement en créer un. Mais les modificateurs fonctionnent comme prévu pour le terrain. Simplement il y a donc un modificateur de poids par case, et plus tard chaque type d’unité aura son NavMesh, cela risque d’être lourd. Aussi les montagnes sont finalement “Not Walkable” pour l’instant pour éviter que les unités se faufilent en diagonale entre deux montagnes. Je reverrais le comportement souhaité plus tard.

image

Pour faciliter la suite du développement, l’éditeur de carte sera la prochaine étape du développement. Pour simplifier les tests je reviendrais peut-être sur un format de tower defense plus classique avec d’un côté une vague ennemie, et de l’autre le joueur qui se défend en plaçant des tours.

Pour aujourd’hui ça sera malheureusement tout, je n’aurais pas plus de temps à accorder à ce développement. To be continue…

PS: Si vous avez connaissance des performances des NavMeshComponents dans ce cas, n’hésitez pas à commenter 😉

Catégories
Tower Defense Pixel Unity

Tower Defense Pixel /log1

Afin de refaire un tour dans les fonctions d’Unity et avec l’espoir de finir un prototype conséquent de gameplay, je m’attaque cette fois à une logique relativement simple, le tower defense. Parce que j’ai toujours du mal à rester simple, ce dernier contiendra du PvP, et un peu de gestion.

Le gameplay rapidement:

  • Au moins deux équipes qui s’affrontent
  • Un cycle jour/nuit. Les vagues partent à l’aube. Une vague de monstre peu démarrer durant la nuit. Durant la nuit les unités n’avancent plus (ou peut-être dans des zones particulières) et ne font que se défendre
  • Les unités ont une sorte de mana qui limite leurs actions chaque jour, et est régénéré durant la phase de sommeil nocturne. Si durant la nuit ils sont attaqués alors ils sont plus faible le lendemain. Ils peuvent se défendre sans mana mais sont moins efficace et/ou peut-être perdraient-ils de la vie.
  • Les joueurs placent leurs bâtiments et configurent leur vagues
  • Le premier à détruire le QG ennemi gagne

C’est donc parti pour ce nouveau prototype de gameplay ! Et cette fois, pour la première fois, je vous raconte comment je procède. 

Il faut bien commencer par quelque chose, c’est donc la base du gameplay qui est attaquée. On va faire un petit brouillon de la logique de base, nous aurons donc une unité simple et un quartier général (QG). Pour la logique, l’unité à sa création ( Start() ) cherchera le QG ennemi le plus proche, et cherchera à l’atteindre.

image

Ok maintenant que nous avons cette unité simple qui cherche à atteindre le quartier général ennemi, nous allons faire en sorte que chaque QG fasse apparaître des unités.

Pour travailler avec des composants de façon à séparer et réutiliser facilement les scripts, nous allons sortir dès maintenant le script de spawn du Headquarter. Ceci car nous avons prévu la possibilité de placer plusieurs points de création d’unité sur la carte. Cependant la vague sera gérée à un seul endroit, les spawn n’étant que des “slots” disponibles à chaque tick.

Le générateur d’unité va donc gérer le type d’unité qu’il peut instancier, le nombre en un tick, et la position des apparitions. On l’appellera de la façon suivante UnitSpawner.Spawn(GameObject[] unitPrefabs), et il se chargera de faire apparaître les unités correctement.

image

Maintenant que les unités cherchent et atteignent le QG ennemi, il est temps que chacun attaque et se défende. Nous allons commencer par ajouter la notion de PV aux unités et bâtiments, puis la notion d’attaque. On peut dès maintenant observer qu’il y a des propriétés communes sur les unités et les bâtiments, et tout de suite créer une class abstraite d’où les objets d’équipe hériterons.

La notion de PV est très simple pour l’instant, des points de vie maximum et courant, ainsi qu’une fonction AddDamage(float power) avec laquelle les ennemis pourront frapper.

Ensuite, je commence par l’attaque du QG. Elle est très sommaire pour l’instant. Le QG a une puissance, une cadence, une distance et un mask de tir, ainsi qu’une cible. Si il n’y a pas de cible, on en cherche une. Une fois une cible trouvée on commence une coroutine d’attaque qui cessera à la destruction de l’ennemi ou lorsque la cible sortira du rayon de tir.

image

Par simple héritage, l’attaque étant la même pour l’instant, il va être possible en déplaçant le script de coroutine dans la classe commune de rendre ces pauvres petites unités agressives. Ensuite il suffit de gérer l’arrêt des unités lorsqu’elles attaquent, et le redémarrage de leur marche une fois la cible vaincue.

image

Il s’agit bien d’un tower defense à la base. Il est donc temps de créer des tours ! Le code est déjà là avec les QG, il n’y a qu’a factoriser tout ça et nous aurons un début de tour rapidement.

Avec les paramètres de puissance de tir, de distance et de cadence il est déjà possible d’avoir plusieurs types de tours. Ci dessous par exemple je paramètre 3 tours : 

  1. (Cylindre) Classique / Mitrailleuse, elle tir avec une bonne cadence et fait des dégâts moyens
  2. (Cube) Laser, elle a une très grosse cadence pour une puissance et portée plus faible
  3. (Sphere) Sniper, elle a une cadence très faible mais tue presque du premier coup une unité et a une portée très large
image

Voilà qui pose une base sympatique pour ce tower defense. Dans la prochaine partie je m’attaquerais à la carte, à l’influence du terrain sur le pathfinding et au placement de tours et bâtiments par le joueur. Pour cela les NavMeshComponents feront gagner du temps avec le nouveau baking à la volée.

To be continue…