Punch "Le survivant", les secrets du tournage !

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

Punch "Le survivant", les secrets du tournage !

Message par Huitbit »

Hello,

Voici la version dépunchée de mon petit jeu.
La petite voiture Pb doit faire son chemin pendant quinze ans (quinze tours) parmi les langages multiplateformes en gérant sa batterie et ses bugs !

Attention ! [mode KCC] ON, ça va être long !

Le titre vient d'un jeu que j'avais étant enfant (ah nostalgie, quand tu nous tiens !)
Image

Le fonctionnement du moteur, vient de remarques de djes, il y a fort longtemps :roll: .
C'était à propos de la manière de gérer le scrolling (si on lie la caméra au joueur, on a vite le mal de mer, pourtant, certains jeux l'ont fait !!!) et de la manière de se repérer sur le circuit (hors-piste ou pas ?).

Pour le scrolling, j'ai associé un sprite caméra à la voiture qui se déplace presque à la même vitesse mais qui suit un "rail" au milieu de la piste.
L'angle de rotation du circuit dépend du coefficient directeur local de la courbe.
La gestion des angles a été infernale(si,si :mrgreen: ) car il a fallu jongler entre les (-PI, +PI) des fonctions trigonométriques et les (0,360) des RotateSprite().
Il a fallu également lisser les valeurs des angles sinon le scrolling était trop saccadé.

Pour la localisation, j'ai opté pour le calcul de l'éloignement par rapport aux points de contrôle de la courbe et du calcul de la distance par rapport au centre de la courbe.
Pour le repérage, je n'ai pas tenté de lire les pixels sous la voiture(je pense que c'est une bonne méthode), c'est une piste que j'explorerai

Pour l'affichage, j'ai tenté de tout afficher, de faire un GrabSprite() puis de faire tourner, ça a été une catastrophe (lenteur dès que le sprite "écran" était trop gros).
J'ai donc opté pour un ClipSprite() autour de la voiture puis une rotation de tous les éléments un par un.


