I. Introduction

Dans cette vidéo, nous allons apprendre à faire un jeu de plates-formes 2D basique dans lequel le joueur pourra déplacer un personnage ramassant des pièces sur son chemin. L'accent est mis sur le contrôle du personnage. Celui-ci peut se déplacer de gauche à droite et sauter.

II. Vidéo


Session en direct : création d'un jeu de plates-formes basique en 2D


III. Résumé

III-A. Importation des ressources

Pour cette session, les ressources viennent du pack « 2D Platformer » publié par Unity Technologies et gratuitement téléchargeable à partir de l'Asset Store.
Toutefois, toutes les ressources ne sont pas utilisées. Voici la liste des éléments importés :

  • les animations ;
  • les contrôleurs ;
  • tous les .asset du dossier des paramètres du projet (ProjectSettings) ;
  • les matériaux physiques ;
  • le préfabriqué du personnage « hero » ;
  • tous les sprites.

Ensuite, il est nécessaire d'ajouter un sprite « CoinSprite.png » du pack « 2D Pack » aussi publié par Unity Technologies.

III-B. Configuration du personnage

Pour commencer la configuration du personnage, glissez puis déposez le préfabriqué « hero » dans la scène. Retirez les composants de type script qui n'ont pu être chargés, car aucun script n'a été importé ainsi que la source audio.
Le jeu est pacifique, donc enlevez le bazooka et le « gun » du héros.

Sachant que la caméra suit toujours le personnage, placez-la comme enfant du héros et réinitialisez sa position en X et Y. Définissez sa taille à 8.

III-C. Scripts

Le premier script (en C#) à créer est le « SimplePlatformController » permettant de déplacer le personnage suivant les actions du joueur.

Dans ce script, l'auteur utilise [HideInInspector] afin de cacher la variable de l'inspecteur (de l'éditeur) tout en définissant la variable comme publique. Celle-ci sera tout de même sérialisée.

III-C-1. Gestion du saut

Le joueur ne peut pas sauter uniquement s'il appuie sur le bouton de saut. Il est aussi nécessaire de vérifier si le personnage est au sol. Pour cela, un lancer de rayon (en 2D avec LineCast) est utilisé :

 
Sélectionnez
grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));

if (Input.GetButtonDown("Jump") && grounded)
{
    jump = true;
}

III-C-2. Retourner le personnage

Afin de retourner le sprite du personnage lorsqu'il va vers la gauche, vous pouvez simplement changer sa transformation en inversant sa coordonnée X :

 
Sélectionnez
void Flip()
{
    facingRight = !facingRight;
    Vector3 theScale = transform.localScale;
    theScale.x *= -1;
    transform.localScale = theScale;
}

III-C-3. Physique du personnage

Le code suivant permet de gérer la physique du personnage : la vitesse, la direction et le saut.

 
Sélectionnez
void FixedUpdate()
{
    float h = Input.GetAxis("Horizontal");

    anim.SetFloat("Speed", Mathf.Abs(h));

    if (h * rb2d.velocity.x < maxSpeed)
        rb2d.AddForce(Vector2.right * h * moveForce);

    // Limitation de la vitesse
    if (Mathf.Abs (rb2d.velocity.x) > maxSpeed)
        rb2d.velocity = new Vector2(Mathf.Sign (rb2d.velocity.x) * maxSpeed, rb2d.velocity.y);

    // Rotation du sprite suivant sa direction
    if (h > 0 && !facingRight)
        Flip ();
    else if (h < 0 && facingRight)
        Flip ();

    if (jump)
    {
        anim.SetTrigger("Jump");
        rb2d.AddForce(new Vector2(0f, jumpForce));
        jump = false;
    }
}

III-C-4. Créer des plates-formes

Une plate-forme peut être créée à partir d'un objet 3D, dont le Box Collider 3D aura été remplacé par un Box Collider 2D. Il ne faut pas oublier de placer la plate-forme sur le calque « Ground ». Afin de pouvoir créer des plates-formes à partir d'un script, il faut transformer cet objet en préfabriqué.
De plus, un nouveau composant vide « SpawnManager » est ajouté à la scène.
Finalement, un nouveau script « SpawnManager » gérera la création des plates-formes. Celui-ci ne fait qu'instancier (avec la fonction Instanciate) les plates-formes suivant des contraintes spécifiques.

III-C-5. Chute des plates-formes

Un nouveau script « PlatformFall » est utilisé pour provoquer la chute des plates-formes une fois qu'elles sont en contact du joueur :

 
Sélectionnez
void OnCollisionEnter2D (Collision2D other)
{
    if (other.gameObject.CompareTag("Player"))
    {
        Invoke ("Fall", fallDelay);
    }
}

void Fall()
{
        rb2d.isKinematic = false;
}

III-C-6. Intégration des pièces

Après l'ajout du sprite « CoinSprite » à la scène, ajoutez un « Circle Collider 2D », cochez la boite « Is Trigger » afin que la collision n'affecte pas la physique, puis créez un nouveau script « Coin ».
Ce script permettra de supprimer la pièce de la scène une fois que celle-ci est touchée par le joueur.

III-C-7. Créer des pièces

Pour faire apparaître les pièces dans le niveau, créez trois composants vides, enfants du sol et placez-les à la position à laquelle vous voulez voir apparaître les pièces. Ensuite, créez un nouveau script « SpawnCoins » qui se chargera d'instancier les pièces aléatoirement à la position des composants vides.

