[RPG 2D] Comment gérer la mémoire ?

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
RedStar
Messages : 38
Inscription : dim. 20/déc./2009 19:28
Localisation : Languedoc-Roussillon

[RPG 2D] Comment gérer la mémoire ?

Message par RedStar »

Bonsoir à tous !

Ayant fait mes débuts sous PureBasic il y'a plus de 5 à 6 mois (avec quelques pauses), je me suis décidé de me lancer dans la création d'un moteur de RPG.

Je tiens à souligner que je ne participais pas énormément sur les forums, et je me contentais juste du titre de "Spectateur", car je dois dire que la fonction "Rechercher" m'a été très utile pour me débrouiller tout seul jusqu'à maintenant.

Alors voila, j'ai attaqué mon moteur de RPG donc il y'a peu (2 ou 3 jours), et j'ai plutôt bien avancé ! (enfin je croît) .

Le moteur n'est capable pour l'instant que de Lire une carte et de l'afficher avec 3 couches. Le tileset est chargé et découpé en fonction des besoins.

Cependant ! Pour l'instant, tout fonctionne rapidement, correctement, mais... Je sais très bien qu'il va falloir gérer la mémoire pour éviter que le jeu "rame". C'est maintenant que je demande votre aide, je souhaiterais savoir comment gérer la mémoire dans un RPG 2D. J'ai entendu parler des "AllocateMemory()" ainsi que des Peek dans la Doc, j'ai lu quelques exemples mais je ne parviens pas à bien comprendre le principe de ceux-ci. Je vous serait très reconnaissant de bien vouloir m'éclairer sur la question.

PS : Pour ceux que ça intéresse, un petit aperçu du Moteur
Image

Amicalement,

RedStar.
Image
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: [RPG 2D] Comment gérer la mémoire ?

Message par Mesa »

Je suis un peu dans ton cas, débutant en purebasic mais pas (trop) en programmation.

Pour optimiser un jeu,je peux te donner quelques pistes, certaines sont évidentes d'autres moins.

Il faut que la boucle principale soit la plus courte possible, par exemple :
repeat
déplacement (gestion clavier/souris)
interaction (collision décors ou méchants personnages)
intelligence artificielle
until...

On peut voir le problème sous un autre angle : il faut penser le jeu pour que le joueur n'ait pas 50 choix possibles à chaque instant mais seulement un petit nombre, comme se déplacer et interagir, sans plus.
Par exemple si on veut ajouter une option de sauvegarde de la partie, on l'ajoute à la gestion du clavier dans "déplacement"; Si le joueur frappe F1 alors le jeu s'arrête, une fenêtre s'ouvre et offre divers options comme la sauvegarde...

Quand les ordinateurs n'étaient pas aussi rapide, il fallait remplacer ou éviter au maximum les "IF" et autres "CASE" pour les remplacer par des calculs ou au moins les regrouper en utilisant les opérateur logique AND OR XOR NOT etc. Par exemple, on évite les IF collision avec soldat rouge ...If collision avec soldat bleu, IF...
et on écrit if collision (soldat rouge ou bleu) et on cherche une astuce de calcul avec les codes couleurs sachant que le rouge c'est $0000FF et le bleu c'est $FF0000, on doit pouvoir jouer avec ça, avec des décalage de bits, des masques, etc.

Une autre piste est de limiter au maximum les accès au disque dur qui sont très lent. Pour cela on crée un disque virtuelle en mémoire ram qui est beaucoup plus rapide. D'ailleurs les instructions de SPRITE utilisent massivement cette mémoire. On peut mettre des data, des images dedans. Allocatememory joue un peu ce rôle, elle ne crée pas de disque virtuelle mais réserve une quantité de mémoire en ram, les peek (lire) et les poke (ecrire) permettent d'y accéder. Les fuites de mémoires (libération correcte de la mémoire) sont toujours difficile à gérer, seule l'expérience peut en venir à bout et en étudiant le code source d'autres jeux.

Et enfin, les meilleurs programmeurs utilisent la mémoires des cartes graphiques qui est encore plus performante, (avec CUDA par exemple).
L'utilisation de l'assembleur peut-être utile mais là ça dépasse mon niveau.

Voilà quelques pistes simples.

Mesa.
Avatar de l’utilisateur
RedStar
Messages : 38
Inscription : dim. 20/déc./2009 19:28
Localisation : Languedoc-Roussillon

Re: [RPG 2D] Comment gérer la mémoire ?

