![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
DelphiX, DoMove, DoCollision [D6, WinXP]
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, я так хотел. Твой модуль можно использовать тоже для гравитации. Буду делать, спасибо.