gestions de l'affichage

Programmation avancée de jeux en PureBasic
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

gestions de l'affichage

Message par graph100 »

yop ! voila un petit exemple d'un truc qui me trotte dans la tête depuis un moment, il a fallut que ça sorte pour que je puisse aller dormir :mrgreen:

Que pensez vous de la gestion des sprites ?
Je me demande si c'est une bonne idée de faire comme suis, il y a des avantages, comme ne pas avoir à s’occuper de l'affichage (ou très peu), mais certainement aussi plein d'inconvénient.
Comme tout les jeux ou applications que j'ai programmé jusqu'à maintenant sont CPUvores, j'aimerais passer à une façon rapide d'afficher, et obtenir un bô rendu sans lag.

Je vous avoue que ce sont les derniers screens de Blendman qui m'on réveiller sur ces points là :lol: (bravo d’ailleurs)

[edit] je voulais savoir aussi si vous trouvez le jeu fluide, (niveau graphique c'est pas lourd, donc surtout pour les déplacements, car j'ai eu des cas d'accélérations)

Code : Tout sélectionner

;######################################
; programme : Jeu Naze vite fait
#VERSION = "1.00"
; description : 	- ressemble vaguement au jeu originel Space Invaders
;								
; détails :				- bah on tire avec espace...
;
;	ajouts prévus :	- avancer le gameplay, peut-être...
;									
; auteur : graph100 alias Kriek106
;######################################


;{ Variables globales

#octet_donne = 8

#w = 800
#h = 600

#terrain_w = 250
#terrain_h = 205

; #l = #h / #terrain_h
#l = 2

Global *sprite.l = 0, EXIT.b = #False, nb_ennemis_tues = 0, nb_a_tuer.l, perdu.b = #False

Global position_globale.POINT

#TEXT_GAGNE = "Vous avez défendu la terre contre les SPACEs INVADERs"
#TEXT_PERDU = "Les SPACEs INVADERs ont envahi la terre, que vous n'avez su défendre..."

;}

;{ init des environnements graphiques
If InitSprite() = 0 Or InitKeyboard() = 0
	End
EndIf
;}

;{ structure sprite
Structure sprite
	sprite.l
	
	x.l
	y.l
	
	w.l ; pas tres tres utile, mais sait-on jamais ???
	h.l
	
	is_pos_globale.b
EndStructure
;}

;{ fonction/macro sur le bloc memoire *sprite

Macro AllocateSprite(nb_sprite)
	If *sprite
		If PeekL(*sprite - #octet_donne) > nb_sprite
			*sprite = ReAllocateMemory(*sprite - #octet_donne, nb_sprite * SizeOf(sprite) + #octet_donne) + #octet_donne
			
			For a = PeekL(*sprite - #octet_donne) - 1 To nb_sprite - 1
				PokeL(*sprite + a * SizeOf(sprite), -1)
			Next
			
			PokeL(*sprite - #octet_donne, nb_sprite)
		EndIf
	Else
		*sprite = AllocateMemory(nb_sprite * SizeOf(sprite) + #octet_donne) + #octet_donne
		; on avance l'index mémoire de 4 pour "cacher" le nombre de sprite en mémoire, (faciliter l'accès aux données)
		
		For a = 0 To nb_sprite - 1
			PokeL(*sprite + a * SizeOf(sprite), -1)
		Next
		
		PokeL(*sprite - #octet_donne, nb_sprite)
	EndIf
EndMacro

Macro FreeAllocatedSprite()
	If *sprite
		For a = 0 To PeekL(*sprite - #octet_donne) - 1
			FreeSprite(a)
		Next
		
		FreeMemory(*sprite - #octet_donne)
	EndIf
EndMacro

Macro NombreSpriteReserver()
	PeekL(*sprite - #octet_donne)
EndMacro

Macro NombreSpriteAllouer()
	PeekL(*sprite - #octet_donne + 4)
EndMacro

Macro SpriteSprite(hd)
	PeekL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\sprite))
EndMacro

Macro SpriteX(hd)
	PeekL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\x))
EndMacro

Macro SpriteY(hd)
	PeekL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\y))
EndMacro

Macro SpriteW(hd)
	PeekL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\w))
EndMacro

Macro SpriteH(hd)
	PeekL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\h))
EndMacro

Macro SpriteIsPosGlobale(hd)
	PeekB(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\is_pos_globale))
EndMacro

Macro Sprite_SetSprite(hd, sprite1)
	PokeL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\sprite), sprite1)
EndMacro

Macro Sprite_SetX(hd, x1)
	PokeL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\x), x1)
EndMacro

Macro Sprite_SetY(hd, y1)
	PokeL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\y), y1)
EndMacro

Macro Sprite_SetW(hd, w1)
	PokeL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\w), w1)
EndMacro

Macro Sprite_SetH(hd, h1)
	PokeL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\h), h1)
EndMacro

Macro Sprite_SetIsPosGlobale(hd, IsPosGlobale1)
	PokeB(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\is_pos_globale), IsPosGlobale1)
EndMacro

