All pastes #15638 Raw Edit

Marble physics engin

public text v1 · immutable
#15638 ·published 2005-06-23 13:25 UTC
rendered paste body
unit Physics;

interface

uses
  Math,
  Math3D;

const
  MAX_PLAYERS = 4;  
  AIR_R: single = 0.01;
  GND_R: single = 0.1;
  GRAV: single = 0.007;
  MOVE_STR: single = 0.1;
  JUMP_STR: single = 1.4;

type
  // type action, pr interfacer les inputs
  TAction = (LEFT, RIGHT, UP, DOWN, JUMP);
  // objet marble
  TMarble = class (TObject)
    r,m: single;
    P,V,Force: TCoord;
    Collision: boolean;
    // trucs pasbô :( gestion de la cam?
    Anglex,Angley: extended;
    A,Cam: TCoord;
    // *shrugs*
    constructor Create(x,y,z,radius,mass: single);
    procedure Effect(Action: TAction); //; Angle: single);
    procedure DoCollision(Marble2: TMarble; Dispatch: boolean);
    procedure Update(Time: single);
  end;            
  // file de traitement des collisions, hyper important ca ! lol
  PCollisionQueue = ^TCollisionQueue;
  TCollisionQueue = class (TObject)
    i,j: integer;
    next,prec: PCollisionQueue;
    //constructor Create;
    function Add(i,j: integer): PCollisionQueue;
    procedure MixUp(n: integer);
  end;
  // tableau de billes, caicool
  TMarbles = class (TObject)
    Items: array[1..MAX_PLAYERS] of TMarble;
    Count: integer;
    CollisionQueue: PCollisionQueue;
    constructor Create(n: integer);
    procedure Update(Time: single);
    procedure RunCollisions;
  end;

function Distance(A,B: TMarble): single;
function IsCollision(A,B: TMarble): boolean;

implementation

constructor TMarble.Create(x,y,z,radius,mass: single);
begin
  with Self do begin
    r := radius;
    m := mass;
    P.x := x;
    P.y := y;
    P.z := z;
    Collision := false;
    // bah! lol
    Anglex := 0;
    Angley := 5.999;
  end;
end;

procedure TMarble.Effect(Action: TAction); //; Angle: single);
var
  F: TCoord;
  Angle: single; // pasbô :(
begin
  Angle := 100*Self.Anglex*180/PI; // lol
  with Self do
  begin
    if P.z=0 then
    begin
      case Action of
        RIGHT:
          SetCoord(F,Sin(Angle)*MOVE_STR,-Cos(Angle)*MOVE_STR,0);
        LEFT:
          SetCoord(F,-Sin(Angle)*MOVE_STR,Cos(Angle)*MOVE_STR,0);
        DOWN:
          SetCoord(F,Cos(Angle)*MOVE_STR,Sin(Angle)*MOVE_STR,0);
        UP:
          SetCoord(F,-Cos(Angle)*MOVE_STR,-Sin(Angle)*MOVE_STR,0);
        JUMP:
        begin
          SetCoord(F,0,0,JUMP_STR);
          //PlaySample(sonjump);
        end;
      end;
      Force := AddCoord(Force,F);
    end;
  end;
end;


procedure TMarble.DoCollision(Marble2: TMarble; Dispatch: boolean);
begin
  //
  // FIX-ME!
  //
  if Dispatch then Marble2.DoCollision(Self,false);
end;

procedure TMarble.Update(Time: single);
begin
  with Self do
  begin
    Force := AddCoord(Force,ScaleCoord(ScaleCoord(Normalize(V),Sqr(Magnitude(V))),AIR_R)); // F=k.V²
    Force := AddCoord(Force,ScaleCoord(V,AIR_R)); // F=k.v
    Force.z := Force.z + m*GRAV; // P=m.g
    V := AddCoord(V,ScaleCoord(Force,Time/m)); // v1 = v0 + F/m*t
    Force := VECT_NULL;
    A:=P; // encore un truc moche :(
    P := AddCoord(P,ScaleCoord(V,Time)); // x1 = x0 + v*t (idem y,z)
    // truc un peu moche de collision avec le sol <:]
    if P.z<0 then
    begin
      P.z := 0;
      V.z := -0.4*V.z; // rebond LOL
    end;
    // alors là, truc ULTRA-moche ! (gestion de la cam, rien a faire là...)
    //Anglex := Anglex+degtorad(arctan(-MouseState.lX/300));
    //Angley := Angley+degtorad(arctan(-mousestate.lY/300));
    Cam.x  := (150 * cos(Anglex*100))+P.x;
    if (Angley<6) then
    begin
      Cam.y  := (150 * sin(Angley*100))+P.z;
    end;
    Cam.z  := (150 * sin(Anglex*100))+P.y;
    // end truc ULTRA-moche
  end;
end;

constructor TMarbles.Create(n: integer);
begin
  with Self do
  begin
    Count := n;
  end;
end;

procedure TMarbles.Update(Time: single);
var
  i,j: integer;
begin
  with Self do
  begin
    for i:=1 to Count do
    begin
      for j:=1 to Count do
      begin
        if IsCollision(Items[i],Items[j]) then
        begin
          CollisionQueue.Add(i,j);
        end;
      end;
    end;       
    CollisionQueue.MixUp(0);
    RunCollisions;
    for i:=1 to Count do Items[i].Update(Time);
  end;
end;

procedure TMarbles.RunCollisions;
var
  p: PCollisionQueue;
begin
  p := Self.CollisionQueue;
  while p<>nil do
  begin
    Self.Items[p.i].DoCollision(Self.Items[p.j],true);
    //PlaySample(samp);
  end;
end;

{constructor TCollisionQueue.Create;
begin
  with Self do
  begin
    i := 0;
    j := 0;
    next := nil;
    prec := nil;
  end;
end;}

function TCollisionQueue.Add(i,j: integer): PCollisionQueue;
var
  p: PCollisionQueue;
  found: boolean;
begin
  result := @Self;
  found := false;
  while (result.next<>nil) and (not found) do
  begin
    p := result;
    if ((p.i=i) and (p.j=j)) or ((p.i=j) and (p.j=i)) then found:=true;
    result := p.next;
  end;
  if not found then
  begin
    New(result);
    p.next := result;
    result.i := i;
    result.j := j;
    result.next := nil;
    result.prec := p;
  end
  else result := nil;
end;

procedure TCollisionQueue.MixUp(n: integer);
var
  i: integer;
begin
  for i:=1 to n do
  begin
    //

  end;
  //
end;

function Distance(A,B: TMarble): single;
begin
  result := sqrt(sqr(A.P.x-B.P.x)+sqr(A.P.y-B.P.y)+sqr(A.P.z-B.P.z))-(A.r+B.r);
end;

function IsCollision(A,B: TMarble): boolean;
begin
  result := Distance(A,B)<0;
end;

// (\_/)
// (=^.^)
// (")-(")

end.