Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Игры";
Текущий архив: 2005.01.23;
Скачать: [xml.tar.bz2];

Вниз

DelphiX, DoMove, DoCollision   Найти похожие ветки 

 
Jus   (2004-10-01 13:03) [0]

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

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


 
KilkennyCat ©   (2004-10-01 13:12) [1]

ниче не понял...


 
NikeOLD ©   (2004-10-01 14:32) [2]

В подобных играх есть прием (это только один ИЗ вариантов решения).
Игрок падает постоянно. Когда под игроком появляется объект, на который он должен встать, падение все равно продолжается. Поскольку объект никуда не исчезает мы видим, что игрок "стоит" на объекте. У тебя таким объектом будет кирпич, лестница и что там еще по сюжету.


 
NikeOLD ©   (2004-10-01 14:36) [3]

Одним словом: нафиг переменную Falling.
В обработчике DoMove проверяешь на столкновение с объектом: да - координата Y игрока = Y объекта - высота игрока, иначе - уменьшаем Y игрока на нужную величину (т.е. падаем).


 
Jus   (2004-10-01 15:33) [4]


> В подобных играх есть прием (это только один ИЗ вариантов
> решения).
> Игрок падает постоянно. Когда под игроком появляется объект,
> на который он должен встать, падение все равно продолжается.
> Поскольку объект никуда не исчезает мы видим, что игрок
> "стоит" на объекте. У тебя таким объектом будет кирпич,
> лестница и что там еще по сюжету.

Я так и сделал, а он скачет, и ещё при столкновении с кирпичём у меня подразумевается и пол и стены, следовалельно: он упал на кирпичи(на пол) и я нажимаю влево, чтоб идти, а при столкновении с кирпичём(левой стеной) уменя X=X+4. И что получается, он постоянно сталкивается с полом, т.к. падает постоянно и следовательно со стеной,(т.к. TKirp это и стена и пол). Значит я нажимаю влево и он стоит как кол вкопанный!


 
Jus   (2004-10-01 15:39) [5]

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

Зы: Без постоянного падения получится как BOLDER DASH какой-то:)


 
cyborg ©   (2004-10-01 15:54) [6]

Просто ты пошёл не по тому пути, от этого проблемы. Тебе посоветуют конечно чего нибудь, но решение скорей всего будет через зад.


 
Servelat ©   (2004-10-01 15:59) [7]

У меня был примерчик подобный, когда я хотел какую-то аркаду с видом сбоку написать. Правда аркады не вышло, но мужичок исправно бегает и прыгает, сталкиваясь с кирпичами. А тебе еще проще, если герой прыгать не умеет, только падать (я в лоде рунер не игра никогда, так что правил не знаю). Могу послать на мыло, если надо.
ЗЫ
> Сдесь

Здесь.


 
Jus   (2004-10-01 16:04) [8]


> Servelat ©   (01.10.04 15:59) [7]
> У меня был примерчик подобный, когда я хотел какую-то аркаду
> с видом сбоку написать. Правда аркады не вышло, но мужичок
> исправно бегает и прыгает, сталкиваясь с кирпичами. А тебе
> еще проще, если герой прыгать не умеет, только падать (я
> в лоде рунер не игра никогда, так что правил не знаю). Могу
> послать на мыло, если надо.
> ЗЫ
> > Сдесь
>
> Здесь.

Давай:)!!!
hitman201@yandex.ru;

> еще проще, если герой прыгать не умеет, только падать

Он умеет перепрыгивать! Он перепрыгнуть может например расстояние с один блок 32х32.


 
NikeOLD ©   (2004-10-01 16:37) [9]

Для общего развития: еще один вариант (по Ламоту). Но это тормоза.

Заводится еще одна поверхность (не знаю, как это в DelphiX выглядит). На ней отображаются однородным цветом непроходимые участки. Поверхность в рендеринге не участвует, но обновляется соответсвенно изменению непроходимых участков на экране. В процессе перемещения героя проводится постоянная проверка на столкновение с этим цветом, если столкнулся - стоим на месте.


 
Servelat ©   (2004-10-01 18:55) [10]

