Chronospatium

Chronospatium

Ce projet de conception de jeu à été réalisé en équipe de 4 contenant 2 artistes et 2 programmeurs. Lors de ce travail d’équipe, mes tâches étaient de :

  • Concevoir la mécanique de génération d’une carte sur une grille donnant l’impression d’être aléatoire.
  • Permettre la téléportation du personnage.
  • Gérer l’affichage des différents éléments de UI (Charges de téléportation et affichage des effets négatifs dans le UI).
  • Programmer le fonctionnement des ennemis dans le mon « futuriste ».
  • Programmer le changement des bonus / malus lors de l’activation d’un interrupteur.
  • Sonoriser certaines interactions.

Exemples de code conçus lors de ce projet

Fonction de patrouille des ennemis du monde « futuriste ».

private IEnumerator CoroutinePatrouille()
{
    // initialisation d'un compteur pour determiner chaque point a atteindre
    int iCible = 0;
    while (true) //pour toujours
    {
        // attend une duree avant de commencer le mouvement
        yield return new WaitForSeconds(_dureePause);
        // augmente la valeur de la cible pour aller a un prochain marqueur ou retour a zero si la valeur est trop grande
        iCible++;
        if (iCible >= _lPos.Count) iCible = 0;

        // tant que la distance entre le gameobject et le marqueur n'est pas assez petite
        while (Vector2.Distance(_rb.position, _lPos[iCible]) > _toleranceDestination)
        {
            // Modifie les coordonnes du point a atteindre pour empecher que l'ennemi se mette a voler
            //Haut et Bas
            if(_orientationEnnemi == SensObjet.haut || _orientationEnnemi == SensObjet.bas)
            {
                // prend le y de l'ennemi au lieu de la valeur du marqueur si l'ennemi doit etre a l'horizontale
                _lPos[iCible] = new Vector2(_lPos[iCible].x, transform.position.y);
            }
            //Gauche
            else if(_orientationEnnemi == SensObjet.gauche || _orientationEnnemi == SensObjet.droite)
            {
                // prend le x de l'ennemi au lieu de la valeur du marqueur si l'ennemi doit etre a la verticale
                _lPos[iCible] = new Vector2(transform.position.x, _lPos[iCible].y);
            }

            // calcule la position pour que le gameobjectse rapproche de sa cible (marqueur)
            Vector2 nouvPos = Vector2.MoveTowards(transform.position, _lPos[iCible], _vitesse * Time.deltaTime); //fixedDeltaTime

            // approche le gamobject (deplacement)
            _rb.MovePosition(nouvPos);

            // retour a l'execution
            yield return new WaitForFixedUpdate();
        }
        _rend.flipX = !_rend.flipX;
    }
}

Fonction nécessaire au fonctionnement du lance portail.

/// <summary>
/// #tim Jeremie
/// Genere le projectile portail si le joueur possede les charges necessaires
/// </summary>
private void LancerPortail()
{
    // instancie le prefab de portail a la position du perso
    _goProjPortail = Instantiate(_prefabProjPortail, transform.position, Quaternion.identity);
    // enregistre la reference du gameobject de portail sur la scene dans le SO InfosPerso
    _iPerso.projectilePortail = _goProjPortail;

    // obtient la composante du script du projectile portail
    ProjectilePortail scriptProjectilePortail = _goProjPortail.GetComponent<ProjectilePortail>();
    // envoie la direction vers laquelle le joueur se deplace (0 s'il ne bouge pas)
    scriptProjectilePortail.directionHorizontale = _srPerso.flipX; // retourne la valeur de la direction vers laquelle le joueur "regarde"
    scriptProjectilePortail.directionVerticale = Input.GetAxisRaw("Vertical"); // retourne la valeur de deplacement horizontal

    _existeProjPortail = true; // enregistre le fait qu'un portail est sur la scene
}

/// <summary>
/// #tim Jeremie
/// Teleporte le personnage sur l'instance du portail present sur la scene
/// (Utilise par le lance portail pour forcer le joueur a retourner a sa position apres son delais
/// + par le lance portial lui meme)
/// </summary>
public void TeleporterSurPortail()
{
    // obtient la composante de script du projectile portail enregistre en reference
    ProjectilePortail scriptProjectilePortail = _goProjPortail.GetComponent<ProjectilePortail>();
    // si le delais necessaire a attendre entre l'apparition et la teleportation est atteint
    if(scriptProjectilePortail.peutTeleporter)
    {
        // deplace le joueur sur le projectile de portail
        transform.position = _goProjPortail.transform.position;
        // enregistre le fait qu'aucun portail n'est sur la scene
        _existeProjPortail = false;
        // detruit le projectile portail enregistre en reference dans les SO infosPerso
        Destroy(_iPerso.projectilePortail);
        // joue le son de teleportation
        GestAudio.instance.JouerSon(_sonTeleportation);
    }
}

Système d’inventaire complet conçus grâce à des « Scriptable Object ». (Pratique d’utilisation de « Scriptable Objects », un inventaire beaucoup plus simple aurait été possible)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Classe du bonus donnant des points en forme bonus ou qui inverse les commandes du joueur en mode malus
/// Auteurs du code: Jeremie Genier
/// Auteur des commentaires: Jeremie Genier
/// </summary>

[CreateAssetMenu(menuName="Infos du perso",fileName="InfosDuPerso")] //consigne de creation du menu de creation de l'asset
public class InfosPerso : ScriptableObject
{
    [Header("Valeurs initiales")] //Entete de section pour les valeurs initiales avant la partie
    [SerializeField] private string _nomIni; //nom par defaut
    [SerializeField] private int _vieIni = 10; // nombre de vie initial
    [SerializeField] private int _nbPtsIni = 0; // nombre de points initial
    [SerializeField] private int _multiPtsIni = 1; // multiplicateur de points initial
    [SerializeField] private int _nbChargesPortailIni = 0; // nombre de charges du lance portail initial
    private Dictionary<string,int> _dEffetsIni = new Dictionary<string,int>(); // effets initiaux sur le perso (aucun)_projectilePortail
    private GameObject _projectilePortailIni = null;

    [Header("Valeurs en cours")] //Entete de section pour les valeurs durant la partie
    [SerializeField] private string _nom; //nom durant la partie
    [SerializeField] private int _vie; // nombre de vie durant la partie
    [SerializeField] private int _nbPts; // nombre de points durant la partie
    [SerializeField] private int _multiPts; // multiplicateur de points durant la partie
    [SerializeField] private int _nbChargesPortail = 0; // nombre de charges du lance portail durant la partie
    private Dictionary<string,int> _dEffets; // effets sur le perso durant la partie
    private GameObject _projectilePortail;

    [HideInInspector] public string _nomIntermediaire =""; //nom intermediaire, correspond au nom inscrit dans le champ par le joueur (avant le jeu)

    public string nom { get => _nom; set => _nom = value; } //accesseur et mutateur du nom
    public int vie { get => _vie; set => _vie = value; } // accesseur et mutateur du nombre de vies en cours de partie
    public int nbPts { get => _nbPts; set => _nbPts = value; } // accesseur et mutateur du pointage en cours de partie
    public int multiPts { get => _multiPts; set => _multiPts = value; } // accesseur et mutateur du multiplicateur de pointage en cours de partie
    public int nbChargesPortail { get => _nbChargesPortail; set => _nbChargesPortail = value; } // accesseur et mutateur du nombre de charges de portail durant la partie
    public string nomIntermediaire { get => _nomIntermediaire; set => _nomIntermediaire = value; } //accesseur et mutateur du nom intermediaire
    public Dictionary<string,int> dEffets { get => _dEffets; } // accesseur au dictionnaire des effets
    public GameObject projectilePortail { get => _projectilePortail; set => _projectilePortail = value; }

    /// <summary>
    /// Initialisation des valeurs par defaut
    /// </summary>
    public void Initialiser()
    {
        if(_nomIntermediaire != "") _nom = _nomIntermediaire;  //si le nom inter n'est pas vide, changer le nom selon le nom inter
        else { _nom = _nomIni; }  //sinon, changer le nom pour le nom par defaut
        _nomIntermediaire = "";  //vider le nom inter, pour la prochaine fois!

        _vie = _vieIni; // La vie obtient sa valeur initiale
        _nbPts = _nbPtsIni; // Le nombre de points obtient sa valeur initiale
        _multiPts = _multiPtsIni; // Le multiplicateur de score obtient sa valeur initiale
        _dEffets = _dEffetsIni; // Vide le dictionnaire des effets
        _projectilePortail = _projectilePortailIni; // efface la reference au projectile si il en as une
    }

    /// <summary>
    /// Enregistre un effet sur le personnage (peut avoir plusieurs fois le meme effet en cours)
    /// </summary>
    /// <param name="nomEffet">Nom de l'effet a ajouter</param>
    /// <param name="quantite">Quantite a ajouter</param>
    public void AjouterEffet(string nomEffet, int quantite)
    {
        // si l'effet existe deja dans le dictionnaire
        if(_dEffets.ContainsKey(nomEffet)){
            // agmente le nombre d'effet
            _dEffets[nomEffet] += quantite;
        }
        else
        {
            // Ajoute l'effet au dictionnaire
            _dEffets.Add(nomEffet,quantite);
        }
    }

    /// <summary>
    /// Reduit l'effet sur le personnage (plusieurs effets en quantite = plusieurs fois le meme effet en cours sur le perso)
    /// </summary>
    /// <param name="nomEffet">Nom de l'effet a reduire</param>
    /// <param name="quantite">Quantite a retirer</param>
    public void ReduireEffet(string nomEffet, int quantite)
    {
        if(_dEffets.ContainsKey(nomEffet)){
            // si la reduction ne reduit pas l'effet en bas de 0
            if((_dEffets[nomEffet] - quantite) >= 0)
            {
                // reduit l'effet de la quantite obtenue en parametre
                _dEffets[nomEffet] -= quantite;
            }
            // sinon, l'effet tombe a zero
            else
            {
                // met la valeur de l'effet a 0 (donc aucun effet)
                _dEffets[nomEffet] = 0;
            }
        }
        else
        {
            // message d'erreur
            Debug.Log("Réduction d'effet impossible : Effet non existant");
        }
    }

}


// Cette fonctionest contenue dans le contrôleur du personnage

/// <summary>
/// #tim jeremie
/// Fonction activee lors d'un changement a propos des effets sur le personnage.
/// Reduction ou Augmentation.
/// </summary>
private void MiseAJourEffets()
{
    //EFFET INVERSEMENT
    // Si le dictionnaire contient le champ "Inversement" avec une valeur plus grande que 0, (donc inversement actif)
    if(_iPerso.dEffets["Inversement"] > 0){
        // Sers à inverser la valeur de deplacement horizontal GetAxis
        _inversementCommandes = true;
        // Affichage icone de l'effet
        GestUI.instance.AfficherEffet("Inversement",1);
    }
    else{
        _inversementCommandes = false; // Desactive l'effet si la valeur est 0 (inactif)
        // Retire l'icone de l'effet
        GestUI.instance.EffacerEffet("Inversement");
    }
}
Logiciels utilisés
  • Unity
  • Blender
  • Photoshop
Crédits et sources
  • Modèles 3D, musique, composants UI et textures crées par Alex Tremblay et Xavier Coursol
  • La programmation à été réalisée avec l’aide de Vincent Chalifoux
  • Effets sonores provenant de opengameart.org