Конференция "Игры" » Как правильно подсчитать траекторию полёта мяча. [Delphi, Windows]
 
  • GAMEZ (31.01.08 10:57) [0]
    Как правильно подсчитать траекторию полёта мяча.

    Вот такой у меня код. В результате от стенок мяч отбивается нормально.
    от ракетки отбивается правильно только от правой стороны ракетки, а слева вообще ведет себя мячик
    не реально, или при сталкивании с левой стороной он просто летит верх или отбивается слева задолго от
    ракетки(на растоянии от ракетки слева).

    function PointInRect(X, Y, Left, Right, Top, Bottom: Single): Boolean;
    begin
     Result := ( ((X >= Left) and (X <= Right)) = (Right > Left) ) and
               ( ((Y >= Bottom) and (Y <= Top)) = (Top > Bottom) );
    end;

    //------------------------------------------------------------------------------
    // Возвращает True, если прямоугольники соприкасаются
    //------------------------------------------------------------------------------
    function RectCollides(Left1, Right1, Top1, Bottom1,
                         Left2, Right2, Top2, Bottom2: Single): Boolean;
    begin
     Result := (PointInRect(Left1,  Top1,    Left2, Right2, Top2, Bottom2)) or
               (PointInRect(Right1, Top1,    Left2, Right2, Top2, Bottom2)) or
               (PointInRect(Right1, Bottom1, Left2, Right2, Top2, Bottom2)) or
               (PointInRect(Left1,  Bottom1, Left2, Right2, Top2, Bottom2));
    end;

    //------------------------------------------------------------------------------
    // Возвращает True, если ПЕРВЫЙ прямоугольник лежит внутри ВТОРОГО (пока без надобности)
    //------------------------------------------------------------------------------
    function RectInside(Left1, Right1, Top1, Bottom1,
                       Left2, Right2, Top2, Bottom2: Single): Boolean;
    begin
     Result := (PointInRect(Left1,  Top1,    Left2, Right2, Top2, Bottom2)) and
               (PointInRect(Right1, Top1,    Left2, Right2, Top2, Bottom2)) and
               (PointInRect(Right1, Bottom1, Left2, Right2, Top2, Bottom2)) and
               (PointInRect(Left1,  Bottom1, Left2, Right2, Top2, Bottom2));
    end;

    procedure TBAll.TraceBallTrajectory;
    var
     BY, BVY,BVX, BX: Single;
     procedure AddPoint;
     begin
       SetLength(Ball.Trajectory, Length(Ball.Trajectory)+1);
       Ball.Trajectory[HIGH(Ball.Trajectory)].X := BX;
       Ball.Trajectory[HIGH(Ball.Trajectory)].Y := BY;
     end;
    begin
     BX := Ball.X;
     BY := Ball.Y;
     BVY := Ball.VY;
     BVX := Ball.VX;

     FillChar(Ball.Trajectory, SizeOf(Ball.Trajectory), 0);
     AddPoint; // начинаем траекторию в текущей позиции шара

     repeat
       BY := BY + BVY;
       BX := BX + BVX;
       if ((BY+Ball.Size >= 300) and (BVY > 0)) or
       ((BY-Ball.Size <= 0) and (BVY < 0)) then
       begin
         BVY := -BVY;
         AddPoint; // добавляем точки, когда шар бьется о стены
       end;
      if ((Bx+Ball.Size >= 300) and (BVx > 0)) or
       ((Bx-Ball.Size <= 0) and (BVx < 0)) then
       begin
         BVx := -BVx;
         AddPoint; // добавляем точки, когда шар бьется о стены
       end;

     until ( (BX+Ball.Size >= player.X-player.PadWidth ) and (Ball.VX > 0) ) or
     ( (By+Ball.Size >= player.y-player.PadWidth ) and (Ball.Vy > 0) );

     AddPoint; // заканчиваем траекторию, там где шар может попасть по доске
    end;

    procedure TBall.BallProc;
    var
     path, deltaX, deltaY: Single;
    begin

     ball.y := ball.y + ball.Vy;
     ball.X := ball.X + ball.VX;

     if ((Ball.Y+Ball.Size >= 300) and (Ball.VY > 0)) or
            ((Ball.Y-Ball.Size <= 0) and (Ball.VY < 0)) then
         begin
           Ball.VY := -Ball.VY;
           Inc(Ball.CurPoint); // показывает к какой точке траектории шар летит
       end;

    if ((Ball.x+Ball.Size >= 300) and (Ball.Vx > 0)) or
            ((Ball.x-Ball.Size <= 0) and (Ball.Vx < 0)) then
         begin
           Ball.Vx := -Ball.Vx;
           Inc(Ball.CurPoint); // показывает к какой точке траектории шар летит
       end;

    if (RectCollides( Ball.X-Ball.Size, Ball.X+Ball.Size, Ball.Y+Ball.Size, Ball.Y-Ball.Size,
     player.X-player.PadWidth, player.X+player.PadWidth, player.y+player.PadHeight, player.Y-player.PadHeight ))
    then
    begin
    if ball.y < 10 then begin

        deltaX := ball.X + (player.X - Focus);
        deltaY := ball.Y + (player.Y - Focus);
    end;

      path := Sqrt( Sqr(deltaX) + Sqr(deltaY) );
           Ball.VX := Ball.CurSpeed * (deltaX / path);
           Ball.VY := Ball.CurSpeed * (deltaY / path);
           TraceBallTrajectory;
           Ball.CurPoint := 1;
    end;

    end;
  • ketmar © (31.01.08 11:28) [1]
    а тебе точно компилятор никаких warning'ов не даёт?
  • GAMEZ (31.01.08 11:45) [2]
    Выдайт разные Сообщения но они же не критични
  • ketmar © (31.01.08 12:04) [3]
    >[2] GAMEZ (31.01.08 11:45)
    >Выдайт разные Сообщения но они же не критични

    вот пока «разные сообщения» не исчезнут — чини код. ибо код крив до умопомрачения.
  • GAMEZ (01.02.08 11:11) [4]
    Блин мучаюсь над этой мелкой проблемой уже четвертый день.
    Узнаю как это делается напишу статьи для программистов, что бы они не ломали себе мозги......
  • ketmar © (01.02.08 12:53) [5]
    лучше не пиши статей, кривых статей и без тебя достаточно. лучше учись программировать — оно полезней будет. ибо код твой — страшная каша.
  • GAMEZ (03.02.08 11:03) [6]
    Вот посмотрите на этот код.

     // точка траекториии шара
     TPoint2f = record
       X, Y: Single;
     end;

     T2DVector = record
       X : single;  // Координата Х
       Y : single;  // Координата У
     end;

     T2DRect = record
       Coord  : T2DVector; // Координаты центра
       Width  : integer;   // Ширина
       Height : integer;   // Высота
     end;

     TPlayer = class
       constructor Create;
     public
       cord: T2DVector;
       PadSpeed: Single;
       PadWidth, PadHeight: Single;
     end;

     TBall = class
       constructor Create;
     public
       cord: T2DVector;
       dV:T2DVector;
       Size   : Single;
     public
       procedure BallProc;
     end;

    var
     Player : TPlayer;
     Ball : TBall;
     i: integer;

    procedure EXInit;
    begin
     player := TPlayer.Create;
     ball   := TBall.Create;
    end;

    procedure Init;
    begin

     player.cord.X := 0;
     player.cord.Y := 0;
     player.PadWidth := 128;
     player.PadHeight := 32;

     ball.cord.X := 150;
     ball.cord.Y := 0;
     ball.dv.x := 0.2;
     ball.dv.y := 0.2;
     ball.Size := 20;

    end;

    constructor TPlayer.Create;
    begin

    end;

    constructor TBall.Create;
    begin

    end;

    PROCEDURE fInc( var Value : single; Amount : single );
    BEGIN
     Value := Value + Amount;
    END;

    FUNCTION SetVector( X, Y : single ) : T2DVector;
    BEGIN
     Result.X := X;
     Result.Y := Y;
    END;

    FUNCTION SetRect( Coord : T2DVector; Width, Height : integer ) : T2DRect;
    BEGIN;

     Result.Coord  := Coord;
     Result.Width  := Width;
     Result.Height := Height;

    END;

    FUNCTION GetLength( First, Second : T2DVector ) : single;
    BEGIN
     Result := sqrt(sqr(First.X - Second.X) + sqr(First.Y - Second.Y));
    END;

    FUNCTION GetAngle( First, Second : T2DVector ) : single;
    VAR
     TMP : single;
    BEGIN
     TMP := GetLength(First, Second);
     if (Second.X >= First.X) and (Second.Y >  First.Y) then Result := arccos((Second.X - First.X)/TMP)*180/Pi + 0;
     if (Second.X <  First.X) and (Second.Y >= First.Y) then Result := arccos((Second.Y - First.Y)/TMP)*180/Pi + 90;
     if (Second.X <= First.X) and (Second.Y <  First.Y) then Result := arccos((First.X - Second.X)/TMP)*180/Pi + 180;
     if (Second.X >  First.X) and (Second.Y <= First.Y) then Result := arccos((First.Y - Second.Y)/TMP)*180/Pi + 270;
    END;

    // Возвращает True, если точка лежит в заданном прямоугольнике
    function PointInRect(X, Y, Left, Right, Top, Bottom: Single): Boolean;
    begin
     Result := ( ((X >= Left) and (X <= Right)) = (Right > Left) ) and
               ( ((Y >= Bottom) and (Y <= Top)) = (Top > Bottom) );
    end;

    // Возвращает True, если прямоугольники соприкасаются
    function RectCollides(Left1, Right1, Top1, Bottom1,
                         Left2, Right2, Top2, Bottom2: Single): Boolean;
    begin
     Result := (PointInRect(Left1,  Top1,    Left2, Right2, Top2, Bottom2)) or
               (PointInRect(Right1, Top1,    Left2, Right2, Top2, Bottom2)) or
               (PointInRect(Right1, Bottom1, Left2, Right2, Top2, Bottom2)) or
               (PointInRect(Left1,  Bottom1, Left2, Right2, Top2, Bottom2));
    end;

    // Возвращает True, если ПЕРВЫЙ прямоугольник лежит внутри ВТОРОГО
    function RectInside(Left1, Right1, Top1, Bottom1,
                       Left2, Right2, Top2, Bottom2: Single): Boolean;
    begin
     Result := (PointInRect(Left1,  Top1,    Left2, Right2, Top2, Bottom2)) and
               (PointInRect(Right1, Top1,    Left2, Right2, Top2, Bottom2)) and
               (PointInRect(Right1, Bottom1, Left2, Right2, Top2, Bottom2)) and
               (PointInRect(Left1,  Bottom1, Left2, Right2, Top2, Bottom2));
    end;

    FUNCTION Collision_Rect( First, Second : T2DRect ) : boolean;
    BEGIN
     Result := (First.Coord.X + First.Width >= Second.Coord.X)  and
               (First.Coord.X <= Second.Coord.X + Second.Width) and
               (First.Coord.Y + First.Height >= Second.Coord.Y) and
               (First.Coord.Y <= Second.Coord.Y + Second.Height);

    END;

    // вот здесь и должно происходить вычисление полёта мяча
    procedure TBall.BallProc;
    begin

    end;

    -------------------------------------------------------------------------

    Не знаю как это сделать. Думал ракетку разбить на секции из квадратов просчитать столкновения
    с этими прямоугольными секциями

    000000  <- это типа ракетка

    Но потом подумал что если мяч столкнётя с двумя то что я тогда буду делать.
    Незнаю.
    Надо Как то подругому просчитывать столкновения. Подскажите пожалуйста.
  • tButton © (03.02.08 11:16) [7]
    Как правильно подсчитать траекторию полёта мяча.

    в какой плоскости?
  • GAMEZ (03.02.08 11:19) [8]
    kakaya ploskosty ???
    2D prostranstvo
  • ketmar © (03.02.08 12:11) [9]
    автор, ты несколько не представляешь себе, что пишешь. у тебя вон координаты пиксельные, чего ты привязался к нескольким квадратам? прямоугольник с прямоугольником, всего лишь.

    а остальное у тебя там сверху было начато, хоть и корявенько. идея верная ж: скорость извесна, квант времени известен — бери, да трассируй вектор. да в каждой точке проверяй, не буцнулось ли куда.

    конечно, проще вычислить расстояние до той же ракетки и безо всякой трассировки выяснить, не шмякнется ли мячик на данном шаге. всё это в принципе обыкновенная планиметрия. вникни в неё да в векторную алгебру — сразу прояснится в голове.
  • ketmar © (03.02.08 12:12) [10]
    кстати, хинт: квадратные мячи человечество не использует, они катятся очень плохо. %-)
  • tButton © (03.02.08 13:09) [11]
    я тебе в 2Д три плоскости назову. XY, XZ, YZ =)
    в каких направлениях ракетка движется?
  • KilkennyCat © (03.02.08 15:16) [12]
    > [11] tButton ©   (03.02.08 13:09)

    это уже не 2D.
  • tButton © (03.02.08 19:50) [13]
    re > KilkennyCat ©   (03.02.08 15:16) [12]
    очень даже два Д, каждая из названых плоскостей имет по два измерения =) просто одна плоскость это проекций сверху, другая - сбоку, третья - с другого бока =)
    от выбраной проекции зависит поведение мяча.
  • GAMEZ (04.02.08 11:50) [14]
    Почитал я про кимематику и про векторы.
    Должно быть такое, если сталкивается мяч с ракеткой то завершается работа приложения это так для проверки
    Посмотрите...

     ball.acceleration.x := force/ball.mass;
     ball.acceleration.y := force/ball.mass;

     ball.Velocity.X := ball.Acceleration.x ;
     ball.Velocity.y := ball.Acceleration.y ;

     ball.Location.X := ball.Location.X + ball.Velocity.x ;
     ball.Location.y := ball.Location.y + ball.Velocity.y ;

     distance.X := player.cord.X - ball.Location.Y;
     distance.y := player.cord.y - ball.Location.y;

     magnitude.X := distance.X * distance.X;
     magnitude.y := distance.y * distance.y;

     minDist := ((player.cord.x + (player.PadWidth / 2)) - (player.cord.y + (player.PadHeight / 2))) + 100 ;

     if  ((magnitude.X <= minDist)) and ((magnitude.y <= minDist))  then engine.Quit;

    Только почему то мячик сталкивается  не со всей ракеткой, а только с нижней левой точкой. Почему.

    P.S.

    А разве этот сайт не называется  ДЕЛФИ МАСТЕРА.
  • rts111 © (04.02.08 19:42) [15]

    > А разве этот сайт не называется  ДЕЛФИ МАСТЕРА.


    Лично меня можешь называть просто МАСТЕР. Приставка ДЕЛФИ вовсе необязательна.
  • tButton © (05.02.08 00:45) [16]
    if (мяч.x <= (левая_ракетка.x - левая_ракетка.width)) and (мяч.y <= левая_ракетка.y) and (мяч.y >= (левая_ракетка.y + левая_ракетка.width)) then begin
     // собсно коллизия
     // отфутболиваем мяч, инвертируем скорость по иксам
    end;


    ну и аналогично для правой.
    трудно писать с наладонника, незная какая у тебя система координа используется.
  • gamez (05.02.08 11:11) [17]
    Вот так я нашол столкновение с ракеткой.

    function BOXVsSphere(Minx,Maxx,Pos :T2DVector;R:Single): boolean;
    var
     d, d2 :single;
    begin
     d := 0;

     // если центр сферы лежит перед AABB,
     if (Pos.x < Minx.x) then
     begin
       // то вычисляем квадрат расстояния по этой оси
       d2:= Pos.x - Minx.x;
       d := d+d2 * d2;
     end;

     // если центр сферы лежит после AABB,
     if (pos.x > Maxx.x) then
     begin
       // то вычисляем квадрат расстояния по этой оси
       d2:= Pos.x - Maxx.x;
       d := d + d2*d2;
     end;

     if (Pos.y < Minx.y) then begin d2:= Pos.y - Minx.y; d := d+d2*d2; end;
     if (pos.y > Maxx.y) then begin d2:= Pos.y - Maxx.y; d := d+d2*d2; end;

     result := d <= (R * R);
    end;

    function Vector(X, Y: single): T2DVector;
    begin
    Result.X := X;
    Result.Y := Y;
    end;

    ---------------------------------

     ball.acceleration.x := force/ball.mass;
     ball.acceleration.y := force/ball.mass;

     ball.Velocity.X := ball.Acceleration.x ;
     ball.Velocity.y := ball.Acceleration.y ;

     ball.Location.X := ball.Location.X + ball.Velocity.x ;
     ball.Location.y := ball.Location.y + ball.Velocity.y ;

    if   BOXVsSphere(vector(player.cord.X,player.cord.Y), vector(player.cord.x+player.PadWidth,player.cord.Y+player.PadHeight),
                                          vector(ball.Location.X , ball.Location.Y),ball.Size)
     then

     engine.Quit;
    ----------------------------------



    А как сделать чтобы мячь обратно отлитал с правильной траекторией.
    Что то нужно делать с углом столкновения наверное. Подскадите.
  • ketmar © (05.02.08 12:44) [18]
    а что такое «правильная траектория»?

    в играх типа арканоида обычно да — угол отражения меняется в зависимости от того, по какой части paddle попал мячик. тебе именно это надо?
  • Pir (05.02.08 18:57) [19]
    http://igdc.ru тебе в руки! конкурс "арканоид"
  • GAMEZ (06.02.08 13:11) [20]
    Написал ДЕМКУ.
    Есть игрок, босс, мячик.
    Интелект у босса туповатый, скомпенсировал его сильными кидками у босса.
    Скажите что необходими изменить если чего то не так.

    http://www.uploading.com/files/F5EMG1TV/pp.rar.html
 
Конференция "Игры" » Как правильно подсчитать траекторию полёта мяча. [Delphi, Windows]
Есть новые Нет новых   [134431   +10][b:0][p:0.002]