Votre avis pour une Map avancé en ISO 3D!

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

Votre avis pour une Map avancé en ISO 3D!

Message par Thyphoon »

Bonjour,

Ayant un peu de temps ces jours-ci j'ai repris une idée de jeu en Iso3D.
Et j'aurais voulu avoir votre avis sur ma façon de faire pour la map.

Théorie:
Pour moi la map est constitué d'élément. Chaque élément ayant plusieurs état, état pouvant être un sprite ou une animation. L'animation d'un élément peut être global ou Unique:
Exemple:
1)Animation Global : de l'eau qui coule, tout les éléments sur la carte on la même animation au même moment.
2)Animation Unique :Une porte que vous ouvrez, il n'y a que cette porte qui s'ouvre et pas les autres. l'animation est unique

Dans le cas de l'animation Global, l'animation se gère au niveau de l'élément.
Au niveau de l'animation Unique, l'animation se gère au niveau de la Map.
Et je pensais aussi a la possibilité de coller un script a un Element si une action est entrepris sur cet element (marché dessus, pousser, tirer, regarder, etc...)
j'espère que suis claire :P
Pratique:
Image
Au vu de tout ça je pense procéder comme ça :
Ce code n'est pas encore opérationel. j'aurais voulu avoir votre avis sur ma reflexion et ma façon de faire avant d'aller plus loin. merci d'avance a tout ceux qui auront prit le temps de me lire :P

Code : Tout sélectionner

;- #### Animation ####
;	*Animation  DataSheet
;	Offset	|	Size	|	Type	|	Description
;	0		 |	2		  |	.w		|	Frames
;	2		    |	1		  |	.b		|	0 No Loop Animation / 1 Loop Animation
;	3		    |	4		  |	*		  |	IdSprite	Frame[ 1]
;	7		    |	2		  |	.w		|	Temps d'affichage en milliseconde
;	9		    |	4		  |	*	  	|	IdSprite	Frame[ 2]
;	13		  |	2		  |	.w		|	Temps d'affichage en milliseconde
;	3+x*6	  |	4		  |	*		  |	IdSprite	Frame[ x]
;	7+x*6	  |	2	  	|	.w		|	Temps d'affichage en milliseconde
;etc....

;Ajout d'un sprite a une animation
Procedure SetSpriteToAnimation(*Anim, IdSprite.l, Time.w)
	If *Anim>0
		Size.l = MemorySize(*Anim)
	Else
		Size.l = 3
		*Anim = AllocateMemory(Size)
	EndIf
	*Anim = ReAllocateMemory(*Anim, Size + 6)
	PokeW(*Anim, PeekW(*Anim) + 1)
	PokeL(*Anim + Size, IdSprite)
	PokeW(*Anim + Size + 4, Time)
	ProcedureReturn *Anim
EndProcedure

;Retourne le sprite correspondant a l'image d'une Animation
Procedure.l GetSpriteFromAnimation(*Anim, Frame.w)
Debug "Frame:"+Str(Frame)+" Anim:"+Str(*Anim)
	Location.l = 3 + Frame*6
	If Location<MemorySize(*Anim)
		ProcedureReturn PeekL(*Anim + Location) : 
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

;Retourne le temps d'affichage d'une imge dans une animation
Procedure.l GetTimeSpriteFromAnimation(*Anim, Frame.w)
	Location.l = 7 + Frame*6
	If Location<MemorySize(*Anim)
	Debug "time:"+Str(PeekW(*Anim + Location))
	ProcedureReturn PeekW(*Anim + Location) : 
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

;Active ou desactive le bouclage de l'annimation
Procedure.b SetAnimationLoop(*Anim, Loop.b)
	If *Anim>0
		PokeB(*Anim + 2, Loop)
		ProcedureReturn #True
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

;Retourne le nombre d'image dans une animation
Procedure GetFramesAnimation(*Anim)
	ProcedureReturn PeekW(*Anim)
EndProcedure

;Retourne 1 si l'animation est Bouclé et 0 dans le cas contraire
Procedure.b GetAnimationLoop(*Anim)
	If *Anim>0
		ProcedureReturn PeekB(*Anim + 2)
	EndIf
EndProcedure

;-#### Element ####
;	*Element  DataSheet
;	Offset	|	Size	|	Type	|	Description
;	0		    |	2		  |	.w		|	States
;	2		    |	1		  |	.b		|	0 l'animation est Global / 1 l'animation est unique
;	3		    |	2		  |	.w		|	CurrentFrame / Si l'animation est Global alors on utilise cet enplassement pour connaitre l'image actuel de l'animation
;	5		    |	4	  	|	.l		|	Si l'animation est Global alors on utilise cet enplassement pour connaitre le prochain temps de changement d'image
;	9		    |	1		  |	.b		|	0 IdSprite / 1 *Animation	State[1]
;	10		  |	4		  |	*		  |	IdSprite or *Animation 	State[1]
;	14		  |	1		  |	.b		|	0 IdSprite / 1 *Animation	State[2]
;	15		  |	4	  	|	*		  |	IdSprite or *Animation 	State[2]
;	9+x*5	  |	1	  	|	.b		|	0 IdSprite / 1 *Animation	State[x]
;	10+x*5	|	4	  	|	*		  |	IdSprite or *Animation 	State[x]