Procedure AddSprite(sprite.l, x.l, y.l, IsPosGlobale.b)
	If *sprite = 0
		AllocateSprite(1)
	EndIf
	
	res = NombreSpriteAllouer()
	
	If res = NombreSpriteReserver()
		AllocateSprite(res + 1)
	Else
		For a = 0 To res
			If SpriteSprite(a) = -1
				res = a
				Break
			EndIf
		Next
	EndIf
	
	
	Sprite_SetSprite(res, sprite)
	Sprite_SetX(res, x)
	Sprite_SetY(res, y)
	Sprite_SetW(res, SpriteWidth(sprite))
	Sprite_SetH(res, SpriteHeight(sprite))
	Sprite_SetIsPosGlobale(res, IsPosGlobale)
	
	PokeL(*sprite - #octet_donne + 4, NombreSpriteAllouer() + 1)
	
	ProcedureReturn res
EndProcedure

Macro DeleteSprite(hd)
	PokeL(*sprite + hd * SizeOf(sprite), -1)
	PokeL(*sprite - #octet_donne + 4, NombreSpriteAllouer() - 1)
EndMacro

;}

Procedure DrawSprite(bla); le bla ne sert que pour pouvoir lancer un thread
	time2 = ElapsedMilliseconds() - 1
	
	Repeat
		;{ calcul temps boucle
		time = ElapsedMilliseconds() - time2
		time2 = ElapsedMilliseconds()
		;}
		
		ClearScreen(0)
		
		If StartDrawing(ScreenOutput())
			If time = 0
				DrawText(0, 0, "FPS : Infini")
			Else
				DrawText(0, 0, "FPS : " + Str(1000 / time))
			EndIf
			
			
			StopDrawing()
		EndIf
		
		If nb_a_tuer = nb_ennemis_tues
			If StartDrawing(ScreenOutput())
				DrawText(#terrain_w * #l / 2 - TextWidth(#TEXT_GAGNE) / 2, #terrain_h * #l / 2, #TEXT_GAGNE)
				
				StopDrawing()
			EndIf
			
		ElseIf perdu = #True
			If StartDrawing(ScreenOutput())
				DrawText(#terrain_w * #l / 2 - TextWidth(#TEXT_PERDU) / 2, #terrain_h * #l / 2, #TEXT_PERDU)
				
				StopDrawing()
			EndIf
			
		Else
			For a = 0 To NombreSpriteReserver() - 1
				If SpriteSprite(a) <> -1
					If SpriteIsPosGlobale(a) = #True
						DisplayTransparentSprite(SpriteSprite(a), SpriteX(a) + position_globale\x, SpriteY(a) + position_globale\y)
						
						If SpriteY(a) + position_globale\y > (#terrain_h - 15) * #l
							perdu = #True
						EndIf
						
					Else
						DisplayTransparentSprite(SpriteSprite(a), SpriteX(a), SpriteY(a))
					EndIf
				EndIf
			Next
			
		EndIf
		
		FlipBuffers()
	Until EXIT = #True
EndProcedure


;{ macro gradient --> sprite

Macro DrawMode_Gradient_Start(hd_sprite)
		qsd_res = GrabDrawingImage(#PB_Any, 0, 0, SpriteWidth(hd_sprite), SpriteHeight(hd_sprite))
		
		StopDrawing()
	EndIf
	
	If StartDrawing(ImageOutput(qsd_res))
		DrawingMode(#PB_2DDrawing_Gradient)
		
EndMacro

Macro DrawMode_Gradient_Stop(hd_sprite)
		StopDrawing()
	EndIf
	
	If StartDrawing(SpriteOutput(hd_sprite))
		DrawImage(ImageID(qsd_res), 0, 0)
		
		FreeImage(qsd_res)
		
EndMacro

Macro DrawBoxedGradient(x, y, w, h)
	BoxedGradient(x, y, w, h)
	Box(x, y, w, h)
EndMacro

;}


Macro CatchAlien(Alien_label, sprite_number)
	Restore Alien_label
	
	Read.l w
	Read.l h
	
	CreateSprite(sprite_number, w * #l, h * #l)
	
	If StartDrawing(SpriteOutput(sprite_number))
		
		DrawMode_Gradient_Start(sprite_number)
		
; 		GradientColor(1, 0)
		GradientColor(1, #White)
		GradientColor(0.8, #White)
		GradientColor(0, #White)
		
		For b = 0 To h - 1
			For a = 0 To w - 1
				Read.b c.b
				
				If c
					DrawBoxedGradient(a * #l, b * #l, #l, #l)
				EndIf
				
			Next
		Next
		
		DrawMode_Gradient_Stop(sprite_number)
		
		StopDrawing()
	EndIf
EndMacro


;{ on ouvre un ecran

If OpenScreen(#w, #h, 32, "Mechants Alien v" + #VERSION) = 0
	End
EndIf

;}


;{ création graphismes

AllocateSprite(100)

;{ création du vaisseau SPRITE 0

CreateSprite(0, #l * 5, #l * 3)

If StartDrawing(SpriteOutput(0))
	
	DrawMode_Gradient_Start(0)
	
	GradientColor(0, $72E510)
	GradientColor(1, $724B10)
	
	DrawBoxedGradient(2 * #l, 0, #l, #l)
	
	For a = 0 To 2
		DrawBoxedGradient(#l + a * #l, #l, #l, #l)
	Next
	
	For a = 0 To 5
		DrawBoxedGradient(a * #l, 2 * #l, #l, #l)
	Next
	
	
	DrawMode_Gradient_Stop(0)
	
	StopDrawing()
EndIf

;}

;{ création des sprites ennemis, 10, 11, 12

CatchAlien(alien1, 10)
CatchAlien(alien2, 11)
CatchAlien(alien3, 12)

;}

;{ fond de l'écran, 1

CreateSprite(1, #terrain_w * #l + 1, #terrain_h * #l + 1)

If StartDrawing(SpriteOutput(1))
	Box(0, 0, SpriteWidth(1), SpriteHeight(1), #White)
	Box(0, 0, SpriteWidth(1) - 1, SpriteHeight(1) - 1, 0)
	
	StopDrawing()
EndIf

AddSprite(1, 0, 0, #False)

;}

;{ tir du phy'sss, 2

CreateSprite(2, #l, 4 * #l)

If StartDrawing(SpriteOutput(2))
	Box(0, 0, SpriteWidth(2), SpriteHeight(2), #White)
	
	StopDrawing()
EndIf

;}

;{ tir des ennemis, 3

CreateSprite(3, #l * 3, 4 * #l)

If StartDrawing(SpriteOutput(3))
	Box(#l, 0, #l, 4 * #l, #White)
	Box(0, 2 * #l, 3 * #l, #l, #White)
	
	StopDrawing()
EndIf

;}


;}


;{ initialisation

; joueur
joueur.sprite\sprite = AddSprite(0, 100, 176 * #l, #False)
joueur\x = SpriteX(joueur\sprite)
joueur\y = SpriteY(joueur\sprite)
joueur\w = SpriteW(joueur\sprite)
joueur\h = SpriteH(joueur\sprite)


;{ ennemis

position_globale\x = 5 * #l
position_globale\y = 5 * #l

vitesse.POINT\x = #l
vitesse\y = 0


Dim ennemis(10, 4)

For a = 0 To 10
	ennemis(a, 0) = AddSprite(10, (a * 15 + 3) * #l, 0, #True)
Next

For a = 0 To 10
	ennemis(a, 1) = AddSprite(11, (a * 15 + 2) * #l, 15 * #l, #True)
	ennemis(a, 2) = AddSprite(11, (a * 15 + 2) * #l, 30 * #l, #True)
Next

For a = 0 To 10
	ennemis(a, 3) = AddSprite(12, (a * 15 + 1) * #l, 45 * #l, #True)
	ennemis(a, 4) = AddSprite(12, (a * 15 + 1) * #l, 60 * #l, #True)
Next



;}

NewList tir_physss()
NewList tir_ennemis()

vitesse_tir = #l * 2

nb_a_tuer = (ArraySize(ennemis(), 1) + 1) * (ArraySize(ennemis(), 2) + 1)

;}


;{ tread d'affichage
thread_affichage = CreateThread(@DrawSprite(), 0)
If thread_affichage = 0 : End : EndIf
;}


; time2 = ElapsedMilliseconds() - 1


;{ boucle principale

Repeat
	;{ calcul temps boucle
; 	time = ElapsedMilliseconds() - time2
; 	time2 = ElapsedMilliseconds()
	;}
	
	Delay(10)
	
	ExamineKeyboard()
	
	If KeyboardReleased(#PB_Key_Escape) : event = #PB_Event_CloseWindow : EndIf
	
	;{ ajouts tirs physss
	
	If KeyboardReleased(#PB_Key_Space)
		AddElement(tir_physss())
		
		tir_physss() = AddSprite(2, joueur\x + joueur\w / 2, joueur\y - 3 * #l, #False)
	EndIf
	
	;}
	
	;{ déplacement joueur
	
	If KeyboardPushed(#PB_Key_Left)
		joueur\x - #l
		If joueur\x < 0 : joueur\x = 0 : EndIf
		
		Sprite_SetX(joueur\sprite, joueur\x)
	EndIf
	
	If KeyboardPushed(#PB_Key_Right)
		joueur\x + #l
		
		If joueur\x > #terrain_w * #l - joueur\w : joueur\x = #terrain_w * #l - joueur\w : EndIf
		
		Sprite_SetX(joueur\sprite, joueur\x)
	EndIf
	
	
	;}
	
	;{ déplacements ennemis
	
	If nb_a_tuer > nb_ennemis_tues Or perdu = #False
		position_globale\x + vitesse\x * #l
		position_globale\y + vitesse\y; * #l
		
		timer - 1
		
		If position_globale\x > 75 * #l
			vitesse\y = 1
			vitesse\x = 0
			
			position_globale\x = 75 * #l
			
			timer = 15
		ElseIf position_globale\x < 15 * #l
			vitesse\y = 1
			vitesse\x = 0
			
			position_globale\x = 15 * #l
			
			timer = 15
		EndIf
		
		If timer = 0 And vitesse\x = 0
			If position_globale\x = 15 * #l
				vitesse\x = 1
			Else
				vitesse\x = -1
			EndIf
			
			vitesse\y = 0
		EndIf
		
	EndIf
	
	;}
	
	;{ déplacements tirs
	
	ForEach tir_physss()
		Sprite_SetY(tir_physss(), SpriteY(tir_physss()) - vitesse_tir)
		
		If SpriteY(tir_physss()) < 0
			DeleteSprite(tir_physss())
			DeleteElement(tir_physss())
		Else
			; controle si on touche un alien
			
			For a = 0 To ArraySize(ennemis(), 1)
				For b = 0 To ArraySize(ennemis(), 2)
					If ennemis(a, b) <> -1
						If SpritePixelCollision(SpriteSprite(ennemis(a, b)), SpriteX(ennemis(a, b)) + position_globale\x, SpriteY(ennemis(a, b)) + position_globale\y, 2, SpriteX(tir_physss()), SpriteY(tir_physss()))
							DeleteSprite(ennemis(a, b))
							ennemis(a, b) = -1
							
							DeleteSprite(tir_physss())
							DeleteElement(tir_physss())
							
							nb_ennemis_tues + 1
							
							Break 2
						EndIf
					EndIf
				Next
			Next
			
		EndIf
	Next
	
	;}
	
Until event = #PB_Event_CloseWindow

;}

;{ on arrete le programme proprement

EXIT = #True
WaitThread(thread_affichage)
;}

End

;{ DATA

DataSection
	alien1:
	Data.l 8, 8
	Data.b 0, 0, 0, 1, 1, 0, 0, 0
	Data.b 0, 0, 1, 1, 1, 1, 0, 0
	Data.b 0, 1, 1, 1, 1, 1, 1, 0
	Data.b 1, 1, 0, 1, 1, 0, 1, 1
	Data.b 1, 1, 1, 1, 1, 1, 1, 1
	Data.b 0, 0, 1, 0, 0, 1, 0, 0
	Data.b 0, 1, 0, 1, 1, 0, 1, 0
	Data.b 1, 0, 1, 0, 0, 1, 0, 1
	
	alien2:
	Data.l 11, 8
	Data.b 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0
	Data.b 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1
	Data.b 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1
	Data.b 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1
	Data.b 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
	Data.b 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
	Data.b 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0
	Data.b 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0
	
	alien3:
	Data.l 12, 8
	Data.b 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0
	Data.b 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
	Data.b 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
	Data.b 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1	
	Data.b 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
	Data.b 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0
	Data.b 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0
	Data.b 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
	
	fin:
	
EndDataSection

;}

:arrow: dodo
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
Thyphoon
Messages : 2697
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: gestions de l'affichage

Message par Thyphoon »

ça marche bien ! :o) Mais peut être que je me trompe, j'ai l'impression que tu te complique un peu la vie non ?
tu peux utiliser des pointeurs et des listes ça sera surement plus simple a manipuler non ?
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: gestions de l'affichage

Message par djes »

Fonctionne bien :)
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: gestions de l'affichage

Message par graph100 »

Thyphoon a écrit :tu peux utiliser des pointeurs et des listes ça sera surement plus simple a manipuler non ?
Eh bien, j'utilise des pointeurs, non ?
Je suis en train de me demander si je devais changer ma structure sprite, mais il me semble que pour gérer les sprite3D se sera plus simple

Et au niveau du thread d'affichage, es-ce une bonne idée ? Je dois ralentir la boucle de saisie des commandes joueurs, car sinon cela va vraiment bcp trop vite : essayez de commenter le delay :lol:
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
Thyphoon
Messages : 2697
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Re: gestions de l'affichage

Message par Thyphoon »

graph100 a écrit : Eh bien, j'utilise des pointeurs, non ?
Oui, oui, j'ai pas été assez claire... je parlais surtout de tes macro avec tes PeekL. a mon avis la gestion de ces données là serait plus efficace dans une liste. Mais je me trompe peut être. Faudrait que je regarde de plus prêt ton code.
graph100 a écrit : Et au niveau du thread d'affichage, es-ce une bonne idée ? Je dois ralentir la boucle de saisie des commandes joueurs, car sinon cela va vraiment bcp trop vite : essayez de commenter le delay :lol:
je ne maitrise pas suffisament les threads...
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: gestions de l'affichage

Message par djes »

Je me suis déjà exprimé là dessus... Pour moi, utiliser des timers pour l'affichage 2D est une atrocité ! L'affichage est synchrone : 60hz sur des écrans plats, tout ce qui n'est pas multiple de cette valeur donnera des hachures et des saccades. En 3D, c'est moins remarquable, même si l'oeil exercé verra quand même la différence. En même temps, ce n'est pas de notre faute, il n'y a que sur les consoles qu'on peut avoir une synchro écran correcte, sur les PC, entre les différentes configs, il y a toujours des différences, et ça influe même sur le jeu, puisqu'on a un avantage certain à avoir une bonne bécane bien optimisée.
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: gestions de l'affichage

Message par graph100 »

djes a écrit :Je me suis déjà exprimé là dessus... Pour moi, utiliser des timers pour l'affichage 2D est une atrocité ! L'affichage est synchrone : 60hz sur des écrans plats, tout ce qui n'est pas multiple de cette valeur donnera des hachures et des saccades.
C'est la raison pour laquelle j'ai mis l'affichage dans un thread, car, si j'ai bien compris, le FlipBuffers() limite la fréquence de la boucle à 60Hz, donc, en théorie, tant que le nombre de sprite resteras raisonnable le FPS seras de 60 ou de 30.

Dans mon exemple, c'est la boucle de récupération des commandes utilisateurs, et des calculs de déplacements, gestions du jeu, etc... qui est à part. Ce que je trouve dommage, c'est que je ne sais pas comment faire pour cette boucle tourne à une fréquence fixe, ou relativement fixe :x
Thyphoon a écrit :Oui, oui, j'ai pas été assez claire... je parlais surtout de tes macro avec tes PeekL. a mon avis la gestion de ces données là serait plus efficace dans une liste. Mais je me trompe peut être. Faudrait que je regarde de plus prêt ton code.
je n'ai pas utiliser les listes, car elles sont plus lentes à gérer, et accéder que les tableaux et les bloc mémoires. J'ai fais le choix d'un bloc mémoire pour les changements de taille (ajout de sprite..) mais je pense que finalement ca doit revenir au même. Il faudrait des tests de vitesse poussés !
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: gestions de l'affichage

Message par djes »

C'est dans openscreen() que tu définis la fréquence d'affichage, dans ton cas

Code : Tout sélectionner

OpenScreen(#w, #h, 32, "Mechants Alien v" + #VERSION, #PB_Screen_WaitSynchronization, 60)
(de fait, cela ne devrait rien changer)

Voici ton code modifié pour sauter une frame

Code : Tout sélectionner

;######################################
; programme : Jeu Naze vite fait
#VERSION = "1.00"
; description :    - ressemble vaguement au jeu originel Space Invaders
;                        
; détails :            - bah on tire avec espace...
;
;   ajouts prévus :   - avancer le gameplay, peut-être...
;                           
; auteur : graph100 alias Kriek106
;######################################


;{ Variables globales

#octet_donne = 8

#w = 800
#h = 600

#terrain_w = 250
#terrain_h = 205

; #l = #h / #terrain_h
#l = 2

Global *sprite.l = 0, EXIT.b = #False, nb_ennemis_tues = 0, nb_a_tuer.l, perdu.b = #False

Global position_globale.POINT

#TEXT_GAGNE = "Vous avez défendu la terre contre les SPACEs INVADERs"
#TEXT_PERDU = "Les SPACEs INVADERs ont envahi la terre, que vous n'avez su défendre..."

;}

;{ init des environnements graphiques
If InitSprite() = 0 Or InitKeyboard() = 0
   End
EndIf
;}

;{ structure sprite
Structure sprite
   sprite.l
   
   x.l
   y.l
   
   w.l ; pas tres tres utile, mais sait-on jamais ???
   h.l
   
   is_pos_globale.b
EndStructure
;}

;{ fonction/macro sur le bloc memoire *sprite

Macro AllocateSprite(nb_sprite)
   If *sprite
      If PeekL(*sprite - #octet_donne) > nb_sprite
         *sprite = ReAllocateMemory(*sprite - #octet_donne, nb_sprite * SizeOf(sprite) + #octet_donne) + #octet_donne
         
         For a = PeekL(*sprite - #octet_donne) - 1 To nb_sprite - 1
            PokeL(*sprite + a * SizeOf(sprite), -1)
         Next
         
         PokeL(*sprite - #octet_donne, nb_sprite)
      EndIf
   Else
      *sprite = AllocateMemory(nb_sprite * SizeOf(sprite) + #octet_donne) + #octet_donne
      ; on avance l'index mémoire de 4 pour "cacher" le nombre de sprite en mémoire, (faciliter l'accès aux données)
      
      For a = 0 To nb_sprite - 1
         PokeL(*sprite + a * SizeOf(sprite), -1)
      Next
      
      PokeL(*sprite - #octet_donne, nb_sprite)
   EndIf
EndMacro

Macro FreeAllocatedSprite()
   If *sprite
      For a = 0 To PeekL(*sprite - #octet_donne) - 1
         FreeSprite(a)
      Next
      
      FreeMemory(*sprite - #octet_donne)
   EndIf
EndMacro

Macro NombreSpriteReserver()
   PeekL(*sprite - #octet_donne)
EndMacro

Macro NombreSpriteAllouer()
   PeekL(*sprite - #octet_donne + 4)
EndMacro

Macro SpriteSprite(hd)
   PeekL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\sprite))
EndMacro

Macro SpriteX(hd)
   PeekL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\x))
EndMacro

Macro SpriteY(hd)
   PeekL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\y))
EndMacro

Macro SpriteW(hd)
   PeekL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\w))
EndMacro

Macro SpriteH(hd)
   PeekL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\h))
EndMacro

Macro SpriteIsPosGlobale(hd)
   PeekB(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\is_pos_globale))
EndMacro

Macro Sprite_SetSprite(hd, sprite1)
   PokeL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\sprite), sprite1)
EndMacro

Macro Sprite_SetX(hd, x1)
   PokeL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\x), x1)
EndMacro

Macro Sprite_SetY(hd, y1)
   PokeL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\y), y1)
EndMacro

Macro Sprite_SetW(hd, w1)
   PokeL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\w), w1)
EndMacro

Macro Sprite_SetH(hd, h1)
   PokeL(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\h), h1)
EndMacro

Macro Sprite_SetIsPosGlobale(hd, IsPosGlobale1)
   PokeB(*sprite + hd * SizeOf(sprite) + OffsetOf(sprite\is_pos_globale), IsPosGlobale1)
EndMacro

Procedure AddSprite(sprite.l, x.l, y.l, IsPosGlobale.b)
   If *sprite = 0
      AllocateSprite(1)
   EndIf
   
   res = NombreSpriteAllouer()
   
   If res = NombreSpriteReserver()
      AllocateSprite(res + 1)
   Else
      For a = 0 To res
         If SpriteSprite(a) = -1
            res = a
            Break
         EndIf
      Next
   EndIf
   
   
   Sprite_SetSprite(res, sprite)
   Sprite_SetX(res, x)
   Sprite_SetY(res, y)
   Sprite_SetW(res, SpriteWidth(sprite))
   Sprite_SetH(res, SpriteHeight(sprite))
   Sprite_SetIsPosGlobale(res, IsPosGlobale)
   
   PokeL(*sprite - #octet_donne + 4, NombreSpriteAllouer() + 1)
   
   ProcedureReturn res
EndProcedure

Macro DeleteSprite(hd)
   PokeL(*sprite + hd * SizeOf(sprite), -1)
   PokeL(*sprite - #octet_donne + 4, NombreSpriteAllouer() - 1)
EndMacro

;}

Procedure DrawSprite(bla); le bla ne sert que pour pouvoir lancer un thread
   time2 = ElapsedMilliseconds() - 1
   
   Repeat
      ;{ calcul temps boucle
      time = ElapsedMilliseconds() - time2
      time2 = ElapsedMilliseconds()
      ;}
      If db = 0
          ClearScreen(0)
          
          If StartDrawing(ScreenOutput())
             If time = 0
                DrawText(0, 0, "FPS : Infini")
             Else
                DrawText(0, 0, "FPS : " + Str(1000 / time))
             EndIf
             
             
             StopDrawing()
          EndIf
          
          If nb_a_tuer = nb_ennemis_tues
             If StartDrawing(ScreenOutput())
                DrawText(#terrain_w * #l / 2 - TextWidth(#TEXT_GAGNE) / 2, #terrain_h * #l / 2, #TEXT_GAGNE)
                
                StopDrawing()
             EndIf
             
          ElseIf perdu = #True
             If StartDrawing(ScreenOutput())
                DrawText(#terrain_w * #l / 2 - TextWidth(#TEXT_PERDU) / 2, #terrain_h * #l / 2, #TEXT_PERDU)
                
                StopDrawing()
             EndIf
             
          Else
             For a = 0 To NombreSpriteReserver() - 1
                If SpriteSprite(a) <> -1
                   If SpriteIsPosGlobale(a) = #True
                      DisplayTransparentSprite(SpriteSprite(a), SpriteX(a) + position_globale\x, SpriteY(a) + position_globale\y)
                      
                      If SpriteY(a) + position_globale\y > (#terrain_h - 15) * #l
                         perdu = #True
                      EndIf
                      
                   Else
                      DisplayTransparentSprite(SpriteSprite(a), SpriteX(a), SpriteY(a))
                   EndIf
                EndIf
             Next
             
          EndIf
          FlipBuffers()
      EndIf
      Delay(16) ;16 correspond à 1000ms / 60 : on saute une frame
      db = (db + 1) % 2   ;le 2 définit le nombre total de frames. Ici, une frame sur 2 sera affichée
    Until EXIT = #True
EndProcedure


;{ macro gradient --> sprite

Macro DrawMode_Gradient_Start(hd_sprite)
      qsd_res = GrabDrawingImage(#PB_Any, 0, 0, SpriteWidth(hd_sprite), SpriteHeight(hd_sprite))
      
      StopDrawing()
   EndIf
   
   If StartDrawing(ImageOutput(qsd_res))
      DrawingMode(#PB_2DDrawing_Gradient)
      
EndMacro

Macro DrawMode_Gradient_Stop(hd_sprite)
      StopDrawing()
   EndIf
   
   If StartDrawing(SpriteOutput(hd_sprite))
      DrawImage(ImageID(qsd_res), 0, 0)
      
      FreeImage(qsd_res)
      
EndMacro

Macro DrawBoxedGradient(x, y, w, h)
   BoxedGradient(x, y, w, h)
   Box(x, y, w, h)
EndMacro

;}


Macro CatchAlien(Alien_label, sprite_number)
   Restore Alien_label
   
   Read.l w
   Read.l h
   
   CreateSprite(sprite_number, w * #l, h * #l)
   
   If StartDrawing(SpriteOutput(sprite_number))
      
      DrawMode_Gradient_Start(sprite_number)
      
;       GradientColor(1, 0)
      GradientColor(1, #White)
      GradientColor(0.8, #White)
      GradientColor(0, #White)
      
      For b = 0 To h - 1
         For a = 0 To w - 1
            Read.b c.b
            
            If c
               DrawBoxedGradient(a * #l, b * #l, #l, #l)
            EndIf
            
         Next
      Next
      
      DrawMode_Gradient_Stop(sprite_number)
      
      StopDrawing()
   EndIf
EndMacro


;{ on ouvre un ecran

If OpenScreen(#w, #h, 32, "Mechants Alien v" + #VERSION, #PB_Screen_WaitSynchronization, 60) = 0
   End
EndIf

;}


;{ création graphismes

AllocateSprite(100)

;{ création du vaisseau SPRITE 0

CreateSprite(0, #l * 5, #l * 3)

If StartDrawing(SpriteOutput(0))
   
   DrawMode_Gradient_Start(0)
   
   GradientColor(0, $72E510)
   GradientColor(1, $724B10)
   
   DrawBoxedGradient(2 * #l, 0, #l, #l)
   
   For a = 0 To 2
      DrawBoxedGradient(#l + a * #l, #l, #l, #l)
   Next
   
   For a = 0 To 5
      DrawBoxedGradient(a * #l, 2 * #l, #l, #l)
   Next
   
   
   DrawMode_Gradient_Stop(0)
   
   StopDrawing()
EndIf

;}

;{ création des sprites ennemis, 10, 11, 12

CatchAlien(alien1, 10)
CatchAlien(alien2, 11)
CatchAlien(alien3, 12)

;}

;{ fond de l'écran, 1

CreateSprite(1, #terrain_w * #l + 1, #terrain_h * #l + 1)

If StartDrawing(SpriteOutput(1))
   Box(0, 0, SpriteWidth(1), SpriteHeight(1), #White)
   Box(0, 0, SpriteWidth(1) - 1, SpriteHeight(1) - 1, 0)
   
   StopDrawing()
EndIf

AddSprite(1, 0, 0, #False)

;}

;{ tir du phy'sss, 2

CreateSprite(2, #l, 4 * #l)

If StartDrawing(SpriteOutput(2))
   Box(0, 0, SpriteWidth(2), SpriteHeight(2), #White)
   
   StopDrawing()
EndIf

;}

;{ tir des ennemis, 3

CreateSprite(3, #l * 3, 4 * #l)

If StartDrawing(SpriteOutput(3))
   Box(#l, 0, #l, 4 * #l, #White)
   Box(0, 2 * #l, 3 * #l, #l, #White)
   
   StopDrawing()
EndIf

;}


;}


;{ initialisation

; joueur
joueur.sprite\sprite = AddSprite(0, 100, 176 * #l, #False)
joueur\x = SpriteX(joueur\sprite)
joueur\y = SpriteY(joueur\sprite)
joueur\w = SpriteW(joueur\sprite)
joueur\h = SpriteH(joueur\sprite)


;{ ennemis

position_globale\x = 5 * #l
position_globale\y = 5 * #l

vitesse.POINT\x = #l
vitesse\y = 0


Dim ennemis(10, 4)

For a = 0 To 10
   ennemis(a, 0) = AddSprite(10, (a * 15 + 3) * #l, 0, #True)
Next

For a = 0 To 10
   ennemis(a, 1) = AddSprite(11, (a * 15 + 2) * #l, 15 * #l, #True)
   ennemis(a, 2) = AddSprite(11, (a * 15 + 2) * #l, 30 * #l, #True)
Next

For a = 0 To 10
   ennemis(a, 3) = AddSprite(12, (a * 15 + 1) * #l, 45 * #l, #True)
   ennemis(a, 4) = AddSprite(12, (a * 15 + 1) * #l, 60 * #l, #True)
Next



;}

NewList tir_physss()
NewList tir_ennemis()

vitesse_tir = #l * 2

nb_a_tuer = (ArraySize(ennemis(), 1) + 1) * (ArraySize(ennemis(), 2) + 1)

;}


;{ tread d'affichage
thread_affichage = CreateThread(@DrawSprite(), 0)
If thread_affichage = 0 : End : EndIf
;}


; time2 = ElapsedMilliseconds() - 1


;{ boucle principale

Repeat
   ;{ calcul temps boucle
;    time = ElapsedMilliseconds() - time2
;    time2 = ElapsedMilliseconds()
   ;}
   
   Delay(10)
   
   ExamineKeyboard()
   
   If KeyboardReleased(#PB_Key_Escape) : event = #PB_Event_CloseWindow : EndIf
   
   ;{ ajouts tirs physss
   
   If KeyboardReleased(#PB_Key_Space)
      AddElement(tir_physss())
      
      tir_physss() = AddSprite(2, joueur\x + joueur\w / 2, joueur\y - 3 * #l, #False)
   EndIf
   
   ;}
   
   ;{ déplacement joueur
   
   If KeyboardPushed(#PB_Key_Left)
      joueur\x - #l
      If joueur\x < 0 : joueur\x = 0 : EndIf
      
      Sprite_SetX(joueur\sprite, joueur\x)
   EndIf
   
   If KeyboardPushed(#PB_Key_Right)
      joueur\x + #l
      
      If joueur\x > #terrain_w * #l - joueur\w : joueur\x = #terrain_w * #l - joueur\w : EndIf
      
      Sprite_SetX(joueur\sprite, joueur\x)
   EndIf
   
   
   ;}
   
   ;{ déplacements ennemis
   
   If nb_a_tuer > nb_ennemis_tues Or perdu = #False
      position_globale\x + vitesse\x * #l
      position_globale\y + vitesse\y; * #l
      
      timer - 1
      
      If position_globale\x > 75 * #l
         vitesse\y = 1
         vitesse\x = 0
         
         position_globale\x = 75 * #l
         
         timer = 15
      ElseIf position_globale\x < 15 * #l
         vitesse\y = 1
         vitesse\x = 0
         
         position_globale\x = 15 * #l
         
         timer = 15
      EndIf
      
      If timer = 0 And vitesse\x = 0
         If position_globale\x = 15 * #l
            vitesse\x = 1
         Else
            vitesse\x = -1
         EndIf
         
         vitesse\y = 0
      EndIf
      
   EndIf
   
   ;}
   
   ;{ déplacements tirs
   
   ForEach tir_physss()
      Sprite_SetY(tir_physss(), SpriteY(tir_physss()) - vitesse_tir)
      
      If SpriteY(tir_physss()) < 0
         DeleteSprite(tir_physss())
         DeleteElement(tir_physss())
      Else
         ; controle si on touche un alien
         
         For a = 0 To ArraySize(ennemis(), 1)
            For b = 0 To ArraySize(ennemis(), 2)
               If ennemis(a, b) <> -1
                  If SpritePixelCollision(SpriteSprite(ennemis(a, b)), SpriteX(ennemis(a, b)) + position_globale\x, SpriteY(ennemis(a, b)) + position_globale\y, 2, SpriteX(tir_physss()), SpriteY(tir_physss()))
                     DeleteSprite(ennemis(a, b))
                     ennemis(a, b) = -1
                     
                     DeleteSprite(tir_physss())
                     DeleteElement(tir_physss())
                     
                     nb_ennemis_tues + 1
                     
                     Break 2
                  EndIf
               EndIf
            Next
         Next
         
      EndIf
   Next
   
   ;}
   
Until event = #PB_Event_CloseWindow

;}

;{ on arrete le programme proprement

EXIT = #True
WaitThread(thread_affichage)
;}

End

;{ DATA

DataSection
   alien1:
   Data.l 8, 8
   Data.b 0, 0, 0, 1, 1, 0, 0, 0
   Data.b 0, 0, 1, 1, 1, 1, 0, 0
   Data.b 0, 1, 1, 1, 1, 1, 1, 0
   Data.b 1, 1, 0, 1, 1, 0, 1, 1
   Data.b 1, 1, 1, 1, 1, 1, 1, 1
   Data.b 0, 0, 1, 0, 0, 1, 0, 0
   Data.b 0, 1, 0, 1, 1, 0, 1, 0
   Data.b 1, 0, 1, 0, 0, 1, 0, 1
   
   alien2:
   Data.l 11, 8
   Data.b 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0
   Data.b 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1
   Data.b 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1
   Data.b 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1
   Data.b 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
   Data.b 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
   Data.b 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0
   Data.b 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0
   
   alien3:
   Data.l 12, 8
   Data.b 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0
   Data.b 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0
   Data.b 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
   Data.b 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1   
   Data.b 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
   Data.b 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0
   Data.b 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0
   Data.b 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
   
   fin:
   
EndDataSection

;}
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: gestions de l'affichage

Message par Kwai chang caine »

J'ai honte...j'me suis éclaté comme une bête avec ton jeu :oops:
J'ai pu défendre la terre une seule fois...mais c'était bon 8)

Je n'aime pas trop les jeux, mais c'est le premier jeu vidéo que j'ai rencontré quand j’étais jeune, dans une table de bar et il m'a marqué a vie 8O
De ce fait, ce doit etre le seul ou je peux pas me retenir de jouer :mrgreen:

Super fluide sur XP PRO
Merci beaucoup du partage GRAPH100 8)
Et merci aussi a DJES :wink:
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: gestions de l'affichage

Message par graph100 »

Kwai chang caine a écrit :J'ai honte...j'me suis éclaté comme une bête avec ton jeu :oops:
J'ai pu défendre la terre une seule fois...mais c'était bon 8)
ça fait drollement plaisir :mrgreen: :mrgreen:

Au début j'avais mis la vitesse de déplacement d'avance ET latéral en mode rapide xD
C'est juste impossible !

Code : Tout sélectionner

		position_globale\x + vitesse\x * #l
		position_globale\y + vitesse\y      ; * #l
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: gestions de l'affichage

Message par Kwai chang caine »

J'ai encore plus honte :oops:
Mais comme j'suis honette, et en parlant de vitesse...ça me fait penser de t'avouer que j'en avait marre que devant ma femme je passe pour un bouffon
Ici, j'suis habitué, mais bon dans la vraie vie, ça le fait moins pour un chef de famille responsable :lol:

Alors n'y connaissant rien au graphisme, j'ai dit a ma femme, je vais rajouter un Delay(100) dans la boucle d'evenement, vu que c'est la seule chose que j'ai compris en premier :D
Ma femme m'a dit que j'etais un tricheur, elle n'avait pour une fois pas tout a fait tort :mrgreen:

Mais bon devant le prix de la terre et sa sauvegarde, je ne recule devant rien :?

Ca a marché, enfin trop bien, 8O
Les alliens y etaient tout mous, mais je pouvais aller pisser entre le temps ou la balle elle partait et qu'elle atteigne un allien :lol: :lol:

J'ai donc du me résoudre a perdre encore :oops: en enlevant ma super ligne de code :lol:
En tout cas merci pour ce retour a mon adolescence et ton travail 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Répondre