Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

DelphiX, DoMove, DoCollision [D6, WinXP]


Страницы:   1 2 3

Jus ©   (2004-10-01 13:03:00) 

Помогите, как мне сделать? Вот есть у меня игрок, он появляется в начале игры над "кирпичами"(Кирпич - это объект TKirp) в воздухе и как делать дальше в DoMove и DoCollision?! Я начал вроде, что у плеера по умолчанию стоит свойство Falling:=True; при Player1.DoCollision пишу
If (Sprite is Tkirp) and (Player1.Falling=True) then Falling:=False;А как потом игрок поймёт, что надо опять падать?

Если можно, приведити пример со столкновением с кирпичём (ЛЕВО ПРАВО ВЕРХ ВНИЗ), учитывая то, что есть ещё гравитация. Плиз!


Megabyte-ceercop   (2004-10-05 06:11:00) [21]


> Спрайт прыгнул, полсе чего падал с некоторой скоростью dу=6,
> (к примеру 6), призимлился, произошёл детекшен колижен (столкновение
> вроде как так произносится). По товему методу необходимо
> вернуть спрайту предыдущее положение тоесть y=y-6. Это подбросит
> его на 6 пикселов вверх, после чего он снова упадёт с dу=2
> или dу=1. В лутшем случае его снова подбросит на 1 пиксел,
> в худшем, на больше.


Не прав :)

Во первых не нужно делать y=y-6 а нужно делать Y = Y_old
Те присваивать ранее запомненое значение координаты, но запомненое не в предыдущем цикле, а в этом.
Пороядок цикла такой:
//Запомнил координату.
Old_Y = Y;
//Наростил её в соответствии со скоростью ускорения вниз:
Y = Y + SpeedDown;
//Проверил колизию, и если что, то востановил старую координату
If (doColision) then Y = Old_Y;

Draw;

Скакать не будет, потому как если спрайт провалился в землю, то он даже не отрисуется, пока не окажется на поверхности.


Falcon(TFSoft)   (2004-10-05 01:15:00) [22]

to Megabyte-ceercop ©

Смотрел твой проэк CeerCop, класная штука. Можно подсесть надолго, только вот 32bit рисунки которые ты кажется говорил, что там используеш очень много весят. А так графа на высоком кровне :))

И метод движения тоже очень неплохой!
Опиши его подробнее здесь, что б Jus, да и другие могли б использовать его в своих наработках.


Falcon(TFSoft)   (2004-10-05 00:49:00) [23]

Special to Jus:
>[30],[31]

Предлагаю ипользовать вместо player1.ScanXпросто player1.X, помоему так гараздо удобнее.
Тогда координаты игрока(пл.) в пространстве игры буду типа ххх.хх (тоетсь Single), а вот что б найти текуще его положение в ячейке товей карты ты будеш использовать:
Map[trunc (player1.Y/32), trunc (player1.X/32)]
Тут 32 - величина ячеек карты 32*32, тогда не прийдётся воспользоватся дополнительной переменной ScanX. Она, я так понял дублирует player1.х.

Исходя из предложения, замены этой переменной, блок управление player1будет выглядеть приблезительно так:


procedure TPlayer.DoMove(MoveCount:Integer);
var
  dx, dy :Single;
begin{1}

   dx := 0;
   dy := 0;

   if isLeft in MFrm.DXInput.States then
    begin
    {(Y+16) - центр спрайта по оси у,      trunc ((Y+16)/32) - номер строки
     (X/32) - берём левый угол спрайта, так как идём влево

     Map[] < 20 - означает, что слева элемент, через который можно проходить,
                  к примеру сделаеш чтоб камень был 1, дерево 2 и т.д.
                  а например трава, или кусты какие-нибудь 21}
     if Map[trunc ((Y+16)/32), trunc (X/32)]<20 then
        dx := -(Speed/1000)*MoveCount;//x:=x+dx;
     DirectionX := -1;  //направление движения, возможно понадобится
     FASPos :=  s_Left  //текущая анимация - движение влево, тоже может понадобится
    end;

   if isRight in MFrm.DXInput.States then
    begin
    {
     всё тоже самое, но вместо (X/32) берём
     (X+32)/32 - тоесть правый конец спрайта, так как движемся в право.}
     if Map[trunc ((Y+16)/32) ,trunc ((X+32)/32)]<20 then
        dx := (Speed/1000)*MoveCount;
     DirectionX := 1;
     FASPos :=  s_Right
    end;

