Steredenn — our game — is available on PC/Mac/Linux and Xbox One!

Menus et chargement du jeu

Nous avons terminé notre premier niveau avec un gameplay de base (certe il manque une condition de victoire), plusieurs sprites, du son et des particules.

Mais quand le joueur meurt, le jeu continue d’avancer dans le vide et il n’est pas possible de recommencer. Il nous faut ajouter un moyen de relancer une partie perdue.

Damien : Pour être honnête, je trouve que les menus et l’interface dans un jeu en général c’est une vraie plaie. Il faut souvent utiliser un framework bancal voir inexistant (coucou XNA), et en tant que joueur j’estime que les menus sont fait pour être passés rapidement.

Matthieu : A l’inverse de pas mal de développeur de jeux, je ne suis pas d’accord. Créer une bonne interface pour un jeu n’est pas chose facile mais c’est en revanche intéressant et gratifiant. Cependant, cela nécessite de bons outils et une certaine connaissance du design (comme pour une application).

Mais c’est vrai qu’un bon menu doit être invisible, pour qu’au final les joueurs le remarquent à peine.

Malheureusement, Unity n’offre pas vraiment de quoi faire de superbes menus facilement à moins d’y consacrer beaucoup de temps pour d’utiliser un plugin.

Il ne sera pas question ici de créer une interface complexe. Nous nous contenterons des outils de base mais vous les trouvrez vite… limités.

Commençons par le commencent.

Assets

Arrière-plan

background

(Clic droit pour sauver l’image sur votre disque)

logo

(Clic droit pour sauver l’image sur votre disque)

Importez ces assets dans votre projet. Vous pouvez faire un sous-dossier “Menu” au dossier “Textures” pour ne pas avoir de conflits sur les noms.

Pour les boutons, nous utiliserons les horribles boutons de base.

Title screen

Presque tous les jeux ont un écran d’accueil, qui s’affiche une fois les divers splashscreens passés.

Damien : Certains écrans titres sont mémorables : Megaman, Metal Slug… (je suis fan des écrans titres).

Ce que nous allons faire sera, disons… plus sobre ! Mais libre à vous de vous amusez ;).

Scène

Créez une nouvelle scène :

  1. “File” -> “New scene”.
  2. Sauvez la dans le dossier “Scenes” sous le nom de “Menu”.

Astuce : Vous pouvez aussi utilisez les raccourcis cmd+N (OS X) ou ctrl+N (Windows).

Notre écran titre sera composé de :

  • Un arrière-plan.
  • Un logo.
  • Un script pour afficher les boutons.

Pour l’arrière-plan :

  1. Créez un novueau Sprite
  2. Position (0, 0, 1)
  3. Scale (2, 2, 1)

Pour le logo :

  1. Créez un novueau Sprite
  2. Position (0, 2, 0)
  3. Scale (0.75, 0.75, 1)

Vous devriez obtenir :

Result

Bien sur vous pouvez ajouter votre nom, les contrôles, des animations sympas… les menus sont aussi un espace de liberté ! Rappelez-vous juste que le joueur doit pouvoir lancer rapidement une partie.

Script du menu

Nous allons créer un nouveau script, “MenuScript”. Il sera chargé d’afficher un bouton et de charger le niveau si on clique dessus.

Attachez ce nouveau script à un nouvel objet vide (que l’on appellera peut-être… “Script” ?). Son contenu :

using UnityEngine;

/// <summary>
/// Script de l'écran titre
/// </summary>
public class MenuScript : MonoBehaviour
{
  void OnGUI()
  {
    const int buttonWidth = 84;
    const int buttonHeight = 60;

    // Affiche un bouton pour démarrer la partie
    if (
      GUI.Button(
        // Centré en x, 2/3 en y
        new Rect(
          Screen.width / 2 - (buttonWidth / 2),
          (2 * Screen.height / 3) - (buttonHeight / 2),
          buttonWidth,
          buttonHeight
        ),
        "Start!"
      )
    )
    {
      // Sur le clic, on démarre le premier niveau
      // "Stage1" est le nom de la première scène que nous avons créés.
      Application.LoadLevel("Stage1");
    }
  }
}

A propos de la syntaxe : oui, elle est vraiment étrange.

Nous affichons juste un bouton qui charge la scène “Stage1” quand l’utilisateur clique dessus.

Note: La méthode OnGUI est appelée à chaque frame et est destinée à afficher tous les éléments d’interface : barres de vies, compteurs, menus, etc.
L’objet GUI permet de créer rapidement dans le code des composants d’interface, comme la méthode GUI.Button par exemple.

Lancez le jeu et admirez notre menu :

Button result

Cliquez et… notre premier crash ! L’erreur est visible dans la console :

Level 'Stage1' (-1) couldn't be loaded because it has not been added to the build settings. To add a level to the build settings use the menu File->Build Settings...

Pour une fois, le message d’erreur est très clair. Voyons cela.

Ajoutez des scènes au package

Allez dans “File” -> “Build Settings”:

Build settings

Maintenant, faites un drag’n’drop de vos deux scènes vers la fenêtre pour les ajouter.

Adding scenes

Relancez le jeu, cliquez et… c’est parti !

Start game

Astuce : La méthode Application.LoadLevel() est radicale : elle instancie la nouvelle scène et supprime l’ancienne. Vous aurez parfois envie qu’un objet transite d’une scène à l’autre, une musique par exemple.

