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

Вниз

Создание анимации для управляемого спрайта   Найти похожие ветки 

 
.cpp   (2004-10-06 17:34) [0]

Сам код для движущегося на месте спрайта:

constructor TSprite11.Create(AParent: TSprite);
begin
 inherited
Create(AParent);
 Image := Form1.DXImageList1.Items.Find("tower1");
 X := 100;
 Y := 100;
 AnimStart := 0;
 AnimLooped := true;
 AnimCount := 6;
 AnimSpeed := 0.1;
end;

// с этим обработчиком спрайт двигается но не анимируется
procedure TSprite11.DoMove(MoveCount: integer);
begin
 inherited DoMove(MoveCount);
 if isLeft in Form1.DXInput1.States then begin
    X := X-2;
 end;

 if isRight in Form1.DXInput1.States then begin
    X := X+2;
 end;
end;

procedure TForm1.DXTimer1Timer(Sender: TObject; LagCount: Integer);
begin
  DXInput1.Update;
  DXSpriteEngine1.Move(1);
  DXDraw1.Surface.Fill(15);
  DXSpriteEngine1.Draw;
  DXDraw1.Flip;
end;

Вопрос следующий:

известно как создать анимацию для неподвижного спрайта, но как быть  если он управляется с клавиатуры ( например при нажатии "ВПРАВО" спрайт должен перемещаться с анимацией - двигать чем он там должен  :) ), ну как в том же Mario нажимаем "вперёд" включается анимация и он бежит, отпускаем - анимация останавливается. он не бежит?


 
Falcon(TFsoft) ©   (2004-10-06 19:37) [1]

Если ты имееш ввиду разную анимацию, тоесть, на примере того же марио, если он влево идёт, значит крутится анимация влево, если вправо, значит анимация движения вправо, если прыжок то ... и т.д.
То есть(на мой взгляд) 2 варианта:
-----------------1-----------------
На каждую анимацию заводит свой рисунок в DXImageList1.Items, и при нажатии нужной клавиши включать соответствующею анимацию, путём выбора нужного имаджа
 Image := Form1.DXImageList1.Items.Find(ххххх);

Вот, к примеру участок кода в котором включается, точнее переключается анимация при взрыве (\DelphiX_forD6\Samples\Sprite\Shoot\Main.pas):

//создание самого спрайта
constructor TPlayerSprite.Create(AParent: TSprite);
begin
 inherited Create(AParent);
 Image := MainForm.ImageList.Items.Find("Machine");
//судя по всему ты не указал этих параметров, и аним. не работал
 Width := Image.Width;
 Height := Image.Height;

//ну тут твои координаы
 X := 20;
 Y := 240-Height div 2;
 Z := 2;}
//вот настройки анимации, как видим не все 4х параметра...
 AnimCount := Image.PatternCount;
 AnimLooped := True;
 AnimSpeed := 15/1000;
end;

procedure TPlayerSprite.DoCollision(Sprite: TSprite; var Done: Boolean);
begin
 if Sprite is TEnemy then
 begin
//А вот собственно и сама замена спрайта с обыкновенного на взрыв
   Image := MainForm.ImageList.Items.Find("Explosion");
   Width := Image.Width;
   Height := Image.Height;

   AnimCount := Image.PatternCount;
   AnimLooped := False;
   AnimSpeed := 15/1000;
   AnimPos := 0;
 end;
end;


Если тебе необходимо сделать неоднократную замену, то сотвори :) функцию, для замены спрайта, что б не писать каждый раз одно и тоже(for examle as this):

procedure SprReplace(SprToFound:Integer; isLooped:Boolean=true);
begin
   Image := MainForm.ImageList.Items.Find("PlrSpr_anim_"+IntToSTr(SprToFound));
   Width := Image.Width;
   Height := Image.Height;

   AnimCount := Image.PatternCount;
   AnimLooped := isLooped;
   AnimSpeed := 15/1000;
   AnimPos := 0;
end;


С её помощью можно заменять спрайты у игрока на любые, но все их прийдётся расфасовывать в отдельный ImageList.Items (тоесть в отдельный рисунок).

-----------------2-----------------
Можно сделать мульти-анимационный спрайт, другими словами забацать абсолютно все фреймы анимации (отдельного объекта) в отдельный рисунок (который будет находится в ImageList-е как один Items разумеется).

После чего прокручивать анимацию вручную, делая выборку из этого рисунка. Это будет выглядеть приблизительно вот так(псевдокод):

Создаём структуру, отвечающую за анимацию
ype
  TAS = record
     SCount   : Integer;
     SLooped: Boolean;
     SSpeed   : Double;
     SStart   : Integer;
//можно добавить ещё своё  
end;

Сначала вместе с созданием самого объекта инициализируем все его виды анимации:
procedure TPlayer.InitAnimation;
Begin
     SCount := 6; // всего позиций для анимирования
     SPos := 0; // текущая позиция анимирования

     //const s_right=0
     //Right
     SSeries[s_right].SCount := 4; //всего фреймов в этой анимации  
     SSeries[s_right].SStart := 0; // начальный фрейм в общем списке имеет индекс 0

     SSeries[s_left].SCount := 4;      //Left
     SSeries[s_left].SStart := 4; //имеет индекс 4...

     SSeries[s_Up].SCount := 2;      //Up
     SSeries[s_Up].SLooped:= false;
     SSeries[s_Up].SSpeed := AnimSpeed/2;
     SSeries[s_Up].SStart := 12;
{*** и т.д.}

после чего с помощью какой либо процедуры, вызываемой из Sprite.DoMove, прокручивать текущую анимацию:
procedure DoMoveХ(MoveCount: Integer);
begin
  with SSeries[SPos] do
  begin
     AnimCount := SCount;
     AnimLooped:= SLooped;
     AnimStart := SStart;
     if SCurrent<>SPos then //Выбрана новая серия анимации, тоесть была ходьба стал бег надо обнулиьт счётчик
        begin
           AnimPos := 0;
           SCurrent := SPos;
        end;

     else
        AnimSpeed := SSpeed;        
  end;
end;

Всё саму прокрутку анимации будет выполнять SpriteEngine, только надо не забывать вызывать эту процедуру DoMoveХ.


Итог:
Первый вариант приемлем, если в игре не будет уж очень много объектов(и соответственно не очень много различных анимаций, у каждого из них). Он не так сложен в эксплуатации и отладке..

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

Хотя первый вариант может быть лишён своих недостатков в гибкости , если передавать в функцию SprReplace(...) большее количество параметров.

Вот вам моё мнение.
С ув. Falcon


 
.cpp   (2004-10-08 19:37) [2]

Не совсем понятен 2-й способ (особенно заинтерисовал). Понятно как выбрать нужный набор спрайтов для события и проиграть их.

Сейчас задача сводится лишь к тому, чтобы ОСТАНОВИТЬ анимацию в тот момент, когда отпускается кнопка "ВПРАВО" (например) и включить анимацию, когда кнопка нажимается.

А пока она включается, если я нажимаю "ВПРАВО" (например)  и спрайт перемещается по экрану (анимировано бежит); отпускаю "ВПРАВО", спрайт останавливается, но анимация не прекращается (хотя должна).

Как можно остановить анимацию? Я так полагаю AnimLoop := False или AnimCount := 0 можно включить, но где.


 
cyborg ©   (2004-10-09 08:21) [3]

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

Когда кнопку нажали, ставь спрайту флаг (не знаю какой там он у тебя) Animated, Anim, Animate или ещё какой, значение True. Когда кнопку отпускают, ставь значение флага анимации равным False. Когда рисуешь спрайт, смотришь значение этого флага, если он равен True то двигаешь прямоугольник выводимого рисунка на нужный кадр, если значение флага равно False, то коорднаты выводимого прямоугольника не изменяй.


 
Falcon(TFSoft) ©   (2004-10-09 13:50) [4]

Делаеш так:

procedure DoMove(MoveCount: Integer);
begin
AnimPos := 0;
***
if key ** then Animate1
if key ** then Animate2
и т.д
end;


Тоесть при DoMove в начале делаеш что б спрайт стоял, а если в DoMove нажимается клавиша движения, то делаеш анимацию нужную...


 
.cpp   (2004-10-11 14:56) [5]

Во-о-о сейчас всё отлично работает, благодарю за ответ!

Кстати никто не знает как для метода DoCollision узнать координаты столкновения? Дело в том, что при выстреле в объект (стена, крепость) нужно организовать взрыв - этоя знаю как сделать.


 
Falcon(TFSoft) ©   (2004-10-11 21:29) [6]


//==============================TGun_Bullet====================================
Procedure TGun_Bullet.DoCollision(Sprite: TSprite; var Done: Boolean);
Begin
//необязательно
 inherited DoCollision(Sprite, Done);

 if Sprite is TFortification then
 begin
 Dead;
  TDestructiveBoomWave.Create(Self.X, Self.Y);   //твоя процедура создание взрыва, можеш заменить на что угодно
  // или что одно  тоже TDestructiveBoomWave.Create(X, Y);
 end;

 if (Sprite is TMapPiece) then
 begin
 Dead;
 TDestructiveWave.Create(X, Y);
 end;
{если есть нужда в доступе конкретных полей класса с которым столкнулся, то используй следующий механизм, к примеру}

 if Sprite is TCastle then
 begin
 Dead; // сама пуля уничтожается, при необходимосте
  TDestructiveBoomWave.Create(Self.X, Self.Y);   // создаём взрывную волну
  (Sprite as TMapPiece).MakeDamage(Self.Power);
  {Объясню конкретнее.
   MakeDamage - процедура класса TMapPiece, описанная как:
   
   procedure TMapPiece.MakeDamage(DamagePower: Single);
   и реализованная как
   
   procedure TMapPiece.MakeDamage(DamagePower: Single);
   begin
        Self.health := Self.health-DamagePower;
        *** и т.д.
   end;
   
   можеш написать свой вариант.
   
   Так вот в эту процедуру мы передаём силу пули MakeDamage(Self.Power);
   Конечно, для этого необходимо в класе пули инициализировать такую переменную:
   class TGun_Bullet = class(TimageSprite)
         ***
            Power : Single;
         ***
   end;
   }
 end;