Voici le code commenté (j'ai mis la partie musique en commentaires) :

Code : Tout sélectionner

;Titre : Le survivant
;Date : Septembre-novembre 2015
;Auteur : Huitbit
;-réussir 15 tours

Enumeration
  #SPR_CIRCUIT
  #SPR_VOIT_C
  #SPR_VOIT_JAVA
  #SPR_VOIT_PB
  #SPR_VOIT_PY
  #SPR_CAMERA1
  #SPR_ECRAN
  #SPR_SOIN
  #SPR_JERRICAN
  #SPR_LEVEL
  #SPR_ECURIES
  #SPR_LAP
  #SPR_DUST
  #FONT_IMPACT_450
  #FONT_IMPACT_20
  #FONT_IMPACT_30
EndEnumeration


Structure PT ;pour les points de contrôle
  x.l
  y.l ; y  =  a  *  x  + b
  s.l ; abscisse curviligne
  a.f ; pente qui dépend du sens de déplacement (de la gauche vers la droite ou l'inverse)
  aEcran.f;pente de la droite vue à l'écran (indépendante du sens de déplacement) 
  b.f     ; ordonnée à l'origine
  hypo.f  ; hypoténuse  (triangle lié au vecteur directeur du segment :côté adjacent : 1
          ;   côté opposé: a    hypothénuse : Sqr[1+(dy/dx)²] = Sqr[1+a²] )
  vertical.b; pour gérer les portions verticales de la courbe (y=a*x+b non valide)
  angleEnRadian.f;angle de la portion de route qui dépend du sens de déplacement
EndStructure     ; PT

Structure COURBE
  x.f
  y.f ; y  =  a  *  x  + b
  Ptctrl.l; point de contrôle dont dépend cette partie de courbe
  cosinus.f
  sinus.f
  angleEnRadian.f; angle lié au point e contrôle en cours
  angleEnDegre.f ; conversion et lissage des valeurs en radian
EndStructure     ; COURBE


Hwindow =600
Lwindow =800
Hscreen = Hwindow 
Lscreen = Lwindow
;Le circuit est dessiné sur un sprite 2048*768
;on clippe une zone de 566*566 autour de la voiture pour l'affichage
;si on clippe en dehors du sprite cela engendre des effets indésirables
;par sécurité, on ajoute une bordure de 566px autour du circuit (normalement, la moitié devrait suffire)

;-taille de la zone de "clippage"
tailleClip=566


Lcircuit = 2048+2*tailleClip; 2*566 bordure pour le clipsprite
Hcircuit = 768+2*tailleClip ; 2*566 bordure pour le clipsprite
demiLargeurRoute.l=60
nbrSubdv.l = 3
nPtCtrl.l = 13 ; 14 points de contrôle initiaux, indices de 0 à 13

rapportSubdv.f = 0.25
longueurCourbe.l;longueur du circuit
cosinus.f
sinus.f
angleEnRadian.f 
ecartAngle.f ; ecartAngle =(angleVoiture - angleRoute)
             ;angles utilisés pour faire zigzaguer les voitures
angleEnnemiC.f
angleEnnemiJava.f
angleEnnemiPy.f
angleBonus.f

;niveaux
battery.f
bugLevel.f
compilationSpeed.f

sprBonus.l; ID du sprite qui alterne entre #SPR_SOIN et   #SPR_JERRICAN

;coordonnées réelles des voitures et des bonus sur le sprite #SPR_CIRCUIT 
xC.f : yC.f
xJava.f : yJava.f
xPb.f : yPb.f
xPy.f : yPy.f
xBonus.f : yBonus.f

;coordonnées des voitures après rotation 
;centre de rotation : la voiture PureBasic
;angle de rotation lié à la forme de la route 
xRotC.f : yRotC.f
xRotJava.f : yRotJava.f
xRotPy.f : yRotPy.f
xRotBonus.f : yRotBonus.f
xRotCam.f :yRotCam.f

;coordonnées pour l'affichage final
xEcranVoiture.f :yEcranVoiture.f
xEcranC.f :yEcranC.f
xEcranJava.f :yEcranJava.f
xEcranPy.f :yEcranPy.f
xEcranBonus.f : yEcranBonus.f

dr.f ; variation du rayon (variable qui va jouer 
     ;le rôle de la vitesse)
drdt.f ;dérivé de dr  par rapport au temps (variable qui va jouer 
       ;le rôle de l'accélération)

dx.f;  dx = dr*Cos(angleVoiture)    et    xVoiture = xVoiture + dx
dy.f;  dy =dr*Sin(angleVoiture)   et     yVoiture = yVoiture + dy


;seuls deux compteurs de tours nous intéressent
; car la voiture C++ est la plus rapide
;et sert de référence
compteurTourC.l
compteurTour.l

;flag pour afficher la poussière lorsqu'on s'écarte de la route
poussiere.f

;paramètres pour l'abscisse curviligne des voitures (repérage sur 
;la courbe du circuit qui a été normée au préalable)
lC.l
lJava.l
lPb.l
lPy.l
lBonus.l

lCam.l ;pour la caméra qui suit la voiture Pb


;chargement des points de contrôle avec décalage de tailleClip = 566
Dim P.PT(nPtCtrl)
Restore circuit
For i = 0 To nPtCtrl
  Read.l P(i)\x
  P(i)\x=P(i)\x+tailleClip; +tailleClip = 566 pour éviter pb avec clipsprite+gagner place dans data
  Read.l P(i)\y
  P(i)\y=P(i)\y+tailleClip
Next i


Procedure.l subdv(Array pP.PT(1), pNptCtrl, pNbrSubdv, pRapportSubdv.f)
  Dim Ptemp.PT(pNptCtrl)
  CopyArray(pP(), Ptemp())
  
  For nSubdv = 1 To pNbrSubdv
    
    ReDim pP(2 * pNptCtrl + 1)
    
    For n = 0 To pNptCtrl - 1
      pP(2 * n)\x = Ptemp(n)\x + pRapportSubdv * (Ptemp(n + 1)\x - Ptemp(n)\x)
      pP(2 * n)\y = Ptemp(n)\y + pRapportSubdv * (Ptemp(n + 1)\y - Ptemp(n)\y)
      pP(2 * n + 1)\x = Ptemp(n)\x + (1 - pRapportSubdv) * (Ptemp(n + 1)\x - Ptemp(n)\x)
      pP(2 * n + 1)\y = Ptemp(n)\y + (1 - pRapportSubdv) * (Ptemp(n + 1)\y - Ptemp(n)\y)
    Next n
    
    ;gestion de la dernière portion de P(n) à P(0)  
    n = pNptCtrl 
    pP(2 * n)\x = Ptemp(n)\x + pRapportSubdv * (Ptemp(0)\x - Ptemp(n)\x)
    pP(2 * n)\y = Ptemp(n)\y + pRapportSubdv * (Ptemp(0)\y - Ptemp(n)\y)
    pP(2 * n + 1)\x = Ptemp(n)\x + (1 - pRapportSubdv) * (Ptemp(0)\x - Ptemp(n)\x)
    pP(2 * n + 1)\y = Ptemp(n)\y + (1 - pRapportSubdv) * (Ptemp(0)\y - Ptemp(n)\y)
    
    pNptCtrl = 2 * pNptCtrl + 1
    ReDim Ptemp.PT(pNptCtrl)
    CopyArray(pP(), Ptemp())
  Next nSubdv
  ProcedureReturn pNptCtrl
  
EndProcedure

Macro affine(a, aEcran, b, xA, yA, xB, yB) ; y = a*x+b
  If xA<>xB
    If xA < xB
      a = (yB - yA) / (xB - xA)
    Else
      a = (yB - yA) / (xA - xB)
    EndIf;xA < xB
         ;aEcran est indépendant du sens de déplacement
         ;contrairement à a
    aEcran =  (yB - yA) / (xB - xA)
    b = yB - aEcran * xB
  EndIf;xA<>xB
EndMacro

Macro eloignement(xA,yA,xB,yB,vX,vY)
  ;basé sur la dérivé du carré de la distance
  ;si dEloignement est positif   => éloignement
  ;si dEloignement est négatif   => raprochement
  dEloignement=(xA - xB) * vX + (yA - YB) * vY
EndMacro

Macro creerVoiture(nom,couleur)
  CreateSprite(nom,48,30)
  
  StartDrawing(SpriteOutput(nom)) 
  
  RoundBox(33, 0, 9, 30, 2, 2, RGB(34,34,34));roue av
  RoundBox(6, 0, 9, 30, 2, 2, RGB(34,34,34)) ;roue ar
  RoundBox(0, 3, 48, 24, 4, 6, couleur)      ;carosserie
  RoundBox(6,6,9,18,3,3, RGB(0,0,64))        ;vitre ar
  Ellipse(24,15,6,9,RGB(0,0,64))             ;vitre av
  RoundBox(12,6,12,18,3,3, couleur)          ;toit
  ;taches de boue
  For i=0 To 20
    Circle(Random(46,2),Random(24,4),1,RGB(139, 69, 19))
  Next i
  
  StopDrawing()
EndMacro

Macro afficherConcurrent(nom,lConc,xConc,yConc, xRot, yRot,xEcran,yEcran)
  ;rotation du sprite en fonction de l'orientation de la route 
  RotateSprite(nom,s(lConc)\angleEnDegre+angleCam,0);#PB_Absolute=0
  
  ;rotation par rapport à la voiture PureBasic
  xRot=(xConc-xVoiture)*Cos(angleCam*#PI/180) - (yConc-yVoiture)*Sin(angleCam*#PI/180)+xVoiture
  yRot=(xConc-xVoiture)*Sin(angleCam*#PI/180) + (yConc-yVoiture)*Cos(angleCam*#PI/180)+yVoiture
  
  ;placement sur l'écran final
  xEcran = (xRot-xVoiture)+tailleClip*0.5-24
  yEcran = (yRot-yVoiture)+tailleClip*0.5-15+17
  If (xRot<tailleClip*0.5+xVoiture) And (yRot<tailleClip*0.5+yVoiture); non affichage en dehors de l'écran
    
    DisplayTransparentSprite(nom, xEcran, yEcran)
    
  EndIf ;affichage concurrent
  
EndMacro

Macro collision(nom,x,y,xEcran,yEcran,l)
  If SpriteCollision(#SPR_VOIT_PB,xVoiture,yVoiture,nom,x,y) 
    
    If yEcranVoiture<yEcran      
      l = l-10      
    EndIf ; ennemi derrière
    
    If yEcranVoiture>=yEcran    
      l = l+10   
    EndIf ; ennemi devant
    
    ; l compris entre 0 et longeurCourbe
    ;gestion des sorties de l'intervalle [0;longueurCourbe]
    If l<0
      l=l+longueurCourbe
    EndIf
    If l>longueurCourbe
      l=l-longueurCourbe
    EndIf    
    
    
    If bugLevel<192
      bugLevel+8
    Else
      ;-fin du jeu, voiture endommagée
      score()
    EndIf;bugLevel<192
    
  EndIf;collision pb-autre
EndMacro

Macro score()
  MessageRequester("GAME OVER",Str(compteurTour)+" TOUR(S)"+Chr(13)+"SCORE :"+Str(compteurTour*longueurCourbe+lCam))
  Goto jeu
EndMacro

;- Subdivision courbe
nPtCtrl = subdv(P(), nPtCtrl, nbrSubdv, rapportSubdv)

;- Calculs des équations affines de chaque segment
For n = 0 To nPtCtrl - 1
  
  If P(n)\x <> P(n+1)\x  
    affine(P(n)\a,P(n)\aEcran, P(n)\b, P(n)\x, P(n)\y, P(n + 1)\x, P(n + 1)\y)
    P(n)\hypo = Sqr(1 + P(n)\a * P(n)\a)
  Else  ;gestion des portions verticales
    P(n)\vertical=1    
  EndIf
Next n

;gestion de la dernière portion de P(n) à P(0)  
n = nPtCtrl
If P(n)\x <> P(0)\x  
  affine(P(n)\a,P(n)\aEcran, P(n)\b, P(n)\x, P(n)\y, P(0)\x, P(0)\y)
  P(n)\hypo = Sqr(1 + P(n)\a * P(n)\a)
Else  ;gestion des portions verticales
  P(n)\vertical=1    
EndIf;P(n)\x <> P(0)\x 



;- calcul de la longueur de la courbe L=Somme(dL) avec dL =Sqr[1+(dy/dx)²].dx et dy/dx = a
P(0)\s = 0
longueurCourbe = 0
For n = 0 To nPtCtrl - 1
  If P(n)\vertical <>0 ;gestion de xA=xB
    longueurCourbe = longueurCourbe + Abs(P(n + 1)\y - P(n)\y) 
  Else
    longueurCourbe = longueurCourbe + P(n)\hypo * Abs(P(n + 1)\x - P(n)\x)
  EndIf;P(n)\vertical <>0
  P(n + 1)\s = longueurCourbe
Next n
;gestion du dernier segment
n = nPtCtrl
If P(n)\vertical <>0 ;gestion de xA=xB
  longueurCourbe = longueurCourbe + Abs(P(0)\y - P(n)\y) 
Else
  longueurCourbe = longueurCourbe + P(n)\hypo * Abs(P(0)\x - P(n)\x)
EndIf;P(n)\vertical <>0


; et détermination de l'abscisse curviligne s des points de contrôle
Dim s.COURBE(longueurCourbe)
; comparaison des triangles rectangles  (côté adj : dx ; côté opp: dy ; hyp : dL )
; et  (côté adj : 1 ;   côté opp: a    ;hyp : Sqr[1+(dy/dx)²]  )
; dL / dx = cos(angle) =  1 / Sqr[1+(dy/dx)²] )
; cas du premier point de contrôle P(0)
;-IMPORTANT 
;-gérer le signe de cos selon le sens de déplacement
;-idem pour le sinus
s(0)\x = P(0)\x
s(0)\y = P(0)\y
s(0)\Ptctrl = 0
If  P(0)\vertical<>1
  s(0)\cosinus = Sign(P(1)\x -P(0)\x) / P(0)\hypo; prise en compte du sens des x croissants pour les calculs
  s(0)\sinus = P(0)\a / P(0)\hypo
  s(0)\angleEnRadian = ATan2(s(0)\cosinus, s(0)\sinus)
Else 
  s(0)\cosinus = 0
  s(0)\sinus = Sign(P(1)\y - P(0)\y)
  s(0)\angleEnRadian = ATan2(s(0)\cosinus, s(0)\sinus)
EndIf;P(0)\vertical<>1
     ;-debut
l = 1
For n = 0 To nPtCtrl - 1
  If  P(n)\vertical<>1
    cosinus = Sign(P(n+1)\x -P(n)\x)  / P(n)\hypo; prise en compte du sens des x croissants pour les calculs
    sinus = P(n)\a / P(n)\hypo    
    angleEnRadian = ATan2(cosinus, sinus)
    P(n)\angleEnRadian = angleEnRadian
  Else 
    cosinus = 0
    sinus = Sign(P(n+1)\y - P(n)\y)
    angleEnRadian = ATan2(cosinus, sinus)
    P(n)\angleEnRadian = angleEnRadian
    
    
  EndIf ;P(n)\vertical<>1
        ;passage d'angle -pi;+pi à 0; k*2pi
  If  n<>0
    If  (P(n)\angleEnRadian-P(n-1)\angleEnRadian)>=#PI
      
      P(n)\angleEnRadian=P(n)\angleEnRadian-2*#PI
    EndIf
    If  (P(n)\angleEnRadian-P(n-1)\angleEnRadian)<=-#PI
      
      P(n)\angleEnRadian=P(n)\angleEnRadian+2*#PI
    EndIf
  EndIf ;n<>0
  While l < P(n + 1)\s
    
    s(l)\x = s(l - 1)\x + cosinus
    s(l)\y = s(l - 1)\y + sinus
    s(l)\Ptctrl = n
    s(l)\cosinus = cosinus
    s(l)\sinus = sinus
    s(l)\angleEnRadian = P(n)\angleEnRadian
    l = l + 1
  Wend; l < P(n + 1)\s
  
  ; ajustement de la valeur de L à chaque point de contrôle
  If l = P(n + 1)\s
    
    s(l)\x = P(n + 1)\x
    s(l)\y = P(n + 1)\y
    s(l)\angleEnRadian = P(n)\angleEnRadian
    s(l)\Ptctrl = n+1
    l = l + 1
    
  EndIf; l = P(n + 1)\s
  
  
Next n

;gestion de la fermeture de la courbe
n = nPtCtrl
If P(n)\vertical <>1
  cosinus = Sign(P(0)\x-P(n)\x) / P(n)\hypo ; prise en compte du sens des x croissants pour les calculs 
  sinus =P(n)\a / P(n)\hypo
  angleEnRadian = ATan2(cosinus, sinus)
  P(n)\angleEnRadian = angleEnRadian
Else 
  cosinus = 0
  sinus = Sign(P(0)\y - P(n)\y)
  angleEnRadian = ATan2(cosinus, sinus)
  P(n)\angleEnRadian = angleEnRadian
EndIf ;P(n)\vertical<>1

If  (P(n)\angleEnRadian-P(n-1)\angleEnRadian)>=#PI
  
  P(n)\angleEnRadian=P(n)\angleEnRadian-2*#PI
EndIf
If  (P(n)\angleEnRadian-P(n-1)\angleEnRadian)<=-#PI
  
  P(n)\angleEnRadian=P(n)\angleEnRadian+2*#PI
EndIf

While l <= longueurCourbe ;<= car pas d'ajustement de la valeur de L au point de contrôle
  
  s(l)\x = s(l - 1)\x + cosinus
  s(l)\y = s(l - 1)\y + sinus
  s(l)\Ptctrl = n
  s(l)\cosinus = cosinus
  s(l)\sinus = sinus
  s(l)\angleEnRadian = P(n)\angleEnRadian
  l = l + 1
  
Wend;l < longueurCourbe


;- lissage des angles pour  avec les 2n voisins pour un scrolling plus doux
iMax= 16

For l=0 To longueurCourbe
  If l>iMax And (l<longueurCourbe-iMax); pas de lissage au niveau de la jonction
    
    
    ;lissage avec les 2n voisins (n devant, n derrière)
    
    indice=0
    
    For i =- iMax To iMax
      
      indice = l+i
      
      angle=s(indice)\angleEnRadian*180/#PI
      
      
      s(l)\angleEnDegre =  s(l)\angleEnDegre + angle ;somme
      
    Next i
    
    s(l)\angleEnDegre=  s(l)\angleEnDegre/(2*iMax+1);moyenne des angles voisins
    
  Else 
    s(l)\angleEnDegre=  s(l)\angleEnRadian*180/#PI
  EndIf
  
Next l

;- PROGRAMME PRINCIPAL
;- 
InitSprite()
InitKeyboard()
InitSound()
OpenWindow(0, 0, 0, Lwindow, Hwindow, "Le survivant", #PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0), 0, 0, Lscreen, Hscreen, 1, 0, 0,#PB_Screen_SmartSynchronization)

LoadFont( #FONT_IMPACT_450,"Impact",450,#PB_Font_Italic)   
LoadFont( #FONT_IMPACT_20,"Impact",20,#PB_Font_Italic  ) 
LoadFont(#FONT_IMPACT_30,"Impact",30,#PB_Font_Italic)
;UseOGGSoundDecoder()
;LoadSound(0, "m.ogg")

;-SPRITES

;-poussiere
CreateSprite(#SPR_DUST,48,48)
StartDrawing(SpriteOutput(#SPR_DUST))
For i=0 To 20
  rnd=Random(128,64)
  Circle(Random(36,12),Random(36,12),Random(12,1),RGB(rnd,rnd,rnd))
Next i
StopDrawing()


;-jerrican
CreateSprite(#SPR_JERRICAN,16,16)
StartDrawing(SpriteOutput(#SPR_JERRICAN))
RoundBox(0,0,16,16,2,2,RGB(184, 134, 11))
DrawText(4,0,"X",RGB(92, 60, 11),RGB(184, 134, 11))
StopDrawing()

;-trousse de secours
CreateSprite(#SPR_SOIN,16,16)
StartDrawing(SpriteOutput(#SPR_SOIN))
RoundBox(0,0,16,16,2,2,RGB(255, 255, 255))
DrawText(4,0,"+",RGB(255, 0, 0),RGB(255, 255,255))
StopDrawing()

;-sprite circuit
CreateSprite(#SPR_CIRCUIT,Lcircuit,Hcircuit)
StartDrawing(SpriteOutput(#SPR_CIRCUIT)) 
Box(0,0,Lcircuit,Hcircuit,(RGB(0,128,64)))
;buissons autour du circuit
For i=0 To 1000
  r=Random(48)
  Circle(Random(Lcircuit),Random(Hcircuit),Random(8,2),RGB(0+r,128+r,64+r))
Next i

DrawingFont(FontID(#FONT_IMPACT_450))
DrawText(744,570,"15 ans",RGB(255, 255, 255),RGB(0,128,64))
For l=1 To longueurCourbe-1 
  ;tracé des virages dangereux en fonction du rayon de courbure
  If Abs(s(l+1)\angleEnRadian-s(l-1)\angleEnRadian)>#PI/15 And l<>longueurCourbe-1
    Circle(s(l)\x,s(l)\y,demiLargeurRoute+2,RGB(255,0,0))
  Else
    Circle(s(l)\x,s(l)\y,demiLargeurRoute,RGB(255,255,255))
  EndIf
  
Next l
;"texture" de la route
For l=0 To longueurCourbe-1 
  r=Random(8)
  Circle(s(l)\x,s(l)\y,demiLargeurRoute-4,RGB(128+r,128+r,255))
Next l   

;ligne d'arrivée
Box(s(0)\x,s(0)\y-demiLargeurRoute,16,118,(RGB(0,0,1)))
For i=0 To 1
  For j=0 To 14
    If (i+j)%2 =0
      Box(s(0)\x+i*8,s(0)\y+j*8-demiLargeurRoute,8,8,RGB(255,255,255))
    EndIf ;i+j%2
  Next j
Next i

StopDrawing()

;SaveSprite(#SPR_CIRCUIT,"circuit.bmp")
;-jeu
jeu:
;-sprites voitures


creerVoiture(#SPR_VOIT_C,$FF5320)
creerVoiture(#SPR_VOIT_JAVA,$FFFFDB)
creerVoiture(#SPR_VOIT_PB,$1011ED)
creerVoiture(#SPR_VOIT_PY,$109606)

;-cam1
CreateSprite(#SPR_CAMERA1,11,11)
StartDrawing(SpriteOutput(#SPR_CAMERA1)) 
Circle(5,5,5,(RGB(128,64,0)))
StopDrawing()

;-écran
CreateSprite(#SPR_ECRAN,800,600)
StartDrawing(SpriteOutput(#SPR_ECRAN)) 
Box(0,0,800,600,RGB(0, 0, 1))
Circle(283,283+17,282,(RGB(0,0,0)));566/2=283=rayon ; 

BackColor(RGB(0,0,1))
DrawText(566+17,200,"COMPILATION SPEED")
DrawText(566+17,266,"BUG LEVEL")
DrawText(566+17,322,"BATTERY")

DrawText (566+17+64,400,"C++")
DrawText (566+17+64,450,"JAVA")
DrawText (566+17+64,500,"PureBasic")
DrawText (566+17+64,550,"Python")

;mini circuit
DrawingFont(FontID(#FONT_IMPACT_30))
DrawText(612,38,"15 ans")
For i=0 To nPtCtrl-1
  LineXY(P(i)\x/15+566,P(i)\y/15,P(i+1)\x/15+566,P(i+1)\y/15,RGB(255,255,255));
Next i
LineXY(P(nPtCtrl)\x/15+566,P(nPtCtrl)\y/15,P(0)\x/15+566,P(0)\y/15,RGB(255,0,0));bouclage circuit

StopDrawing()

;-level
CreateSprite(#SPR_LEVEL,192,8)
StartDrawing(SpriteOutput(#SPR_LEVEL)) 
Box(0,0,192,8,RGB(0,255,0))
For i=1 To 47 
  Line(i*4,0,1,8,RGB(255,255,0))
Next i
StopDrawing()

;lap
CreateSprite(#SPR_LAP,512,32)
StartDrawing(SpriteOutput(#SPR_LAP))
DrawingFont(FontID(#FONT_IMPACT_20))
For i=0 To 15
  DrawText(i*32,0,Hex(i),RGB(255,255,255),RGB(0, 0, 1))
Next i
StopDrawing()


;-FIN SPRITES

;-Initialisation
;PlaySound(0,1);#PB_Sound_Loop=1
xVoiture.f = s(0)\x
yVoiture.f = s(0)\y
angleVoiture.f =s(0)\angleEnRadian
nControle=1; test de la position entre les points de contrôle P0 et P1
           ;démarrages décalés dans l'espace des voitures
lC=180
lJava=100
lPy=40

;caméra associée à la voiture PureBasic
lCam=0

lBonus=200
battery=192
bugLevel=0
compilationSpeed=0

dr=0
drdt=0

collision=0
sprBonus =#SPR_SOIN

compteurTourC=0
compteurTour=0 

;-sprite écuries avec GrabSprite()
ClearScreen(RGB(0, 0, 1))
DisplaySprite(#SPR_VOIT_C,0,0)
DisplaySprite(#SPR_VOIT_JAVA,0,50)
DisplaySprite(#SPR_VOIT_PB,0,100)
DisplaySprite(#SPR_VOIT_PY,0,150)
;-grab écuries
GrabSprite(#SPR_ECURIES,0,0,48,150+48)

;-BOUCLE PRINCIPALE
Repeat
  ;-collision Pb-autres
  collision(#SPR_VOIT_C,xC,yC,xEcranC,yEcranC,lC)  
  collision(#SPR_VOIT_JAVA,xJava,yJava,xEcranJava,yEcranJava,lJava)  
  collision(#SPR_VOIT_PY,xPy,yPy,xEcranPy,yEcranPy,lPy)  
  ;-collision pb-bonus
  If SpriteCollision(#SPR_VOIT_PB,xVoiture,yVoiture,sprBonus,xBonus,yBonus)
    If sprBonus = #SPR_SOIN 
      bugLevel = bugLevel -24
      If bugLevel<0
        bugLevel=0
      EndIf;bugLevel<0
    EndIf  ;sprBonus = #SPR_SOIN 
    If sprBonus = #SPR_JERRICAN
      battery = battery +48
      If battery>192
        battery=192
      EndIf;battery>192
    EndIf  ;sprBonus = #SPR_JERRICAN
    
    lBonus=lBonus+longueurCourbe*0.4
    sprBonus=sprBonus+1
    If sprBonus>#SPR_JERRICAN
      sprBonus=#SPR_SOIN
    EndIf
  EndIf ;SpriteCollision
  
  ExamineKeyboard()
  
  If KeyboardPushed(#PB_Key_Up) 
    If dr<6.6
      drdt=0.08
    EndIf     
    
  ElseIf KeyboardPushed(#PB_Key_Down)
    If dr>0
      drdt=-0.1
    EndIf
    
  Else
    If dr>0
      drdt=-0.01
    EndIf
    
  EndIf; accélération freinage
  
  ;-limiter les virages à gauche
  If KeyboardPushed(#PB_Key_Left) 
    
    If  nControle<>0
      ecartAngle =(angleVoiture - P(nControle-1)\angleEnRadian)
    Else
      ecartAngle =(angleVoiture - P(nPtCtrl)\angleEnRadian)
    EndIf
    
    If ecartAngle>#PI        
      ecartAngle=ecartAngle-2*#PI
    EndIf
    If ecartAngle<-#PI        
      ecartAngle=ecartAngle+2*#PI
    EndIf  
    
    If ecartAngle>-#PI/4
      angleVoiture=angleVoiture - #PI/60
    EndIf
    If angleVoiture>#PI        
      angleVoiture=angleVoiture-2*#PI
    EndIf
    If angleVoiture<-#PI        
      angleVoiture=angleVoiture+2*#PI
    EndIf  
  EndIf
  
  If KeyboardPushed( #PB_Key_Right)
    
    ;-limiter les virages à droite
    If  nControle<>0
      ecartAngle =(angleVoiture - P(nControle-1)\angleEnRadian)
    Else
      ecartAngle =(angleVoiture - P(nPtCtrl)\angleEnRadian)
    EndIf
    
    If ecartAngle>#PI        
      ecartAngle=ecartAngle-2*#PI
    EndIf
    If ecartAngle<-#PI        
      ecartAngle=ecartAngle+2*#PI
    EndIf  
    
    If ecartAngle<#PI/4
      angleVoiture=angleVoiture + #PI/60
    EndIf
    If angleVoiture>#PI        
      angleVoiture=angleVoiture-2*#PI
    EndIf
    If angleVoiture<-#PI        
      angleVoiture=angleVoiture+2*#PI
    EndIf  
    
  EndIf;fin keyboard
  
  
  ;-distance voiture-milieu de la route P(nControle-1)P(nControle)
  
  If nControle<>0 ;prise en compte du bouclage du circuit
    If P(nControle-1)\vertical <>1
      dRoute=(Abs(P(nControle-1)\aEcran*xVoiture - yVoiture+P(nControle-1)\b) / P(nControle-1)\hypo)
    Else
      dRoute=(Abs(P(nControle-1)\x - xVoiture))
    EndIf ;P(nControle-1)\vertical <>1
  Else
    If P(nPtCtrl)\vertical <>1
      dRoute=(Abs(P(nPtCtrl)\aEcran*xVoiture - yVoiture+P(nPtCtrl)\b) / P(nPtCtrl)\hypo)
    Else
      dRoute=(Abs(P(nPtCtrl)\x - xVoiture))
    EndIf ;P(nPtCtrl)\vertical <>1
    
  EndIf ;nControle<>0
  
  ;-ralentissement si léger hors-piste
  If dRoute>demiLargeurRoute+6 ;ralentissement
    If dr>1
      drdt=-1
    EndIf
    bugLevel=bugLevel+0.1
    poussiere=1
  Else
    poussiere=0
  EndIf ;ralentissement
  
  ;-fin du jeu si hors-piste
  If dRoute>demiLargeurRoute+24 
    score()
  EndIf
  
  dr=dr+drdt
  If dr>6.5
    dr=6.5
  EndIf
  If dr<0
    dr=0
  EndIf
  compilationSpeed=dr*192/6.5;pour le clipSprite(#SPR_LEVEL)
  dx = dr*Cos(angleVoiture)
  dy =dr*Sin(angleVoiture)
  
  ;-localisation par rapport aux points de contrôle
  ;éloignement P(nControle)
  ;on garde le même point de contrôle de référence P(nControle) tant qu'on est dans une phase d'approche
  eloignement(xVoiture,yVoiture,P(nControle)\x,P(nControle)\y,dx,dy)
  If dEloignement > 0
    nControle =nControle +1
    If nControle > nPtCtrl
      nControle =0
      lCam=0
      compteurTour =compteurTour+1
      
      If compteurTour>compteurTourC And lC<longueurCourbe-30 ; 30 pour gérer décalage lC et lCam
        battery=192                                          ;on gagne un plein si on passe la ligne en premier
      EndIf                                                  ;compteurTour>compteurTourC
      
    EndIf;nControle = nPtCtrl
  EndIf  ;dEloignement > 0
  
  ;-fin du jeu si la voiture C++ a effectué ses 15 tours
  If compteurTour=15 And lCam>20
    MessageRequester ("CONGRATULATIONS !","SCORE :"+Str(compteurTour*longueurCourbe+lCam))
    Goto jeu
  EndIf;compteurTour=15 
  
  
  ;-Timing
  If ElapsedMilliseconds() - chrono > 2
    chrono = ElapsedMilliseconds() 
    lC=lC+5
    lJava=lJava+3
    lPy=lPy+2
    lBonus = lBonus+1
    
    ;-gestion des dépassements  de  longueurCourbe par les l
    If lC>=longueurCourbe
      compteurTourC=compteurTourC+1   
      If compteurTourC=15
        score()
      EndIf 
      lC=0
      
    EndIf; lC>longueurCourbe
    
    If lJava>=longueurCourbe
      lJava=0
      
    EndIf; lJava>longueurCourbe
    
    If lPy>=longueurCourbe
      lPy=0
      
    EndIf; lPy>longueurCourbe
    
    If lBonus>=longueurCourbe
      lBonus=0
      
    EndIf; lBonus>=longueurCourbe
    
    ;batterie consommée en cas de déplacement
    If dr<>0 
      battery=battery - 0.1
    EndIf
    
    ;-position de la voiture sur le sprite circuit
    xVoiture = xVoiture + dx
    yVoiture = yVoiture + dy
    
  EndIf ;ElapsedMilliseconds() - chrono > 2
  
  
  angleEnnemiC=  lC*2*#PI/longueurCourbe
  angleEnnemiJava=  lJava*2*#PI/longueurCourbe
  angleEnnemiPy=  lPy*2*#PI/longueurCourbe
  angleBonus=  lBonus*2*#PI/longueurCourbe
  
  
  If battery<0
    ;-fin batterie
    score()
  EndIf;battery<0
  
  ;-positions des voitures sur le sprite circuit
  xC= s(lC)\x +35*Cos(4*angleEnnemiC)
  yC= s(lC)\y+35*Sin(4*angleEnnemiC)
  
  xJava= s(lJava)\x +35*Cos(8*angleEnnemiJava+#PI/4)
  yJava= s(lJava)\y+35*Sin(8*angleEnnemiJava+#PI/4)
  
  xPy= s(lPy)\x +35*Cos(4*angleEnnemiPy+#PI/2)
  yPy= s(lPy)\y+35*Sin(4*angleEnnemiPy+#PI/2)
  
  xBonus= s(lBonus)\x+50*Cos(16*angleBonus)
  yBonus= s(lBonus)\y+50*Sin(16*angleBonus)
  
  ;-gestion lCam
  lCam=lCam+dr
  If lCam>longueurCourbe
    lCam=0
  EndIf
  ;correction, si au point de contrôle, l'écart est trop grand entre lCam et l(PointDeControle)
  If s(lCam)\Ptctrl>nControle And lCam<>0 
    lCam=lCam-2
  ElseIf s(lCam)\Ptctrl<nControle 
    lCam=lCam+1   
  EndIf 
  
  
  ClipSprite(#SPR_CIRCUIT, xVoiture - tailleClip*0.5,yVoiture - tailleClip*0.5,tailleClip,tailleClip)
  
  angleCam=-90-s(lCam)\angleEnDegre
  RotateSprite(#SPR_CIRCUIT,angleCam,0);#PB_Absolute=0
  DisplaySprite(#SPR_CIRCUIT,0,17)     ;17 dû au centrage 
  
  ;affichage de la voiture Pb
  RotateSprite(#SPR_VOIT_PB,angleVoiture*180/#PI+angleCam,0)
  xEcranVoiture=(tailleClip*0.5-24)
  yEcranVoiture=(tailleClip*0.5-15)+17
  DisplayTransparentSprite(#SPR_VOIT_PB,xEcranVoiture,yEcranVoiture)
  
  afficherConcurrent(#SPR_VOIT_C,lC,xC,yC,xRotC,yRotC,xEcranC,yEcranC)
  afficherConcurrent(#SPR_VOIT_JAVA,lJava,xJava,yJava,xRotJava,yRotJava,xEcranJava,yEcranJava)
  afficherConcurrent(#SPR_VOIT_PY,lPy,xPy,yPy,xRotPy,yRotPy,xEcranPy,yEcranPy)
  
  ;-décommenter pour voir le déplacement de la caméra
  ;   xRotCam =(s(lCam)\x-xVoiture)*Cos(angleCam*#PI/180) - (s(lCam)\y-yVoiture)*Sin(angleCam*#PI/180)+xVoiture
  ;   yRotCam=(s(lCam)\x-xVoiture)*Sin(angleCam*#PI/180) + (s(lCam)\y-yVoiture)*Cos(angleCam*#PI/180)+yVoiture
  ;   
  ;   DisplayTransparentSprite(#SPR_CAMERA1,(xRotCam-xVoiture)+tailleClip*0.5-5,(yRotCam-yVoiture)+tailleClip*0.5-5+17)
  
  ;affichage du bonus
  xRotBonus =(xBonus-xVoiture)*Cos(angleCam*#PI/180) - (yBonus-yVoiture)*Sin(angleCam*#PI/180)+xVoiture
  yRotBonus=(xBonus-xVoiture)*Sin(angleCam*#PI/180) + (yBonus-yVoiture)*Cos(angleCam*#PI/180)+yVoiture
  
  xEcranBonus=(xRotBonus-xVoiture)+tailleClip*0.5-5
  yEcranBonus=(yRotBonus-yVoiture)+tailleClip*0.5-5+17
  
  If (xRotBonus<tailleClip*0.5+xVoiture) And (yRotBonus<tailleClip*0.5+yVoiture); non affichage en dehors de l'écran
    DisplayTransparentSprite(sprBonus,xEcranBonus,yEcranBonus) 
  EndIf
  
  DisplayTransparentSprite(#SPR_ECRAN,0,0); cache noir avec les informations (minicircuit, levels, tours)
                                          ;posé sur l'ensemble transparent uniquement
                                          ;au niveau du circuit (grand disque noir)
  
  ;-mini circuit
  DisplayTransparentSprite(#SPR_CAMERA1,xVoiture/15+tailleClip-5,yVoiture/15-5,255,RGB(255,0,0))
  DisplayTransparentSprite(#SPR_CAMERA1,xC/15+tailleClip-5,yC/15-5)
  DisplayTransparentSprite(#SPR_CAMERA1,xJava/15+tailleClip-5,yJava/15-5)
  DisplayTransparentSprite(#SPR_CAMERA1,xPy/15+tailleClip-5,yPy/15-5)
  
  ;-levels
  ClipSprite(#SPR_LEVEL,0,0,compilationSpeed,8)
  DisplaySprite(#SPR_LEVEL,tailleClip+17,200+33-8)
  ClipSprite(#SPR_LEVEL,0,0,bugLevel,8)
  DisplayTransparentSprite(#SPR_LEVEL,tailleClip+17,266+33-8,255,RGB(255,0,0))
  ClipSprite(#SPR_LEVEL,0,0,battery,8)
  DisplaySprite(#SPR_LEVEL,tailleClip+17,322+33-8)
  
  ;-écuries  
  DisplaySprite(#SPR_ECURIES,tailleClip+17,400-16)
  
  ;-nombre de tours
  ClipSprite(#SPR_LAP,compteurTour*32,0,32,32)
  DisplaySprite(#SPR_LAP,800-32,150-32)
  
  ;-poussière
  If poussiere=1
    DisplayTransparentSprite(#SPR_DUST,xEcranVoiture+Random(2,0),yEcranVoiture+Random(2,0),128)
  EndIf ;poussiere
  
  FlipBuffers()
Until WindowEvent() = #PB_Event_CloseWindow

DataSection
  circuit:
  Data.l 443,61,861,61,1083,145,1661,141,1985,121
  Data.l 1953,423,1943,679,1499,711,1053,681,689,659
  Data.l 65,695,145,333,99,145,253,115
  Data.l 803,135,1225,135,1531,391,1475,707,1041,759
  
EndDataSection



Hasta la vista !
Dernière modification par Huitbit le jeu. 26/nov./2015 1:17, modifié 1 fois.
Elevé au MSX !
Avatar de l’utilisateur
case
Messages : 1528
Inscription : lun. 10/sept./2007 11:13

Re: Punch "Le survivant", les secrets du tournage !

Message par case »

merci pour le partage :)
ImageImage
Avatar de l’utilisateur
Huitbit
Messages : 939
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Re: Punch "Le survivant", les secrets du tournage !

Message par Huitbit »

You're welcome :P !

Sans Punch, je n'aurais pas eu la motivation de finir ce code !

Il y a des trucs à améliorer.
Le CreateSprite() avec un sprite "circuit" aussi grand pose problème avec les PC qui marchent avec XP.
Il faudrait faire avec des tiles, l'avantage, ce serait la possibilité de faire un circuit gigantesque avec des décors sympas.

La détection des bordures avec des pixels permettrait plus de possibilités pour le jeu.
Je n'ai pas tenté car je ne sentais pas l'utilisation d'un Point() (avec l'obligation d'un StartDrawing() et d'autres fonctions), j'avais peur que ça rame trop !

:idea: On peut créer le sprite circuit, charger (hors boucle principale) tous les pixels dans un tableau (ou des groupes de pixels 2*2, 4*4, ...) et après comparer des points particuliers(les quatre coins par exemple) du véhicule avec les cases survolées.
Je ne sais pas si je suis bien clair ! :lol:

Hasta la vista !
Elevé au MSX !
Micheao
Messages : 533
Inscription : dim. 07/déc./2014 10:12
Localisation : Sud-Est

Re: Punch "Le survivant", les secrets du tournage !

Message par Micheao »

Un grand merci pour ce partage
Avatar de l’utilisateur
Kwai chang caine
Messages : 6962
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Punch "Le survivant", les secrets du tournage !

Message par Kwai chang caine »

Pffffff !!! texte long, texte long....T'es p'tit joueur :mrgreen:
Parce que pour kcc c'est une intro, que dis je une intro...un préambule, une preface....et encore t'explique plein de trucs... 8O
Alors que le maitre il peut tartiner le double sans avoir rien à dire :D

En tout cas merci, pour ce travail, ce partage et d'avoir levé les jupes du tournage. ..à mon age c'est toujours intéressant de voir des dessous. ...quels qu'ils soient 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Torp
Messages : 360
Inscription : lun. 22/nov./2004 13:05

Re: Punch "Le survivant", les secrets du tournage !

Message par Torp »

Merci pour le partage !
Avatar de l’utilisateur
Cool Dji
Messages : 1126
Inscription : ven. 05/sept./2008 11:42
Localisation : Besançon
Contact :

Re: Punch "Le survivant", les secrets du tournage !

Message par Cool Dji »

Bravo, joli projet qui vient de loin !
Only PureBasic makes it possible
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Punch "Le survivant", les secrets du tournage !

Message par djes »

C'est du grand art, surtout en matière de mise au point. Je me suis demandé comment tu avais fait :) Merci pour le partage !
Avatar de l’utilisateur
Huitbit
Messages : 939
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Re: Punch "Le survivant", les secrets du tournage !

Message par Huitbit »

Merci à tous !
djes a écrit : Je me suis demandé comment tu avais fait !
8O
C'est toi qui avais parlé de points de contrôle lors d'une discussion !

Tu as oublié, tant mieux, je n'aurai pas de droits d'auteur à payer :lol: :lol: :lol:


Hasta la vista !
Elevé au MSX !
Avatar de l’utilisateur
djes
Messages : 4252
Inscription : ven. 11/févr./2005 17:34
Localisation : Arras, France

Re: Punch "Le survivant", les secrets du tournage !

Message par djes »

Huitbit a écrit :Merci à tous !
djes a écrit : Je me suis demandé comment tu avais fait !
8O
C'est toi qui avais parlé de points de contrôle lors d'une discussion !

Tu as oublié, tant mieux, je n'aurai pas de droits d'auteur à payer :lol: :lol: :lol:


Hasta la vista !
Oh, tu sais, j'ai dormi depuis...
Répondre