Message par RedStar »

Bonjour Mesa,

Avant tout, je tiens à te remercier de ta réponse très approfondie. Tu m'a éclairé sur un certains points et je t'en remercie !
Toi aussi tu travaille sur un RPG ou quelque chose de similaire ? Tu en es où? Tu t'en sors ?

RedStar.
Image
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: [RPG 2D] Comment gérer la mémoire ?

Message par djes »

La première chose que tu dois savoir faire est de calculer l'espace mémoire (je parle de la RAM) occupé par les cartes de ton jeu. Par ex s'il s'agit d'un tableau de longs (.l sur un x86), de 30 sur 30, ça fait 30x30x4 octets. S'il y a trois niveaux, tu multiplies par 3. De là, tu sais si tu est dans le domaine du raisonnable, ou si tu vas devoir utiliser le disque dur et donc faire des chargements avec gestion de la mémoire de façon dynamique. Si tu utilises des structures ou d'autres choses, tu peux utiliser sizeof() pour avoir cette information. Même pour un RPG, je doute que tu doives faire quelque chose d'ultra compliqué ; à ta place je me limiterais de façon à faire simple !
Avatar de l’utilisateur
Fig
Messages : 1176
Inscription : jeu. 14/oct./2004 19:48

Re: [RPG 2D] Comment gérer la mémoire ?

Message par Fig »

Il n'y a aucune raison qu'avec un rpg tu dépasse la taille mémoire disponible à moins de faire vraiment n'importe quoi avec les dimensions de tes structures.
Fait des "checkpoints" pour passer d'une carte à l'autre et ajuste la dimension de chaque carte en fonction de la mémoire supposée. (1Go de mémoire disponible ça fait déjà des cartes monstrueuses, et c'est généralement le minimum sur un pc aujourd'hui)

Ton screenshot est vraiment "kawaï", bonne continuation ! :wink:
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
Avatar de l’utilisateur
RedStar
Messages : 38
Inscription : dim. 20/déc./2009 19:28
Localisation : Languedoc-Roussillon

Re: [RPG 2D] Comment gérer la mémoire ?

Message par RedStar »

Tout d'abord, merci à vous pour vos réponses qui m'ont été très utiles je dois l'avouer !

Cependant, je pense qu'il est nécéssaire dans un RPG 2D de gérer un minimum la mémoire, du moins pour mon moteur, car je compte ajouter une multitude d'effets au moteur (effets de lumière, brouillards, pluie, orages, etc...).

Mais bon je vais quand même tenter de continuer le développement du moteur sans toucher à la mémoire et lorsque ça se mettra à "ramer", j'essayerait de gérer la mémoire.

Si vous souhaitez encore partager vos avis, n'hésitez pas :)

Et oui le Screen fais un peu "Kawaï" mais ce n'est qu'un Tileset d'exemple :).

RedStar.
Image
Avatar de l’utilisateur
Fig
Messages : 1176
Inscription : jeu. 14/oct./2004 19:48

Re: [RPG 2D] Comment gérer la mémoire ?

Message par Fig »

Tu devrais pouvoir afficher 4000-5000 tiles sans descendre sous les 60FPS.

Un grand sprite pour le brouillard, une alternance de 4-5 pour la pluie... Pas de problème apparemment niveau mémoire à prévoir.
Juste, quand tu as fini un monde/niveau, tu recharge une nouvelle carte...

Et Kawaii c'est un compliment je trouve Image
Il y a deux méthodes pour écrire des programmes sans erreurs. Mais il n’y a que la troisième qui marche.
Version de PB : 6.00LTS - 64 bits
Avatar de l’utilisateur
RedStar
Messages : 38
Inscription : dim. 20/déc./2009 19:28
Localisation : Languedoc-Roussillon

Re: [RPG 2D] Comment gérer la mémoire ?

Message par RedStar »

Et bien merci du compliment alors ! :p

Je vais continuer de trafiquer un peu de mon côté et on verra bien ce que ça donne :).
Image
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: [RPG 2D] Comment gérer la mémoire ?

Message par blendman »

Salut Redstar, c'est chouette de voir un autre jeu style RPG développé en pure :D.
En plus, j'aime beaucoup les jeux kawaï, si le scénario est un peu poussé, ça peut être vraiment très sympa.

Sinon, concernant la mémoire, je suis loin d'être un spécialiste, mais étant donné que je développe moi aussi un jeu de ce style/genre-là, je me dis que quelques remarques/réflexions pourraient t'être utiles, qui sait ;).

Alors, tout d'abord, je dirais qu'il y a plusieurs types de mémoires (si je ne dis pas de bêtises) :
- la mémoire vidéo
- la RAM
Je pense que l'on peut voir assez facilement ce que l'on utilise grâce au gestionnaire des taches.
Je ne sais pas par contre ce que cela donne niveau mémoire vidéo, doit-on ajouter la taille de chaque sprite utilisé sur la map et faire la somme pour connaitre ce que l'on consomme en mémoire vidéo ?

Sinon, pour tes cartes, il faut partir sur une taille de base pas trop grande. Personnellement, j'utilise en général quelque chose comme 4000*3000 (environ). C'est assez petit, mais déjà largement suffisant pour faire des maps assez variées.

Sur ces maps, si tu utilises des sprites en tilesets, tu vas donc diviser par les cases que tu gères (dans ton tableau). Moi, je ne fais pas cela, j'utilise comme fond une image qui se répète sur la longueur de ma map. Et au dessus, j'ajoute mes couches de sprites (en général des png).
J'utilise catchsprite() pour les charger directement en mémoire.

Quelques remarques concernant l'optimisation :
- il ne faut afficher et ne s'occuper que de ce que l'on voit à l'écran. sauf pour certaines choses, comme le déplacement des mobs par exemple si c'est nécessaire.
- il vaut mieux utiliser des sprites3D que des sprites.
- il faut éviter d'utiliser des fonctions comme plot(), drawtext() circle(), etc.. et préférer les sprites3D encore (conseil de G-rom).
- il faut privilégier lorsque cela est possible les map(), plutôt que les listes c'est un peu plus rapide (conseil de G-rom).
- il faut aussi privilégier les constantes par rapport au map() par exemple lorsque cela est possible, c'est plus rapide (conseil de Djes et G-rom).
- si tu dois gérer beaucoup d'objets, et de structures, il peut être intéressant de créer plusieurs petites structures, plutôt que des grosses structures. Idem pour les liste (list()), map() ou tableau.
- il faut toujours veiller à utiliser le meilleur type pour la variable (a,b,w,q..), voire gérer plusieurs choses dans une seule variable (par exemple le fullscreen + le choix de la résolution).
- lorsque tu charges une nouvelle carte, si tu as utilisés des map(), list() ou array (tableau), n'oublies pas de faire un freemap(), freelist(), etc si ce la est possible.
- enfin, une chose importante, il faut gérer l'affichage et ce qui est lié à cela dans une boucle spécifique (c'est un conseil de G-rom ;))

un exemple rapide pour comprendre la gestion de l'affichage dans une "boucle" spécifique :

Code : Tout sélectionner

;{ structures & variables globales
Structure StEnnemi
id.w
x.w
y.w
vie.q
degat.q
radar.q
level.a
type.a
agressivite.a
speed.b
sprite.a
EndStructure

Global NewList ennemis.StEnnemi()

Global GbChecktime.l,GbFpsMax.b=60
;}

;{ enumeration
Enumeration 
  #SpEnnemiNeutre
  #SpEnnemiBad
EndEnumeration
;}

;{ declaration
Declare DisplayEnnemis()
Declare Affichage()
Declare FPS()
;}

;{ init
If InitSprite() =0 Or InitSprite3D() =0 Or InitKeyboard() =0 Or UseJPEGImageDecoder() =0 Or UsePNGImageDecoder() =0 
  MessageRequester("Error","Error directX")
  End
EndIf
;}

;{ open window
OpenWindow(0,0,0,1024,768,"Ennemis",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0),0,0,1024,768,0,0,0)

CreateSprite(#SpEnnemiNeutre,32,32, #PB_Sprite_Texture)
CreateSprite3D(#SpEnnemiNeutre,#SpEnnemiNeutre)
StartDrawing(SpriteOutput(#SpEnnemiNeutre))
Box(0,0,32,32,RGB(0,0,50))
StopDrawing()

CreateSprite(#SpEnnemiBad,32,32, #PB_Sprite_Texture)
CreateSprite3D(#SpEnnemiBad,#SpEnnemiBad)
StartDrawing(SpriteOutput(#SpEnnemiBad))
Box(0,0,32,32,RGB(50,0,0))
StopDrawing()

For i = 0 To 19
  AddElement(ennemis())
  With ennemis()
    \level = 1+Random(5)
    \degat = 2 + \level
    \agressivite = Random(1)
    \radar = 150 + \agressivite*250
    While \speed = 0;Not (\speed = -1 Or \speed = 1)
      \speed = Random(1)-Random(1)+ \agressivite*(Random(1)-Random(1))
    Wend
    \x = Random(1024)
    \y = Random(768)
    \sprite = \agressivite*#SpEnnemiBad + (1-\agressivite)*#SpEnnemiNeutre
  EndWith
Next i

;}

;{ boucle
Repeat
  If (ElapsedMilliseconds() > GbCheckTime + 1000 / GbFpsMax)
    GbCheckTime = ElapsedMilliseconds() 
    ; ici, tu places l'affichage (y compris le déplacement des ennemis par exemple, car cela doit être régulier)
    Affichage()
    FPS() ; pour afficher le fps du drawing
  Else   
    Delay(1)
  EndIf 
  ; ici, tu places les events 
  ;FPS() ; pour afficher le fps des events normaux -> les 2 fps seront différents.
  event = WaitWindowEvent(1) 
Until quit = 1 Or event = #PB_Event_CloseWindow

FreeList(ennemis())
End

;}

;{ procedures
Procedure DisplayEnnemis()
  ForEach ennemis()
    With ennemis()
      If \x >=-32 And \x <= 1024+32 And \y>=-32 And \y <= 768+32
        \x + \speed
        \y + \speed
        DisplaySprite3D(\sprite,\x,\y)
      Else
        If \speed>0
          \x = -32
          \y = Random(768)
        Else
          \x = 1024+32
          \y = Random(768)
        EndIf      
      EndIf      
    EndWith    
  Next
EndProcedure
Procedure Affichage()
  ClearScreen(RGB(125,125,125))
  Start3D()
  DisplayEnnemis()
  Stop3D()  
  FlipBuffers()  
EndProcedure
Procedure FPS()
  Shared s, fps
  ss=Second(Date())
  fps+1
  If s<>ss
    s=ss
    SetWindowTitle(0,"FPS: "+Str(FPS))
    fps=0
  EndIf
EndProcedure
;}
Dans cet exemple, on pourrait avoir 2 structures pour les ennemis : avec agressivité et sans, histoire de ne gérer qu'un seul type d'ennemi à la fois.

Logiquement, tu ne devrais avoir aucun problème de ralentissement, sauf si tu utilises 1000 sprites de 1024*1024 et que tu les affiches tous à l'écran en même avec des effets de lumières :).

Pour tes effets de pluie, je te conseille de créer un système de particules avec quelques sprites 3D, ça fonctionne super bien ;-).
Voici un exemple de celui que j'ai conçu :
http://vimeo.com/29825802
http://vimeo.com/29917047
Avatar de l’utilisateur
RedStar
Messages : 38
Inscription : dim. 20/déc./2009 19:28
Localisation : Languedoc-Roussillon

Re: [RPG 2D] Comment gérer la mémoire ?

Message par RedStar »

Bonjour Blendman !

Heureux de savoir que tu développe un jeu de ce style aussi (j'y est d'ailleurs jeté un coup d'oeil et je dois dire que je suis bluffé !).

Je te remercie aussi de ta réponse très complète qui me sera plus qu'utile notamment concernant les sprites 3D car il me semble qu'ils utilisent la mémoire vidéo ce qui permet un affichage plus rapide (j'avais lu quelque chose comme ca sur les forums).

Concernant le screenshot, je ne réalise pas un jeu mais un moteur qui me permettra de développer mon propre jeu par la suite !

Je vous tiens au courant de l'avancement du moteur :).

Amicalement,

RedStar.
Image
Fred
Site Admin
Messages : 2809
Inscription : mer. 21/janv./2004 11:03

Re: [RPG 2D] Comment gérer la mémoire ?

Message par Fred »

Un conseil: n'essaie jamais d'optimiser qqchose avant d'etre confronté reellement au problème. Dans ton cas, il y a de tres fortes chances que la memoire ne soit pas du tout un probleme.
Avatar de l’utilisateur
RedStar
Messages : 38
Inscription : dim. 20/déc./2009 19:28
Localisation : Languedoc-Roussillon

Re: [RPG 2D] Comment gérer la mémoire ?

Message par RedStar »

Merci Fred pour ton aide :).

Pour consulter l'avancement du projet (comme je vous l'avais promis), ça se passe ici ! : http://www.purebasic.fr/french/viewtopi ... =8&t=12388
Image
Répondre