une map 2D evolué

Programmation avancée de jeux en PureBasic
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

une map 2D evolué

Message par Thyphoon »

des jeux avec des Map 2D j'en ai déjà fait des tonnes, mais jusqu'a present le decor était fixe.
j'avais donc un simple tableau
Global Dim Map.l(512,512) qui retournait le n° du sprite a afficher
Oui mais voilà maintenant je veux une MAp ou l'on puisse avoir des portes qui s'ouvre, des ventilateurs, etc.... mais aussi de simple sprite fixe.
Le problème est qu'il faudrait que si un objet s'actionne sur une partie de la carte qui n'est pas affiché, elle se joue quand même, même si on la voie pas.
Exemple vous avez un bouton vous cliquez et ça ouvre une porte au bout d'un long, long couloire. Vous avez un temps limité pour y arriver avant qu'elle ne se referme.
Il ne faut pas non plus que lorsque vous ouvrez une porte. Toute les portes s'anime aussi.

Mon problème est là comment structurer toutes ces données.
j'ai déjà fait plusieurs test, mais j'arrive a des tableaux tres lourds...
Comment fait on dans les jeux style alien breed par exemple ? (quoi que là l'annimation n'a lieu que si on la voie)

Tout vos conseille sont les bienvenus.
minirop
Messages : 321
Inscription : mer. 02/août/2006 21:06

Message par minirop »

perso je passerais pas un tableau de "Sprite" (une classe perso dont descend les classes "Portes", "Interrupteur",...)

enfin en PB ce sont des structures et des fonctions.
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

minirop a écrit :perso je passerais pas un tableau de "Sprite" (une classe perso dont descend les classes "Portes", "Interrupteur",...)

enfin en PB ce sont des structures et des fonctions.
Si tu as un exemples n'hesite pas...voilà pour l'instant ce que j'ai étudié mais je ne sais pas si c'est vraiment comment ça qu'il faut procéde

Code : Tout sélectionner

Structure Anim
 NoSprite.l ; No du sprite
 Time.w     ; temps durant la quelle l'image est affiché
 Sound.l    ;si il y a un son a jouer
EndStructure

Global Dim Anim.Anim(1000,100) ;(No de l'Animation, le nombre d'image
Global Dim Anim_NbImage.w(1000);(No de l'Animation) contient le nombre d'image de l'anim
Global NbSprite,NbAnim

;- Bloc
#_NbBlocMax=500 ; Nombre de Bloc maximum

Structure Bloc
  Type.l
  State.l
  NoImage.l
  WaitImage.l
EndStructure

Global Dim Bloc.Bloc(#_NbBlocMax),NbBloc.l
Global Dim BlocState.l (#_NbBlocMax,14)
;BlocState renvoie le n° d'Animation corespondant a un etat Ex: BloState(NoBloc,State)=NoAnim

Structure Map
  NoBloc.l      ; No du bloc
  State.l         ; son état 
  NoImage.l   ;le n° de l'image de l'animation
  WaitImage.l ;le temps avant la prochaine image
 EndStructure

;- Map
#_MapMax=512 ; Largeur ou Hauteur Maximum d'une carte
Global Dim Map.Map(#_MapMax,#_MapMax)
je sais pas si c'est tres claire parcontre... :?
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

Dans le tutoriel d'un RPG 2D qui se trouve dans ma signature, il y a un chapitre sur la gestion des événements.

Tu peux créer différents événements comme l'ouverture d'une porte, la gestion des ventilateurs etc..

de cette façon tu vas créer une structure par événement et une procédure par événement, et tu pourras en ajouter à volonté sans casser le reste de ton programme.

Voici un extrait du tutoriel concernant les événements
dans le tutoriel on peut se téléporter, ouvrir un dialogue simple, gérer une bataille, gérer une auberge, changer un tile par exemple pour ouvrir un coffre ( ou une porte dans ton cas).

Ensuite tu as une procédure qui teste les événements et appelle la procédure correspondante.

Code : Tout sélectionner

;Type d'évènement : e_event_type
Enumeration
  #EVENT_NULL
  #EVENT_TELEPORT
  #EVENT_DIALOG   
  #EVENT_BATTLE
  #EVENT_SHOP
  #EVENT_INN
  #EVENT_CHANGETILE
EndEnumeration

;définit quelle action permet de déclencher un événement : e_event_action
Enumeration
  #EVENT_ACTION_AUTO
  #EVENT_ACTION_ONKEYPRESS
EndEnumeration

Structure s_event
  type.l
  onaction.l
  proba.b
  *param.LONG
  player_anim.l
  *sound.l
  is_unique.b
  *Next.s_event
EndStructure

Structure s_lib_event 
  global_event.s_event
  *map_event.s_event
  *sprite_event.s_event
EndStructure

;paramètres des événements 
Structure s_event_param_teleport 
  filename.s
  startX.l
  startY.l
EndStructure

Structure s_event_param_dialog 
  dialog.s
EndStructure

Structure s_event_param_battle 
  n_monstre.l
  *fond
  *fondu
  *monstres.s_monstre
EndStructure

Structure s_event_param_shop 
  n_item.l
  *itemId.long
  *coutItem.long
  *prixVente.long
EndStructure

Structure s_event_param_inn 
  cout.l
EndStructure

Structure s_event_param_changetile 
  x.l
  y.l
  newtile.l
EndStructure
voici la procédure qui teste les événements du jeu

Code : Tout sélectionner

Procedure DoEvent(*event.s_event, *libevent.s_lib_event, *map.s_map, *libsprite.s_lib_sprite, *player.s_player,*gui.s_gui)
  Define.s_event_param_shop *Ptparam_shop 
  Define.s_event_param_inn  *Ptparam_inn
  
  If *event = #Null : ProcedureReturn 0 : EndIf
  If *event\type = #EVENT_NULL : ProcedureReturn 0 : EndIf
  If *event\sound : PlaySound(*event\sound) : *event\sound = 0 : EndIf        

  Select *event\type
      
    Case #EVENT_TELEPORT
      DoEventTeleport(*event, *libevent, *map, *libsprite)
      ProcedureReturn 1
        
    Case #EVENT_DIALOG
      DoEventDialog(*event, *gui, *map, *libsprite)
        
    Case #EVENT_BATTLE
      DoEventBattle(*event, *libevent, *map, *libsprite)
        
    Case #EVENT_SHOP
      DoEventShop(*event, *map, *libsprite, *player, *gui)
        
    Case #EVENT_INN
      DoEventInn(*event, *map, *libsprite, *player, *gui)
          
    Case #EVENT_CHANGETILE
      DoEventChangetile(*event, *map)
            
  EndSelect    
  
  If *event\is_unique
      
    ;suppr. de l'événement 
    Select *event\type
        
      Case #EVENT_NULL
          
      Case #EVENT_TELEPORT
        FreeMemory(*event\param)
          
      Case #EVENT_DIALOG
        FreeMemory(*event\param)
          
      Case #EVENT_BATTLE
        FreeMemory(*event\param)
          
      Case #EVENT_SHOP
        *Ptparam_shop = *event\param
        FreeMemory(*Ptparam_shop\itemId)
        FreeMemory(*Ptparam_shop\coutItem)
        FreeMemory(*Ptparam_shop\prixVente)
        FreeMemory(*event\param)
          
      Case #EVENT_INN
        FreeMemory(*event\param)
      
      Case #EVENT_CHANGETILE
        FreeMemory(*event\param)  
            
    EndSelect
    *event\type = #EVENT_NULL
    *event\onaction = #EVENT_ACTION_AUTO
    *event\param = #Null
  EndIf
  
  ProcedureReturn 0
    
EndProcedure
et voici une procédure simple qui gère un événement

Code : Tout sélectionner

Procedure DoEventTeleport(*event.s_event, *libevent.s_lib_event, *map.s_map, *libsprite.s_lib_sprite)
    
  Define.s file_map, file_sprite, file_event
  Define.s_event_param_teleport *param
  
  *param = *event\param
  
  If *param\filename = #NULL$
      
    SpriteMove(*libsprite\sprites, *param\startX, *param\startY, *map)
      
  Else 
    file_map    = *param\filename + ".map"
    file_sprite = *param\filename + ".sprite"
    file_event  = *param\filename + ".event"

    FreeMap(*map)
    FreeSprites(*libsprite)
    FreeLibEvent(*libevent,*map,*libsprite)
    
    LoadSprites(*libsprite, file_sprite)
    
    LoadMap(*map, file_map)
     
    loadEvent(*libevent,*map,*libsprite,file_event)
    
    SpriteMove(*libsprite\sprites, *param\startX, *param\startY, *map)
      
  EndIf
EndProcedure
ET là je sais que ce n'est pas très clair, il faut se taper le tutoriel depuis le début pour bien suivre :)

[EDIT]
Voici l'introduction sur les événements

Code : Tout sélectionner

Avant de commencer, qu'est-ce qu'un événement dans un rpg?

Il s'agit de toutes les interactions possibles entre le joueur et le jeu durant la partie. Quelques exemples:

    * un dialogue entre un pnj et notre héros
    * un changement de carte
    * une téléportation dans la carte actuelle
    * l'affichage du menu de l'auberge ou bien d'un marchand
    * une bataille
    * un changement de musique
    * un effet graphique: pluie, neige, tremblement de terre, éclair, etc.
    * etc. 

Ce ne sont évidemment que quelques exemples. Ce système est conçu pour que vous puissiez rajouter n'importe quel autre événement non-géré actuellement. Cinq événements différents seront prévus dans cette étape. Seule l'événement téléportation sera totalement fonctionnel à la fin de cette partie, les autres suivront dans les prochaines étapes.


Ces événements peuvent être liés:

    * à la carte: l'événement se déclenche quand on passe sur un tile déterminé
    * à un sprite: l'événement se déclenche quand on passe près d'un sprite donné
    * ou bien il peut s'agir d'un événement global. Il peut se déclencher potentiellement à tout moment. 


D'autres paramétrages sont intégrés au système:

    * l'événement se déclenche si l'on appuie sur espace au lieu de se déclencher automatiquement
    * l'événement se déclenche X fois sur 100
    * l'événement est unique: il n'arrivera qu'une fois. 

Un son peut être associé à l'événement et l'événement peut également changer l'animation actuelle du joueur.


En combinant plusieurs événements, ce système permet de réaliser n'importe quelle opération complexe. 
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Merci comtois. J'ai bien compris l'interret d'avoir une liste concernant les evenements. Mais je nage complètement concernant les structures complète. Pourtant j'ai déjà étudier ton tutoriel. Je comprends ce qui est marqué etc... mais je n'arrive pas a transposer pour mes besoins
dans ma tête voilà comment ça se structure

j'ai des sprites
j'ai des animations
j'ai des Objets qui ont différent état et ces etats peuvent être lié ou a un sprite ou a une animation

La carte qui elle même est constituer d'Objet a un état.(même le sol peux avoir plusieurs état différent)


Et si j'ai bien compris ton tutoriel il me faudrait alors un Objet part case de la Map ce qui devient lourd non ? ça fait 3 mois que je passe mon temps a faire et défaire cette partie là de mon code.
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

j'ai des sprites
j'ai des animations
j'ai des Objets qui ont différent état et ces etats peuvent être lié ou a un sprite ou a une animation
C'est à dire ? Précise un peu je ne comprends pas.

J'imagine que tu parles d'une porte qui peut être ouverte ou fermée c'est ça ? par contre lié à un sprite ou une animation , je ne comprends pas.
J'imagine que tu parles d'un interrupteur qui permet d'ouvrir une porte ? l'interrupteur est animé ou il n'y a que deux sprites pour les deux états possible ? s'il y a une d'animation tu voudrais agir sur l'ouverture de la porte à la fin de l'animation de l'interrupteur? ou il s'agit d'autre chose ?
La carte qui elle même est constituer d'Objet a un état.(même le sol peux avoir plusieurs état différent)
là aussi je ne comprends pas trop , précise un peu comment est construite ta carte ? sur une couche ? les objets sont des sprites posés sur la carte ou ils font partie de la carte ?
quels sont les états que peut prendre le sol ? ces états changent en fonction de quoi ?
Et si j'ai bien compris ton tutoriel il me faudrait alors un Objet part case de la Map ce qui devient lourd non ?
pas forcément, dans le RPG il y a un événement sur le coffre, un événement sur l'aubergiste, le commerçant, et un événement sur les portes pour changer de map.
ça fait très peu d'événements par carte.

Dans ton cas il faudrait un événement par interrupteur pour ouvrir la porte correspondante. pas besoin de mettre des événements partout.
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

C'est gentils comtois de t'intéresser a mon problème
C'est à dire ? Précise un peu je ne comprends pas.
Je vais essayer d'être plus claire ...

donc
J'ai tout mes sprites le N°1, le n°2, le n°3 etc...

ensuite j'ai des animations constituer de ces sprites
Exemple :Animation 1 :Sprite 2 10ms, Sprite 3 10ms,Sprite 2 10ms, Sprite 4 5ms

j'ai des Types D'Objet
Exemple: Une porte. Une porte peut avoir un certain nombre d'état
-porte fermé
-porte souvrant
-porte ouverte
-porte se fermant
-porte explosé
A chaqu'un de ses etats j'ai une animation ou un sprite correspondant


et ensuite j'ai des Objets qui sont constitué
-de son nom
-du type d'objet
-de son etat (exe la porte est en train de s'ouvrire)

ainsi chaque objet est unique (l'Objet n+3 est la porte qui permet de rentré a tel endroit)

Et j'ai ensuite ma carte qui est constitué de ces objets

Alors dans ma tête je me dis que vu comme ça il y a un objet part case dans la map donc c'est lourd. Surtout que certain objet n'auront qu'un seul état et qu'un seul sprite. Donc je me dis qu'il faut peut être mettre dans le structure de la map toutes ces infos mais c'est super lourd..Non ?

Surtout si dans le décore j'ai des animations qui ne demande pas de surveillance ni d'interaction directe...(eau qui coule)

Est ce que c'est plus claire ?

tout ce qui est personnage est gérer autrement, je fait défiler les personnages et si il est visible je l'affiche. ça me permet de gerer en a ce moment là l'IA de personnage.

mais je n'ai apprioris pas de couche pour la map...

voici les sources et un executable du debut de mon....POurl 'instant il n'y a qu'une map fictive...
File:1->Aliens_Invasion.zip
Image
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

Alors dans ma tête je me dis que vu comme ça il y a un objet part case dans la map donc c'est lourd. Surtout que certain objet n'auront qu'un seul état et qu'un seul sprite. Donc je me dis qu'il faut peut être mettre dans le structure de la map toutes ces infos mais c'est super lourd..Non ?

Surtout si dans le décore j'ai des animations qui ne demande pas de surveillance ni d'interaction directe...(eau qui coule)
Pour les animations de ta carte il faut le traiter en même temps que l'affichage de la carte, tu n'as pas besoin de gérer des événements pour ça.

Voici vite fait un exemple pour l'animation de la carte, c'est à adapter à ton besoin.

Il y a 10 animations possibles, tu peux aussi faire un pointeur et allouer un bloc mémoire en fonction d'un nombre d'animation pour utiliser la mémoire au plus juste.

Code : Tout sélectionner

Structure s_Tile
  NoSprite.l
  Time.l
EndStructure

Structure s_Map
  Tile.l
  Animation.l
EndStructure

Structure s_Anim
  Index.l
  NbTile.l     ;Nombre de tiles pour l'animation 
  TempsEnCours.l 
  *TabTile.s_Tile ;Pointe sur un tableau de tiles pour l'animation
EndStructure

Dim Animation.s_Anim(10)
Dim Map.s_Map(10,10)


;Préparation des animations dans un fichier
;Animation 1 :Sprite 2 10ms, Sprite 3 10ms,Sprite 2 10ms, Sprite 4 5ms
Animation(1)\Index = 0
Animation(1)\NbTile = 4 ; L'animation se joue avec les sprites 2,puis 3 puis 2 et 4 
Animation(1)\TempsEnCours = 0
Animation(1)\TabTile = AllocateMemory(SizeOf(s_Tile) * Animation(1)\NbTile)

*Ptr.s_Tile = Animation(1)\TabTile

;Première image de l'animation
*Ptr\NoSprite = 2
*Ptr\Time = 10
*Ptr + SizeOf(s_tile)
;Deuxième image de l'animation
*Ptr\NoSprite = 3
*Ptr\Time = 10
*Ptr + SizeOf(s_tile)
;Troisième image de l'animation
*Ptr\NoSprite = 2
*Ptr\Time = 10
*Ptr + SizeOf(s_tile)
;Quatrième image de l'animation
*Ptr\NoSprite = 4
*Ptr\Time = 5

;Ensuite dans ta map il faut indiquer si le tile est animé ou non 

;Un tile fixe
Map(2,2)\Tile = 3
Map(2,2)\Animation = 0

;Un tile avec l'animation 1
Map(4,5)\Tile = 0
Map(4,5)\Animation = 1


;Et ensuite quand tu affiches ta map
For y = 0 To 9
  For x = 0 To 9
    If Map(x,y)\Animation 
      AnimationMap(x,y,Map(x,y)\Animation)
    Else
      DisplaySprite(x,y,Map\Tile)
    EndIf  
  Next x
Next y
   

Procedure AnimationMap(x,y,Anim)
  *Ptr.s_Tile
  ;On se place sur le tile en cours d'animation
  *Ptr=Animation(Anim)\TabTile + Animation(Anim)\Index*SizeOf(S_tile)
  ;Test la durée d'affichage du Tile
  If ElapsedMilliseconds() > Animation(Anim)\TempsEnCours + *Ptr\Time
    Animation(Anim)\Index + 1
    If Animation(Anim)\Index > Animation(Anim)\NbTile-1
      Animation(Anim)\Index = 0
    EndIf
    Animation(Anim)\TempsEnCours = ElapsedMilliseconds()  
    ;Calcul la position du nouveau Tile à afficher
    *Ptr=Animation(Anim)\TabTile + Animation(Anim)\Index*SizeOf(S_tile)
  EndIf   
   
  DisplaySprite(x,y,*Ptr\Tile)
EndProcedure
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Merci Comtois c'est grandiose ! :D
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Message par comtois »

Petite correction , si dans ta map tu as plusieurs fois l'animation 1 tu vas appeler la procédure AnimationMap() autant de fois inutilement.

Il vaut mieux mettre à jour les animations avant d'afficher la map , ce qui donne.

Code : Tout sélectionner

Structure s_Tile
  NoSprite.l
  Time.l
EndStructure

Structure s_Map
  Tile.l
  Animation.l
EndStructure

Structure s_Anim
  Index.l
  NbTile.l     ;Nombre de tiles pour l'animation
  TempsEnCours.l
  *TabTile.s_Tile ;Pointe sur un tableau de tiles pour l'animation
EndStructure

Global Dim Animation.s_Anim(10)
Global Dim Map.s_Map(10,10)


;Préparation des animations dans un fichier
;Animation 1 :Sprite 2 10ms, Sprite 3 10ms,Sprite 2 10ms, Sprite 4 5ms
Animation(1)\Index = 0
Animation(1)\NbTile = 4 ; L'animation se joue avec les sprites 2,puis 3 puis 2 et 4
Animation(1)\TempsEnCours = 0
Animation(1)\TabTile = AllocateMemory(SizeOf(s_Tile) * Animation(1)\NbTile)

*Ptr.s_Tile = Animation(1)\TabTile

;Première image de l'animation
*Ptr\NoSprite = 2
*Ptr\Time = 10
*Ptr + SizeOf(s_tile)
;Deuxième image de l'animation
*Ptr\NoSprite = 3
*Ptr\Time = 10
*Ptr + SizeOf(s_tile)
;Troisième image de l'animation
*Ptr\NoSprite = 2
*Ptr\Time = 10
*Ptr + SizeOf(s_tile)
;Quatrième image de l'animation
*Ptr\NoSprite = 4
*Ptr\Time = 5

;Ensuite dans ta map il faut indiquer si le tile est animé ou non

;Un tile fixe
Map(2,2)\Tile = 3
Map(2,2)\Animation = 0

;Un tile avec l'animation 1
Map(4,5)\Tile = 0
Map(4,5)\Animation = 1

Procedure AffMap()
  *Ptr.s_Tile
 
  ;Mise à jour des animations avant affichage de la map
  For i=1 To 10
    AnimationMap(i)
  Next i
 
  ;Et ensuite quand tu affiches ta map
  For y = 0 To 9
    For x = 0 To 9
      If Map(x,y)\Animation
        ;On se place sur le tile en cours d'animation
        *Ptr=Animation(Map(x,y)\Animation)\TabTile + Animation(Map(x,y)\Animation)\Index*SizeOf(S_tile)
        DisplaySprite(x,y,*Ptr\NoSprite)
      Else
        DisplaySprite(x,y,Map(x,y)\Tile)
      EndIf 
    Next x
  Next y
EndProcedure
 
Procedure AnimationMap(Anim)
  *Ptr.s_Tile
  ;On se place sur le tile en cours d'animation
  *Ptr=Animation(Anim)\TabTile + Animation(Anim)\Index*SizeOf(S_tile)
  ;Test la durée d'affichage du Tile
  If ElapsedMilliseconds() > Animation(Anim)\TempsEnCours + *Ptr\Time
    Animation(Anim)\Index + 1
    If Animation(Anim)\Index > Animation(Anim)\NbTile-1
      Animation(Anim)\Index = 0
    EndIf
    Animation(Anim)\TempsEnCours = ElapsedMilliseconds() 
  EndIf   
EndProcedure
Dernière modification par comtois le sam. 24/févr./2007 14:30, modifié 1 fois.
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Merci beaucoup c'est vraiment sympa
:D
Répondre