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
SGO Unity

SGO: Week 3

Hi everyone !

This week was time to implement a major feature, the night attack. With this came some other things to manage.

image

Firstly Simon has to allow the player to hide in the shelter. With it he has to lock the camera on the shelter, so the GPS, and hide the loots around. After that he works on the night attack and its report, locally faked for now, and finally on the player death. So we are pretty close to the core gameplay loop and ready to start play-tests.

During this week we also had to manage the versioning of  the project. Indeed we use new computers as we move at the incubator, and we had to clone the project from our git repository. But, surprise ! Some plugins we use have .dll, and Unity is unable to correctly rebuild the Libraries, not stored with Git. 

The tips was finally to keep a Unity package of all the plugins, versioned with git. For some reason that we doesn’t really get, that way Unity is able to reimport multiple plugins with .dll at the same time without creating an error chain reaction.

Art

image

This week I work on some tests about the way to display informations on the map, constraint with the mobile performances and the UX. We get inspiration on Sid Meier’s Civilisation VI fog of war to hide details away from the character.

image

This is finally the preview of the visual we choose for now.

image

See you next week ! And don’t forget to join the Discord if you want to follow our journey 🙂 

Catégories
SGO Unity

SGO: Week 2

This week on the SGO Project Simon continue the first prototype phase. He implement the object durability, so your equipment is no longer infinite.

This previous feature request to have some specific items. To be able to test it Simon has coded a developer console usable on mobile.

For me, after some days trying to use the C# feature System.Net.Http for the API calls, I finally learn that it’s not possible to use the Unity’s API outside the main thread. And it’s seams to especially be true when using the .Net 4.x API on Unity. So I finally rollback on the UnityWebRequest API that use Unity’s coroutines coupled with callback to create a manager callable from any component on the scene.

The problem with usage of C# Task was still present because of our usage of Firebase. Indeed the Firebase plugin use Tasks. This is a problem because it makes unable to use delegates listened by functions that will interact with the Unity API. Fortunately I found an elegant way to manage it.

image

Finally this week we need to preview some effects of the elements designed on the map. This isn’t easy for two developers to make graphic placeholder, but some picked 2D arts helped us to imagine how the map could looks.

See you next week ! And don’t forget to join the Discord if you want to follow our journey 🙂

Catégories
SGO Unity

SGO: Let’s begin this journey !

Hi everyone !

That’s it ! We took off by integrating a local incubator and we officially start our journey to publish our own first game !

image

Who are we ? Two guys from Lille (France) who dream about publishing our mobile game and work on it for already a year now.

We are two longtime friends, both game-designer / developer working with Unity, Simon and me Jonathan. After having each had professional experience, in game development and web, we decide to take the plunge and work fully on Simon personal student project.

After a year working on the project, writing a deep GDD and prototyping it, we just enter in an incubator of our region at “La Plaine Images” and that’s the first serious step to make our dream true, we are pretty proud today 😉

image

To share our journey (and also keep us on a positive rythme) we will try to publish weekly our updates on the project. We hope you will be interested and mostly that could engage you to follow this kind of dream you have too 😉

Quick resume of the game

Our game is a survival RPG by mobile geolocation. the player must keep his character alive for the most days in a row.

The player is immersed in a post-apocalyptic universe in which intelligent machines reign and spread terror. Every night they redouble their aggression and directly attack the survivors and their facilities.

To prepare for these nights, he will have to explore the safe world in order to recover resources, equip himself and improve the shelters he has built.
In this quest for survival the player can cooperate with other players by sharing his resources and shelter or through trade.

Week 1

This week Simon works to end the development of the craft system. It’s finally possible to get what you craft ! And he add notification on that to alert the player when it’s time.

image

Beside the development of the core gameplay, we are still searching to build a deep univers to immerse players, and there was also some questions about the way to display the map.

See you next week ! And don’t forget to join the Discord if you want to follow our journey 🙂