2010-04-20 2 views
4

Je suis assez nouveau pour Lua, j'ai travaillé sur la mise en œuvre de scripts Lua pour la logique dans un moteur de jeu que je suis en train de mettre en place. Jusqu'à présent, je n'ai eu aucun mal à faire fonctionner Lua à travers le moteur, et je suis capable d'appeler les fonctions Lua des fonctions C et C de Lua.Comment pourrais-je faire pour partager des variables dans une classe C++ avec Lua?

De la façon dont le moteur fonctionne maintenant, chaque classe d'objets contient un ensemble de variables que le moteur peut rapidement parcourir pour dessiner ou traiter la physique. Alors que les objets du jeu ont tous besoin d'accéder et de manipuler ces variables pour que le moteur de jeu puisse voir les changements, ils sont libres de créer leurs propres variables, un Lua est extrêmement flexible à ce sujet.

Quoi qu'il en soit, actuellement, le côté Game Engine est assis en terre C, et je veux vraiment qu'ils restent là pour des raisons de performance. Donc, dans un monde idéal, lorsque je lance un nouvel objet de jeu, je dois pouvoir donner à Lua un accès en lecture/écriture à cet ensemble standard de variables en tant que partie de la classe de base de l'objet Lua. courir sauvage avec. Jusqu'à présent, je garde deux tables d'objets distinctes en place: Lua génère un nouvel objet de jeu qui s'ajoute à une table globale d'objets numériquement indexée, puis appelle une fonction C++, qui crée un nouvelle classe GameObject et enregistre l'index Lua (un int) avec la classe. Jusqu'ici tout va bien, les fonctions C++ peuvent maintenant voir l'objet Lua et effectuer facilement des opérations ou appeler des fonctions en Lua à l'aide de dostring. Ce que je dois faire maintenant est de prendre les variables C++, une partie de la classe GameObject, et de les exposer à Lua, et c'est là que google échoue. J'ai rencontré une très belle méthode here qui détaille le processus en utilisant des balises, mais j'ai lu que cette méthode est déconseillée en faveur des métabalises.

Quelle est la manière idéale d'accomplir ceci? Cela vaut-il la peine d'apprendre comment transmettre des définitions de classe en utilisant libBind ou une méthode équivalente, ou existe-t-il un moyen simple d'enregistrer chaque variable (une fois, au moment de spawn) avec l'objet global lua? Quelle est la meilleure façon "actuelle" de faire cela, à partir de Lua 5.1.4?

Répondre

4

Une approche consiste à utiliser

  • un pointage lightuserdata à la variable C++
  • une fonction C pour accéder à la variable C en utilisant la lightuserdata
  • garder le lightuserdata comme upvalue de la fonction C afin une fonction suffit pour toutes les variables
  • utiliser le nombre d'arguments de la fonction pour choisir entre obtenir et définir la variable

Par exemple:

int game_state_var_accessor (lua_State *L) 
{ 
    int *p = lua_topointer(L, lua_upvalueindex(1)); 
    if (lua_gettop(L) == 0) 
    { // stack empty, so get 
     lua_pushinteger(L, *p); 
     return 1; 
    } 
    else 
    { // arg provided, so set 
     *p = lua_tointeger(L,1); 
     return 0; 
    } 
} 

Lorsque vous faites un nouvel état de jeu, vous pouvez créer des accesseurs pour chaque variable en utilisant:

lua_pushlightuserdata(L, (int *)p); // where p points to your variable 
lua_pushcclosure(L, game_state_var_accessor, 1); 

L'accesseur est maintenant sur la pile et peut être lié à un nom global ou au nom d'une méthode dans une classe Lua. Si votre table de classe Lua est sur la pile à l'index t ce serait:

lua_setfield(L, t, "name_of_accessor"); 
+0

Question: Vous lancez le pointeur, p, à (int *), mais lua_pushlightuserdata accepts (void *) dans la documentation.Y a-t-il un avantage, autre que la lisibilité du code, à le faire de cette façon? Je me dis que je devrais créer des fonctions wrapper séparées pour différents types de variables de toute façon, cela semble juste un peu étrange. –

+0

La distribution est uniquement là pour mettre en évidence la correspondance avec le type de retour de game_state_var_accessor; en d'autres termes, pour la lisibilité. Si vous créez des wrappers pour d'autres types, vous pouvez le renommer game_state_int_accessor pour le rendre plus sain. –

+0

Cette solution fonctionne à merveille. Merci beaucoup! Et oui, j'ai fini par utiliser différentes fonctions de liant, car chacune avait besoin d'une fonction de gestion différente. Je suis encore en train d'apprendre ici, mais l'API de communication de Lua est * pure génie * et je l'aime beaucoup.^_^ –

Questions connexes