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 !)
Le fonctionnement du moteur, vient de remarques de djes, il y a fort longtemps .
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 ) 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