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 :
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;
Une classe Cvector :
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;
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
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;
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
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;
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
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;
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
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;
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
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;
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
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;
Pour finir j'ai cette ligne dans l'unité principale :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
(mobjects.objects[i] as CMObject).collision(mobjects);
Je sais que c'est assez moche mais si vous pouviez m'aider, je vous en serais très reconnaissant. Je suis vraiment bloqué...

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