III-C-8. Réinitialisation après la chute

Finalement, lorsque le joueur tombe, le jeu doit être réinitialisé. Pour cela, ajoutez un cube d'une longueur taille de 500 sur l'axe des X et placez-le en dessus du niveau. Cochez la case « Is Trigger » et associez-lui le nouveau script « Reset ». Lorsque le joueur entre en collision avec le cube, le script recharge le niveau avec la fonction LoadLevel :

 
Sélectionnez
void OnTriggerEnter2D (Collider2D other)
{
    if (other.gameObject.CompareTag("Player"))
        Application.LoadLevel(Application.loadedLevel);
}

III-D. Récapitulatif

Voici le code de chacun des scripts :

SimplePlatformController.cs
Sélectionnez
using UnityEngine;
using System.Collections;

public class SimplePlatformController : MonoBehaviour {

    [HideInInspector] public bool facingRight = true;
    [HideInInspector] public bool jump = false;
    public float moveForce = 365f;
    public float maxSpeed = 5f;
    public float jumpForce = 1000f;
    public Transform groundCheck;


    private bool grounded = false;
    private Animator anim;
    private Rigidbody2D rb2d;


    // Utilisez cette fonction pour l'initialisation
    void Awake () 
    {
        anim = GetComponent<Animator>();
        rb2d = GetComponent<Rigidbody2D>();
    }
    
    // Update est appelee une fois par frame
    void Update () 
    {
        grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));

        if (Input.GetButtonDown("Jump") && grounded)
        {
            jump = true;
        }
    }

    void FixedUpdate()
    {
        float h = Input.GetAxis("Horizontal");

        anim.SetFloat("Speed", Mathf.Abs(h));

        if (h * rb2d.velocity.x < maxSpeed)
            rb2d.AddForce(Vector2.right * h * moveForce);

        if (Mathf.Abs (rb2d.velocity.x) > maxSpeed)
            rb2d.velocity = new Vector2(Mathf.Sign (rb2d.velocity.x) * maxSpeed, rb2d.velocity.y);

        if (h > 0 && !facingRight)
            Flip ();
        else if (h < 0 && facingRight)
            Flip ();

        if (jump)
        {
            anim.SetTrigger("Jump");
            rb2d.AddForce(new Vector2(0f, jumpForce));
            jump = false;
        }
    }


    void Flip()
    {
        facingRight = !facingRight;
        Vector3 theScale = transform.localScale;
        theScale.x *= -1;
        transform.localScale = theScale;
    }
}
SpawnPlatforms.cs
Sélectionnez
using UnityEngine;
using System.Collections;

public class SpawnPlatforms : MonoBehaviour {

    public int maxPlatforms = 20;
    public GameObject platform;
    public float horizontalMin = 7.5f;
    public float horizontalMax = 14f;
    public float verticalMin = -6f;
    public float verticalMax = 6;


    private Vector2 originPosition;


    void Start () {

        originPosition = transform.position;
        Spawn ();
    
    }

    void Spawn()
    {
        for (int i = 0; i < maxPlatforms; i++)
        {
            Vector2 randomPosition = originPosition + new Vector2 (Random.Range(horizontalMin, horizontalMax), Random.Range (verticalMin, verticalMax));
            Instantiate(platform, randomPosition, Quaternion.identity);
            originPosition = randomPosition;
        }
    }

}
PlatformFall.cs
Sélectionnez
using UnityEngine;
using System.Collections;

public class PlatformFall : MonoBehaviour {

    public float fallDelay = 1f;


    private Rigidbody2D rb2d;

    void Awake()
    {
        rb2d = GetComponent<Rigidbody2D>();
    }

    void OnCollisionEnter2D (Collision2D other)
    {
        if (other.gameObject.CompareTag("Player"))
        {
            Invoke ("Fall", fallDelay);
        }
    }

    void Fall()
    {
            rb2d.isKinematic = false;
    }
}
SpawnCoins.cs
Sélectionnez
using UnityEngine;
using System.Collections;

public class SpawnCoins : MonoBehaviour {

    public Transform[] coinSpawns;
    public GameObject coin;

    // Utilisez cette fonction pour l'initialisation
    void Start () {
    
        Spawn();
    }

    void Spawn()
    {
        for (int i = 0; i < coinSpawns.Length; i++)
        {
            int coinFlip = Random.Range (0, 2);
            if (coinFlip > 0)
                Instantiate(coin, coinSpawns[i].position, Quaternion.identity);
        }
    }

}
PickupCoin.cs
Sélectionnez
using UnityEngine;
using System.Collections;

public class PickupCoin : MonoBehaviour {

    // Utilisez cette fonction pour l'initialisation
    void Start () {
    
    }
    
    // Update est appelee une fois par frame
    void Update () {
    
    }

    void OnTriggerEnter2D (Collider2D other)
    {
        if (other.gameObject.CompareTag("Player"))
            Destroy(gameObject);
    }
}
Reset.cs
Sélectionnez
using UnityEngine;
using System.Collections;

public class Reset : MonoBehaviour {

    // Utilisez cette fonction pour l'initialisation
    void Start () {
    
    }
    
    // Update est appelee une fois par frame
    void Update () {
    
    }

    void OnTriggerEnter2D (Collider2D other)
    {
        if (other.gameObject.CompareTag("Player"))
            Application.LoadLevel(Application.loadedLevel);
    }
}

IV. Commenter

Vous pouvez commenter et donner vos avis dans la discussion associée sur le forum.