Collision d'objets dans un jeu
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:
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:
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:
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:
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:
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:
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:
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:
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:
(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