Jugando con Elipses en Delphi
Hoy os traigo una pequeña aplicación didáctica en delphi que dibuja elipses (mejor dicho círculos, pero utilizo el metodo elipse del TCanvas para dibujarlo) y detecta las colisiones entre estas arrastrando el mouse por encima. Observareis que es muy simple pero sirve para jugar un poco con el canvas y el ratón y ver que tipo de aplicaciones visuales podemos llegar a hacer con delphi. Al pasar el mouse por encima del objeto detecta su paso y muestra un color de colisión. Además al mover una de las elipses hacia otro objeto, se detecta la colisión entre estos y se frena el movimiento si dejarte mover el objeto. La detección es muy sencilla, mediante la posición del mouse se comprueba que la distancia de éste con el centro de cualquiera de las otras elipses sea mayor que la distancia del objeto a arrastrar y las otras elipses, un principio muy simple pero que funciona muy bien y sin tener que hacer cálculos desorbitados. Aquí os dejo la aplicación Thundax Draw Ellipses, y parte del código fuente y un pantallazo de la aplicación:
La clase TEllipse:
El cálculo de las colisiones:
La clase TEllipse:
unit ThundaxEllipse; interface uses types, Graphics, Classes, Controls; type TEllipse = class(TObject) private FborderColor: TColor; Flength: integer; FlineWidth: integer; FCollisionColor: TColor; FColor: TColor; Fposition: TPoint; FCanvas: TCanvas; FDrag: boolean; Fid: string; Fradium: integer; FCenter: TPoint; procedure SetborderColor(const Value: TColor); procedure SetCollisionColor(const Value: TColor); procedure SetColor(const Value: TColor); procedure Setlength(const Value: integer); procedure SetlineWidth(const Value: integer); procedure Setposition(const Value: TPoint); procedure SetDrag(const Value: boolean); procedure SetCenter(const Value: TPoint); procedure Setid(const Value: string); procedure Setradium(const Value: integer); public property position: TPoint read Fposition write Setposition; property id: string read Fid write Setid; property Drag: boolean read FDrag write SetDrag; property length: integer read Flength write Setlength; property Color: TColor read FColor write SetColor; property borderColor: TColor read FborderColor write SetborderColor; property lineWidth: integer read FlineWidth write SetlineWidth; property CollisionColor: TColor read FCollisionColor write SetCollisionColor; constructor Create(Canvas: TCanvas; center: TPoint; length: integer); function PointInside(x, y: integer): boolean; procedure SetMousePosition(x, y: integer); procedure Draw(x, y: integer); procedure EnableDrag(x, y: integer); property Center: TPoint read FCenter write SetCenter; property radium: integer read Fradium write Setradium; end; implementation { TEllipse } constructor TEllipse.Create(Canvas: TCanvas; center: TPoint; length: integer); begin FCanvas := Canvas; Fposition := center; FLength := length; FDrag := false; FCenter := point(Fposition.x + (Flength div 2), Fposition.y + (Flength div 2)); FRadium := FLength div 2; end; procedure TEllipse.Draw(x, y: integer); begin if FDrag then SetMousePosition(x, y); if PointInside(x, y) then FCanvas.Brush.Color := FCollisionColor else FCanvas.Brush.Color := FColor; FCanvas.Pen.Color := FborderColor; FCanvas.Pen.Width := 1; FCanvas.Ellipse(Fposition.x, Fposition.y, Fposition.x + FLength, Fposition.y + FLength); FCanvas.Font.Color := clWhite; FCanvas.TextOut(Fposition.x + (Flength div 2) - 5, Fposition.y + (Flength div 2) - 7, FId); end; procedure TEllipse.EnableDrag(x, y: integer); begin if PointInside(x, y) then Fdrag := true; end; function TEllipse.PointInside(x, y: integer): boolean; var x0, y0, a, b: integer; point2: TPoint; begin point2 := Point(Fposition.x + Flength, FPosition.y + Flength); x0 := (Fposition.x + point2.x) div 2; y0 := (Fposition.y + point2.y) div 2; a := (point2.x - Fposition.x) div 2; b := (point2.y - Fposition.y) div 2; result := (Sqr((x - x0) / a) + Sqr((y - y0) / b) <= 1); end; procedure TEllipse.SetborderColor(const Value: TColor); begin FborderColor := Value; end; procedure TEllipse.SetCenter(const Value: TPoint); begin FCenter := Value; end; procedure TEllipse.SetCollisionColor(const Value: TColor); begin FCollisionColor := Value; end; procedure TEllipse.SetColor(const Value: TColor); begin FColor := Value; end; procedure TEllipse.SetDrag(const Value: boolean); begin FDrag := Value; end; procedure TEllipse.Setid(const Value: string); begin Fid := Value; end; procedure TEllipse.Setlength(const Value: integer); begin Flength := Value; end; procedure TEllipse.SetlineWidth(const Value: integer); begin FlineWidth := Value; end; procedure TEllipse.SetMousePosition(x, y: integer); begin FPosition := point(x - (Flength div 2), y - (Flength div 2)); FCenter := point(Fposition.x + (Flength div 2), Fposition.y + (Flength div 2)); end; procedure TEllipse.Setposition(const Value: TPoint); begin Fposition := Value; end; procedure TEllipse.Setradium(const Value: integer); begin Fradium := Value; end; end.
El cálculo de las colisiones:
procedure TForm3.Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var i, j: integer; Collide: boolean; textCollision: string; Collisions: array[1..20] of integer; begin DrawRectangle(clWhite, clWhite); Memo1.lines.Clear; textCollision := ''; Collide := false; for i := 1 to 20 do Collisions[i] := -1; for i := 1 to number do begin for j := 1 to number do if Ellipses[i].drag and distanciaMouse(Point(x, y), Ellipses[i].center, Ellipses[j].center) and Collision(ellipses[i], ellipses[j]) then begin Memo1.lines.add('Collide True ->' + inttostr(i) + ' ' + inttostr(j)); Collide := true; Collisions[i] := i; end; end; for i := 1 to number do begin if Collisions[i] = -1 then ellipses[i].Draw(x, y) else ellipses[i].draw(ellipses[i].center.x, ellipses[i].center.y); Memo1.lines.add('Collision ' + inttostr(Collisions[i])); end; if collide then textCollision := 'Collision!'; StatusBar1.Panels[0].Text := 'x : ' + inttostr(x) + ' y : ' + inttostr(y) + ' ' + textCollision; end; function TForm3.DistanciaMouse(p1, p2, p3: TPoint): boolean; begin result := false; if (p2.x <> p3.x) and (p2.y <> p3.y) then result := (distancia(p1, p3) < distancia(p2, p3)) end; function TForm3.Collision(p1, p2: TEllipse): boolean; begin result := false; if p1 <> p2 then result := distancia(p1.center, p2.center) < (2 * (p1.radium)); end; function TForm3.distancia(p1, p2: TPoint): double; begin result := sqrt(sqr(p1.x - p2.x) + sqr(p1.y - p2.y)); end;
Comments
Post a Comment