2 [8] Jus
Чего-то у меня письма не посылаются, наверное сервак глючит.
В общем выложил сюды:
http://www.servelat.nm.ru/arcade.zip
качать лучше FlashGet"ом или подобными, а то если просто - то там окна дурацкие появляются типа "вы хотите скаачть файл с хостинга такого-то". Во FlashGet"е без проблем.
Сразу предупреждаю: писал пару лет назад, за качество кода ответственности не несу, за отсутствие комментариев - тоже. Откуда выдрал картинки - не помню.
Тебе наверное интересны будут процедуры в модуле uSprite:
TSprite.Move;
TPlayer.Move.
Кстатим там используются не делфииксовские спрайты, а мои объекты, отдаленно их напоминающие. В общем погляди, может чем и поможет.
Удачи.


 
breakmaster ©   (2004-10-01 20:52) [11]

(8)Чето я не помню,чтоб в лодраннере кто-то прыгал...


 
МЯУ   (2004-10-01 21:24) [12]

Servelat ©   (01.10.04 18:55) [10]

хотел скачать аркаду, но, блин, не смог. DAP её не хочет, а стандартная закачка обламывается всё время на ~150kb. Не мог бы ты положить её в какое-то другое место? Посмотреть охота...


 
Jus   (2004-10-02 08:31) [13]


> качать лучше FlashGet"ом или подобными, а то если просто
> - то там окна дурацкие появляются типа "вы хотите скаачть
> файл с хостинга такого-то". Во FlashGet"е без проблем.

скачал обычным способом, без проблем. спасибо!


 
Jus   (2004-10-02 09:59) [14]

Вот класс игрока:
TPlayer=class(TImageSprite)
  MoveR:Boolean;
  MoveL:Boolean;
  MoveU:Boolean;
  MoveD:Boolean;
  falling:Boolean;
  DownY:Double;
  StayOnTop:Boolean;
   public
    procedure DoCollision(Sprite: TSprite; var Done: Boolean); override;
    procedure DoMove(MoveCount:Integer);override;
  end;


Falling:=True; // по умолчанию в начале игры

procedure TPlayer.DoMove(MoveCount:Integer);
var s:string;
begin{1}
 if Falling=True then DownY:=DownY+1;
 if isRight in Form1.DXInput.States then begin MoveR:=True; x:=x+1;end;
 if IsLeft in Form1.DXInput.States then begin MoveL:=True; x:=x-4;end;
collision;
 end;{1}


procedure TPlayer.DoCollision(Sprite:TSprite;var Done:Boolean);
begin
 if MoveL=True Then Begin
     If (Sprite is TKirp) and (MoveL=True) Then X:=X+4;
     MoveL:=False;
                    end;
 if MoveR=True Then Begin
     If (Sprite is TKirp) and (MoveR=True) Then X:=X-4;
     MoveR:=False;
                    end;
//  if Falling=True Then
//      If  (Sprite is TKirp) Then Begin DownY:=DownY-1; end else Falling:=True;

end;


Пожалуйстл, прошу ВАС, подумать тоже, как мне это сделать, у меня не получается, я тоже думаю над этим! :-О

Если хотите помочь мне и проекту, чтоб он реализовался быстрее, то, пожалуйсто, помогите! Кто разбирался в примере Servilatа, может нашел выход из положения?!

Зы: У меня очень сжатые сроки, до примерно 20.10.04, потом начнутся головняки, и закончатся где-то через месяц. Мне-бы хотябы демку сделать к этому сроку:(
Плиззз! )-;


 
Falcon(TFSoft)   (2004-10-02 13:34) [15]

ПРивет всем!
Возможно я позно подкл. к обсуждению игры НЕ ЛОДЕ РУНЕР, но советом помогу...

Я не сильно програмёрю, поэтому приведённый ниже код сильно не критиковать(хотя программеру именно это и нужно!).

Итак, хотя в not LodeRyner игрок не прыгает но я приведу код, который позволяет создавать гравитацию на все необходимые (точнее задаваемые прогрм объекты):

unit Gravity_Unit;