Procedure DebugElement(*Element)
	Debug"__________"
	Debug "Element:"+Str(*Element )
	Debug "States :"+Str(PeekW(*Element));	0		    |	2		  |	.w		|	States
	Debug "Animation Type :"+Str(PeekB(*Element+2));	2		    |	1		  |	.b		|	0 l'animation est Global / 1 l'animation est unique
	Debug "CurrentFrame:"+Str(PeekW(*Element+3));	3		    |	2		  |	.w		|	CurrentFrame / Si l'animation est Global alors on utilise cet enplassement pour connaitre l'image actuel de l'animation
	Debug "NextTime:"+Str(PeekL(*Element+3));;	5		    |	4	  	|	.l		|	Si l'animation est Global alors on utilise cet enplassement pour connaitre le prochain temps de changement d'image
	For z=0 To PeekW(*Element)-1
		Debug  "Type"+Str(z+1)+" :"+Str(PeekB(*Element+9*z*5));	9		    |	1		  |	.b		|	0 IdSprite / 1 *Animation	State[1]
		Debug "Sprite/Anim"+Str(z+1)+" :"+Str(PeekL(*Element+10*z*5));	10		  |	4		  |	*		  |	IdSprite or *Animation 	State[1]
	Next
EndProcedure

;Rajoute une animation ou une image a un Element
Procedure SetStatetoElement(*Element, *Anim, IdSprite = 0)
	If *Element>0 ;si l'element existe on regarde sa taille
		Size.l = MemorySize(*Element)
	Else ;si l'element n'existe pas on le créer
		Size.l = 9
		*Element = AllocateMemory(Size)
		PokeB(*Element+2,0)
	EndIf
	*Element = ReAllocateMemory(*Element , Size + 5)
	PokeW(*Element, PeekW(*Element) + 1) ;Ajout d'un etat
	State=PeekW(*Element)-1
	Debug "State"
	If *Anim>0 ; Si c'est une Animation
		PokeB(*Element+9+State*5, 1)
		PokeL(*Element+10+State*5, *Anim)
		Debug PeekW(*Element)
		Debug "ajout d'une Anim"
		Debug  PeekL(*Element+10+State*5)
	Else  ; Si c'est un Sprite
		PokeB(*Element+9+State*5, 0)
		PokeL(*Element+10+State*5, IdSprite)
		Debug "ajour d'un sprite"
	EndIf
	ProcedureReturn *Element
EndProcedure

;position l'animation d'un element
Procedure SetFrameToElement(*Element, Frame.w)
 	PokeW(*Element + 3, Frame)
EndProcedure

;-#### Map ####
;*Map(Coord X, Coord Y, Level)
#MapMaxWidth = 512
#MapMaxHeight = 512
#MapMaxLevel = 4
Structure Map
	*Element			;Pointeur vers l'element
	ElementState.w		;Etat de l'element
	Time.l				;Si l'animation est uniquel alors on utilise cet enplassement pour connaitre le prochain  temps de changement d'image
	IdScript.l			;Script lors d'un action sur cet Element
EndStructure

Global Dim Map.Map(#MapMaxWidth, #MapMaxHeight, #MapMaxLevel)

Procedure GetSpriteFromMap(X.l, Y.l, L.l)
	*Element = Map(X, Y, L)\Element;
	State=(Map(X, Y, L)\ElementState+1)-1
	If PeekB(*Element + 9 + State*5) = 0 ;Si c'est un Sprite
		ProcedureReturn PeekL(*Element + 10 + State*5);On retourne l'idsprite
	Else ;Si c'est une animation
		*Anim = PeekL(*Element + 10 + State*5)
		If PeekB(*Element + 2) = 0 ;Si l'animation est Global
			Frame.w = PeekW(*Element + 3)
			If PeekL(*Element + 5) = 0 : 
				PokeL(*Element + 5, ElapsedMilliseconds()+GetTimeSpriteFromAnimation(*Anim, Frame))
			EndIf
				
			If ElapsedMilliseconds()>PeekL(*Element + 5);Si le temps s'est écoulé pour cette image
				Frame.w + 1;on passe a l'image suivante
				If Frame>GetFramesAnimation(*Anim)-1 ; si on depasse le nombre d'image du film
					SetAnimationLoop(*Anim,#True)
					If GetAnimationLoop(*Anim) = #True ;Si  on boucle
						Frame = 0
					Else
						Frame-1
					EndIf
				EndIf
				SetFrameToElement(*Element,Frame);On rafraichit l'image courante
				PokeL(*Element + 5, ElapsedMilliseconds() + GetTimeSpriteFromAnimation(*Anim, Frame));(On note quand est ce qu'on passera a l'image suivante
			EndIf
		EndIf
		ProcedureReturn GetSpriteFromAnimation(*Anim, Frame.w)
	EndIf
EndProcedure

;###############################################################################
;On test
;###############################################################################

InitSprite()
OpenWindow(0, 0, 0, 640, 480, "Un écran dans une fenêtre...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, 640, 480, 0, 0, 0)

;Creation d'une animation
*Anim = 0
For z = 0 To 10
	CreateSprite(z, 64, 64)
	StartDrawing(SpriteOutput(z))
		Box(0, 0, 64, 64, #Blue)
		Circle(z*6, 32, 4, #Red)
	StopDrawing()
	*Anim = SetSpriteToAnimation(*Anim, z, 500)
Next

;Creation d'un Element et attribution d'une animation

*Element=0
*Element = SetStatetoElement(*Element, *Anim)
DebugElement(*Element)
Debug"______"



Map(0, 0, 0)\Element = *Element

Repeat
	; Il est très important de traiter tous les événements restants dans la file d'attente à chaque tour
	;
	Repeat
		Event = WindowEvent()
		If Event = #PB_Event_CloseWindow
			End
		EndIf
	Until Event = 0
	
	FlipBuffers()
	ClearScreen(RGB(0, 0, 0))
	Sprite=GetSpriteFromMap(0,0,0)
	DisplaySprite(Sprite,128,128)
	
	Delay(1)
ForEver


Dernière modification par Thyphoon le mar. 14/oct./2008 10:37, modifié 3 fois.
Avatar de l’utilisateur
Thyphoon
Messages : 2697
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Dans le premier message j'ai éditer le code pour mettre un exemple d'animation avec cette technique...
Qu'en pensez vous ?
Avatar de l’utilisateur
Thyphoon
Messages : 2697
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Voici un nouvel exemple un peu plus parlant
Image
Et voici le code !

Code : Tout sélectionner

;- #### Animation ####
;	*Animation  DataSheet
;	Offset	|	Size	|	Type	|	Description
;	0		 |	2		  |	.w		|	Frames
;	2		    |	1		  |	.b		|	0 No Loop Animation / 1 Loop Animation
;	3		    |	4		  |	*		  |	IdSprite	Frame[ 1]
;	7		    |	2		  |	.w		|	Temps d'affichage en milliseconde
;	9		    |	4		  |	*	  	|	IdSprite	Frame[ 2]
;	13		  |	2		  |	.w		|	Temps d'affichage en milliseconde
;	3+x*6	  |	4		  |	*		  |	IdSprite	Frame[ x]
;	7+x*6	  |	2	  	|	.w		|	Temps d'affichage en milliseconde
;etc....

;Ajout d'un sprite a une animation
Procedure SetSpriteToAnimation(*Anim, IdSprite.l, Time.w)
	If *Anim>0
		Size.l = MemorySize(*Anim)
	Else
		Size.l = 3
		*Anim = AllocateMemory(Size)
	EndIf
	*Anim = ReAllocateMemory(*Anim, Size + 6)
	PokeW(*Anim, PeekW(*Anim) + 1)
	PokeL(*Anim + Size, IdSprite)
	PokeW(*Anim + Size + 4, Time)
	ProcedureReturn *Anim
EndProcedure

;Retourne le sprite correspondant a l'image d'une Animation
Procedure.l GetSpriteFromAnimation(*Anim, Frame.w)
	Location.l = 3 + Frame*6
	If Location<MemorySize(*Anim)
		ProcedureReturn PeekL(*Anim + Location) : 
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

;Retourne le temps d'affichage d'une imge dans une animation
Procedure.l GetTimeSpriteFromAnimation(*Anim, Frame.w)
	Location.l = 7 + Frame*6
	If Location<MemorySize(*Anim)
	ProcedureReturn PeekW(*Anim + Location) : 
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

;Active ou desactive le bouclage de l'annimation
Procedure.b SetAnimationLoop(*Anim, Loop.b)
	If *Anim>0
		PokeB(*Anim + 2, Loop)
		ProcedureReturn #True
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

;Retourne le nombre d'image dans une animation
Procedure GetFramesAnimation(*Anim)
	ProcedureReturn PeekW(*Anim)
EndProcedure

;Retourne 1 si l'animation est Bouclé et 0 dans le cas contraire
Procedure.b GetAnimationLoop(*Anim)
	If *Anim>0
		ProcedureReturn PeekB(*Anim + 2)
	EndIf
EndProcedure

;-#### Element ####
;	*Element  DataSheet
;	Offset	|	Size	|	Type	|	Description
;	0		    |	2		  |	.w		|	States
;	2		    |	1		  |	.b		|	0 l'animation est Global / 1 l'animation est unique
;	3		    |	2		  |	.w		|	CurrentFrame / Si l'animation est Global alors on utilise cet enplassement pour connaitre l'image actuel de l'animation
;	5		    |	4	  	|	.l		|	Si l'animation est Global alors on utilise cet enplassement pour connaitre le prochain temps de changement d'image
;	9		    |	1		  |	.b		|	0 IdSprite / 1 *Animation	State[1]
;	10		  |	4		  |	*		  |	IdSprite or *Animation 	State[1]
;	14		  |	1		  |	.b		|	0 IdSprite / 1 *Animation	State[2]
;	15		  |	4	  	|	*		  |	IdSprite or *Animation 	State[2]
;	9+x*5	  |	1	  	|	.b		|	0 IdSprite / 1 *Animation	State[x]
;	10+x*5	|	4	  	|	*		  |	IdSprite or *Animation 	State[x]

Procedure DebugElement(*Element)
	Debug"__________"
	Debug "Element:"+Str(*Element )
	Debug "States :"+Str(PeekW(*Element));	0		    |	2		  |	.w		|	States
	Debug "Animation Type :"+Str(PeekB(*Element+2));	2		    |	1		  |	.b		|	0 l'animation est Global / 1 l'animation est unique
	Debug "CurrentFrame:"+Str(PeekW(*Element+3));	3		    |	2		  |	.w		|	CurrentFrame / Si l'animation est Global alors on utilise cet enplassement pour connaitre l'image actuel de l'animation
	Debug "NextTime:"+Str(PeekL(*Element+3));;	5		    |	4	  	|	.l		|	Si l'animation est Global alors on utilise cet enplassement pour connaitre le prochain temps de changement d'image
	For z=0 To PeekW(*Element)-1
		Debug  "Type"+Str(z+1)+" :"+Str(PeekB(*Element+9*z*5));	9		    |	1		  |	.b		|	0 IdSprite / 1 *Animation	State[1]
		Debug "Sprite/Anim"+Str(z+1)+" :"+Str(PeekL(*Element+10*z*5));	10		  |	4		  |	*		  |	IdSprite or *Animation 	State[1]
	Next
EndProcedure

;Rajoute une animation ou une image a un Element
Procedure SetStatetoElement(*Element, *Anim, IdSprite = 0)
	If *Element>0 ;si l'element existe on regarde sa taille
		Size.l = MemorySize(*Element)
	Else ;si l'element n'existe pas on le créer
		Size.l = 9
		*Element = AllocateMemory(Size)
		PokeB(*Element+2,0)
	EndIf
	*Element = ReAllocateMemory(*Element , Size + 5)
	PokeW(*Element, PeekW(*Element) + 1) ;Ajout d'un etat
	State=PeekW(*Element)-1
	If *Anim>0 ; Si c'est une Animation
		PokeB(*Element+9+State*5, 1)
		PokeL(*Element+10+State*5, *Anim)
	Else  ; Si c'est un Sprite
		PokeB(*Element+9+State*5, 0)
		PokeL(*Element+10+State*5, IdSprite)
	EndIf
	ProcedureReturn *Element
EndProcedure

;position l'animation d'un element
Procedure SetFrameToElement(*Element, Frame.w)
 	PokeW(*Element + 3, Frame)
EndProcedure

;-#### Map ####
;*Map(Coord X, Coord Y, Level)
#MapMaxWidth = 512
#MapMaxHeight = 512
#MapMaxLevel = 4
Structure Map
	*Element			;Pointeur vers l'element
	ElementState.w		;Etat de l'element
	Time.l				;Si l'animation est uniquel alors on utilise cet enplassement pour connaitre le prochain  temps de changement d'image
	IdScript.l			;Script lors d'un action sur cet Element
EndStructure

Global Dim Map.Map(#MapMaxWidth, #MapMaxHeight, #MapMaxLevel)

Procedure GetSpriteFromMap(X.l, Y.l, L.l)
	*Element = Map(X, Y, L)\Element;
	State=(Map(X, Y, L)\ElementState+1)-1
	If PeekB(*Element + 9 + State*5) = 0 ;Si c'est un Sprite
		ProcedureReturn PeekL(*Element + 10 + State*5);On retourne l'idsprite
	Else ;Si c'est une animation
		*Anim = PeekL(*Element + 10 + State*5)
		If PeekB(*Element + 2) = 0 ;Si l'animation est Global
			Frame.w = PeekW(*Element + 3)
			If PeekL(*Element + 5) = 0 : 
				PokeL(*Element + 5, ElapsedMilliseconds()+GetTimeSpriteFromAnimation(*Anim, Frame))
			EndIf
				
			If ElapsedMilliseconds()>PeekL(*Element + 5);Si le temps s'est écoulé pour cette image
				Frame.w + 1;on passe a l'image suivante
				If Frame>GetFramesAnimation(*Anim)-1 ; si on depasse le nombre d'image du film
					SetAnimationLoop(*Anim,#True)
					If GetAnimationLoop(*Anim) = #True ;Si  on boucle
						Frame = 0
					Else
						Frame-1
					EndIf
				EndIf
				SetFrameToElement(*Element,Frame);On rafraichit l'image courante
				PokeL(*Element + 5, ElapsedMilliseconds() + GetTimeSpriteFromAnimation(*Anim, Frame));(On note quand est ce qu'on passera a l'image suivante
			EndIf
		EndIf
		ProcedureReturn GetSpriteFromAnimation(*Anim, Frame.w)
	EndIf
EndProcedure

;###############################################################################
;On test
;###############################################################################

InitSprite()
OpenWindow(0, 0, 0, 640, 480, "Un écran dans une fenêtre...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, 640, 480, 0, 0, 0)

;Creation d'un Element et attribution d'une animation

;Sol
CreateSprite(0,64,64)
StartDrawing(SpriteOutput(0))
	col=RGB(115,53,8)
	LineXY(0,48,32,32,col)
	LineXY(32,32,64,48,col)
	LineXY(64,48,32,64,col)
	LineXY(32,64,0,48,col)
	FillArea(32,48, -1,RGB(115,53,8))
StopDrawing()
*ElementSol=0
*ElementSol = SetStatetoElement(*ElementSol, 0,0)

;Eau
*AnimEau=0
For z = 1 To 10
CreateSprite(z,64,64)
StartDrawing(SpriteOutput(z))
	col=#Blue
	LineXY(0,48,32,32,col)
	LineXY(32,32,64,48,col)
	LineXY(64,48,32,64,col)
	LineXY(32,64,0,48,col)
	FillArea(32,48, -1,#Blue)
	For n=1 To 10
	Line (Random(64),32+Random(32),Random(16),0,RGB(100,100,255))
	Next
StopDrawing()
*AnimEau=SetSpriteToAnimation(*AnimEau,z, 50)
Next


;creation d'une carte
*ElementEau=0
*ElementEau = SetStatetoElement(*ElementEau,*AnimEau )
For x=0 To 10
For y=0 To 16
Map(x,y,0)\Element=*ElementEau
Next
Next

Map(5,5,0)\Element=*ElementSol
Map(5,6,0)\Element=*ElementSol
Map(6,6,0)\Element=*ElementSol
Map(5,7,0)\Element=*ElementSol

;Simple render de tile
Procedure render()
	For y=0 To 16
		For x=0 To 10
			tmpx=x*64+y%2*32
			
			Sprite=GetSpriteFromMap(x,y,0)
			DisplayTransparentSprite(Sprite,tmpx,y*16)
		Next x
	Next y
EndProcedure



Repeat
	; Il est très important de traiter tous les événements restants dans la file d'attente à chaque tour
	;
	Repeat
		Event = WindowEvent()
		If Event = #PB_Event_CloseWindow
			End
		EndIf
	Until Event = 0
	
	FlipBuffers()
	ClearScreen(RGB(0, 0, 0))
	render()
	Delay(1)
ForEver

Avatar de l’utilisateur
Thyphoon
Messages : 2697
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

ImageImage
Plus de 100 personnes sont passé ici et 0 commentaire. Sniff!! :cry:

Developpé un jeu en ISO est bien plus complexe que je l'aurais pensé...

Voici la dernière version de mon code, mais j'ai encore pas mal de souci ...

Code : Tout sélectionner

;- #### Animation ####
;	*Animation  DataSheet
;	Offset	|	Size	|	Type	|	Description
;	0		 |	2		  |	.w		|	Frames
;	2		    |	1		  |	.b		|	0 No Loop Animation / 1 Loop Animation
;	3		    |	4		  |	*		  |	IdSprite	Frame[ 1]
;	7		    |	2		  |	.w		|	Temps d'affichage en milliseconde
;	9		    |	4		  |	*	  	|	IdSprite	Frame[ 2]
;	13		  |	2		  |	.w		|	Temps d'affichage en milliseconde
;	3+x*6	  |	4		  |	*		  |	IdSprite	Frame[ x]
;	7+x*6	  |	2	  	|	.w		|	Temps d'affichage en milliseconde
;etc....

;Ajout d'un sprite a une animation
Procedure SetSpriteToAnimation(*Anim, IdSprite.l, Time.w)
	If *Anim>0
		Size.l = MemorySize(*Anim)
	Else
		Size.l = 3
		*Anim = AllocateMemory(Size)
	EndIf
	*Anim = ReAllocateMemory(*Anim, Size + 6)
	PokeW(*Anim, PeekW(*Anim) + 1)
	PokeL(*Anim + Size, IdSprite)
	PokeW(*Anim + Size + 4, Time)
	ProcedureReturn *Anim
EndProcedure

;Retourne le sprite correspondant a l'image d'une Animation
Procedure.l GetSpriteFromAnimation(*Anim, Frame.w)
	Location.l = 3 + Frame*6
	If Location<MemorySize(*Anim)
		ProcedureReturn PeekL(*Anim + Location) : 
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

;Retourne le temps d'affichage d'une imge dans une animation
Procedure.l GetTimeSpriteFromAnimation(*Anim, Frame.w)
	Location.l = 7 + Frame*6
	If Location<MemorySize(*Anim)
		ProcedureReturn PeekW(*Anim + Location) : 
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

;Active ou desactive le bouclage de l'annimation
Procedure.b SetAnimationLoop(*Anim, Loop.b)
	If *Anim>0
		PokeB(*Anim + 2, Loop)
		ProcedureReturn #True
	Else
		ProcedureReturn #False
	EndIf
EndProcedure

;Retourne le nombre d'image dans une animation
Procedure GetFramesAnimation(*Anim)
	ProcedureReturn PeekW(*Anim)
EndProcedure

;Retourne 1 si l'animation est Bouclé et 0 dans le cas contraire
Procedure.b GetAnimationLoop(*Anim)
	If *Anim>0
		ProcedureReturn PeekB(*Anim + 2)
	EndIf
EndProcedure

;-#### Element ####
;	*Element  DataSheet
;	Offset	|	Size	|	Type	|	Description
;	0		    |	2		  |	.w		|	States
;	2		    |	1		  |	.b		|	0 l'animation est Global / 1 l'animation est unique
;	3		    |	2		  |	.w		|	CurrentFrame / Si l'animation est Global alors on utilise cet enplassement pour connaitre l'image actuel de l'animation
;	5		    |	4	  	|	.l		|	Si l'animation est Global alors on utilise cet enplassement pour connaitre le prochain temps de changement d'image
;	9		    |	1		  |	.b		|	0 IdSprite / 1 *Animation	State[1]
;	10		  |	4		  |	*		  |	IdSprite or *Animation 	State[1]
;	14		  |	1		  |	.b		|	0 IdSprite / 1 *Animation	State[2]
;	15		  |	4	  	|	*		  |	IdSprite or *Animation 	State[2]
;	9+x*5	  |	1	  	|	.b		|	0 IdSprite / 1 *Animation	State[x]
;	10+x*5	|	4	  	|	*		  |	IdSprite or *Animation 	State[x]

Procedure DebugElement(*Element)
	Debug"__________"
	Debug "Element:" + Str(*Element)
	Debug "States :" + Str(PeekW(*Element));	0		    |	2		  |	.w		|	States
	Debug "Animation Type :" + Str(PeekB(*Element + 2));	2		    |	1		  |	.b		|	0 l'animation est Global / 1 l'animation est unique
	Debug "CurrentFrame:" + Str(PeekW(*Element + 3));	3		    |	2		  |	.w		|	CurrentFrame / Si l'animation est Global alors on utilise cet enplassement pour connaitre l'image actuel de l'animation
	Debug "NextTime:" + Str(PeekL(*Element + 3));;	5		    |	4	  	|	.l		|	Si l'animation est Global alors on utilise cet enplassement pour connaitre le prochain temps de changement d'image
	For z = 0 To PeekW(*Element)-1
		Debug "Type" + Str(z + 1) + " :" + Str(PeekB(*Element + 9*z*5));	9		    |	1		  |	.b		|	0 IdSprite / 1 *Animation	State[1]
		Debug "Sprite/Anim" + Str(z + 1) + " :" + Str(PeekL(*Element + 10*z*5));	10		  |	4		  |	*		  |	IdSprite or *Animation 	State[1]
	Next
EndProcedure

;Rajoute une animation ou une image a un Element
Procedure SetStatetoElement(*Element, *Anim, IdSprite = 0)
	If *Element>0 ;si l'element existe on regarde sa taille
		Size.l = MemorySize(*Element)
	Else ;si l'element n'existe pas on le créer
		Size.l = 9
		*Element = AllocateMemory(Size)
		PokeB(*Element + 2, 0)
	EndIf
	*Element = ReAllocateMemory(*Element, Size + 5)
	PokeW(*Element, PeekW(*Element) + 1) ;Ajout d'un etat
	State = PeekW(*Element)-1
	If *Anim>0 ; Si c'est une Animation
		PokeB(*Element + 9 + State*5, 1)
		PokeL(*Element + 10 + State*5, *Anim)
	Else  ; Si c'est un Sprite
		PokeB(*Element + 9 + State*5, 0)
		PokeL(*Element + 10 + State*5, IdSprite)
	EndIf
	ProcedureReturn *Element
EndProcedure

;position l'animation d'un element
Procedure SetFrameToElement(*Element, Frame.w)
 	PokeW(*Element + 3, Frame)
EndProcedure

;-#### Map ####
;*Map(Coord X, Coord Y, Level)
#MapMaxWidth = 512
#MapMaxHeight = 512
#MapMaxLevel = 4
Structure Map
	*Element			;Pointeur vers l'element
	ElementState.w		;Etat de l'element
	Time.l				;Si l'animation est uniquel alors on utilise cet enplassement pour connaitre le prochain  temps de changement d'image
	IdScript.l			;Script lors d'un action sur cet Element
EndStructure

Global Dim Map.Map(#MapMaxWidth, #MapMaxHeight, #MapMaxLevel)

Procedure GetSpriteFromMap(X.l, Y.l, L.l)
	If X<0 Or X>#MapMaxWidth Or Y<0 Or Y>#MapMaxHeight
		ProcedureReturn 0
	EndIf
	*Element = Map(X, Y, L)\Element;
	If *Element>0
		State = (Map(X, Y, L)\ElementState + 1)-1
		If PeekB(*Element + 9 + State*5) = 0 ;Si c'est un Sprite
			ProcedureReturn PeekL(*Element + 10 + State*5);On retourne l'idsprite
		Else ;Si c'est une animation
			*Anim = PeekL(*Element + 10 + State*5)
			If PeekB(*Element + 2) = 0 ;Si l'animation est Global
				Frame.w = PeekW(*Element + 3)
				If PeekL(*Element + 5) = 0 : 
					PokeL(*Element + 5, ElapsedMilliseconds() + GetTimeSpriteFromAnimation(*Anim, Frame))
				EndIf
				
				If ElapsedMilliseconds()>PeekL(*Element + 5);Si le temps s'est écoulé pour cette image
					Frame.w + 1;on passe a l'image suivante
					If Frame>GetFramesAnimation(*Anim)-1 ; si on depasse le nombre d'image du film
						SetAnimationLoop(*Anim, #True)
						If GetAnimationLoop(*Anim) = #True ;Si  on boucle
							Frame = 0
						Else
							Frame-1
						EndIf
					EndIf
					SetFrameToElement(*Element, Frame);On rafraichit l'image courante
					PokeL(*Element + 5, ElapsedMilliseconds() + GetTimeSpriteFromAnimation(*Anim, Frame));(On note quand est ce qu'on passera a l'image suivante
				EndIf
			EndIf
			ProcedureReturn GetSpriteFromAnimation(*Anim, Frame.w)
		EndIf
	EndIf
EndProcedure

;###############################################################################
;On test
;###############################################################################

InitSprite()
InitKeyboard()
OpenWindow(0, 0, 0, 640, 480, "Un écran dans une fenêtre...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(0), 0, 0, 640, 480, 0, 0, 0)

;Creation d'un Element et attribution d'une animation

;Sol
CreateSprite(0, 64, 64)
StartDrawing(SpriteOutput(0))
	col = RGB(115, 53, 8)
	LineXY(0, 48, 32, 32, col)
	LineXY(32, 32, 64, 48, col)
	LineXY(64, 48, 32, 64, col)
	LineXY(32, 64, 0, 48, col)
	FillArea(32, 48, -1, RGB(115, 53, 8))
StopDrawing()
*ElementSol = 0
*ElementSol = SetStatetoElement(*ElementSol, 0, 0)

;Poteau
CreateSprite(11, 64, 64)
StartDrawing(SpriteOutput(11))
	col = RGB(115, 53, 8)
	LineXY(0, 48, 32, 32, col)
	LineXY(32, 32, 64, 48, col)
	LineXY(64, 48, 32, 64, col)
	LineXY(32, 64, 0, 48, col)
	FillArea(32, 48, -1, RGB(115, 53, 8))
	LineXY(30, 48, 30, 0, #Green)
	LineXY(31, 49, 31, 1, #Green)
	LineXY(32, 50, 32, 2, #Green)
	LineXY(33, 49, 33, 1, RGB(0,150, 0))
	LineXY(34, 48, 34, 0, RGB(0, 150, 0))
StopDrawing()
*ElementPoteau = 0
*ElementPoteau = SetStatetoElement(*ElementPoteau, 0, 11)
SaveSprite(11,"test.bmp")
;Eau
*AnimEau = 0
For z = 1 To 10
	CreateSprite(z, 64, 64)
	StartDrawing(SpriteOutput(z))
		col = #Blue
		LineXY(0, 48, 32, 32, col)
		LineXY(32, 32, 64, 48, col)
		LineXY(64, 48, 32, 64, col)
		LineXY(32, 64, 0, 48, col)
		FillArea(32, 48, -1, #Blue)
		For n = 1 To 10
			Line(Random(64), 32 + Random(32), Random(16), 0, RGB(100, 100, 255))
		Next
	StopDrawing()
	*AnimEau = SetSpriteToAnimation(*AnimEau, z, 500)
Next

;creation d'une carte
*ElementEau = 0
*ElementEau = SetStatetoElement(*ElementEau, *AnimEau)
For x = 0 To 10
	For y = 0 To 16
		Map(x, y, 0)\Element = *ElementEau
	Next
Next

Map(2, 2, 0)\Element = *ElementPoteau
Map(5, 5, 0)\Element = *ElementSol
Map(5, 6, 0)\Element = *ElementSol
Map(6, 6, 0)\Element = *ElementSol
Map(5, 7, 0)\Element = *ElementSol

;Simple render de tile

Procedure Real2IsoX(X.l, YL)
	ProcedureReturn X-Y
EndProcedure

Procedure Real2IsoY(X.l, YL)
	ProcedureReturn (Y + X)/2
EndProcedure

Procedure render(PointerXReal, PointerYReal)
	SpriteWidth = 64
	SpriteHeight = 32
	WindowWidth.l = 512
	WindowHeight.l = 400
	PointerX =Int(PointerXReal/SpriteWidth)
	PointerY = Int(PointerYReal/SpriteHeight)
	CreateSprite(200, WindowWidth, WindowHeight)
	
	CenterWindowX = Int((WindowWidth/32)/2)
	CenterWindowY = Int((WindowHeight/32)/2)
	TileWidth = Round(WindowWidth/SpriteWidth, #PB_Round_Up)
	TileHeight = Round(WindowHeight/SpriteHeight, #PB_Round_Up)
	DeltaXReal = Real2IsoX(PointerXReal-PointX*SpriteWidth, PointerYReal-PointY*SpriteHeight)
	DeltaYReal = Real2IsoY(PointerXReal-PointX*SpriteWidth, PointerYReal-PointY*SpriteHeight)
	
	DeltaX = PointerX-CenterWindowX
	DeltaY = PointerY-CenterWindowY
	
	Diag = Sqr((TileWidth*TileWidth) + (TileHeight*TileHeight))
	UseBuffer(200)
	
	For y = 0 To Diag
		For x = 0 To Diag
			tmpx = x*32-y*32-DeltaXReal 
			tmpy = y*16 + x*16-DeltaYReal 
			
			Sprite = GetSpriteFromMap(PointerX + x-CenterWindowX, PointerY + y-CenterWindowY, 0)
			If Sprite> = 0 And IsSprite(Sprite)
				DisplayTransparentSprite(Sprite, tmpx, tmpy)
			EndIf
		Next x
	Next y
	
	StartDrawing(SpriteOutput(200))
		Line(X + CenterWindowX*32, Y + CenterWindowY*16, Real2IsoX(100, 0), Real2IsoY(100, 0), #Blue)
			DrawText(10, 40, "X:" + Str(PointerX) + "  Y:" + Str(PointerY))
		;	CoordX = (CenterWindowX)*SpriteWidth-DeltaXReal
		;	CoordY = (CenterWindowY)*SpriteHeight-DeltaYReal
		;	LineXY(CoordX, CoordY + 48, CoordX + 32, CoordY + 32, #Red)
		;	LineXY(CoordX + 32, CoordY + 32, CoordX + 64, CoordY + 48, #Red)
		;	LineXY(CoordX + 64, CoordY + 48, CoordX + 32, CoordY + 64, #Red)
		;	LineXY(CoordX + 32, CoordY + 64, CoordX, CoordY + 48, #Red)
		;
	StopDrawing()
	UseBuffer(-1)
	DisplaySprite(200, 20, 20)
EndProcedure

Repeat
	; Il est très important de traiter tous les événements restants dans la file d'attente à chaque tour
	;
	Repeat
		Event = WindowEvent()
		If Event = #PB_Event_CloseWindow
			End
		EndIf
	Until Event = 0
	ExamineKeyboard()
	If KeyboardPushed(#PB_Key_Up) : PointerYReal + 1 : EndIf
	If KeyboardPushed(#PB_Key_Down) : PointerYReal-1 : EndIf
	If KeyboardPushed(#PB_Key_Left) : PointerXReal-1 : EndIf
	If KeyboardPushed(#PB_Key_Right) : PointerXReal + 1 : EndIf
	FlipBuffers()
	ClearScreen(#Red)
	
	render(PointerXReal, PointerYReal)
	Delay(1)
ForEver

Avatar de l’utilisateur
case
Messages : 1527
Inscription : lun. 10/sept./2007 11:13

Message par case »

alors pour le manque de commentaires je parle pour moi en tout cas, vu que le code n'était pas fonctionnel je ne l'ai pas testé :)

et prendre le temps d'analyser ton code ben j'ai pas que cela a faire (sans vouloir te vexer hein) ceci dit en 3diso ou en simple 2D c'est pareil ta map tu la gère de la même façon, c'est juste pour l'affichage que c'est un poil différent :)


mais je regarderais cela d'un peu plus prés des que j'aurais un peu plus de temps :)
Avatar de l’utilisateur
Thyphoon
Messages : 2697
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

case a écrit :alors pour le manque de commentaires je parle pour moi en tout cas, vu que le code n'était pas fonctionnel je ne l'ai pas testé :)
Merci d'avoir repondu ! Mais j'ai peut être mal expliquer mon problème.C'était plus sur le principe de ma façon de faire que sur le code
case a écrit : et prendre le temps d'analyser ton code ben j'ai pas que cela a faire (sans vouloir te vexer hein)
T'inquiète pas je le comprends tout a fait, et ce n'étais pas dans ce but. Mon souci était vraiment sur le principe utilisé pour y avoir une map avec des animations dynamic !
case a écrit : ceci dit en 3diso ou en simple 2D c'est pareil ta map tu la gère de la même façon, c'est juste pour l'affichage que c'est un poil différent :)
c'est ce que je pensais avant d'essayer ! Je sais pas pourquoi dans ma tête c'est tout floue ...lollllllll
Avatar de l’utilisateur
case
Messages : 1527
Inscription : lun. 10/sept./2007 11:13

Message par case »

pour ce qui est de la facon de faire, j'aurais peut etre eu une approche differente

j'ai pas tout analysé dans ton code mais moi j'aurais procede comme ca

ATTENTION PSEUDO CODE CA NE FONCTIONNEA PAS TEL QUEL
c'est juste une maniere possibble, j'utilise des chaines de caracteres
dans mon exemple mais ce j'est clairement pas une bonne idée si la vitesse
d'execution est primordiale et que tu gere d'enormes cartes mais c'est flexible je trouves

a toi d'adapter cette reflection a tes besoins

une structure pour chaque case, la on est d'accord

Code : Tout sélectionner

structure tile
  id.l      ; id de la tuile 	    1+
  animation ; id de l'animation     si 0 ignorée
  frame.l   ; etape de l'animation  si pas d'anim ignorée
  timer.l   ; id du timer utilisé pour l'animation
  triger.l  ; cette tuile active un evenement si 0 pas d'evenement activé
endstructure
une structure pour les timers

Code : Tout sélectionner

structure tim
  ticks.l   ; delai de declenchement
  casesx.s   ; liste de tuiles x
  casesy.s   ; liste de tuiles y
endstructure

Code : Tout sélectionner

dim timer.tim(20) ; 20 timer programmables pour la map
dim animation$(1000) ; on stoque la dedans les animation
dim map.tile(50,50)
au chargement de la map on cree les timers exemple

Code : Tout sélectionner

timer(1)\ticks=10 donc tout les 10 incrementation du timer ce timer met a jour ses tuiles
les animations

j'ai choisis de les stocker dans des chaines parceque ca permet de faire un peu ce qu'on veux

exemple

Code : Tout sélectionner

animation$(1)="32,33,34,35" ; affiche les tuiles 32,33,34,35 
au chargement de la carte tu ajoute dans chaque timer les coordonées de la carte qu'il doit updater en lisant le champ map(x,y)\timer

Code : Tout sélectionner

timerid=map(x,y)\timer
timer(timerid)\casesx=timer(timerid)\casesx + str(x)+","
timer(timerid)\casesy=timer(timerid)\casesy + str(y)+","
donc a la fin du chargement chaque timer possède sa propre liste des coordonnées de la carte qu'il gère

donc on a pour chaque animation, une description de l'animation, un timer associé et sa vitesse

il ne reste plus qu'a utiliser tout cela pour gérer les animations

Code : Tout sélectionner

repeat
tick=tick+1 ; incremente la mesure du temps
;
for a=1 to 20 ; verifie les timers un apres l'autre
   if timer(a)\ticks <> 0 ;timer actif 
      if tick % timer(a)\ticks = 0 ; on regarde si il y a un reste en divisant le temps par le delai du timer si pas de reste on active le timer
	for update=1 to countstring(timer(a)\casesx,",") ; pour chaque case contenues dans le timer
          ;coorodonée de la case a modifier
	  xmap=stringfield(timer(a)\casesx,update,",")
	  ymap=stringfield(timer(a)\casesy,update,",")
          ; avance d'une image dans lanimation
	  frame=map(xmap,ymap)\frame + 1
	  ; recupere le handle de l'animation
          anim=map(xmap,ymap)\animation
	  ; compte le nombre d'images dans l'animation
	  maxframes=countstring(animation$(anim),",")+1
          ; si l'image actuelle est plus grande que le nombre total d'images
	  if frame > maxframes
             frame=1
          endif
          ; change l'image actuelle
          map(xmap,ymap)\frame=frame
          ;change l'id de la tuile actuelle
          map(xmap,ymap)\id=stringfield(animation$(anim),frame,",")
	next
      endif
   endif
next



; ici la routine d'affichage de la carte

flipbuffers()

forever


je pense n'avoir rien oublié
le principal avantage c'est que par exemple on peux avoir plusieurs animations identiques a plusieurs vitesse différentes

les animations peuvent avoir des images qui ne se suivent pas

en modifiant la frame de départ on peux utiliser la même animation a la même vitesse avec un léger décalage visuel
Avatar de l’utilisateur
Thyphoon
Messages : 2697
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Merci case ta proposition est intéressante je vais l'étudier de plus prêt :D
Répondre