Bonsoir à tous,
Je réalise un jeu ressemblant à "angry birds" sur Lazarus. J'ai actuellement réalisé tout le code permettant le mouvement du projectile et je m'attaque maintenant au code permettant la collisions des blocs cibles (avec le projectile et entre eux).
J'ai pour l'instant réalisé un ensemble de fonctions et procédures permettant la détection de la collision. Cela compile mais Lazarus me dit que j'ai une exception de classe...
J'ai une classe mère abstraite définie comme suit :
Une classe Cvector :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 CMObject = class // The position of the moving object fposition:Cvector; fspeedy, fspeedx:real; // The size of the window in which it moves fwinw,fwinh:real; // angle fangle:real; procedure drawYourself(canv:TCanvas); virtual; abstract; function absolutetolocal(V:Cvector):Cvector; function localtoabsolute(V:Cvector):Cvector; procedure collision(mobjects:tstringlist); function collidewithblock(other:Cmobject):Cvector;virtual;abstract; function collisionprecheck(other:Cmobject):Cvector;virtual;abstract; procedure move(); virtual; abstract; procedure drawDebug(canv:TCanvas); virtual; abstract; end;
Et une classe Cblock (définissant les blocs cibles) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 Cvector= class fx:real; fy:real; constructor create (ax,ay:real); end;
Voilà le constructeur de la classe Cblock :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 Cblock = Class (CMobject) fL:real; fimage : TBitmap; fshape:array [1..4] of Cvector; constructor create (aao : TstringList; awinw,awinh,aangle, ax,ay, aL, aspeedx,aspeedy:real; aimgfname:string); procedure drawyourself(canv:Tcanvas); override ; procedure move(); override; function collidewithblock(other:Cmobject):Cvector;override; function collisionprecheck(other:Cmobject):Cvector;override; function getside(V:Cvector):integer; //return the side of the block where the collision occurs //procedure setspeed(vx,vy); //function getrelativespeed //procedure collisionspeedxy();//modifies linear speed of incoming block in the absolute frame //procedure collisionspeedtheta();//modifies rotation speed of the current block in the absolute frame end;
J'ai deux fonctions permettant de passer du repère local du bloc au repère absolu et inversement :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 constructor Cblock.create(aao:TStringList; awinw,awinh, aangle,ax,ay,aL,aspeedx,aspeedy:real; aimgfname:string); Var V1,V2,V3,V4:Cvector; begin // The window width and height fwinw := awinw; fwinh := awinh; // Position of the blocks fposition:=Cvector.create(ax,ay); fangle:=aangle; //size of the block fL:= aL; // initial speed fspeedx:=aspeedx; fspeedy:=aspeedy; //image fimage:=Tbitmap.create; fimage.LoadFromFile(aimgfname); V1:=Cvector.create(-aL/2,-aL/2); V2:=Cvector.create(aL/2,-aL/2); V3:=Cvector.create(aL/2,aL/2); V4:=Cvector.create(-aL/2,aL/2); fshape[1]:=localtoabsolute(V1); fshape[2]:=localtoabsolute(V2); fshape[3]:=localtoabsolute(V3); fshape[4]:=localtoabsolute(V4); end;
Voilà les fonctions de collision :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 function Cmobject.absolutetolocal(V:Cvector):Cvector; var ax,ay:real; begin ax:=(V.fx-fposition.fx)*cos(fangle)-(V.fy-fposition.fy)*sin(fangle); ay:=(V.fx-fposition.fx)*sin(fangle)+(V.fy-fposition.fy)*cos(fangle); absolutetolocal:=Cvector.create(ax,ay); end; function Cmobject.localtoabsolute(V:Cvector):Cvector; var ax,ay:real; begin ax:=V.fx*cos(fangle)+V.fy*sin(fangle)+fposition.fx; ay:=V.fy*cos(fangle)-V.fx*sin(fangle)+fposition.fy; localtoabsolute:=Cvector.create(ax,ay); end;
J'ai aussi des fonctions de collision entre le projectile et les blocs (Cprojectile étant la classe du projectile qui ressemble grandement à la classe Cblock) :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 function Cblock.getside(V:Cvector):integer; var x,y,x1,x2,x3,x4,y1,y2,y3,y4:real; side:integer; begin x:=absolutetolocal(V).fx; //coordinates of v in the absolute frame y:=absolutetolocal(V).fy; x1:=absolutetolocal(fshape[1]).fx; y1:=absolutetolocal(fshape[1]).fy; x2:=absolutetolocal(fshape[2]).fx; y2:=absolutetolocal(fshape[2]).fy; x3:=absolutetolocal(fshape[3]).fx; y3:=absolutetolocal(fshape[3]).fy; x4:=absolutetolocal(fshape[4]).fx; y4:=absolutetolocal(fshape[4]).fy; if y>=0 //cadran x, y positifs then if x>=0 then if abs(x3-x)<=abs(y3-y) then side:=3 else side:=4 else //cadran x negatif, y positif if abs(x4-x)<=abs(y4-y) then side:=1 else side:=4 else //y<0 if x>=0 // cadran x positif, y negatif then if abs(x2-x)<=abs(y2-y) then side:=3 else side:=2 else // cadran x, y negatifs if abs((x1-x))<=abs(y1-y) then side:=1 else side:=2 ; getside:=side; end; function Cblock.collisionprecheck(other:Cmobject):Cvector; begin other.collidewithblock(self); end; function Cblock.collidewithblock(other:Cmobject ):Cvector;//attention repère locaux!! //rectifier avec un centrage sur le point d'inertie ! var i:integer; begin for i:=1 to 4 do if (self.absolutetolocal((other as Cblock).fshape[i]).fy>=-(self.fL)/2) and ( self.absolutetolocal((other as Cblock).fshape[i]).fx>=-(self.fl)/2) and (self.absolutetolocal((other as Cblock).fshape[i]).fy<=self.fL/2) and (self.absolutetolocal((other as Cblock).fshape[i]).fx<=self.fL/2) then collidewithblock:=(other as Cblock).fshape[i] else collidewithblock:=nil; end;
Enfin j'ai la procédure suivante :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 function Cprojectile.collidewithblock(other:Cmobject):Cvector; //attention repères locaux!! begin if (other.absolutetolocal(self.fposition).fx)>=-(((other as Cblock).fL)/2) then if(other.absolutetolocal(self.fposition).fy)>=-(((other as Cblock).fL)/2) then if (other.absolutetolocal(self.fposition).fx)<=(((other as Cblock).fL)/2) then if(other.absolutetolocal(self.fposition).fy)<=(((other as Cblock).fL)/2) then collidewithblock:=self.fposition else collidewithblock:=nil else collidewithblock:=nil else collidewithblock:=nil else collidewithblock:=nil end; function Cprojectile.collisionprecheck(other:Cmobject):Cvector; begin self.collidewithblock(other); end;
Pour finir j'ai cette ligne dans l'unité principale :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 procedure Cmobject.collision(mobjects:tstringlist); var i,j:integer; begin for j:=0 to mobjects.count do if self <> mobjects.objects[j] then begin if (self.collisionprecheck(mobjects.objects[j] as Cmobject)<>nil ) then self.fspeedx:=0; self.fspeedy:=0; end; end;
Je sais que c'est assez moche mais si vous pouviez m'aider, je vous en serais très reconnaissant. Je suis vraiment bloqué...
Code : Sélectionner tout - Visualiser dans une fenêtre à part (mobjects.objects[i] as CMObject).collision(mobjects);
Dernière chose. Ne serait-il pas plus facile pour moi de réaliser les blocs avec 4 lignes plutôt qu'avec des images? Je souhaite effectivement faire tourner les blocs sur eux-même après la collision pour plus de réalité...
Bonne soirée
Merci d'avance
Partager