Le systeme que j'utilise dans ColorSwitch est simple mais peut paraitre compliqué à comprendre à cause de ma manie a vouloir optimiser tout en y gardant une lisibilité.
Ca se presente comme ça :

  • Un script qui contient toute mes macro/enum
  • Un script qui reference les sprites pour chaque perso.
  • Un script qui contient les paramètres de chaque perso et appelle le script precedent pour les sprite
  • des script pour choper les parametres.

Ca peut s'utiliser avec ou sans parenting, mais vu qu'il y a du code commun pour le comportement des personnages (ils se controlent tous pareils et seul leur sprite et leur param sont modifiés) c'est mieux d'utiliser le parenting.

Bon pour l'instant, j'ai pas implémenté le parenting (et vas falloir que je m'y mettent)

Donc tout d'abord, j'ai un enum_macro_init :

///@func enum_macro_init()
///@desc toute les macro/enum du jeu

//les etats pour truestates
enum States{ 
    NOCHANNELING,
    HARMONY,
    PLENITUDE,
    DOMINATION,
    COMBUSTION,
    SUBMISSION,
    DEARTH,
    INIT
}

 //les perso pour recup' leur param
enum Characters{
    Marisa
}

//les parametres des perso
enum PARAMS{ 
    ID,
    NAME,
    HARMONYSPEED,
    CHAOSSPEED,
    SYNC,
    HANDLING,
    SPRITESET
}

//les nom des anim'
enum Animation{
    Idle,
    RunInHarmony,
    RunInDomination,
    RunInSubmission
}

Ensuite, j'ai un script pour référencé les anim' (leur sprites) de chaque perso.
settings_characters_spriteset(character)

 /// @func settings_characters_spriteset(character)
/// @desc La liste des sprites pour chaque personnages. Sous forme de script a appeler avec le personnage pour argument. Evite d'avoir un Array dedier pour les anims alors qu'il y en a deja un dedié dans settings_characters_data(), tout en etant plus simple a lire.
/// @arg _c
var _spriteset = [], _c = argument0
switch (_c){
    case Characters.Marisa:
        // Run in Harmony
        _spriteset[Direction.RIGHT,       Animation.RunInHarmony] = sMarisa_Harmony_Right
        _spriteset[Direction.UP_RIGHT,    Animation.RunInHarmony] = sMarisa_Harmony_UpRight
        _spriteset[Direction.UP,          Animation.RunInHarmony] = sMarisa_Harmony_Up
        _spriteset[Direction.UP_LEFT,     Animation.RunInHarmony] = sMarisa_Harmony_UpLeft
        _spriteset[Direction.LEFT,        Animation.RunInHarmony] = sMarisa_Harmony_Left
        _spriteset[Direction.DOWN_LEFT,   Animation.RunInHarmony] = sMarisa_Harmony_DownLeft
        _spriteset[Direction.DOWN,        Animation.RunInHarmony] = sMarisa_Harmony_Down
        _spriteset[Direction.DOWN_RIGHT,  Animation.RunInHarmony] = sMarisa_Harmony_DownRight
        // Run in Domination
        _spriteset[Direction.RIGHT,       Animation.RunInDomination] = sMarisa_Domination_Right
        _spriteset[Direction.UP_RIGHT,    Animation.RunInDomination] = sMarisa_Domination_UpRight
        _spriteset[Direction.UP,          Animation.RunInDomination] = sMarisa_Domination_Up
        _spriteset[Direction.UP_LEFT,     Animation.RunInDomination] = sMarisa_Domination_UpLeft
        _spriteset[Direction.LEFT,        Animation.RunInDomination] = sMarisa_Domination_Left
        _spriteset[Direction.DOWN_LEFT,   Animation.RunInDomination] = sMarisa_Domination_DownLeft
        _spriteset[Direction.DOWN,        Animation.RunInDomination] = sMarisa_Domination_Down
        _spriteset[Direction.DOWN_RIGHT,  Animation.RunInDomination] = sMarisa_Domination_DownRight
        // Run in Submission
        _spriteset[Direction.RIGHT,       Animation.RunInSubmission] = sMarisa_Submission_Right
        _spriteset[Direction.UP_RIGHT,    Animation.RunInSubmission] = sMarisa_Submission_UpRight
        _spriteset[Direction.UP,          Animation.RunInSubmission] = sMarisa_Submission_Up
        _spriteset[Direction.UP_LEFT,     Animation.RunInSubmission] = sMarisa_Submission_UpLeft
        _spriteset[Direction.LEFT,        Animation.RunInSubmission] = sMarisa_Submission_Left
        _spriteset[Direction.DOWN_LEFT,   Animation.RunInSubmission] = sMarisa_Submission_DownLeft
        _spriteset[Direction.DOWN,        Animation.RunInSubmission] = sMarisa_Submission_Down
        _spriteset[Direction.DOWN_RIGHT,  Animation.RunInSubmission] = sMarisa_Submission_DownRight
        // Idle (no Channeling)Submission
        _spriteset[Direction.RIGHT,       Animation.Idle] = sMarisa_Idle_Right
        _spriteset[Direction.UP_RIGHT,    Animation.Idle] = sMarisa_Idle_UpRight
        _spriteset[Direction.UP,          Animation.Idle] = sMarisa_Idle_Up
        _spriteset[Direction.UP_LEFT,     Animation.Idle] = sMarisa_Idle_UpLeft
        _spriteset[Direction.LEFT,        Animation.Idle] = sMarisa_Idle_Left
        _spriteset[Direction.DOWN_LEFT,   Animation.Idle] = sMarisa_Idle_DownLeft
        _spriteset[Direction.DOWN,        Animation.Idle] = sMarisa_Idle_Down
        _spriteset[Direction.DOWN_RIGHT,  Animation.Idle] = sMarisa_Idle_DownRight
        break;
}
return _spriteset

J'explique.
C'est un script qui est appelé dans l'objet Marisa (enfin a terme, vu que j'ai pas de parenting), donc dans ton cas, tu l'appelle dans le Create de ton objet Player_Red (par exemple)
Le script est un switch qui va prendre comme argument l'enum Characters Marisa.1
L'astuce, c'est que j'utilise un array temporaire dont les coordonnées corresponde à :

  • x : la direction
  • y : le type d'animation

Et j'assigne la ressource sprite correspondante.

Pour ton cas, ça serait plutot comme ça :

  • x : l'arme équipée (bazooka, noweapon, etc)
  • y : l'anim' (idle, shoot, etc)

    Ensuite je return l'array temporaire, devenu un array 2D 2 ... dans le prochain script.

    Ce prochain script, c'est celui qui va deffinir les params de chaque perso. J'ai mis ça en place avec Fuga et ca marchait bien donc je l'ai repris.

    settings_character_data()

    
    ///@func settings_character_data

///@desc Dans un global Array ou List, A l'Index Characters.name, stock un array des infos.

//characterAnims[Up,Harmony] = sMarisa_Harmony_Up

// Exemple de Setting pris de Fuga.
/*
global.db_characters = []

var _character = []
_character[@ PARAMS.ID] = characters.Malt
_character[@ PARAMS.NAME] = "Malt";
_character[@ PARAMS.JOB] = Buster
_character[@ PARAMS.SKILLSUPPORT] = SKILL.FalconEye;
_character[@ PARAMS.SKILLATTACK] = SKILL.BraveShot;
_character[@ PARAMS.ATK] = 20;
_character[@ PARAMS.CRIT] = 10;
_character[@ PARAMS.PREC] = 90;
_character[@ PARAMS.ICO] = s_ico_Malt
global.db_characters[@ _character[@ PARAMS.ID] ] = _character;
*/

global.character_db = []

var _character = []
_character[@ PARAMS.ID] = Characters.Marisa
_character[@ PARAMS.NAME] = "Marisa Kirisame"
_character[@ PARAMS.HANDLING] = 1.5
_character[@ PARAMS.SYNC] = 0.1
_character[@ PARAMS.HARMONYSPEED] = 7
_character[@ PARAMS.CHAOSSPEED] = 4
_character[@ PARAMS.SPRITESET] = settings_characters_spriteset(Characters.Marisa)
global.character_db[Characters.Marisa] = _character


  Donc une fois encore, je crée un array temporaire et chaque index correspond a un element de l'enum *Params*, la difference, c'est que je renvoie cet array dans un autre array **global** *character_db* cette fois que j'utiliserais pour recup' les params.[^atmark]

  Tu remarqueras que le script *settings_character_spriteset()* est utilisé pour le params *SPRITESET*. Ce qui veut dire que ce params contient un array egalement.

  C'est a ce moment la que je te perds : je nest les arrays comme un porc :D

  Donc faut se souvenir quoi est où (quel index de *character_db* contient une valeur ou un type de data structure) et c'est la recup' de ces valeurs qui est un peu relou avec la version actuel de GMS, la ou les nouveau array de la version 2.3 sont tout de suis plus simple a utiliser dans ce cas.
  Mais j'en parle plus tard.

 En résumé j'ai un array *global.characters_db* qui, à l'index enum *Characters* (Marisa=0 dans ce cas), contient un array (*_character*) qui contient des valeurs de *PARAMS* a chacun de ces index dont l'un (index *SPRITESET*) contient un array (2D parce que c'est pas drole) donc les index sont rempli de sprite.
 T'es toujours là ?

 Voila. Ca c'est la base du système.
 Faut bien penser a ce que chaque "block" de personnage commence par `var _character = []` et se termine par `global.character_db[Characters.Marisa] = _character`

 Ce dernier script, tu le fout dans un objet *init* dans ta premiere room ou wherever, mais faut qu'il s'execute avant la creation de n'importe quel objet *player*.

 Ensuite, on s'occupe de l'objet Marisa.

 **CREATE**
 ```gml
 var _data = global.character_db[Characters.Marisa]
spriteSet = _data[PARAMS.SPRITESET]

Et ouais, je fais une copie du block de data correspondant au personnage à partir du characters_db, j'utilise une variable temporaire (qui contient donc un array, la meme chose que l'array _character du script settings_characters_data en fait) et a partir de ça, je recupere le param SPRITESET du personnage dans une variable ... spriteset (qui devient donc l'array 2D contrnant les sprites).
Oui, on désosse ce qu'on a fait avant.

Faut savoir que la, je recupe que le spriteset, mais que je pourrais très bien recup' tout les params du perso et les assigner a une variable local. Comme ça :

   var _data = global.character_db[Characters.Marisa]
spriteSet = _data[PARAMS.SPRITESET]
charName = _data[PARAMS.NAME]
charHarmonySpeed = _data[PARAMS.HARMONYSPEED]
//etc

D'ailleurs, comme on vas utiliser le parenting, il faut rajouter et modifier un truc :

  • Creer une variable character qui contient l'enum Characters.Marisa
  • Changer var data = global.character_db[Characters.Marisa] en global.character_db[character]

Du coup, toute la recup' des params peut se faire dans l'objet Parent a condition que tu appele event_inherited APRES character = Characters.Marisa
Mais bon, une chose a la fois, parce que les ordre d'initialisation dans GMS c'est relou.

Si moi, je recup pas tout les data dans le create, c'est pour que ca reste lisible dans les script de state, j'ai donc fait un script qui me permet fe recup' le param' voulu quand j'en ai besoin. Bien sur, si tu decide de tout stocker dans des variable local, c'est moins pertinent.

character_get_param(character, parameter)

/// @func character_get_param(character, parameter)
/// @desc Permet de recuperer un parametre du personnage.
/// @param _character
/// @param _parameter
var _character = argument0, _parameter = argument1;

var _characterParams = global.character_db[_character]
var _param = _characterParams[_parameter]
return _param

Voila, tout simple mais tu remarque comment extraire des truc concatener est un peu relou. Faut a chaque fois faire une variable tempiraire qui contiendra la premiere valeur puis utiliser ces variable dans une nouvelle variable temporaire pour contenir la valeur final.
Si j'utilisais GMS v2.3, ca se ferait comme ça :
return global.characters_db[@ _character][@ _parameter]
Tu ajoutes les crochet avec l'accessor correspondant au type de data structure
Comme j'ai dit, faut juste ce rappeler le type, quoi.

Et pour finir, dans mon script concernant l'etat Harmony (j'utilise l'ancienne version de truestate, avec des if, mais tu dois avoir celle avec le switch donc ce qu'il y a dans if state_new doit ce mettre dans le case equivalent), j'appelle


//STEP---------------------------------------
if(argument0==step)
{
    if state_new{
        maxSpeed = character_get_param(Characters.Marisa, PARAMS.CHAOSSPEED)
        acceleration = character_get_param(Characters.Marisa, PARAMS.SYNC)
    }
    // code du state
}
//DRAW---------------------------------------
else if(argument0==draw)
{
    sprite = spriteSet[spriteDir,Animation.RunInDomination]
    draw_sprite(sprite, image_index, x,y)
}

Dans la partie STEP, j'appelle mon character_get_param() pour recup' les param qui m'intéresse.
Dans la partie DRAW, je recup' le sprite issue de la variable spriteset et je l'affiche.

DONE.


  1. t'occupe pas du arg, c'est comme param 

  2. y'a plus d'array 2D dans la version 2.3 de GMS, donc faut modifier le script pour utiliser les nested array 1D