Unity a une méthode pour cela, DontDestroyOnLoad(aGameObject). Il suffit de l’appeler sur l’objet que l’on veut conserver et il ne disparaîtra pas pendant le chargement. D’ailleurs il ne disparaîtra plus jamais à moins de le supprimer manuellement.

Mort du joueur et nouvelle partie

Nous voulons aussi que notre joueur puisse redémarrer une partie quand il a perdu. Et pour le moment, cela arrive très souvent (nous y remédierons dans un chapitre à venir).

Actuellement le déroulement du partie est :

  1. Le joueur entre en collision avec un projectile ennemi
  2. HealthScript.OnCollisionEnter est levé
  3. Le joueur perd 1 point de vies
  4. “HealthScript” détruit le joueur car il a moins d’un point de vie

Et nous allons ajouter :

  1. PlayerScript.OnDestroy est levé
  2. Un “GameOverScript” est créé et ajouté à la scène

Mais d’abord, créons un nouveau script “GameOverScript”. C’est un petit bout de code qui affichera deux boutons pour quitter ou recommencer :

using UnityEngine;

/// <summary>
/// Relance ou quitte la partie en cours
/// </summary>
public class GameOverScript : MonoBehaviour
{
  void OnGUI()
  {
    const int buttonWidth = 120;
    const int buttonHeight = 60;

    if (
      GUI.Button(
        // Centré en x, 1/3 en y
        new Rect(
          Screen.width / 2 - (buttonWidth / 2),
          (1 * Screen.height / 3) - (buttonHeight / 2),
          buttonWidth,
          buttonHeight
        ),
        "Retry!"
      )
    )
    {
      // Recharge le niveau
      Application.LoadLevel("Stage1");
    }

    if (
      GUI.Button(
        // Centré en x, 2/3 en y
        new Rect(
          Screen.width / 2 - (buttonWidth / 2),
          (2 * Screen.height / 3) - (buttonHeight / 2),
          buttonWidth,
          buttonHeight
        ),
        "Back to menu"
      )
    )
    {
      // Retourne au menu
      Application.LoadLevel("Menu");
    }
  }
}

C’est exactement comme le premier script sauf que nous avons deux boutons.

Maintenant il faut modifier le “PlayerScript et ajouter ceci :

void OnDestroy()
{
  // Game Over.
  // Ajouter un nouveau script au parent
  // Car cet objet va être détruit sous peu
  transform.parent.gameObject.AddComponent<GameOverScript>();
}

Lancez le jeu et perdez :

Game Over

Le script a été placé dans la scène, dans le parent du joueur (logiquement le plan 3 - Foreground) :

Game Over Script

Bien sur il faudra afficher le score, avoir des animations… mais ça fonctionne ! :)

“Oh secours que c’est laid”

Eh oui… pour y remédier, pas de miracle, il va falloir s’acharner. Vous pouvez essayer en créant une “GUI Skin”.

  • “Assets” -> “Create” -> “Gui Skin” :

GUISkin

Depuis l’Inspector, vous pourrez modifiez l’apparence de tous les contrôles de l’interface.

Assurez-vous de sauvegardez ce fichier “GUISkin” dans le dossier “Resources”.

Note : le dossier “Resources” est spécial pour Unity. Tout ce qui s’y trouve sera embarqué avec le jeu et peut être chargé depuis un script en utilisant la méthode Resources.Load().
Vous pouvez donc charger des objets extérieurs pendant l’exécution… cela ne vous rappelle pas le principe des mods ?

Mais votre nouvelle skin pour interface n’est pas encore appliquée.

Il faut modifier nos deux scripts précédents et la charger manuellement avec GUI.skin = Resources.Load("GUISkin");… Attention à le faire qu’une seule fois).

Un exemple du “MenuScript” (au niveau de la méthode Start()) :

using UnityEngine;

/// <summary>
/// Script de l'écran titre
/// </summary>
public class MenuScript : MonoBehaviour
{
  private GUISkin skin;

  void Start()
  {
	// Chargement de l'apparence
    skin = Resources.Load("GUISkin") as GUISkin;
  }

  void OnGUI()
  {
    const int buttonWidth = 128;
    const int buttonHeight = 60;

	// On applique l'apparence
    GUI.skin = skin;

    if (GUI.Button(
      new Rect(Screen.width / 2 - (buttonWidth / 2), (2 * Screen.height / 3) - (buttonHeight / 2), buttonWidth, buttonHeight),
      "START"
      ))
    {
      Application.LoadLevel("Stage1"); // "Stage1" is the scene name
    }
  }
}

Comme vous le voyez, c’est pas mal de boulot pour un simple bout de menu.

Note : Si vousavez un peu d’argent à investir et que vous avez besoins de menus et/ou d’afficher du texte, jetez un œil au plugin NGUI. Il vaut le coup._ Vraiment_.

Prochaine étape

Vous avez appris à faire un simple menu pour un jeu. Jusqu’à présent nous avons fait :

  • Un parallax scrolling sur 3 plans
  • Des particules !
  • Un écran titre !
  • Des sprites et des sons
  • Un gameplay shmup avec un joueur et des ennemis.

Félicitations ! Bon par contre, c’est uniquement sur votre ordinateur… et pour vendre un jeu promis à un grand avenir, c’est mal barré, il faut un moyen de le distribuer.

C’est justement ce dont nous allons parler dans cette dernière partie : créer un exécutable et le déployer sur un terminal iOS.

Steredenn
Click to get more information about our roguelike/shmup!