25 января 2011

glVehicles-Gibbets или насколько трудно программировать физику?

Снова я... И сразу же - ура! обновления в репозитории! добавилась еще одна демка! Правда еще пару дней назад я не планировал делать то, что получилось. Отчего такая спонтанность? Ну, немного предыстории...
Недавно закончился 11ый конкурс на glscene.ru и в данный момент подводятся итоги. Конкурс выдался на редкость замечательным! Большое количество участников, высокий уровень работ, интересные находки в плане геймплея... супер! Без шуток! Рад, что довелось оценивать работы конкурсантов! 
Теперь происходит выбор новой темы для следующего конкурса... Как всегда я предложил выбрать для темы игровую механику какой-нибудь флеш-игры. Среди них есть множество действительно чумовых! На мое удивление, прозвучала фраза, что это сложно и только с виду выглядит простым. Наверно, это задело мое самолюбие и я решил продемонстрировать, что программирование физической основы игровой механики предложенных мною игр не столь трудно, как представляется... завернул мощно, ничего не поделаешь, но суть проста - я попробовал запрограммировать что-то из тех физических штук, что я предложил...
Предыстория закончена, теперь к делу... Итак, выбор пал на Gibbets. Игра простая - стреляем из лука, стрелы физические, втыкаются в предметы. Цель - перерезать веревку у висельников, чтобы спасти несчастных.
Код простой, но нагромождается обильными методами вроде AddArrow(), LaunchArrow(), AttachArrow() и т.д. Скрин (стрела слева-внизу, указывает на курсор мыши):


А вот я уже немного "пострелял":


Сила выстрела зависит от удаленности мыши от изначального положения стрелы. Чем дальше мышь - тем сильнее выстрелит стрела.
При программировании полета стрелы оставалась одна проблема - допустим, вы кидаете палку, какова вероятность того, что она будет красиво лететь, причем ударится о землю именно своим наконечником? Оказалось, невелика. Что-то я крутил-вертел физические свойства стрелы (массы наконечника и основания, начальную скорость, сопротивление воздуха и т.д.) - ничего не получалось. Затем я решил сделать грубо - выставлять ориентацию стрелы в зависимости от её линейной скорости. Но решение мне показалось "некрасивым". В итоге я глянул, как сделано в оригинальных Gibbets и узрел тот же самый "грязный хак" - ориентация выставляется вручную. "Тому и быть" - подумал я и дописал маленький метод CorrectDirection() для более красивого полета стрелы. Сам код выглядит так:

Procedure TfrmDemo8.CorrectDirection;
var
  vel: TVector;
  ang: Single;
begin
  vel := fArrow.Velocity;
  if (fArrowJoint = nil) and (fAttachJoint = nil) and (sqr(vel[0]) + sqr(vel[1]) <= 10) then
  begin
    ang := ArcTan2(vel[1], vel[0]);
    fArrow.Rotation := ang;
  end;
end;

Как видите, ничего сложного. "Достали" линейную скорость, посмотрели, в полете ли сейчас стрела, если да - выставили угол поворота тела. С бубном бегать не пришлось - а это уже хорошо :)
А вот небольшое видео моей "пострелялки":



Веревку пока добавлять не стал, ибо нет на это времени... но это не сложно, поверьте!
Итак, glVehicles не заброшен! Не падать духом, господа! Основа для 8ой демки имеется, сейчас 20ая ревизия. Обновляемся, компилируем и в путь! Опять же, так как мало кто любит качать что-либо из репозиториев, поэтому я выложил итоговый ехе для тестов отдельно...

Вот как-то так)).. до новых встреч!

Сообщения, схожие по тематике:

7 коммент.:

  1. подскажи, пожалуйста, а как сделать чтоб стрелы втыкались в стены?(as3.0)

    ОтветитьУдалить
  2. Анонимный,
    в месте контакта создаю Revolute-сочленение между телами, создавшими контакт (стрела + стена)... у сочленения также задаю пределы, чтобы стрела могла немного двигаться в точке касания.

    ОтветитьУдалить
  3. че-то не получается, проблема в том, что надо же создавать Revolute-сочленение в функции обновления мира, а там не определены ни стрелы ни стена
    я хоть правильно делаю:
    var r:b2RevoluteJointDef = new b2RevoluteJointDef()
    r.Initialize(strela, stena, strela.GetPosition());
    world.CreateJoint(r);

    ОтветитьУдалить
  4. Анонимный,
    да, то, что ты написал - правильно!
    по поводу определения - я в UserData толкаю ссылку на какой-нибудь объект с информацией о теле, чтобы при контакте можно было определить, кто с кем столкнулся :)
    а сами тела передаются в слушатель контактов через ContactData'у!

    в итоге должно работать! если не получается - скинь куда-нибудь демку, чтобы можно было потестить, что именно там не так!

    ОтветитьУдалить
  5. Этот комментарий был удален администратором блога.

    ОтветитьУдалить
  6. Анонимный,
    внутрь классов box2d (как например b2ContactListener) лезть не нужно, от них следует наследоваться и перекрывать необходимые методы...
    я на скорую руку постарался поправить твой пример:

    http://ifolder.ru/26745127

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

    p.s. кстати, у тебя довольно старая версия бокса, вышла уже поновее... а то я долго не мог понять в чем дело, когда добавил твои файлы в FD для редактирования - и по подсказке выползали файлы бокса, который используется у меня; а в твоем боксе таких методов нет... и IDE при компиляции ругался))
    в общем, надеюсь мои изменения помогут понять, как работать со слушателем контактов! успехов!

    ОтветитьУдалить
  7. привет эт я) Спасибо тебе за уделенное время на меня. Так бы и работал я на старом боксе, если бы не ты))
    есть 1 но... когда стрела прилетает в препятствие ее колбасит, я подумал что надо при столкновении обнулить линейную скорость, но че-то не помогает, пишу это в классе MyContactListener правильно?
    не мог бы ты стереть пост, в котором указана моя почта)

    ОтветитьУдалить