Создание базового движка для игры. Часть 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]
Все остальное, что не попадает ни под одну категорию.

Мини-Опрос
Какие языки программирования вы знаете?
Всего ответов: 897

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

 Главная » Статьи » Программирование » 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 | Просмотров: 4129 | Добавил: ДядяВолк (11.08.2010) | Рейтинг: 0.0/0
Источник: http://quadrathell.cn.ua | Автор: Михаил Христосенко |
HTML ссылка на материал:
BB ссылка на материал:
Похожие материалы :
Возможно вам будет интересно:
Borland Assembler (BASM) уроки для начинающих (уроки 1-4) (0)
С чего начать создание игры для начинающих? (13)
Золотые Правила Игродела (0)
3D Rad - делаем компас. (0)
Учебник по Blitz 3D (0)
Уроки по C/C++ (Части с 21 по 40) (0)
Библиотека STL (0)
Blitz 3D - полезная дипломная работа (часть 2) (0)
Урок про скелетную анимацию (0)
Game Maker. Начало (1)
Создание MMORPG игр. (3)
Подробности о Unreal Engine 3.0 (3)
Инветарь на Game Maker (0)
startDrag или как заставить объект двигаться за мышью? (0)
30 советов по программированию в Delphi (Дельфи) часть 1 (0)
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
Поиск
Поиск по всему сайту:
Поиск по разделу:

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


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

Ваш IP: 3.144.35.148

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

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

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

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

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

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