//----------------движение по лестнице-----------------
   if isUp in MFrm.DXInput.States then
    begin
     if (Map[ trunc (Y/32), trunc ((X+16)/32)]=19) and //Проверяем, лесница ли в Руках? 19=лестница
        (Map[trunc (Y/32) ,trunc ((X+16)/32)]<20)      //Нет ли чего-то непроходимого сверху?
         then
           begin
              dY :=-1.2*(Speed/1000)*MoveCount; // скорость поднятия по леснице чуть другая, нежели ход пешком
              FASPos :=  s_Up // анимация, может понадобится
           end;
    end;

   if isDown in MFrm.DXInput.States then
    begin
     if (Map[trunc ((Y+34)/32), trunc ((X+16)/32)]=19) and //Проверяем, лесница ли в ногах?, точнее в руках :)
        (Map[trunc ((Y+32)/32) ,trunc ((X+16)/32)]<20)  //Нет ли чего-то снизу?
        then
        dY :=1.2*(Speed/1000)*MoveCount;
        DirectionY := 1;
        FASPos :=  s_Down
    end;

//--------------Прыжки...------------------------------
//нажаиа ли клавиша, и призимлился ли я, что б начать прыгать снова :)
   if ((isButton1 in MFrm.DXInput.States) and (Gravity.FlyingFinish)) then
     begin
      //выставляем переменный для прыжка :)
       Gravity.Jumping    := True;
       Gravity.FlyingFinish := False;
       //убараем автоматическое нажатие клавиши, (как у Авт. Калаш. одиночные выстрелы)
       Mfrm.DXInput.States := Mfrm.DXInput.States - [isButton1];
     end;
     
     
{   далее на своё усмотрение...
   if (isButton2 in MFrm.DXInput.States) then  Weapon.Fire;
   if (isButton3 in MFrm.DXInput.States) then ***
}
  //Собственно вызываем гравитацию
  Gravity.DoGravity(Self as TSprite, MoveCount);
  Сollision;
end;{1}


И вот это ещё, что б не влезал в запретные 32*32.
(Я уже писал, но это лишним здесь не будет)

//==============================================================================
procedure TPlayer.DoCollision(Sprite: TSprite; var Done: Boolean);
begin
inherited DoCollision(Sprite,Done);

if Sprite is TMapPiece then
 begin
    X := X + (X-Sprite.X)/32;
    Y := Y + (Y-Sprite.Y)/32;

//    Coord := Coord + (Coord-Sprite.Coord)/NormalizeSpeed;
 end;

Done := True;
end;


Ну вот приблезительно так смотрится мне управление.
(увы, ... я всё подмял под свою теорию, увы ...)


Faclon(TFSoft)   (2004-10-04 20:47:00) [24]

Я решил эту проблему следующим методом, возможно не таким прогресивным, как того хотелось бы..
Сначала на словах:
Проверка идёт по масиву карты(преобразовую координаты спрайта, в номер текущего элемента масива), если следующая "клетка" является непроходимой, то кордината спрайта просто не изменяется.
Но это не даёт хорошего результата, спрайт иногда просто "впухает", влезает и т.п в запрещённый объект. Что б решить этоту проблему в обработке столкновения проводятся дополнительные пересчёты, нормализация текущей позиции, координат спрайта.

А теперь пример (работающий, кто захочет убедится, просите вышлю ехе файл...)

Procedure TPlayer.DoMove(MoveCount: Integer);
 ***
if isLeft in MFrm.DXInput.States then
    begin
     if Map[trunc ((Y+16)/32), trunc (X/32)]<20 then
        dx := -(Speed/1000)*MoveCount;
    end;

   if isRight in MFrm.DXInput.States then
    begin
     if Map[trunc ((Y+16)/32) ,trunc ((X+32)/32)]<20 then
        dx := (Speed/1000)*MoveCount;
    end;
***
   
//==============================================================================
procedure TPlayer.DoCollision(Sprite: TSprite; var Done: Boolean);
Var
  xo, xs, yo, ys : Byte;
begin
 inherited DoCollision(Sprite,Done);

 if Sprite is TMapPiece then
  begin
     X := X + (X-Sprite.X)/32;
     Y := Y + (Y-Sprite.Y)/32;
     
//    Coord := Coord + (Coord-Sprite.Coord)/NormalizeSpeed;
  end;

 Done := True;
end;


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


Faclon(TFSoft)   (2004-10-04 20:46:00) [25]

>Megabyte-ceercop ©

Ты всё правильно говориш, но вот незадача, если использовать "гравитацию", то по твоей технологии спрайт будет дёргатся.

Пример:
Спрайт прыгнул, полсе чего падал с некоторой скоростью dу=6, (к примеру 6), призимлился, произошёл детекшен колижен (столкновение вроде как так произносится). По товему методу необходимо вернуть спрайту предыдущее положение тоесть y=y-6. Это подбросит его на 6 пикселов вверх, после чего он снова упадёт с dу=2 или dу=1. В лутшем случае его снова подбросит на 1 пиксел, в худшем, на больше.

Так будет продолжатся до бесконечности или пока спрайт не приземлится на 1 пиксел выше поверхности и будет летать над ней.

Я долго пытался выйти из этой ситуации, но мой код так и не выплыл..

И ещё раз повторюсь, если я не прав, то пожайлуста поправте меня...

с ув. Faclon


Faclon(TFSoft)   (2004-10-04 20:45:00) [26]

Не хочется выступать критиком, но помоему вариант предлагаемый  ув. cyborg-ом чуть чуть не подходит.  Не потому, что приняв этот вариант Jus будет переделывать достаточно участков кода, что б этого не делать (тафтологоия какая-то ;)).
Вопервых игра будет сильно "шаговая", тоесть если шаг сделан влево, значит что б  отойти опять назад, необходио дождаться пока завершится текущий шаг, что уж говориь о прыжках. Но в этом всём есть большой плюс - просчёт столкновений упрощается в несколько раз. ведь мы точно знаем на перёд за каждый шаг где будет находится спрайт.
А что надо сделать, чтоб реализовать прыжок с отвеса ???
Во-вторых, лодерунер был всегда игрой с шагами в 1п. (ну может не в один а в 2,3 ну мах в 4 пиксела).

P.S. Простите за орфографию.


Megabyte-ceercop   (2004-10-04 13:15:00) [27]


>  падает постоянно и следовательно со стеной,(т.к. TKirp
> это и стена и пол). Значит я нажимаю влево и он стоит как
> кол вкопанный!


Ты проверяешь столкновение объекта при его новом положении, и если это столкновение есть, ты возвращаешь предыдущее положение. Поэтому его столкновение с полом и расценивается как столкновение со стеной.

Делай так:
Измени координату X, проверь столкновения, и в случае столкновения со стеной, верни предыдущее значение координаты X.

Измени координату Y, проверь столкновения, в случае столкновения с полом или потолком, верни предыдущее значение координаты Y.

Теперь горизонтальное перемещение объекта не будет зависеть от вертикального.


cyborg   (2004-10-04 09:40:00) [28]


> [30] Jus   (04.10.04 08:24)

В этой игре игрок бегает поклеточно, а не попиксельно, следовательно обрабатывать ввод нужно только тогда, когда игрок ровно стоит в клетке. Нажали, нарипмер, клавишу влево, ставишь игроку флаг двжения, у тебя клетка карты 32х32 пикселя, вот он должен двигаться эти 32 пиксела, пока их не пройдёт. На кадр прибавляй ему по 2 или по 4 пикселя, подбери, чтобы скорость нормальная была. Проверять на падение нужно будет 1 раз, когда игрок дошёл до назначения, т.е. встал ровно в клетку, тогда и смотри что под ним. Так же с падением, ставишь флаг "падает" и крутишь цикл программы, пока не упадёт на клетку вниз, затем опять проверяй на падение или ввод клавиш управления.

Момент дохода до назначения (ну и слово :), координата игрока будет кратна 32-ум, т.е. if (X mod 32=0) and (Y mod 32 = 0) then (остановить игрока, посмотреть, есть ли под ним земля, если есть обработать ввод, если нет, то падает). А чтобы не пропустить этот момент, то прибавляй ему координаты по единице, например, если скорость у игрока = 3 пикселя на кадр, то for i:=1 to Speed do (двигай игрока на пиксель и прверяй дошёл ли он до места назначения, т.е. координаты кратны 32-ум)


Jus   (2004-10-04 08:38:00) [29]

Фрагмент из программы создания карты по массиву [ix,iy]
...
IF ScrMap[ix,iy]=36 then  //Игрок 1
   begin
player1:=TPlayer.Create(DXSpriteEngine.Engine);
 player1.Image:=DXImagePlayer1.Items.Find('IPlayerR');
 player1.Width:=player1.Image.Width;
 player1.Height:=player1.Image.Height;
 player1.X:=ScrX;
 player1.Y:=ScrY;
 player1.Z:=2;
 player1.PixelCheck:=True;
 fplayer1:=true;// создан игрок или нет
 player1.ScanX:=ix; //
 player1.ScanY:=iY; // ScrMap[ScanX,ScanY]
 end;

...

 procedure TPlayer.DoMove(MoveCount:Integer);
var s:string; i:integer;
begin{1}
 If (ScrMap[Trunc(player1.ScanX),Trunc(player1.ScanY+1)]) and (ScrMap[Trunc(player1.ScanX+1),Trunc(player1.ScanY+1)]) =0 then falling:=true else falling:=false;
 if isRight in Form1.DXInput.States then begin MoveR:=True; l:=1;ScanX:=ScanX+0.125; x:=x+4;end;
 if IsLeft in Form1.DXInput.States then begin MoveL:=True;l:=0; x:=x-4;ScanX:=ScanX-0.125;end;
 if IsButton1 in Form1.DXInput.States then Falling:=True;
 if Falling=true then begin Y:=Y+8; ScanY:=ScanY+0.25 end;
 collision;
 end;{1}


Зы: if Falling=true then begin Y:=Y+8; ScanY:=ScanY+0.25end;

В подчёркнутой строчке я поясню: ести бы Y:=Y+4(1/8-я часть спрайта 12.5%) то ScanY:=ScanY+0.125(переместился на 1/8-ю часть массива 12.5%)если Y+32(целая чась спрайта 100%) то ScanY+1;(... 100%).


Jus   (2004-10-04 08:24:00) [30]


> Щас делал, с кирпичами чисто, всё работает, спасибо всем!:)))Всё
> ок!)


Блин, я вот вчера, поспешил с заключением.
У меня игрок допустим находится в массиве(x,y) [12,7], а кирпич [12,8]. когда он идётвправо то по X он как только переходит на [13,7] начинает падать, а если идти влево, то по X он уже будет [11,7] и тоже начнёт падать. вроде ну так и надо, правильно. Но визуально ведь объект 32х32 и Х у этого объекта находится в левой части объекта, а правая часть объекта находится на 32 пикселя правей от Х. Так что получается (на экране) вправо падает нормально, а влево как только один пиксель успевает пройти за кирпич - начинает падать сквозь него. Как же мне делать, чтоб "угодить" и для движения вправо и также влево?;(


Jus   (2004-10-04 05:28:00) [31]


> ninja ©   (03.10.04 17:33) [27]
> как там прогресс? когда играть можно будет?

Во что? Альфа версии ещё даже нет, но скоро будет:)


> Falcon(TFSoft)   (03.10.04 18:07) [28]
> Если нужна помощь, то обращайся... *)
> да, ещё вопрос, как тебе игрулина которую я прислал?

Нормально, даже больше чем. Ты б её доделал! ...?:)


Falcon(TFSoft)   (2004-10-03 18:07:00) [32]

Если нужна помощь, то обращайся... *)
да, ещё вопрос, как тебе игрулина которую я прислал?


ninja   (2004-10-03 17:33:00) [33]

как там прогресс? когда играть можно будет?


Jus   (2004-10-03 17:16:00) [34]


> Falcon(TFSoft)   (03.10.04 16:03) [25]
> >obomen   (03.10.04 11:06) [24]
> изыди ведьма
> ???К чему это сказано???

А он вроде того, он всем всегда ченибудь говорит, надоел уже. извеняюсь.


> А кгде скриншоты посмотреть можно?
> Если они уже есть...


ftp://cyborghome.ru/ScreenShots/


Falcon(TFSoft)   (2004-10-03 16:03:00) [35]

>obomen   (03.10.04 11:06) [24]
изыди ведьма

???К чему это сказано???

А кгде скриншоты посмотреть можно?
Если они уже есть...


bobomen   (2004-10-03 11:06:00) [36]

изыди ведьма


Jus   (2004-10-03 09:58:00) [37]


> Trunc();

Я уже догадался:)


> Массив  карты в подобной игре наиболее оптимальный вариант,
> быстро работает и лёгок в обработке.

Щас делал, с кирпичами чисто, всё работает, спасибо всем!:)))Всё ок!)


cyborg   (2004-10-03 09:37:00) [38]


> [20] Jus   (03.10.04 06:16)

Массив  карты в подобной игре наиболее оптимальный вариант, быстро работает и лёгок в обработке.


> [21] Jus   (03.10.04 08:28)

Trunc();


Jus   (2004-10-03 08:28:00) [39]

Какая функция округляет (обрубает) число после запятой? Сам не понял как выразился:)

Ну например:  7.25  = 7  
                       7.99  = 7
                       8.01  = 8
                       8.84  = 8


Jus   (2004-10-03 06:16:00) [40]

Собственно всё понятно! Но у тебя всё в игре проверяется по массиву(идея хорошая), а можно ведь без этого. Я использовал в своей игре массив для того лишь, чтоб загружать карту и объекты по массиву, а в дальнейшем может и для поисков путей для врагов(АИ). Получается у меня, что по массиву загрузились объекты и мне массив больше не нужен, дальше я использую DoCollision и DoMove, я так хотел. Твой модуль можно использовать тоже для  гравитации. Буду делать, спасибо.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо