Mini-code pour débutants : T.A.N.K.S

Programmation avancée de jeux en PureBasic
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Mini-code pour débutants : T.A.N.K.S

Message par Huitbit »

'alut

Dans la série des mini-codes(ou plutôt "j'ai pas le temps mais je code quand même" :lol: :lol: :lol: , "un jeu" pour deux joueurs. Jeu entre guillemets car pouvant être utilisé en 2nde pour aborder la notion de projectile !
Toujours pareil, j'essaye de faire court(200 lignes) avec peu de mots-clés, etc, etc...
J'espère que ça pourra motiver ceux qui débutent.

Le paysage est généré aléatoirement.
La trajectoire des obus est calculée avec la méthode d'Euler(calcul de proches en proches).
J'ai utilisé des gadgets :P !

S'il y a un truc qui cloche n'hésitez pas !
Idem, toute amélioration du code est bienvenue !

Image
Images à mettre dans le même dossier que le code !
Image
Image

Code : Tout sélectionner

;T.A.N.K.S
;auteur Huitbit
;pb v4.10
;-déclarations
#largeur_ecran=1024
#hauteur_ecran=768
;-caractéristiques des montagnes
#amplitude=#hauteur_ecran/6
#pulsation=2*#PI/#largeur_ecran
#valeur_moyenne=#hauteur_ecran*0.5
deformation.f=1+Random(10)
Enumeration
  #spr_ciel
  #spr_montagne
  #spr_decor
  #spr_tank_1
  #spr_tank_2
  #spr_boulet
  #Text_0
  #TrackBar_0
  #Text_1
  #TrackBar_1
  #TrackBar_2
  #Text_2
  #TrackBar_3
  #Text_3
  #Button_0
  #Text_4
EndEnumeration
;fonction pour dessiner les montagnes
Macro f(x)
#amplitude*Sin(#pulsation*x)+#valeur_moyenne+#amplitude*0.25*Sin(#pulsation*deformation*x)
EndMacro
i.l
;variables utilisées pour tracer les montagnes
x_precedent.l
y_precedent.l
x.l
y.l
;-coordonnées initiales  des tanks
x_1.f=20+Random(200)
y_1.f=f(x_1)
x_2.f=#largeur_ecran-20-Random(200)
y_2.f=f(x_2)
;-données pour les obus 
#g=9.8
x_boulet_1.f=x_1-8
y_boulet_1.f=y_1-49
v_boulet_1.f=90
angle_1.f=45*#PI/180 ;conversion degrés / radians
vx_boulet_1.f=v_boulet_1*Cos(angle_1)
vy_boulet_1.f=-v_boulet_1*Sin(angle_1)
ay_boulet_1.f=#g
x_boulet_2.f=x_2-8
y_boulet_2.f=y_2-49
v_boulet_2.f=90
angle_2.f=45*#PI/180
vx_boulet_2.f=-v_boulet_2*Cos(angle_2)
vy_boulet_2.f=-v_boulet_2*Sin(angle_2)
ay_boulet_2.f=#g
dt.f=0.1 ;"pas" pour le calcul des  coordonnées  
feu.b=0; gestion du bouton de tir
score_1.b=0
score_2.b=0
tank_1_touche.b=0; pour savoir si un tank est touché
tank_2_touche.b=0
;-PROGRAMME PRINCIPAL
InitSprite()
InitKeyboard()
OpenWindow(0,0,0,#largeur_ecran,#hauteur_ecran,"T.A.N.K.S",#PB_Window_ScreenCentered|#PB_Window_SystemMenu  )
OpenWindowedScreen(WindowID(0),0,0,#largeur_ecran,#hauteur_ecran-200,0,0,0)
;-gadgets
CreateGadgetList(WindowID(0))
TextGadget(#Text_0, 0, 593+0, 356, 20, "Vitesse initiale = 90   (de 1 m/s à 180 m/s)", #PB_Text_Center)
TrackBarGadget(#TrackBar_0, 0, 593+20, 356, 20, 1, 179, #PB_TrackBar_Ticks)
SetGadgetState(#TrackBar_0,90)
TextGadget(#Text_1, 0, 593+60, 356, 20, "Angle de tir = 45   (de 1° à 89°)", #PB_Text_Center)
TrackBarGadget(#TrackBar_1, 0, 593+80, 356, 20, 0, 89, #PB_TrackBar_Ticks)
SetGadgetState(#TrackBar_1,45)
TextGadget(#Text_2, 668, 593+0, 356, 20, "Vitesse initiale = 90   (de 1 m/s à 180 m/s)", #PB_Text_Center)
TrackBarGadget(#TrackBar_2, 668, 593+20, 356, 20, 1, 179, #PB_TrackBar_Ticks)
SetGadgetState(#TrackBar_2,90)
TextGadget(#Text_3, 668, 593+60, 356, 20, "Angle de tir = 45   (de 1° à 89°)", #PB_Text_Center)
TrackBarGadget(#TrackBar_3, 668, 593+80, 356, 20, 0, 89, #PB_TrackBar_Ticks)
SetGadgetState(#TrackBar_3,45)
ButtonGadget(#Button_0, 376, 593+20, 272, 80, "*** FEU ! ***",#PB_Button_MultiLine)
TextGadget(#Text_4, 376, 593, 272, 20, "Score   "+Str(score_1)+" : "+Str(score_2), #PB_Text_Center)
;-Active le support du format PNG 
UsePNGImageDecoder()
;-dessin du décor ciel et montagne
CreateSprite(#spr_ciel,#largeur_ecran,#hauteur_ecran)
StartDrawing(SpriteOutput(#spr_ciel))
For i=0 To 255 Step 8
  Circle(#largeur_ecran/8,#hauteur_ecran/8,#largeur_ecran-i*4,RGB(i,255,255))
Next i
StopDrawing()
CreateSprite(#spr_montagne,#largeur_ecran,#hauteur_ecran)
StartDrawing(SpriteOutput(#spr_montagne))
DrawingMode( #PB_2DDrawing_Outlined)
x_precedent=0
y_precedent=f(x_precedent)
For x=1 To #largeur_ecran 
  y=f(x)
  LineXY(x_precedent,y_precedent,x,y,RGB(189, 114, 66))
  x_precedent=x
  y_precedent=y
Next x
FillArea(2,#hauteur_ecran-2,RGB(189, 114, 66),RGB(25, 114, 66))
StopDrawing()
;-chargement des sprites tanks 1&2
LoadSprite(#spr_tank_1,"tank_1.png")
LoadSprite(#spr_tank_2,"tank_2.png")
;-dessin d'un obus
CreateSprite(#spr_boulet,16,16)
StartDrawing(SpriteOutput(#spr_boulet))
For i = 0 To 7
  Circle(8,8,8-i,RGB(20+25*i,20+25*i,20+25*i))
Next i
StopDrawing()
;-BOUCLE PRINCIPALE
Repeat
  ;-tank_1 touché ?
  If SpritePixelCollision(#spr_boulet,x_boulet_2,y_boulet_2,#spr_tank_1,x_1-24,y_1-32)  And tank_1_touche=0
    score_2=score_2+1
    SetGadgetText(#Text_4,"Score   "+Str(score_1)+" : "+Str(score_2))
    tank_1_touche=1
  EndIf
  ;-tank_2 touché ?
  If SpritePixelCollision(#spr_boulet,x_boulet_1,y_boulet_1,#spr_tank_2,x_2-24,y_2-32) And tank_2_touche=0
    score_1=score_1+1
    SetGadgetText(#Text_4,"Score   "+Str(score_1)+" : "+Str(score_2))
    tank_2_touche=1
  EndIf
  ;-l'obus_1 a touché le sol ?
  If SpritePixelCollision(#spr_boulet,x_boulet_1,y_boulet_1,#spr_montagne,0,0)=0  And x_boulet_1<#largeur_ecran+16 And tank_2_touche=0  And   feu=1
    vy_boulet_1=vy_boulet_1+ay_boulet_1*dt
    x_boulet_1=x_boulet_1+vx_boulet_1*dt
    y_boulet_1=y_boulet_1+vy_boulet_1*dt
  EndIf
  ;-l'obus_2 a touché le sol ?
  If SpritePixelCollision(#spr_boulet,x_boulet_2,y_boulet_2,#spr_montagne,0,0)=0  And x_boulet_2>-16  And tank_1_touche=0  And  feu=1
    vy_boulet_2=vy_boulet_2+ay_boulet_2*dt
    x_boulet_2=x_boulet_2+vx_boulet_2*dt
    y_boulet_2=y_boulet_2+vy_boulet_2*dt
  EndIf
  ;-BOUCLE DE GESTION DES EVENEMENTS DE LA FENETRE
  Repeat
    Event = WindowEvent()   
    GadgetID = EventGadget()
    
    If  Event = #PB_Event_CloseWindow
      End 
    ElseIf  Event =#PB_Event_Gadget    
      
      If GadgetID = #TrackBar_0
        SetGadgetText(#Text_0,  "Vitesse initiale = "+Str(GetGadgetState(#TrackBar_0))+ "   (de 1 m/s à 180 m/s)")
      ElseIf GadgetID = #TrackBar_1
        SetGadgetText(#Text_1,  "Angle de tir = "+Str(GetGadgetState(#TrackBar_1)) +"   (de 1° à 89°)")
      ElseIf GadgetID = #TrackBar_2
        SetGadgetText(#Text_2,  "Vitesse initiale = "+Str(GetGadgetState(#TrackBar_2))+ "   (de 1 m/s à 180 m/s)")
      ElseIf GadgetID = #TrackBar_3
        SetGadgetText(#Text_3,  "Angle de tir = "+Str(GetGadgetState(#TrackBar_3)) +"   (de 1° à 89°)")
      ElseIf GadgetID = #Button_0
        feu=feu+1
        If feu>1
          feu=0
        EndIf
        If feu=1 ;on récupère les valeurs de vitesses initiales
          v_boulet_1=GetGadgetState(#TrackBar_0)
          angle_1=GetGadgetState(#TrackBar_1)*#PI/180
          vx_boulet_1=v_boulet_1*Cos(angle_1)
          vy_boulet_1=-v_boulet_1*Sin(angle_1)
          v_boulet_2=GetGadgetState(#TrackBar_2)
          angle_2=GetGadgetState(#TrackBar_3)*#PI/180
          vx_boulet_2=-v_boulet_2*Cos(angle_2)
          vy_boulet_2=-v_boulet_2*Sin(angle_2)
          SetGadgetText(#Button_0,"REJOUER ?")
        ElseIf feu =0 ;on replace au hasard les tanks
          x_1=20+Random(200)
          y_1=f(x_1)
          x_2=#largeur_ecran-20-Random(200)
          y_2=f(x_2)
          x_boulet_1=x_1-8
          y_boulet_1=y_1-49
          x_boulet_2=x_2-8
          y_boulet_2=y_2-49
          tank_1_touche=0
          tank_2_touche=0
          SetGadgetText(#Button_0,"FEU !")
        EndIf
      EndIf
    EndIf
  Until Event = 0
  
  DisplaySprite(#spr_ciel,0,0)
  DisplayTransparentSprite(#spr_montagne,0,0)
  DisplayTransparentSprite(#spr_tank_1,x_1-24,y_1-32)
  DisplayTransparentSprite(#spr_tank_2,x_2-24,y_2-32)
  DisplayTransparentSprite(#spr_boulet,x_boulet_1,y_boulet_1)
  DisplayTransparentSprite(#spr_boulet,x_boulet_2,y_boulet_2)
  Delay(1)
  FlipBuffers() 
ForEver
Hasta la vista !

PS : pour tenir compte des frottements dus à l'air (modèle en f = k*v²)
il faut modifier quelques lignes :

Code : Tout sélectionner

 

v_boulet=sqr(vx_boulet*vx_boulet+vy_boulet*vy_boulet)
 ax_boulet=-#beta*v_boulet*vx_boulet
  ay_boulet=#g-#beta*v_boulet*vy_boulet
  vx_boulet=vx_boulet+ax_boulet*dt
  vy_boulet=vy_boulet+ay_boulet*dt
  x_boulet=x_boulet+vx_boulet*dt
  y_boulet=y_boulet+vy_boulet*dt
avec #beta=0.0005; coefficient de frottements de l'air divisé par la masse du missile
Dernière modification par Huitbit le dim. 04/mai/2008 9:48, modifié 3 fois.
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Message par Backup »

excellent ! :)

t'es un grand malade toi :lol:
Neosis
Messages : 113
Inscription : dim. 24/févr./2008 20:11

Message par Neosis »

he... ça me fait penser au jeu que j'ai dans ma calculatrice "casio"^^
pas mal, c'est quand même assez bien fait pour un code de 200 lignes :)
Avatar de l’utilisateur
Chris
Messages : 3731
Inscription : sam. 24/janv./2004 14:54
Contact :

Message par Chris »

Moi, j'aurai juste changé deux trucs.

1 : Les conducteurs de tank ont la tête qui dépasse, c'est pas leur casque qui va arrêter les obus.

2 : à la place des variables "boulet" (x_boulet, y_boulet, etc...) j'aurai mis un autre nom.
Je sais pas, moi! ...
Au hasard... x_Bernard13, y_Bernard_13, ..... etc. :lol:
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Message par Huitbit »

@Dobro
Merci :wink:
La section jeu est un peu délaissée ces temps-ci :cry:
J'espère que certains sont sur des gros coups!!!
@Neosis
Une casio, t'en as de la chance !
Au lycée j'avais une TI62 Galaxy : 100 pas de programmation (mode pas à pas et mode rapide :lol: :lol: :lol: )
Il fallait optimiser le code !!!!
Image
Les autres ils avaient une casio 8500 :x et ils pouvaient faire des jeux (starwars, etc...).
Maintenant, j'ai purebasic :P :P :P

@Chris
:lol: :lol: :lol:
beauregard
Messages : 1307
Inscription : dim. 08/juil./2007 18:32
Localisation : Toulouse

Message par beauregard »

Huitbit a écrit :J'espère que certains sont sur des gros coups!!!
qu'est ce que tu voudrai voir ? Un jeu à scrolling ? Plus y a d'interactions, plus y a de variables à gérer, et plus la mise en oeuvre est longue:
exemple de jeux avec difficulté de conception par ordre croissant:
space invader
r-type
mega man( j'ai bien aimé le 2 sur famicom, une vrai petite perle)

. Et la conception des images étant elle bien plus longue que la programmation( interminable même, surtout si on est perfectionniste... et pas très doué en dessin ;) )

pour ta dernière oeuvre:
-> une fois le tir terminée, nous subissons une remise à 0, voyez, pourquoi?
-> le décor n'est pas destructible( chuis pacifique donc çà ne me gêne pas, mais bon).

Au plaisir !
config de mon ordi: seven, directx11, Pentium(R) DualCore E5700, RadeonHD 4550 512MB, PureBasic 4.61 x86
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Message par Huitbit »

@beauregard
qu'est ce que tu voudrai voir ?
En fait cette remarque était plutôt pour les débutants, il faut OSER (j'en suis un, alors je sais que c'est en essayant des petits projets que l'on fait des gros progrès), derrière un petit code peut se cacher une bonne idée :wink:

Tu nous as annoncé la couleur il y a quelques mois (grosse production de sprites!) alors tu n'étais pas visé!
J'espère que ton projet avance bien :P
une fois le tir terminée, nous subissons une remise à 0, voyez, pourquoi?
Remise à zéro des gadgets ?

Hasta la vista !
Avatar de l’utilisateur
Ar-S
Messages : 9540
Inscription : dim. 09/oct./2005 16:51
Contact :

Message par Ar-S »

Huitbit, lorsque je réponds à tes topics c'est pour te congratuler..
et la je continue.

Tu déchires ! :P
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Bonus

Message par Huitbit »

Merci Ar-S !
:P

Un petit bonus : comparaison de trajectoires (avec ou sans frottements)

Tout le calcul dépend de l'expression de l'accélération (obtenu avec la projection de la 2ème loi de Newton (m*Accélération=Poids+Frottements c'est à dire m*A=mG-kv²*U les lettres majuscules représentent des vecteurs et U=V/v un vecteur unitaire de même sens et de même direction que V c'est à dire tangent à la trajectoire et orienté dans le sens du mouvement))
Dans le code #beta=k/m

Le calcul peut s'utiliser tel quel dans une application car il n'a besoin que du x et du y de départ(voir utilisation dans T.A.N.K.S plus haut).

Code : Tout sélectionner

;trajectoires de projectiles
;pb v4.10
;*********************************
#largeur_ecran=1024
#hauteur_ecran=400

#g=9.8 ;intensité du champ de pesanteur
;-données courbe avec frottements
#beta=0.0008; coefficient de frottements de l'air divisé par la masse du missile
x.f=5;abscisse initiale
y.f=398;ordonnée initiale
v0.f=100;intensité de la vitesse initiale
angle.f=45*#PI/180;angle initial
vx.f=v0*Cos(angle)
vy.f=-v0*Sin(angle)
v.f=Sqr(vx*vx+vy*vy)
ax.f=-#beta*v*vx
ay.f=#g-#beta*v*vy

;-données courbe sans frottements
x1.f=x
y1.f=y
vx1.f=v0*Cos(angle)
vy1.f=-v0*Sin(angle)
ay1.f=#g

;-pas du calcul
dt.f=0.1
dt1.f=dt

InitSprite()
InitKeyboard()
OpenWindow(0,0,0,#largeur_ecran,#hauteur_ecran,"Projectile",#PB_Window_ScreenCentered|#PB_Window_SystemMenu  )
OpenWindowedScreen(WindowID(0),0,0,#largeur_ecran,#hauteur_ecran,0,0,0)

Repeat
  
  Repeat
    Event = WindowEvent()      
    If  Event = #PB_Event_CloseWindow
      End 
    EndIf
  Until Event = 0
  
  ;-cas avec frottements (courbe rouge)
  v=Sqr(vx*vx+vy*vy)
  ax=-#beta*v*vx
  ay=#g-#beta*v*vy
  vx=vx+ax*dt
  vy=vy+ay*dt
  x=x+vx*dt
  y=y+vy*dt
  
  ;-cas sans frottements (courbe verte)
  vy1=vy1+ay1*dt1
  x1=x1+vx1*dt1
  y1=y1+vy1*dt1
  
  StartDrawing(ScreenOutput())
  If x>2 And x<#largeur_ecran-2 And y>2 And y<#hauteur_ecran-2 
    Plot(x,y,RGB(255,0,0))
  Else
    dt=0
  EndIf
  If  x1>2 And x1<#largeur_ecran-2 And y1>2 And y1<#hauteur_ecran-2
    Plot(x1,y1,RGB(0,255,0))
  Else
    dt1=0
  EndIf
  StopDrawing()
  
  Delay(1)
  FlipBuffers() 
ForEver

Questions :
Quelle est la fonction la plus rapide Sqr(x) ou Pow(x,0.5) ?

Ca marche avec un "pas" dt=1.
Ca doit être possible de faire la même chose avec des nombres entiers en faisant le changement d'échelle adéquat. Ca économiserait le processeur, non ? Ca veut dire plus d'objets en mouvement.....

[EDIT]
fonction pow(x,0.5)

Code : Tout sélectionner

chrono=ElapsedMilliseconds()
For x=0 To 1000000
y=Pow(x,0.5)
Next x
Debug ElapsedMilliseconds()-chrono
fonction sqr(x)

Code : Tout sélectionner

chrono=ElapsedMilliseconds()
For x=0 To 1000000
y=Sqr(x)
Next x
Debug ElapsedMilliseconds()-chrono
je ne sais pas si la méthode de comparaison est très rigoureuse, en tout cas les résultats sont flagrants :
Sqr(x) WINS!


Hasta la vista !

PS: comme vx=v*cos(angle) et vy=v*sin(angle) on a vy/vx=tan(angle), on peut avoir accès à la valeur de l'angle à n'importe quel moment avec l'arctangente, ça peut-être utile pour calculer l'inclinaison du projectile :wink:
beauregard
Messages : 1307
Inscription : dim. 08/juil./2007 18:32
Localisation : Toulouse

Message par beauregard »

Huitbit a écrit :
une fois le tir terminée, nous subissons une remise à 0, voyez, pourquoi?
Remise à zéro des gadgets ?Hasta la vista !
-> "on replace au hasard les tanks" : tu devrais proposer un petit stock de munition( disons 5 obus) avant la remise à zéro. Et si on touche au but, image explosion.
Huitbit a écrit :J'espère que ton projet avance bien :P
oui merci( je suis au milieu du gué, là où le courant est le plus fort, mais je m'accroche avec mes petites griffes).
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Salut Huitbit,

Trop lourd la lecture du code. A part ça...

Bravo ! Bravo pour l'idée, la recherche d'algo réalistes, et l'achèvement de ce petit jeu.
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Salut HuitBit,
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

ça m'intéresse tes chars ! Je peux?
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Message par Huitbit »

Hello,
Ils ne sont pas à moi, c'est une image prise sur le net légèrement modifiée.

Hasta la vista!

[EDIT] adresse où j'ai dû prendre l'image (avec altavista):
http://www.ben-newman.de/smilie/index.p ... =transport
Ollivier
Messages : 4197
Inscription : ven. 29/juin/2007 17:50
Localisation : Encore ?
Contact :

Message par Ollivier »

Nan, je suis plus ambitieux que cela : j'aimerais faire une version en 3D. Mais les conseils d'experts plus doués dans ce domaine m'aideraient à savoir si c'est réalisable en un seul code.

Et si jamais je parviens à faire quelque chose de concrèt, les calculs de trajectoires seront faux. Il me faudra alors aussi tes propres conseils concernant les calculs, car mes notions de microtech (positions, vitesse et accélérations, PFS and Co) sont au fond de mon crâne, quelque part après le 3ème feu à droite...
Répondre