interface
Uses DXSprite;

Type
  TGravityPower = class
     Public
        dy             : Real; //отвечает за текущее ускорение
        MaxJumpCount : Real; //просто необходимая переменная :)
        Jumping,   FlyingFinish : Boolean; /*ответ за текущее состояние описывать буду ниже*/
        LadderSens             : Boolean; //чувствителен ли к лестнице (или другим объектам по сценарию)?
        Weight       : Real; // вес ;)

        Constructor Create (Distance : Real);
        Function DoFly (InfluenceSprite: TSprite; MoveCount: Integer): Boolean; //Возвращает true, если приземлились
        Function DoJump (InfluenceSprite: TSprite; MoveCount: Integer): Boolean; //Возвращает true, если приземлились
        Procedure DoGravity (InfluenceSprite: TSprite; MoveCount: Integer); //собственно сама гравитация, вызываемая при каждом DoMove объекта
     Private
        JumpCount : Real;//необходимый счётчик прыжка
end;

Var
  Gravity : Real = 200;//типа g=9,80655 :)

implementation
Uses
  Main_Unit; //подключаем модуль, в котором описывается карта и т.д. короче название модуля само за себя говорит

//конструктор
Constructor TGravityPower.Create (Distance : Real);
begin
  inherited Create;
  MaxJumpCount := Distance;
  Self.Jumping := False;
  Self.FlyingFinish := False; //???? ???? ????????, ?? ????? ?? ??? :0
  LadderSens := False;
  Weight := 1;
end;

//делаем прыжок, этой функцией
Function TGravityPower.DoJump (InfluenceSprite: TSprite; MoveCount: Integer): Boolean;
begin
with InfluenceSprite do
  begin  //????????
        if (Map[trunc (Y/32), trunc ((X+16)/32)]<20) and //?????? ?????? ???
           (Map[trunc ((Y+25)/32), trunc ((X+16)/32)]<20-ord(LadderSens))    then //????? ?????? ???  ??. +25/
           begin
              JumpCount := JumpCount + (Gravity/5000)*MoveCount*Weight;
              dy :=(MaxJumpCount*MoveCount*0.05 - 0.5*JumpCount*JumpCount)/10;
              If dy<=-4 then dy:=-4; //??? ? ?? ??????? ????? ? ????? 32?32
              Y := Y - dy;
              Result := False;              
           end
        else
           begin
              JumpCount := 0;
              Jumping := false;
              Result := True;
             //   FlyingFinish := True; //????? ????????? ? ???????
           end;
     end
end;

//делаем полёт - когда под ногами ничего нет, этой функцией
Function TGravityPower.DoFly (InfluenceSprite: TSprite; MoveCount: Integer): Boolean;
begin
with InfluenceSprite do
//34 - ???? ?? ??????? ? ????????????? ??????
  if Map[trunc ((Y+34)/32), trunc ((X+16)/32)]<20-ord(LadderSens) then //??????, ... ????? ?????? ????!
     begin
        JumpCount := JumpCount + (Gravity/5000)*MoveCount*Weight;//???????, ???? ????????, ?? FPS
        dy :=-0.5*(JumpCount*JumpCount)/10;
        If dy<-9 then dy:=-9; //??? ? ?? ??????? ????? ? ????? 32?32        
        Y := Y - dy;
        Result := False; //?? ??? ? ??????
        FlyingFinish := False;
     end
  else //????????????
     Begin
       JumpCount:=0;
       Jumping := false;   //??????? ?????
       FlyingFinish := True; //????? ????????, (??????? ??? ??????????????? ?????? ... ???????!)
       Result := True;
     end;
end;

//вообщемто эту функцию и надо вызывать, в обработке domove, и в зависимости от состояния переменных Jumping and FlyingFinish
будут производится либо прыжок, либо падение

Procedure TGravityPower.DoGravity (InfluenceSprite: TSprite; MoveCount: Integer);
begin
  if (Jumping and not FlyingFinish) then
        DoJump(InfluenceSprite, MoveCount)
  else
        DoFly(InfluenceSprite, MoveCount);
end;

end.


*-------------------------------------------------------------*


 
Falcon(TFSoft)   (2004-10-02 13:36) [16]

А теперь немного подробнее...
Итак тут выложен целый модуль, который без лишних коментариев, вместе с реализованым на нём примером высылаю тебе в писме, извени что без предуприждения (надеюсь там есть свободных 500k).
Он позволяет делать гравитацию (`почти) одинаковой для всех объектов, не зависимо от FPS, причём гравитация по ходу дела ещё и физическая, тоесть с ускорением. Возможно не сильно реалестично но....

Чтоб воспользоватся необходимо например:

//+=========================   TEnemy_1 =======================================+
Procedure TEnemy_1.DoMove(MoveCount: Integer);
Var
  Speed : Integer;
  dy      : Real;
begin
inherited DoMove(MoveCount);

  Speed := 200;
  dx := (Speed/1000)*MoveCount;
//далее примитивная проверка на столкновение (в полученном примере это красный шарик-монстр)
  Case Direction of
     0: //Left
        Begin
           if Map[trunc ((Y+16)/32), trunc (X/32)]<20 then
                 X := X-dx
           else
               Direction := 1;
        end;
     1: //Right
        Begin
           if Map[trunc ((Y+16)/32), trunc ((X+32)/32)]<20 then
                 X := X+dx
           else
               Direction := 0;
        end;
  end;

//А вот и наша граитация!!!
  Gravity.DoGravity(Self as TSprite, MoveCount);
end;


Вот и всё!
Причём, если ты хочеш, чтоб монстр(спрайт) "прыгал" то необходимо сделать:
begin
       Gravity.Jumping    := True;
       Gravity.FlyingFinish := False;
     end;

И при вызове Gravity.DoGravity(Self as TSprite, MoveCount); спрайт подпрыгнет!

Ну вот и всё, почти тянет на статью :)
Ах, да ещё я сказал, что опишу зачем нужны некоторые переменные:

MaxJumpCount : Real; - фактически высота прыжка, только не в пиклселах а в ... каких-то относительных еденицах
LadderSens : Boolean; - говорит о том, что к объекту не будет применена гравитация, и прыжок на некоторых объектах(тафтология конечно ну ничего не поделаеш). К примеру на лестнице прыгать нельзя, но если ты падаеш, и попадаеш на лестницу то ты останавливаешся, а не "проскальзываеш" дальше.
Weight : Real; - отвеачет за вес,и соответсвенно за гравитацию, но помоему он здесь вообще не фурычит :(

И ещё одно, наверное не самое безполезное. Картра реализована как масив данных (спрайтов с набором свойств как к примеру разрушаемость), размером 32*32. Вот почему там фигурирует это число, ведь оно есть основным структурным элементом.

Ну а в остальном думаю всё понятно, если нет, то на то он и форум, что б отвечать на вопросы.

И в конце маленький примерчик реализации монстров:
unit Enemy_Movable_Unit;

interface
Uses
  DXClass, DXSprite, DXDraws,
  Gravity_Unit,
  Enemy_Unit,
  TPoints_Unit,
  TBoom_Unit;

Type
 TEnemy_1 = class (TEnemy)
   Direction       : Byte;
   dx              : Double;
   procedure DoMove(MoveCount: Integer); override;
   Constructor Create (X,Y: Double; Health,Power: Single; Hitpoints:Word);
 end;

implementation
Uses
  Main_Unit;

//+=========================   TEnemy_1 =======================================+
Constructor TEnemy_1.Create (X,Y: Double; Health,Power: Single; Hitpoints:Word);
begin
  Inherited Create(X,Y,Health,Power,Hitpoints);

  Image := MFrm.DXImageList.Items.Find("Enemy_1");
  Z:=1;
  Width := Image.Width;
  Height := Image.Height;

  Direction :=0;
end;
//==============================================================================
Procedure TEnemy_1.DoMove(MoveCount: Integer);
Var
  Speed : Integer;
  dy      : Real;
begin
if not OverlapRect(Engine.SurfaceRect, BoundsRect) then Exit; //для оптимизаци, если вне видимости, то не производить ниже идущие вычисления. помогает если монстор >25

if Self.Health<=0 then
Begin
  dead;
  exit;
end;

//вне карты - умираем
 if (X<0) or (X+32>LevelCols*32) or
    (Y<0) or (Y+32>LevelRows*32) then
    Begin
     Dead;
     Exit;
    end;

inherited DoMove(MoveCount);

  Speed := 200;
  dx := (Speed/1000)*MoveCount;

  Case Direction of
     0: //Left
        Begin
           if Map[trunc ((Y+16)/32), trunc (X/32)]<20 then
                 X := X-dx
           else
               Direction := 1;
        end;
     1: //Right
        Begin
           if Map[trunc ((Y+16)/32), trunc ((X+32)/32)]<20 then
                 X := X+dx
           else
               Direction := 0;
        end;
  end;

 
  Gravity.DoGravity(Self as TSprite, MoveCount);
end;
//+=========================   TEnemy_1 =======================================+
//+=========================     END    =======================================+
end.


Ёще не плохо было б написать копирайт, так как всё это я выдрал из игрулины своей недоделаной, но ПОЛЬЗУЙТЕСЬ на здоровье...


 
Jus   (2004-10-02 17:07) [17]


> Falcon(TFSoft)   (02.10.04 13:36) [16]

благодарю!получил модуль по почте.

InfluenceSprite - это сам персонаж, или все персонажи к которым относится гравитация?
Map[,] - это массив карты, как я понял?

> with InfluenceSprite do
>   begin  
>         if (Map[trunc (Y/32), trunc ((X+16)/32)]<20) and
>            (Map[trunc ((Y+25)/32), trunc ((X+16)/32)]<20-ord(LadderSens))
>    then
>            begin
> ...


Я так понимаю что сдесь InfluenceSprite проверяет своё место положение и прочии свойства по массиву карты.
Растолкуйте пожатуйста этот фрагмент.


 
Falcon(TFSfot)   (2004-10-02 20:31) [18]

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


 
Falcon(TFSfot)   (2004-10-02 20:40) [19]


with InfluenceSprite do
  begin  
        if (Map[trunc (Y/32), trunc ((X+16)/32)]<20) and
           (Map[trunc ((Y+25)/32), trunc ((X+16)/32)]<20-ord(LadderSens))
   then
           begin


Ок. Слушай....
Сначала мы глабальные координаты преобразовываем в координаты масива карты trunc (Y/32), trunc ((X+16)/32), тоесть получаем значение i,j (Map[i,j]), после чего проверяем что это за элемент <20
Тут 20 - означает что это воздух и все остальные элементы через которые можно прлетать, земли(их много типов) например имеет индкексы <10, лестница 19
Эта строчка проверяет выше описанное
Map[trunc (Y/32), trunc ((X+16)/32)]<20)
А эта
(Map[trunc ((Y+25)/32), trunc ((X+16)/32)]<20-ord(LadderSens))
Проверяет не является ли данная ячейка карты лестницей...

Дальше собственно идёт "физика" прыжка, вот и всё...


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

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


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

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

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


 
cyborg ©   (2004-10-03 09:37) [22]


> [20] Jus   (03.10.04 06:16)

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


> [21] Jus   (03.10.04 08:28)

Trunc();


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


> Trunc();

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


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

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


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

изыди ведьма


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

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

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

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


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


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

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


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


ftp://cyborghome.ru/ScreenShots/


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

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


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

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


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


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

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


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

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


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


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


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


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

Фрагмент из программы создания карты по массиву [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.25 end;

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


 
cyborg ©   (2004-10-04 09:40) [32]


> [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-ум)


 
Megabyte-ceercop ©   (2004-10-04 13:15) [33]


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


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

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

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

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


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

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

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


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

>Megabyte-ceercop ©

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

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

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

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

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

с ув. Faclon


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

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

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

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;


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


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

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;


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


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

to Megabyte-ceercop ©

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

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


 
Megabyte-ceercop ©   (2004-10-05 06:11) [39]


> Спрайт прыгнул, полсе чего падал с некоторой скоростью 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;

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


 
Jus   (2004-10-05 06:35) [40]

Megabyte-ceercop ©   (05.10.04 06:11) [39]

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

А если врежится в стену, то взлетит на самый верх этой стены.


 
Jus   (2004-10-05 06:43) [41]

А если сделать что если нажать влево х=х-4(врезолся в стену), то х=х+4, а только после этого проверяет под собой пол, то получится что в полёте, им можно ещё управлять влево право, и если в полёте(падении) прикоснуться к стене то он будет за неё усердно держаться и не падать, пока не отпустить клавишу влево!


 
Megabyte-ceercop ©   (2004-10-05 06:45) [42]


> Falcon(TFSoft)   (05.10.04 01:15) [38]


Спасибо за теплые слова Falcon!  :))
Сразу появилось желание выложить все исходники на общее благо, только вот немогу, только через три года :));

Но могу рассказать по подробнее о физике и устройству игры.

Все спрайты там одинаковы обсолютно, имеют один на всех цикл обработки, даже глобальный - управляющий сценарием (только он невидим, или стоит где нить в виде столбика или флажка :)
имеют все они следующие свойства:

X,Y  - Координаты
Xusk, Yusk   - Скорость по оси Х и Y

Image  - номер картинки
AnimPos - позиция анимации

Ider - Индификатор в котором биты значат примерно такое:

1 - координаты отсчитываются от начала экрана (нампимер счетчики не двигаются вместе с миром, а всегда в одной точке экрана).

2 - Спрайт на заднем плане (за ландшавтом) / если 0 - то на переднем плане.

4 - невидимый;

и т. д.

Более подробно о физике и прыжках:
(Анимацию упускаю)

Например спрайт неподвижен

Xusk := 0;
Yusk := 0;

//*****
//Напомню что в каждом цикле независимо от обстоятельств происходит

X := X + Xusk; //изменение координат объекта в зависимости от его скорости
Y := Y + Yusk;

Yusk := Yusk + 0.1 ; //Постояное воздействие гравитации (скорость растет вниз);

//*********

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

После придания толчка вверх

Для прыжка ровно вверх придаем спрайту толчек в верх

If key = Up  then
     Yusk := - 7;  //Прыжок при нажатии кнопки вверх;

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

Столкновение с землей (прекращение падения) сделано так:

If (Спрайт в земле) then
 begin
    Yusk := 0;
    while (Спрайт в земле) Y := Y - 1;  //выталкиваем спрайт вверх,
             //пока он не окажется ровно на поверхности.
 end;

Движение влево вправо:

If (key = left) and (Xusk > - 10) then Xusk := Xusk - 1.0;
//При нажатии кнопки влево спрайт начнет ускоряться влево до тех пор, пока не достигнет скорости ( -10 );

If (key = Right) and (Xusk < 10) then Xusk := Xusk + 1.0;
//При нажатии кнопки вправо он начнет ускоряться в прова тоже до скорости 10;

Если сперва долго давить вправо, а затем резко влево, то спрайт типа занесет. (какоето время он будет лететь по инерции.

Тут еще нужна сила трения, которая будет останавливать спрайт постоянно.

IF X > 0 then X := X - 0.5;
IF X < 0 then X := X + 0.5; //Трение всегда старается притянуть скорость к нулю.

Ну вот примерно и всё в краце.
Если кто понял, то дальше сам всё додумает :)))


 
Megabyte-ceercop ©   (2004-10-05 06:51) [43]


> Jus   (05.10.04 06:43) [41]

Я тут забыл добавить что проверяю столкновение с ландшавтом не простым DoColision
А выборкой грунта по определенным координатам относительно спрайта

If Land_AT (X + 50 , Y + 100) = Grunt then Замля_подомной

If Land_AT (X + 100 , Y + 50) = Grunt then Замля_справа

и т. д.
То есть я не просто знаю столкнулся или нет, а знаю с какой стороны это столкновение (земля или стена);


 
Jus   (2004-10-05 06:57) [44]

Falcon(TFSoft)

Если делать как ты говорил, то наверное получится, но не совсем то. Если нажимать влево, то проверяется Х+ширина, а если вправо, то Х.(я правильно понял?)

Значит он ходит влево проверяется Х+ширина, кирпич кончился, он полетел вниз.Ок!

Если он находится на одном кубике кирпича к примеру, а вокруг пусто:
 Нажимаю влево, идёт, наполовину свисает с левого края кирпича, тоесть Х над пропостью, но проверяется х+ширина, резко нажимаю вправо - теперь проверяется Х, он уже находится над пропостью и сразу падает.


> cyborg ©   (04.10.04 09:40) [32]


> Момент дохода до назначения (ну и слово :), координата игрока
> будет кратна 32-ум, т.е. if (X mod 32=0) and (Y mod 32 =
> 0)
then (остановить игрока, посмотреть, есть ли под ним
> земля, если есть обработать ввод, если нет, то падает).
>

Выдаётся ошибка:
[Error] Unit1.pas(854): Operator not applicable to this operand type
[Fatal Error] Project1.dpr(5): Could not compile used unit "Unit1.pas"

(X mod 32=0) хотя это уменя не работает по неизвестным причинам(может это используется в Делфи7 и выше, а у меня 6-я), то раскажи что это означает подробно.  Это я так понял Если Х делится на 32, но не понимаю зачем =0 ? не разу mod не использовал.


 
Megabyte-ceercop ©   (2004-10-05 07:14) [45]


> Jus   (05.10.04 06:57) [44]

mod - возвращает остаток от деления
> (X mod 32=0)

это условие правильнее писать так:
((X mod 32) = 0)
Условие это будет соблюдаться в том случае, если X кратно 32 (т.е. делится на 32 с нулевым остатком)
Здесь означает что спрайт стоит ровно в клетке карты.


 
Jus   (2004-10-05 07:21) [46]

Понял, X - у нас Double;
((round(X) mod 32) = 0)


 
Jus   (2004-10-05 07:39) [47]

С падением с кирпичей вроде разобрались, благодаря вам, падает с кирпичей исправно!:)
От каждого из ваших советов брал по чуть-чуть, и немножко своего добавил(или оставил):)

procedure TPlayer.DoMove(MoveCount:Integer);
var
begin{1}
 If ((round(player1.X) mod 32)=0) then If (ScrMap[Trunc(player1.ScanX),Trunc(player1.ScanY+1)]) =0 then falling:=true else falling:=false;// взял из совета Cyborga, спасибо
 If Falling=false then begin
 If isRight in Form1.DXInput.States then begin x:=x+4; ScanX:=ScanX+0.125; end;// -||-Falcon(TFSoft)+своё
 If IsLeft  in Form1.DXInput.States then begin x:=x-4; scanX:=ScanX-0.125; end;// -||-Falcon(TFSoft)+своё
 end;
 If Falling=true then begin Y:=Y+8; ScanY:=ScanY+0.25 end; //NikeOLD ©   (01.10.04 14:36) [3] постоянное падение
 collision;
 end;{1}

procedure TPlayer.DoCollision(Sprite:TSprite;var Done:Boolean);
begin
/////////////
end;

И остольных всех тоже благодарю за внимание, теперь буду проверять на столкновение со стенами, мож по принципу Falcon(TFSoft) или Megabyte-ceercop © .


 
cyborg ©   (2004-10-05 10:13) [48]

так чтоли переделай

procedure TPlayer.DoMove(MoveCount:Integer);
var
begin{1}
 if ((round(player1.X) mod 32)=0) and ((round(player1.Y) mod 32)=0) then
 falling:=(ScrMap[Trunc(player1.ScanX),Trunc(player1.ScanY+1)]) =0;

If Falling then
begin
  Y:=Y+8;
  ScanY:=ScanY+0.25;
end else
begin
   If isRight in Form1.DXInput.States then begin x:=x+4; ScanX:=ScanX+0.125; end;
   If IsLeft  in Form1.DXInput.States then begin x:=x-4; scanX:=ScanX-0.125; end;
end;

collision;
end;{1}

И-то мне кажется, что криво ты делаешь ;)


> [34] Faclon(TFSoft)   (04.10.04 20:45)

Вроде они там поклеточно бегали :)


 
Jus   (2004-10-05 14:59) [49]


> так чтоли переделай


> falling:=(ScrMap[Trunc...

falling:boolean;
почему ты так написал, и чё обозначает?

>
> И-то мне кажется, что криво ты делаешь ;)

Почему это криво, всё пашет, чё кривого то?:(
> Вроде они там поклеточно бегали :)

Там то по клеточно, а почему бы не сделать по пиксельно? Ты думаеш, что на лестницу трудно будет попасть или что, кирпичи пробивать? будет нетрудно, он по 4 пикселя бегает а не по 1, а на счёт кирпичей не переживай, всё будет нормально!:)


 
cyborg ©   (2004-10-05 15:04) [50]


> [49] Jus   (05.10.04 14:59)

Это обозначает простоту............. и так надо! :)


 
Jus   (2004-10-05 15:27) [51]


> cyborg ©   (05.10.04 15:04) [50]
>
> > [49] Jus   (05.10.04 14:59)
>
> Это обозначает простоту............. и так надо! :)

Ну хорошо!
А кривого то чё?:) почему?


 
cyborg ©   (2004-10-05 15:44) [52]


> [51] Jus   (05.10.04 15:27)
> Ну хорошо!
> А кривого то чё?:) почему?

Не нравится мне реализация ;)


 
Jus   (2004-10-05 16:22) [53]

Всётаки считаешь, что лучше ходить поклеточно? если да, то к примеру я нажал идти вправо, он прошёл пол клетки и я резко нажал вправо, он пойдёт сразу вправо или сначало пройлёт клетку до конца, а потом развернётся и пойдёт?


 
Megabyte-ceercop ©   (2004-10-05 16:30) [54]

У меня в самом первом Киркопе он ходил поклеточно, но мог разворачиваться напол пути между клетками. А останавливался только ровно в клетке. Для первого раза этого достаточно, к тому же позваляет избежать сомнительных ситуаций в логических играх.
Точно знаешь какую клетку герой будет капать.


 
Jus   (2004-10-05 16:51) [55]

Я наверное сделаю так: нажал, отпустил кнопку - он пошёл сам пока не остановился в конце клетки? Ок:)?!


 
Falcon(TFSoft)   (2004-10-05 20:36) [56]

to Jus   (05.10.04 16:51) [55]

Мне кажется, что лутше сделать как в ceercop 1.0(by Megabyte) закачай, да посмотри как там всё плвано бегает...

to Megabyte-ceercop ©
А тебе случайно не влом будет посмотреть на мою про альфа версию игрушки (800k). Мне просто хочется оценить её с точки зрения человека, у кторого уже есть 2-е поколение игры...

если да то намыль мне письмецо... falcon_support@ua.fm


 
Megabyte-CeerCop ©   (2004-10-07 13:15) [57]

Написал уже...


 
Jus   (2004-10-07 16:26) [58]

Кто желает посмотреть, что поучается? Бегает где надо и как надо, лазиет по лестницам, падает и т.д.:) Кому дать посмотреть?...
Заодно посмотрите графику в динамике, а не на скринах:)
архив RАR 250Кб.


 
Jus   (2004-10-08 09:14) [59]

переход
http://delphimaster.net/view/9-1095732632/



Страницы: 1 2 вся ветка

Форум: "Игры";
Текущий архив: 2005.01.23;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.83 MB
Время: 0.036 c
1-1105018562
Лёха
2005-01-06 16:36
2005.01.23
Окно


1-1105326484
barbar
2005-01-10 06:08
2005.01.23
Нужно нарисовать на форме порялка 1000 элементов.


1-1105539217
NeDum
2005-01-12 17:13
2005.01.23
ProgressBar


3-1103416263
Fantasy
2004-12-19 03:31
2005.01.23
SQL


4-1102398395
Помощник админа
2004-12-07 08:46
2005.01.23
Логин пользователя, запустившего процесс





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский