Contrôler et Lier le Jeu



Maintenant que nous avons un bon "quelque chose" avec quoi démarrer, c'est le temps de vraiment contrôler le jeu à travers la boucle principale précemment créée.


Avant l'appel à la fonction simon.Create() précédemment ajouté, nous allons ajouter un nouvel appel à la fonction simon.SetMediaPath(). Ceci spécifiera au moteur du jeu d'analyser le répertoire spécifié pour trouver ses fichiers multimédia (*.wav). Voici comment à quoi la boucle complète devrait ressembler à:



-- Show Simon game main form
simon.SetMediaPath("C:\\Prog\\Delphi\\MNet\\Bin\\Medias")
simon.Create()

-- Main processing loop
while simon.GetPowerStatus() == 1 do
    if simon.GetPlayStatus() == 1 then
        simon:Initialize()

        -- Game processing loop
        while GameState do
            UserSequenceCount = 0
            simon:AddSequence()
            simon:DisplayMessage("Simon's Turn!", "clRed", 750)
            simon:PlaySequence(MainSequence)

            simon:DisplayMessage("Your Turn!", "clLime", 1000)
            GameState = simon.GetUserSequence(SequenceCount, 2000)

            if simon:GetScore() > 1000 then
                simon:DisplayMessage("You Win!", "clAqua", -1)
                GameState = false
            end
        end
    end

    -- Make sure the processor doesn't runs for no reason
    Sleep(10)
end

simon.Destroy()


La fonction simon.GetPowerStatus() est utilisé pour déterminer si "l'allimentation" (dans notre cas virtuel) est toujours "ouverte". Si cette fonction retourne 1, cela signifie que "l'alimentation" est toujours "ouverte". La fonction simon.GetPlayerStatus() retourne 1 si le joueur à appuyé sur le boutton "play". Appeler simon.DisplayMessage() affichera la chaîne de caractères spécifiée en utilisant la couleur spécifiée (pour les codes de couleurs, jettez un coup d'oeil à la colonne "Delphi/C++ Builder" de ce site web) et et la longueur spécifiée en milisecondes. Dans notre cas, ceci sera utilisé afin de faire savoir au joueur à quel tour il s'agit. La fonction simon.GetUserSequence() demandera au joueur d'entrer sa séquence. Le premier argument spécifie la durée de la séquence à obtenir et le deuxième spécifie la valeur du "timeout" en milisecondes à utiliser avant de considérer le tour comme échec. En terme d'exécution, dans la script Lua, cet appel devrait être suspendre le code en attedant la réponse du joueur. mais eventuellement déclanchera un appel automatique du moteur du jeu à la fonction simon:OnButtonClick() chaque fois le joueur appuiera un boutton depuis le jeu. Cette fonction retourne égallement l'état de la partie (false == "game over"). Maintenant, ce qui suit devrait brièvement expliquer comment configurer la dll en C++/Delphi pour actuellement permettre à LuaEdit de se lier à votre code, dans ce cas-ci: simon.dll. (La source complète du code est disponible dans les sources du tutoriel mais pour des raison de temps et de complexité ne sera pas expliqué complètement en détails comme la script simon.lua. Seul la partie "initializer" le sera.)

Comme discuté dans l'étape 1 de ce tutoriel, votre dll DOIT exporter la fonction spécifique LuaDebug_Initializer(). Cette fonction sera appelée par LuaEdit juste avant de démarrer une session de débug. Nous allons ensuite utiliser ce "hook"/"callback" afin d'enregister toute les fonctions du moteur du jeu précédemment décrite. Ceci tracera les fonctions en Lua et préviendra LuaEdit de notifier des erreurs parce qu'il ne trouve peut trouver une référence à la fonction dans le script. De cette manière, le débuggage en temps réel sera dispnible à travers LuaEdit.


Delphi: (Cette fonction doit être ajouté dans l'instruction "exports" de votre code tout comme chacune des fonctions enregistré à l'environnement Lua qui se trouve à l'intérieur de celle-ci)


// Register a c function in a specified table
procedure LuaRegisterCustom(L: PLua_State; ndx: Integer; funcname: String; func: lua_CFunction);
begin
    lua_pushstring(L, funcname);
    lua_pushcfunction(L, func);
    lua_rawset(L, ndx - 2);
end;

// Register a c function using the globalsindex constant
procedure LuaRegister(L: PLua_State; funcname: String; func: lua_CFunction);
begin
    LuaRegisterCustom(L, LUA_GLOBALSINDEX, funcname, func);
end;

// LuaEdit is calling this function everytime a script with a project
// specifying this dll as the initializer when debugging
function LuaDebug_Initializer(L: PLua_State): Integer;
begin
    // Create new table on the lua stack
    lua_newtable(L);

    // Register delphi functions in that new table
    LuaRegisterCustom(L, -1, 'SetMediaPath', SetMediaPath);
    LuaRegisterCustom(L, -1, 'SetLight', SetLight);
    LuaRegisterCustom(L, -1, 'Create', Create);
    LuaRegisterCustom(L, -1, 'Destroy', Destroy);
    LuaRegisterCustom(L, -1, 'GetUserSequence', GetUserSequence);
    LuaRegisterCustom(L, -1, 'GetPowerStatus', GetPowerStatus);
    LuaRegisterCustom(L, -1, 'GetPlayStatus', GetPlayStatus);
    LuaRegisterCustom(L, -1, 'SetScore', SetScore);
    LuaRegisterCustom(L, -1, 'GetScore', GetScore);
    LuaRegisterCustom(L, -1, 'LockControls', LockControls);
    LuaRegisterCustom(L, -1, 'UnlockControls', UnlockControls);
    LuaRegisterCustom(L, -1, 'DisplayMessage', DisplayMessage);

    // Register other miscalleneous functions
    LuaRegister(L, 'Sleep', LuaSleep);

    // Assing "simon" lua global variable to the new table
    lua_setglobal(L, 'simon');
end;


C/C++: (Cette fonction doit être ajouté dans l'instruction "EXPORTS" de votre fichier *.def tout comme chacune des fonctions enregistré à l'environnement Lua qui se trouve à l'intérieur de celle-ci)


// Register a c function in a specified table
void LuaRegisterCustom(lua_State *L, long ndx, const char* funcname, lua_CFunction func)
{
    lua_pushstring(L, funcname);
    lua_pushcfunction(L, func);
    lua_rawset(L, ndx - 2);
}

// Register a c function using the globalsindex constant
void LuaRegister(lua_State *L, const char* funcname, lua_CFunction func)
{
    LuaRegisterCustom(L, LUA_GLOBALSINDEX, funcname, func);
}

// LuaEdit is calling this function everytime a script with a project
// specifying this dll as the initializer when debugging
int LuaDebug_Initializer(lua_State *L)
{
    // Create new table on the lua stack
    lua_newtable(L);

    // Register delphi functions in that new table
    LuaRegisterCustom(L, -1, "SetMediaPath", SetMediaPath);
    LuaRegisterCustom(L, -1, "SetLight", SetLight);
    LuaRegisterCustom(L, -1, "Create", Create);
    LuaRegisterCustom(L, -1, "Destroy", Destroy);
    LuaRegisterCustom(L, -1, "GetUserSequence", GetUserSequence);
    LuaRegisterCustom(L, -1, "GetPowerStatus", GetPowerStatus);
    LuaRegisterCustom(L, -1, "GetPlayStatus", GetPlayStatus);
    LuaRegisterCustom(L, -1, "SetScore", SetScore);
    LuaRegisterCustom(L, -1, "GetScore", GetScore);
    LuaRegisterCustom(L, -1, "LockControls", LockControls);
    LuaRegisterCustom(L, -1, "UnlockControls", UnlockControls);
    LuaRegisterCustom(L, -1, "DisplayMessage", DisplayMessage);

    // Register other miscalleneous functions
    LuaRegister(L, "Sleep", LuaSleep);

    // Assing "simon" lua global variable to the new table
    lua_setglobal(L, "simon");
}


Les fonctions LuaRegisterCustom() et LuaRegister() simplifieront la complexité du code étant donné le fait que nous aurions à répéter ces 3 lignes de code pour chaque fonction qui a besoins d'être enregistré à l'environnement Lua. Maintenant, pour complété ce projet/turotiel, tout ce dont vous avez besoins de faire est de vous inspirer du code fournis et de terminer cette dll. Comme mentionné ci-haut, cette partie ne sera pas expliqué en détails.


Maintenant, vous devriez en avoir suffisamment vue pour savoir comment Lua interragit avec LuaEdit pour éventuellement bâtir votre propre projet de cette manière afin que le code Lua soit une chose facile à débogger. J'espère grandement que ce tutoriel vous a aider de plusieurs manière. Si vous avez toujours des questions, vous pouvez toujours poster une nouvelle "thread" dans la section "Tutorial" de notre forum ou sentez à l'aiser de me contacter à l'addresse courriel suivante: jf.goulet@luaedit.net. Merci d'avoir utilisé ce tutoriel et bonne chance dans vos futur projets!



Hints:
  • Essayez le déboggage en temps réel avec la script que vous venez juste d'accomplir en utilisant le fichiers compilé simon.dll et lua.dll situés dans le répertoire bin du tutoriel. Copiez et collez le projet et la script Lua que venez de créer dans ce même répertoire, lancez LuaEdit, ajoutez un "breakpoint" sur n'importe quelle ligne de code (pas de commentaire...) et appuyez sur "play".
  • Essayez d'ajouter une logique de "Level" dans le code Lua en modifiant certaines variantes du jeu comme la vitesse d'affichage de la séquence, le "timeout" du joueur, le nombre d'item ajouté à la séquence par tour, etc...
  • Défiez vos amis/amies avec une script modifié "impossible à gagner"! :P
  • Pour des utilisateurs plus avancé, essayez d'ajouter un moteur multijoueur pour joueur sur un LAN.
  • Implémentez une application *.exe qui lancera la dll de la même manière que LuaEdit en appelant d'abord la fonction LuaDebug_Initializer() et ensuite en chargant la script Lua en utilisant l'API luaL_loadbuffer(). Jettez un coup d'oeil au code Delphi du projet SimonExec.


www.luaedit.org
© Copyright 2004-2005 LuaEdit
Lier une Dll à LuaEdit (Tutoriel)