end;



Вообщем я думаю пример более чем красноречиво отвечает на твой вопрос....


 
.cpp   (2004-10-12 12:59) [7]

Всё!
ТАНК видит препятствия, стреляет, создаётся взрыв при выстреле в поверхность, анимируются некоторые объекты (башня, деревья, трова).

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

Есть пример в котором пошагово создаётся игра (космический корабль, может кто видел) там в 3 уроке рассматривается поворот спрайта, но автор утверждает, что в DelphiX это большая проблема. Он предлагает скачать модифицированный им же модуль DXSprite.pas в котором он заменил метод DoDraw для возможности поворота на заданный угол.

Дело в том, что этим модулем нельзя воспользоваться, много ошибок.

У меня DelphiX для Delphi 7 и в моём модуле DXSprite.pas есть такой метод TImageSpriteEx.DoDraw он кажется отвечает за разворот спрайтов (возможно он добавлен в DelphiX для Delphi 7). Никто не пользовался? Может есть отдельный метод для этого?


 
Falcon(TFsoft) ©   (2004-10-12 22:38) [8]

Привет! Снова я... :) вы мне рады :)
Вобщем предлагаю возможно не самый лучший варинат, но если использовать не TimageSprite а его наследник TimageSpriteEX, то у него есть такое свойство Alpha - прозрачность(0-255), Angel - угол (0.0-360.0). Вот его я тебе и советую использовать. Для этого просот замени

= class(TimageSprite)
на = class(TimageSpriteEX)

Дай скриншоты посмотреть :)


 
Megabyte-ceercop ©   (2004-10-13 06:37) [9]


> Falcon(TFsoft) ©   (12.10.04 22:38) [8]

Да, Falcon дело говорит.
Видать автор урока про танчик нифига в DelphiX Не смыслит.

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


 
.cpp   (2004-10-14 08:11) [10]

Falcon я заметил в этом классе метод DoDraw (с помощью него можно кажется поворачивать спрайт), но не знаю как...

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

Кстати ящик свой проверь.

Megabyte-ceercop кстати да, только спрайты героев. Если не узнаю как разворот делается (ну плавный на угол), то придётся заготовить спрайты по поворотам (вверх, вниз, вправо, влево,
вверх+вправо, вверх+влево, вниз+вправо, вниз+влево) - так в Diablo. Будет проще, но погрубее.


 
Falcon(TFSoft) ©   (2004-10-14 22:58) [11]

ok here is a simple example:

Procedure TEnemy_1.DoMove(MoveCount: Integer);
begin
inherited DoMove(MoveCount);
if key then
  begin
    Self.Angle := Self.Angle + ValueOfAddAngle;//короче просто изменяеш значение угла и всё, оно само тебе его повернёт.
  end;
end;


 
Megabyte-ceercop ©   (2004-10-15 07:31) [12]


> Кстати ящик свой проверь.

Кидай и мене, тоже погляжу (если не боишся что обосру ;).


 
.cpp   (2004-10-17 20:02) [13]

Falcon ты (вы) мне здорово помог (ли).

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

Megabyte-ceercop  тоже тебе (вам) кинул фоты.


 
.cpp   (2004-10-17 20:12) [14]

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

Вообще я заметил, что это довольно таки проблематично сделать, чтобы точно из пушки вылетал.

Смотрел несколько исходников, но везде выстрел неточен. Есть небольшие смещения от пушки. Но у меня эти смещения огромны.

Вот как я делаю выстрел:
_______________________

if isButton1 in Form1.DXInput1.States then begin            // ВЫСТРЕЛ
   if (FCounter-FOldTamaTime>=35) then begin
     with TEnemy.Create(Engine)do begin

      X := self.X + cos256(self.angle)*50;
      Y := self.Y + sin256(self.angle)*50;

      angle_enemy := self.angle; // передал угол в метод полёта //снаряда
     end;
     FOldTamaTime := FCounter;
   end;


 
Megabyte-ceercop ©   (2004-10-18 11:11) [15]


> ты (вы)


> помог (ли).


> тебе (вам)

:))) Вежливо...

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


 
.cpp   (2004-10-20 13:04) [16]

Хорошо. Но эту проблему я так и нерешил ;)



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

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

Наверх




Память: 0.52 MB
Время: 0.039 c
3-1104314918
Gemini
2004-12-29 13:08
2005.01.30
Как добавить драйвер MS SQL?


6-1100514038
arhis
2004-11-15 13:20
2005.01.30
Sockets Delphi 7


4-1102597995
Timer
2004-12-09 16:13
2005.01.30
SystemTimer


3-1103943993
Guitar
2004-12-25 06:06
2005.01.30
Ошибка Key column information is insufficient or incorrect ... ?


1-1106164534
Degobar
2005-01-19 22:55
2005.01.30
Image1.Canvas.Pixels выдает ошибку ????





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский