Создание базового движка для игры. Часть 2. Анимация, Столкновения и воспроизведения музыки - Delphi, Pascal, ObjectPascal - Программирование
Навигация по сайту
Сайт:

Дополнительно:

Файловый архив:

Каталог статей:

Форум:


Категории раздела
Delphi, Pascal, ObjectPascal [18]
Программирование на Delphi, Pascal, ObjectPascal
C, C++, C# [7]
Программирование на C, C++, C#
ПХП (PHP) [6]
Все что связано с программированием на PHP.
DirectX [0]
Программирование с использованием графического API DirectX
OpenGL [0]
Программирование с использованием графического API OpenGL
Работа с базами данных (БД) [0]
Работа с базами данных MySQL и т.д. Разработка, теории, алгоритмы.
Сетевое программирование [0]
Сетевое программирование, организация сетей.
Программирование игр [0]
Все что связано с программированием игр, организацией их разработки.
Работа с мультимедиа данными [0]
Загрузка, обработка, воспроизведение и все что связано со звуком и видео.
Работа с устройсвами ввода и вывода [0]
Программирование устройств ввода и вывода. Работа с геймпадом, рулем и многим другим.
Программирование HTML 5 игр [0]
Программирование HTML 5 игр, html верстка, JS (JavaScript)
Остальное [0]
Все остальное, что не попадает ни под одну категорию.

Мини-Опрос
Вы следите за обновлениями конструкторо игр, движков?
Всего ответов: 345

Партнеры сайта
....

 Главная » Статьи » Программирование » Delphi, Pascal, ObjectPascal » Создание базового движка для игры. Часть 2. Анимация, Столкновения и воспроизведения музыки

Создание базового движка для игры. Часть 2. Анимация, Столкновения и воспроизведения музыки

00:42
Откройте наш проект (то что мы сделали в первой части: http://quadrathell.do.am/publ/13-1-0-147)
Давайте начнем с анимации. Откройте модуль uGraphics. В type добавьте следующую строчку:
Code

TAnimationMode = (amNone,amLoop,amPlayOnce);

это наш тип анимации: amNone значит нет анимации, amLoop анимация проигрывается бсконечно, amPlayOnce анимация проигрывается один раз... Теперь нам надо изменить класс TSprite добавив новые перменные и функции, таким образом класс TSprite будет выглядеть следующим образом:
Code

TSprite = class //наш спрайт =)
public
Position: TCoordinates; //координаты спрайта (X,Y)
Tag: Integer; //номер спрайта
Name: String; //имя спрайта

Destroy: Boolean; //если Destroy = true то спрайт рисоваться не будет
FramesCount: Integer; //число кадров
FrameID: Integer; //номер проигрываемого кадра
Frames: array[0..999] of TImage; //все кадры
Interval: Integer; //интервал между показами
CurrentFrame: TImage; //проигрываемый кадр
AnimationMode: TAnimationMode; //тип анимации
Other: TSprite; //столкнувшийся объект

function AddFrame: TImage;
procedure Update;
constructor Create; //конструктор класса
end;

Обратите внимание, теперь у нас нету переменной Iamge, следовательно нам нужно переписать конструктор класса TSprite и функцию обновления класса TViewer.
Code

//конструктор класса TSprite
constructor TSprite.Create; //конструктор спрайта
begin
inherited Create; //создаем спрайт

Frames[0]:= TImage.Create(nil); //создаем первый кадр
Frames[0].Visible:= false; //делаем его невилимым
Frames[0].AutoSize:= true; //узнаем размер кадра
CurrentFrame:= Frames[0]; //проигрываемый кадр равен нулевому кадру
FramesCount:= 1; //всего 1 кадр
FrameID:= 0; //номер проигрываемого кадра равен нулю
Interval:= 3; //интервал (задержка) вопроизведения анимации
end;
//функция обновления класса TViewer
procedure TViewer.Update; //обновление изображения
Var
i: Integer; //перменная i понадобится нам для цмкла for
begin
BackBuffer.Canvas.CopyRect(Rect(0,0,Width,Height),Canvas,Rect(0,0,Width,Height)); //копируем с основного экрана на задний буффер
BackBuffer.Canvas.Brush.Color:= $000000; //выбираем цвет для заливки
BackBuffer.Canvas.FillRect(Rect(0,0,Width,Height)); //заливаем экран

for i:= 0 to Scene.SpritesCount - 1 do //цикл для каждого спрайта на сцене
if Scene.Sprites[i].Destroy then //если объект не уничтожен
//то рисуем его в зависимости от положения камеры
BackBuffer.Canvas.Draw((Scene.Sprites[i].Position.X - (Scene.Sprites[i].Frames[0].Width div 2)) -
(Scene.Camera.Position.X - (Scene.Camera.Width div 2)),
(Scene.Sprites[i].Position.Y - (Scene.Sprites[i].Frames[0].Height div 2)) -
(Scene.Camera.Position.Y - (Scene.Camera.Height div 2)),
Scene.Sprites[i].CurrentFrame.Picture.Graphic);

Canvas.CopyRect(Rect(0,0,Width,Height),BackBuffer.Canvas,Rect(0,0,Width,Height)); //копируем все на основной экран
end;

думаю здесь все понятно, теперь опишем новые функции и процедуры для класса TSprite:
Code

function TSprite.AddFrame: TImage; //функция добавления кадра
begin
Frames[FramesCount]:= TImage.Create(nil); //создаем новый кадр
Frames[FramesCount].AutoSize:= true; //узнаем размер кадра
Result:= Frames[FramesCount]; //результат наш новый кадр
FramesCount:= FramesCount + 1; //число кадров стало на один больше
end;

procedure TSprite.Update; //обновление спрайта
begin
case AnimationMode of
amNone: //если нет анимации, то
begin
CurrentFrame:= Frames[0]; //текущий кадр равен нулевому кадру
FrameID:= 0; //номер кадра равен нулю
end;
amLoop: //если цикличная, то
begin
FrameID:= FrameID + 1; //текущей номер кадра больше на один
CurrentFrame:= Frames[FrameID div Interval]; //текущий кадр равен кдру с номером FrameID c задержкой Interval
//если кадр больше или равен чеслу кадров с задержкой Interval, то
if FrameID >= (FramesCount - 1) * Interval then FrameID:= 0; //текущей номер равен нулю
end;
amPlayOnce: //если надо проиграть один раз, то
if FrameID < (FramesCount - 1) * Interval then //проверяем, меньше ли значение FrameID
begin //и если меньше, то
FrameID:= FrameID + 1; //текущей номер кадра больше на один
CurrentFrame:= Frames[FrameID div Interval]; //текущий кадр равен кдру с номером FrameID c задержкой Interval
end;
end;
end;

Далее нам нужно создать процедуру Update в классе TScene:
Code

procedure TScene.Update; //процедура обновления сцены
Var
i: Integer;
begin
for i:= 0 to SpritesCount - 1 do
Sprites[i].Update; //обновляем каждый спрайт
end;

с анимацией кажись разобрались, теперь давайте проверим ее в деле Для начала подготовьте картинки для анимации, у меня это будет 16 картинок составляющих анимацию... Откройте модуль uMain и в обработчике событий удалите код добавляющий спрайты на сцену (если они у вас есть :)) и вставьте данный код:
Code

with GameViewer.Scene.AddSprite do //добавляем новый спрайт
begin //и выбираем его для изменения параметров
AnimationMode:= amLoop; //анимация цикличная
Frames[0].Picture.LoadFromFile('Data\Images\1.png'); //загружаем первый кадр
Frames[0].Transparent:= true; //устанавливаем прозрачность

for i:= 1 to 16 do //цикл для загрузки 16'ти кадров
with AddFrame do //добавляем новый кадр
begin
Picture.LoadFromFile('Data\Images\' + IntToStr(i) + '.png'); //загружаем картинку
Transparent:= true; //устанавливаем прозрачность
end;
end;

так же не забудьте в таймер вписать следующую строчку:
Code

GameScene.Update;

иначе анимация не будет воспроизводиться Я советую вам использовать формат png для ваших игр, т.к. картинка в формате png весит не много, и так же грузится из фала альфа текстура! скачать компонент для загрузки png картинок можно здесь: http://ifolder.ru/9783150
Если сейчас запустить приложение, то вы увидите как все работает =) наша картинка анимированная ура!!

Пора приступить к столкновениям создайте новый модуль и назовите его uCollisions я приведу полный код модуля:
Code

unit uCollisions;

interface

uses
uGraphics;

//функции обработки столкновений
function IsCollision(Scene: TScene; Obj1: TSprite; Tag: Integer): Boolean; overload;
function IsCollision(Scene: TScene; Obj1: TSprite; Obj2: TSprite): Boolean; overload;

implementation

//*Collisions*//
function IsCollision(Scene: TScene; Obj1: TSprite; Tag: Integer): Boolean;
Var
i: Integer;
Obj2: TSprite;
begin
Result:= False; //изначально мы результат равен False
//тоесть мы не счем не столкнулись
for i:= 0 to Scene.SpritesCount - 1 do //проверяем каждый объект
if Scene.Sprites[i].Tag = Tag then //если tag совпадает
if (not Obj1.Destroy) and (not Scene.Sprites[i].Destroy) then //и если объекты не уничтожен
begin
//то проверяем на столкновения
Obj2:= Scene.Sprites[i];

if (((Obj1.Position.X + Obj1.CurrentFrame.Width / 2) >= (Obj2.Position.X - Obj2.CurrentFrame.Width / 2)) and
((Obj1.Position.X - Obj1.CurrentFrame.Width / 2) <= (Obj2.Position.X + Obj2.CurrentFrame.Width / 2))) and
(((Obj1.Position.Y + Obj1.CurrentFrame.Height / 2) >= (Obj2.Position.Y - Obj2.CurrentFrame.Height / 2)) and
((Obj1.Position.Y - Obj1.CurrentFrame.Height / 2) <= (Obj2.Position.Y + Obj2.CurrentFrame.Height / 2))) then
begin
//и если столкнулся
Obj1.Other:= Obj2; //выбираем Other объект
Result:= True; //результат True
end;
end;
end;

function IsCollision(Scene: TScene; Obj1: TSprite; Obj2: TSprite): Boolean;
begin
Result:= False;//изначально мы результат равен False
//тоесть мы не счем не столкнулись
if (not Obj1.Destroy) and (not Obj2.Destroy) then // если объекты не уничтожен
//то, проверяем столкнулись ли объекты
if (((Obj1.Position.X + Obj1.CurrentFrame.Width / 2) >= (Obj2.Position.X - Obj2.CurrentFrame.Width / 2)) and
((Obj1.Position.X - Obj1.CurrentFrame.Width / 2) <= (Obj2.Position.X + Obj2.CurrentFrame.Width / 2))) and
(((Obj1.Position.Y + Obj1.CurrentFrame.Height / 2) >= (Obj2.Position.Y - Obj2.CurrentFrame.Height / 2)) and
((Obj1.Position.Y - Obj1.CurrentFrame.Height / 2) <= (Obj2.Position.Y + Obj2.CurrentFrame.Height / 2))) then
begin
//и если столкнулся
Obj1.Other:= Obj2; //выбираем Other объект
Result:= True; //результат True
end;
end;

end.

Теперь проверим столкновения в действии, ну для начала создайте два объекта и у второго поставьте значение Tag равное одному.
Code

with GameViewer.Scene.AddSprite do //добавляем новый спрайт
begin //и выбираем его для изменения параметров
AnimationMode:= amLoop; //анимация цикличная
Frames[0].Picture.LoadFromFile('Data\Images\1.bmp'); //загружаем первый кадр
Frames[0].Transparent:= true; //устанавливаем прозрачность
end;

with GameViewer.Scene.AddSprite do //добавляем новый спрайт
begin //и выбираем его для изменения параметров
AnimationMode:= amLoop; //анимация цикличная
Frames[0].Picture.LoadFromFile('Data\Images\1.gif'); //загружаем первый кадр
Frames[0].Transparent:= true; //устанавливаем прозрачность

Position.X:= 100;
Tag:= 1;

for i:= 1 to 16 do //цикл для загрузки 16'ти кадров
with AddFrame do //добавляем новый кадр
begin
Picture.LoadFromFile('Data\Images\' + IntToStr(i) + '.gif'); //загружаем картинку
Transparent:= true; //устанавливаем прозрачность
end;
end;

GameScene.Camera.CameraObject:= GameScene.Sprites[0]; //привязываем камеру к объекту

далее измените обработчик события OnTimer следующим образом:
Code

GameViewer.Update; //обналвяем основной экран для рисования
GameCamera.Update; //обналвяем камеру
GameScene.Update; //обналвяем сцену

//перемещаем спрайт в зависимомти от нажатой клавиши
if OnKey(VK_LEFT) then GameScene.Sprites[0].Position.X:= GameScene.Sprites[0].Position.X - 4;
if OnKey(VK_RIGHT) then GameScene.Sprites[0].Position.X:= GameScene.Sprites[0].Position.X + 4;
if OnKey(VK_UP) then GameScene.Sprites[0].Position.Y:= GameScene.Sprites[0].Position.Y - 4;
if OnKey(VK_DOWN) then GameScene.Sprites[0].Position.Y:= GameScene.Sprites[0].Position.Y + 4;

if isCollision(GameScene,GameScene.Sprites[0],GameScene.Sprites[1]) then GameScene.Sprites[0].Other.Destroy:= true;

запустите приложение. Теперь при столкновении со вторым объектом, то второй объект умрет но это как то не интересно без музыки и звуков, давайте напишем модуль специальный для этих целей! Для начала скачайте следующий файл: http://ifolder.ru/9784983, это библиотека Bass она нам поможет со звуком. Файл Bass.pas и Bass.dll должны всегда быть в папке с игрой. создайте новый модуль и назовите его uAudio

Code

unit uAudio;

interface

uses
Windows, Bass;

//процедуры для работы со звуком
procedure InitSongs(Handle: Hwnd);
procedure FreeSongs(Stream: HStream);
procedure PlaySong(Stream: HStream; FileName: String; Loop: Boolean);

implementation

//*Song*//
procedure InitSongs(Handle: Hwnd); //инициализация
begin
BASS_Init(-1,44100,0,Handle,0); //инициализируем Bass
BASS_Start(); //и запускаем его
end;

procedure FreeSongs(Stream: HStream); //освобождение памяти
begin
BASS_Stop(); //Останавливаем Bass
BASS_ChannelStop(Stream); //останавливаем каннал
BASS_StreamFree(Stream); //и освобаждаем его
BASS_Free(); //освобождаем Bass
end;

procedure PlaySong(Stream: HStream; FileName: String; Loop: Boolean); //функция проигрывания
begin
if not Loop then // если не Loop (не повторяется)
Stream:= BASS_StreamCreateFile(False,PChar(FileName),0,0,0) //то воспроизводим звук/музыку без цикла
else //иначе
Stream:= BASS_StreamCreateFile(False,PChar(FileName),0,0,BASS_SAMPLE_LOOP); //воспроизводим звук/музыку с циклом

BASS_ChannelPlay(Stream,True); //проигрываем звук
end;

end.

Добавьте в обработчик события главной формы OnCreate следующюю строчку кода:
Code

InitSongs(Handle); //инициализируем Bass
PlaySong(AudioStream,'Data\Audio\world.ogg',true); //включаем музыку

и в обработчик OnDestroy:
Code

FreeSongs(AudioStream); //Освобождаем bass

ВНИМАНИЕ! эти две строчки (не считая PlaySong) должны всегда присутвовать в коде, иначе может выскочить много ошибок. Если вы хотите остановить музыку и загрузить новую то пишите следующее:
Code

FreeSongs(AudioStream); //Освобождаем bass
InitSongs(Handle); //инициализируем Bass

и после этого кода можете снова загружать мелодию...
Теперь обработчике событий OnTimer измените следующим образом:
Code

GameViewer.Update; //обналвяем основной экран для рисования
GameCamera.Update; //обналвяем камеру
GameScene.Update; //обналвяем сцену

//перемещаем спрайт в зависимомти от нажатой клавиши
if OnKey(VK_LEFT) then GameScene.Sprites[0].Position.X:= GameScene.Sprites[0].Position.X - 4;
if OnKey(VK_RIGHT) then GameScene.Sprites[0].Position.X:= GameScene.Sprites[0].Position.X + 4;
if OnKey(VK_UP) then GameScene.Sprites[0].Position.Y:= GameScene.Sprites[0].Position.Y - 4;
if OnKey(VK_DOWN) then GameScene.Sprites[0].Position.Y:= GameScene.Sprites[0].Position.Y + 4;

if isCollision(GameScene,GameScene.Sprites[0],GameScene.Sprites[1]) then
begin
GameScene.Sprites[0].Other.Destroy:= true; //уничтожаем объект с которым мы столкнулись
PlaySong(AudioStream,'Data\Audio\beep.wav',false); //и воспроизводим звук
end;

Перед запуском закинте все ресурсы в папку здесь у меня world.ogg мелодия которая вопроизводится при запуске игры, второй это звук beep.wav он воспроизводится при столкновении...
Ну вообщем то и все, привожу полный код того что получилось (решил еще и коментарии написать :))

Авторские права принадлежат Каыблину Андрею (Xakep) (с) 2008 год


Категория: Delphi, Pascal, ObjectPascal | Просмотров: 2680 | Добавил: ДядяВолк (11.08.2010) | Рейтинг: 0.0/0
Источник: http://quadrathell.cn.ua | Автор: Михаил Христосенко |
HTML ссылка на материал:
BB ссылка на материал:
Похожие материалы :
Возможно вам будет интересно:
Сохранение и чекпоинты (0)
Про HTML (1)
Решение проблемы с перевернутыми гранями (1)
[Статья] Создаем дополнительное оружие (2)
Наложение Текстуры На Модель в 3DGS (MED) (0)
Создание многопользовательской(online) игры на Game Maker. (часть 2) (0)
Borland Assembler (BASM) уроки для начинающих (урок 5) (0)
Создаем платформер. Scirra Construct (4)
Несколько советов (ГМ) (0)
Полезные функции и процедуры: часть 1 (0)
Моя первая страница на PHP (0)
3d Rad - Про конструктор (0)
Пингуем (Ping) под Delphi (1)
Урок для начинающих по Game Maker v8 (платформенная игра) (1)
Знакомство с Движком! (0)
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Мы в социальных сетях

Поиск
Поиск по всему сайту:
Поиск по разделу:

Панель пользователя
Здравствуйте, Гость


Ник:
Пароль:
Запомнить :

Ваш IP: 54.92.150.98

Случайные конструкторы

Случайные движки

Случайные статьи

Статистика
Онлайн всего: 2
Гостей: 2
Пользователей: 0

На сайте были:

При полном или частичном копировании материалов сайта ссылка на Make-Games.ru обязательна. Make-Games.ru © 2008 - 2018 Хостинг от uWeb
Топ Разработка игр Рейтинг@Mail.ru