0.) Доброе время...
Доброе время суток мои читатели. Этот пост - продолжение постов про gamedev(игростроении). Давайте мельком пробежимся по уже сделанному нами.
- Итак:
Мы мельком рассмотрели основы графики и даже создали нашего героя.
- Рассмотрели компоненты которые вскоре и помогут нам создать полноценную игру.
- И рассмотрели стандартные классы и их иерархию.
Какие у нас планы на этот урок:
- Мы должны поработать с DXInput - компонент отвечающий за ввод данных с устройств ввода
- Рассмотреть основы анимации
- Заставить mario бегать.
Вроде всё сказано, чего медлить ближе к делу!
1.) Чтение с устройств ввода
Я уже упоминал в прошлом посте про компонент TDXInput (подробнее тут) . Разберём его концепцию.
То есть TDXInput.States принимает состояние, если же оно совпадает с табличным значением(которое можно настраивать):
Когда мы должны узнавать о изменениях состояния? - Всё время. По этой причине мы должны добавить компонент таймер - TDXTimer. Его значение Interval лучше установить на 33. То есть частота обновления будет 33 милисекунды. Это же будет и частота обновления графики. Создаём его процедуру OnTimer.
Всё , что у нас было мы изменим. Теперь проверим можем ли мы рисовать? т.е. установлен ли DirectX , рабочая видеокарта и т.д.
Получим код :
if not DXDraw.CanDraw then exit; //если не можем рисовать - значит выход |
{ Информация } with DXDraw.Surface.Canvas do //работаем с холстом begin Brush.Style := bsClear; //прозрачный фон Font.Color := clBlack; //цвет шрифта Font.Size := 12; //размер шрифта Textout(0, 0, 'FPS: '+inttostr(DXTimer.FrameRate)); //FS Textout(0, 24, 'Sprite: '+inttostr(DXSpriteEngine.Engine.AllCount)); //кол - во спрайтов Textout(0, 48, 'Draw: '+inttostr(DXSpriteEngine.Engine.DrawCount)); if FMoveMode then //Time mod Textout(0, 72, 'Time mode: 60 FPS') else Textout(0, 72, 'Time mode: Real time'); Release; //Освобождаем память... end; //конец работы с холстом |
DXInput.Update; |
И в конце-концов наша процедура получит полностью извращённый вид:
procedure TMainForm.DXTimerTimer(Sender: TObject; LagCount: Integer); begin if not DXDraw.CanDraw then exit; //выходим при проблемах DXInput.Update; //обновляем состояние if FMoveMode then LagCount := 1000 div 60; //кол-во перемещений DXSpriteEngine.Move(LagCount); //перемещяем DXSpriteEngine.Dead; //уираем { Рисование } DXDraw.Surface.Fill(0); DXSpriteEngine.Draw; //Нарисовать { Информация } with DXDraw.Surface.Canvas do //работаем с холстом begin Brush.Style := bsClear; //прозрачный фон Font.Color := clBlack; //цвет шрифта Font.Size := 12; //размер шрифта Textout(0, 0, 'FPS: '+inttostr(DXTimer.FrameRate)); //FS Textout(0, 24, 'Sprite: '+inttostr(DXSpriteEngine.Engine.AllCount)); //кол - во спрайтов Textout(0, 48, 'Draw: '+inttostr(DXSpriteEngine.Engine.DrawCount)); if FMoveMode then //Time mod Textout(0, 72, 'Time mode: 60 FPS') else Textout(0, 72, 'Time mode: Real time'); Release; //Освобождаем память... end; //конец работы с холстом DXDraw.Flip; //Нарисовать end; |
Ответный вопрос - "А мы. что сказали ему , что либо сделать?".
Объясним mario!
Мы когда-то описывали процедуру
TMarioHero.DoMove(MoveCount: Integer); |
AnimLooped := False; //Прекращаем анимацию
Хотя анимацию мы разберём позже, строка нужна.
После опишем огромный код:
if (MainForm.DXInput.Joystick.X<>0) or (MainForm.DXInput.Joystick.Y<>0) then //если значения не равны нулю переместимся begin X := X + (MainForm.DXInput.Joystick.X/1000)*MoveCount; Y := Y + (MainForm.DXInput.Joystick.Y/1000)*MoveCount; end else begin if isUp in MainForm.DXInput.States then //марио должен идти вверх? begin Y := Y - (300/1000)*MoveCount; end; if isDown in MainForm.DXInput.States then //или в низ? begin // end; if isLeft in MainForm.DXInput.States then //а может на лево begin X := X - (300/1000)*MoveCount; end; if isRight in MainForm.DXInput.States then //или на право begin X := X + (400/1000)*MoveCount; end; end; Collision; // проверим столкновения //обновим информацию движку Engine.X := -X+Engine.Width div 2-Width div 2; Engine.Y := -Y+Engine.Height div 2-Height div 2; |
2.) Анимация
Вот спрайты которые мы будем использовать(Эх сколько работы!)
Выделю важные моменты относительно Листа Изображений.
PaternWidth и PaternHeight обязаны быть отличны от нуля!
Рассмотрим основы анимации:
После всего процедура будет иметь такой вид:
procedure TMarioHero.DoMove(MoveCount: Integer); begin inherited DoMove(MoveCount); AnimLooped := False; if (MainForm.DXInput.Joystick.X<>0) or (MainForm.DXInput.Joystick.Y<>0) then begin X := X + (MainForm.DXInput.Joystick.X/1000)*MoveCount; Y := Y + (MainForm.DXInput.Joystick.Y/1000)*MoveCount; end else begin if isUp in MainForm.DXInput.States then begin Y := Y - (300/1000)*MoveCount; if Image.Name='mario_down' then begin Image := MainForm.ImageList.Items.Find('mario_downtoup'); //загружаем его спрайт AnimCount := Image.PatternCount; AnimLooped := True; AnimSpeed := (400/1000); end; end; if isDown in MainForm.DXInput.States then if Image.Name<>'mario_down' then begin Image := MainForm.ImageList.Items.Find('mario_down'); //загружаем его спрайт AnimCount := Image.PatternCount; AnimLooped := True; AnimSpeed := (400/1000); end; if isLeft in MainForm.DXInput.States then begin X := X - (300/1000)*MoveCount; Image := MainForm.ImageList.Items.Find('mario_left'); //загружаем его спрайт AnimCount := Image.PatternCount; AnimLooped := True; AnimSpeed := (300/1000); end; if isRight in MainForm.DXInput.States then begin X := X + (400/1000)*MoveCount; Image := MainForm.ImageList.Items.Find('mario_right'); //загружаем его спрайт AnimCount := Image.PatternCount; AnimLooped := True; AnimSpeed := (400/1000); end; end; Collision; Engine.X := -X+Engine.Width div 2-Width div 2; Engine.Y := -Y+Engine.Height div 2-Height div 2; end; |
Теперь наша игра станет ещё интереснее и привлекательней, действия более анимированы, изменён фон игры, и добавлена игровая информация.
Сегодняшний The End :