Даю порулить - программируем движение автомобиля для флэш-игр

09.07.2008, автор Stormit, рубрики: ActionScript, Flash игры

Много есть флэш-игр, связанных с автомобилями, когда игра ведется от третьего лица при виде сверху. В основном это гонки, где нужно намотать круги и обогнать противников. В таких случаях обычно не учитывают колеса автомобиля и при поворотах, просто поворачивают клип вокруг центра. Это не соответствует правде, но если машину окружить выхлопными газами, пылью и другими эффектами, то  этого никто и не заметит. Все потому, что игровой движок не на этом строится.

Другое дело, если цель игры - припарковать машину или пройти курсы вождения. Тогда без более-менее реальной модели автомобиля (передние колеса задают поворот, а задний мост - ведущий) ничего не получится.

Решение которое я предлагаю не использует физических законов, по крайней мере я пока об этом не подозреваю,  но довольно хорошо имитирует реальное поведение четырехколесного автомобиля с ведущим задним приводом.

Логика здесь такая: автомобиль вначале поворачивается (если передние колеса не смотрят прямо) и едет в этом направлении. Со смещением проблем нет, но вот поворот на правильный угол не давал мне покоя. По логике, скорость поворота прямо пропорциональна поступательной скорости автомобиля и обратно пропорциональна расстоянию между передними и задними колесами. На удивление, этого хватило, и не пришлось подбирать поправочные коэффициенты.

Чтобы это проверить, нам нужен подготовленный символ автомобиля. Достаточно иметь 4 колеса и какой-либо каркас.

  1. Создаем символ car и внутри него 2 колеса с именами left и right. Центр символа car должен находиться строго между задними колесами. Это ВАЖНО. Это та точка, к которой прикладывается сила тяги.
  2. В той же линейке, где лежит символ car, кадром выше пишем код:
    speed = 0;
    speedLimit = 8;
    speedStep = .5;
    rotLimit = 35;
    rotStep = 3;
    processKey = function () {
    	if (Key.isDown(Key.LEFT)) {
    		if (car.left._rotation > -rotLimit) {
    			car.left._rotation = car.right._rotation -= rotStep;
    		}
    	} else if (Key.isDown(Key.RIGHT)) {
    		if (car.left._rotation < rotLimit) {
    			car.left._rotation = car.right._rotation += rotStep;
    		}
    	}
    	if (Key.isDown(Key.UP)) {
    		speed += (speed < speedLimit)? speedStep : 0;
    	} else if (Key.isDown(Key.DOWN)) {
    		speed += (speed > -speedLimit)? -speedStep : 0;
    	} else {
    		speed += (speed < 0)? speedStep : (speed > 0)? -speedStep : 0;
    	}
    };
    function move(){
    	if(Math.abs(speed) > 0) {
    		car._rotation += car.left._rotation * speed / car.left._x;
    	}
    	angle = car._rotation * Math.PI / 180;
    	speedX = speed * Math.cos(angle);
    	speedY = speed * Math.sin(angle);
    	car._x += speedX;
    	car._y += speedY;
    }
    onEnterFrame = function() {
    	processKey();
    	move();
    }

    Я постарался разнести все величины по переменным, так что настроить их под другой тип машины дело не сложное. Замедление с ускорением тоже есть - все как учили :)

  3. Получаем такой результат. Управление осуществляется с клавиатуры - стрелки ←,↑,→,↓.
  4. Сразу проверим, как это будет работать, если передвинуть передние колеса вперед. Вроде неплохой автобус.
  5. Небольшой пример из жизни.

Еще немного о том, как машина исчезает с одной стороны и появляется с другой.
Я люблю наглядные способы, поэтому зону для маневров будет задавать клип box с габаритами, идентичными размеру флэшки. А уже с него я считаю ограничивающие координаты по ширине и по высоте. Тогда в дополнение к вышеизложенному, дописывается такой код:

WIDTH = zone._width;
HEIGHT = zone._height;
LEFT = zone._x;
TOP = zone._y;
RIGHT = LEFT + WIDTH;
BOTTOM = TOP + HEIGHT;
 
checkCycle = function () {
	bounds = car.getBounds(this);
	boundWidth = bounds.xMax - bounds.xMin;
	boundHeight = bounds.yMax - bounds.yMin
	if(bounds.xMax < LEFT) {
		car._x = RIGHT + car._x - bounds.xMin;
	} else if(bounds.xMin > RIGHT) {
		car._x = LEFT - (bounds.xMax - car._x);
	}
	if(bounds.yMax < TOP) {
		car._y = BOTTOM + (car._y - bounds.yMin);
	} else if(bounds.yMin > BOTTOM) {
		car._y = TOP - (bounds.yMax - car._y);
	}
};

Теперь эту функцию нужно добавить в вызов по событию EnterFrame, после вызова функции move().

Получается вполне универсальный движок для многих видов транспорта. Но все это сделано чисто интуитивно, а я бы не прочь взглянуть, как это объясняется физикой. Так что если кто-то начертит схему с силами и всеми делами,- милости просим.

Интересно на 33%

(91) Хитрых на тему «Даю порулить - программируем движение автомобиля для флэш-игр»

  1. ded pb|xto

    Вах :) маладэц :)

  2. Ixifeus

    Супер! Спасибо. И как всегда классно оформлена флешка =)

  3. Ixifeus

    Кто нибудь может разжевать эту сточку
    ” speed += (speed 0)? -speedStep : 0; ”
    Просто такую форму записи я вроде ещё не видел

  4. Stormit

    Это альтернативный вариант if…else
    Если условие в скобках истинно, то вместо всего этого подставляется значение идущее после вопросительного знака, иначе - после двоеточия.

  5. Ixifeus

    а реально прицеп сзади прикрутить ?

  6. Hitokiri

    Очередной отличный урок! Спасибо! :)

    Про прицеп - очень класный вопрос.

    Если уж пошли такие навороты, можно и дрифт на скорости просчитать! :) Но это уже совсем другие гигабайты кода :)

  7. GB

    Супер, а когда комбайн увидел, вспомнил Вангеров.

  8. ded pb|xto

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

  9. Stormit

    Придумаю что-нибуть с прицепом :)

  10. LadyIce

    погоняв трактор, стало ясно, что игры в гонки надо делать не вертикальные, а горизонтальные, так интереснее управлять))

    Отличный пример. А траектория практически верна, маленькая неточность - не грех )

  11. Segas

    Прикольно, посмотрл подзадумался. Автор молодец одним словом! респект!

  12. Читун

    Супер! Вот это профессионал! Доделай в игру про парковку. Кстати в IE комментарии съезжают вниз некрасиво.

  13. Stormit

    А какой у тебя IE?
    У меня в 6-м не съезжают

  14. mephi

    Ай, зачем таким пользоваться а, IE - ну его, юзайте лучеше Оперу или Файрфокс, и наслаждайтесь творениями автора.

  15. Ixifeus

    По поводу дрифта.Нашёл классную игруху
    http://www.demonfiles.my1.ru/load/7-1-0-198
    осталось тока узнать как это реализовать )))

  16. Destroyer

    А в этом “дрифте” машина поворачивается по центровой оси =)

  17. Destroyer

    А можете дать исходник, а то мне ваш трактор сильно понравился? =)

  18. Славентий (Zloba)

    Здорова Стормит зацини прикол: http://www.free-lance.ru/blogs/view.php?tr=236455&ord=new Там в середине парню одному ответил зип архивом. Посмотри его))) и обрати внимание на даты) ты кстате никак с этим несвязан? а то уж больно похоже получилось) (зы код да разный))

  19. Destroyer

    Нет, я никак с этим не связан =)

  20. Destroyer

    Славентий (Zloba), спасибо конечно, но это не то, о чем я просил =) Мне нужен вот именно этот трактор =)

  21. Destroyer

    А еще, как можно сделать чтобы следы от машины оставались?

  22. Stormit

    to Славентий (Zloba)
    нет, не связан, этому комбайну уже несколько лет
    >>Мне нужен вот именно этот трактор =)
    А зачем? Плагиат это плохо, а суть движка и код приведен выше, осталось только обрисовать фото любого трактора при виде сверху.

  23. Stormit

    >>А еще, как можно сделать чтобы следы от машины оставались
    рисуешь квадратный отпечаток по ширине колеса и дальше либо на EnterFrame (либо когда проехал минимально допустимое расстояние) дублируешь его и ложишь точно под колесом (машине swapDepths(10000000000)). Для остальных колес тоже самое.
    Еще, дублированием (по тому же типу что и огонь), можно сделать и выброс грязи из-под задних колес.

  24. Destroyer

    Stormit, спасибо!

  25. Destroyer

    А как можно сделать такой дымок, как в тракторе? Я понимаю, что по принципу огня, но непонимаю как привязать дымок в клип с машиной. Я вставляю мувик дымка в машину, а дальше что? Какой код?
    Разжуйте пожалуйста.

  26. Destroyer

    А вот мне нужно впихнуть все это в мувиклип. Что изменить в коде, чтобы он работал?

  27. Destroyer

    Ну, мне кто-то поможет?

  28. Destroyer

    Ало-о!

  29. ded pb|xto

    Destroyer - есть ресурсы где разжовывают (чаще форумы). В этом блоге рассказывают о хитростях. Если Художник нарисовал картину - это не обязывает его рассказывать как он ложит масло на холст. Если тебе так уж хочеться такой трактор - напряги себя и сделай. В этом блоге есть все что бы сделать самостоятельно такой трактор.

  30. Destroyer

    Ну как еще нужно попросить…

  31. mainmix

    Господа! А мне кажется, что колеса с рулем все-таки должны сами возвращаться в центральное положение во время движения! Так реалистичней!

  32. Dmitry Matyukhin

    Да, я тоже заметил что было бы неплохо сделать возвращение колес при движении в зависимости от скорости. То есть, наверное. должно получатся, что колеса должны оставаться под одним углом относительно земли если клавиша “влево” или “вправо” не нажаты.

  33. KUSAKA

    Заметил одну вещь - при повороте скорость машинки сильно возрастает…

  34. Stormit

    Занос машины не учитывается. По идее, при повороте на быстрой скорости, машину должно нести по инерции (по касательной к радиусу поворота)

  35. Stormit

    to Dmitry Matyukhin

    if(!Key.isDown(Key.LEFT) && !Key.isDown(Key.RIGHT)) {
        car.left._rotation = car.right._rotation *= .8 * (speed / speedLimit);
    }
    

    типа того (нужно еще и к скорости движения привязаться)

  36. Stormit

    to Destroyer
    Дымок так же как и в примере с огнем, остается огненный шлейф за мячиком.
    Не вижу проблем чтобы все это в мувик засунуть. У меня так все и работает. Конкретно, как обернуть несколько слоев в символ описано здесь: http://xitri.com/2008/05/17/tools-for-flash.html

  37. Саша юный флешер

    спасибо очень круто

  38. Werewolf

    Спасибо за статью оказалась очень полезной.

  39. Maestro

    Отличная идея. Сначала пытался сам спрограмировать автомобиль, но потом нашел этот сайт. Идея очень понравилась. Только немножко физики добавил, ну там инерция, автоматическое возвращение колес в исходное положение, занос автомобиля при движении на большой скорости и т.д. Только вот пришлось код писать не на кадре а на самом клипе автомобиля, так как надо было сделать много автомобилей, чтобы код не переписывать для каждого в отдельности.

  40. Михаэль

    Здраствуйте Stormit пытался разобрать ваш код но сколько не пробую невыходит (неработает) если вам не сложно немоглибы вы выслать на SilverForce@yandex.ru исходник (рабочий). буду очень благодарен

  41. RuStep

    Здраствуйте! У меня ничего не получилось! :( А не поделитесь исходничком? сюда - RuStep@list.ru

  42. Stormit

    Исходники потерялись, но могу подсказать, если скажете с какого момента перестало получаться (какие переменные становятся undefined и т.д.).

  43. RuStep

    Дело в том, что сам “car” и колёса я сделал! Но вот когда вставляю в это кадр код - он не работает! Не пойму в чём проблема!

  44. RuStep

    плохо что нет исходника, а вы не могли бы составить его по уроку?

  45. Stormit

    Если компилятор не выдаёт никаких ошибок, пройдитесь по коду и проверьте функцией trace(), какие переменные становятся NaN, null или undefined. Там и нужно искать причину.
    В первую очередь, стоит проверить видны ли сами символы машины и колёс в коде.

  46. RuStep

    Извините но в AS я не особый мастер :), поэтому не очень понимаю что вы написали, но всё же прошёлся по коду - нашёл эти элементы в коде, то есть они там присутствуют!

  47. Алик

    Вы уж меня извините что я подряд пишу, но система комментариев обрезает код, а я подумал что я ошибся. Немогу сюда вставить то что хочу. Вобщем действие в else после после key.DOWN.
    Модеры удалите плиз все лишнее что наговорил :D

  48. Stormit
    if (Key.isDown(Key.UP)) {
    	speed += (speed < speedLimit)? speedStep : 0;
    } else if (Key.isDown(Key.DOWN)) {
    	speed += (speed > -speedLimit)? -speedStep : 0;
    } else {
    	speed += (speed < 0)? speedStep : (speed > 0)? -speedStep : 0;
    }
    

    Если клавиша “UP” нажата, то скорость увеличивается (но не больше speedLimit), если “DOWN” - уменьшается (но не меньше -speedLimit), иначе - скорость постепенно падает до нуля (прибавляется или вычитается в зависимости от знака).

  49. Iron Man

    у меня нечего не вышло :(((

  50. Лаки

    С дымом тоже не понял. Помещаю его в клип с машиной и он “не тянется”. Просто дымик “внутри” машины.

  51. Лаки

    Сделал автоматический возврат колёс в исходное положение, снижение скорости при повороте. Делаю заносы, ручник, следы при торможении.
    Я в AS не профи, но пока всё получается. Но с дымом так и не разобрался.
    Если клип (объект) внутри другого клипа, его координаты (и вообще его бытие) относительны родительского клипа? Т.е. не удивительно, что клубья дыма копируются внутри машины. Как сделать, чтобы дым коптил с нужной точки автомобиля?

  52. Stormit

    Помести внутри символа с машинкой невидимый символ (помести его центр на выхлопную трубу). Потом, при помощи методов localToGlobal() и globalToLocal() пересчитывай координаты этого символа в тот timeline где лежит машина и клип дыма. Дальше дублируй клип дыма и помещай в полученные координаты.

  53. Лаки

    Спасибо, Stormit! Просто не знал эти методы.
    Машинка задымила, а теперь еще больше люблю этот бложик :-D

  54. Albert

    Nice tutorial.
    I try your tutorial everything is fine, but i want to add collision detection against wall and bounce back but no idea where to start ?

  55. Stormit

    You can place 8 or more point clips in the car and arrange them on perimetre and check collision with hitTest() function. After that, return the car to the previous position and rotate around collided point. I didn’t do it but I think similar way.

  56. DarkSnow

    Спасибо очень класно! Stormit могли бы вы идейки подкинуть, насчет заноса и вращение машины волчком (если сильно занесет), а то неполучается что-то

  57. Артур

    я во флеше не очень хорошо разбираюсь. но не могли бы вы мне прислать код того, чтобы когда авто попадало на определенныю територию её скорость менялась

  58. Stormit

    Пробуйте hitTest()
    Если координаты 4-х колёс совпадают с вашей зоной, уменьшайте скорость. Так будет даже круче - чем больше колёс в штрафной зоне - тем медленней едет машинка.

  59. maaboo

    А как бы сделать чтобы привод можно было передвинуть? Или сделать полноприводную? Это какой-то оффсет надо класть, не могу сообразить куда.

  60. Anj

    Здравствуйте Stormit у меня к вам вопрос при изменении параметра SpeedStep авто неприобретает состояния “покоя” тоесть флешка всегда в движении, как это можно поправить? пытался прописывать нечто вроде “если скорость меньше 1 то присваиваем ей значение 0″ но видать невте дебри лезу…

  61. Moroz777

    Пробывал сделать…выдал=> **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 1: Statement must appear within on/onClipEvent handler
    speed = 0;

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 2: Statement must appear within on/onClipEvent handler
    speedLimit = 8;

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 3: Statement must appear within on/onClipEvent handler
    speedStep = .5;

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 4: Statement must appear within on/onClipEvent handler
    rotLimit = 35;

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 5: Statement must appear within on/onClipEvent handler
    rotStep = 3;

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 6: Statement must appear within on/onClipEvent handler
    processKey = function () {

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 24: Statement must appear within on/onClipEvent handler
    function move(){

    **Error** Scene=Scene 1, layer=Layer 1, frame=1:Line 34: Statement must appear within on/onClipEvent handler
    onEnterFrame = function() {

    Total ActionScript Errors: 8 Reported Errors: 8
    подскажите как исправить?…плиз!!!

  62. Moroz777

    ….или поделитесь исходником=> morozov-dedulya@mail.ru

  63. Пит

    У меня такая же ошибка как у Moroz777. Что за шляпа? =( Подскажите

  64. Grinder13

    Люди!я в ActionScript вообще ничего не понимаю,а научиться блин хочется!
    Я вот по какому вопросу…вы не могли бы написать код(ну или написать че нужно исправить)чтоб как в самых обычных гонках нажатие вправо-поворот направо нажатие влево…Пожалуйста напишите!!!!а то я вообще не знаю где еще мона это посмотреть!!!!!

  65. Nikolaus

    а как зделать границу, за которую машина заехать не может? и бокс для парковки, чтоб игру полноценную создать.

  66. Stormit

    to Nikolaus
    car._x += speedX;
    car._y += speedY;
    Вот тут делайте проверку. Если координата выходит за пределы зоны, то её не менять.
    Бокс для парковки проще всего проверять на hitTest() по колёсам.

  67. Nikolaus

    и куда это вставлять? да, и как сделать границу, за которую машина заехать не может? Можно как нибудь типо создать символ “graniza” и при наезжании на него символа “car” игра переходила на другой кадр?
    P.S.мой id7418368 атор этого всего, если не трудно добавься в друзья, но только с пометкой “флэш”

  68. In-Finity

    Спасибо за урок. Утащил к себе код частично. (:
    Давно хотел такую штуку сделать - знакомым начинающим водителям практиковаться.
    Там небольшая поправка только.
    В описании ко второй части кода - там зону для манёвров создаёт не клип BOX а клип ZONE.
    Ещё раз спасиба.

  69. terminator200911

    Здраствуйте! Пробывал машину сделать,но не получилось код не работает и выдает ошибку А не сделаете исходник для скачки, чтобы посмотреть что не так сделал? А то хочется чтобы все таки машина ездила!!! или скиньте мне на email terminator200911@mail.ru

  70. terminator200911

    Statement must appear within on/onClipEvent handler speed = 0;
    Statement must appear within on/onClipEvent handler speedLimit = 8;
    Statement must appear within on/onClipEvent handler speedStep = .5;
    Statement must appear within on/onClipEvent handler rotLimit = 35;
    Statement must appear within on/onClipEvent handler rotStep = 3;
    Statement must appear within on/onClipEvent handler processKey = function () {
    Statement must appear within on/onClipEvent handler function move(){
    Statement must appear within on/onClipEvent handler onEnterFrame = function() {

    Помогите, машину сделал и выдает ошибку!!! что делать и как исправить машина мертвым грузом стоит!!!

  71. terminator200911

    Народ машина назад в перед едит,а вот калеса не поворачивают что мне делать?

  72. Corsar2232

    Спасибо за идею! Незнаю почему но только чтобы у меня все работало норм на AS2 пришлось несколько переработать ваш код. Кому нужен исходник вот моя почта corsar-2232@rambler.ru

  73. Кирилл

    Stormit а как можно сделать что бы если машина встала в определёную зону он
    переходил на следущий кадр

  74. Сашка

    я не не понял куда вписывать скрипт ?

  75. Денис

    Подскажите пожалуйста почему у меня колеса поворачивается не по центру а с угла?

    http://dmhope.ru/mycar.swf

  76. Moroz777

    onEnterFrame = function() {
    processKey();
    move();
    погдскажите зачем это здесь?

  77. Денис

    Все просто и гениально. Автор огромное спасибо за урок.
    Вот моя реализация.

    http://dmhope.ru/flash/mycar2.swf

  78. Сашка

    В той же линейке, где лежит символ car, кадром выше пишем код как это понять ???

  79. Денис

    Сашка, Добавь новый слой и в нем в первом фрейме пиши код.

    http://s52.radikal.ru/i137/1004/a6/452d02a8a3ae.png

  80. Сашка

    ок спс попробую )

  81. Сашка

    а писать в муве или нет ?

  82. Сашка

    блин не получается я просто мало знаю чего во флеше ((

  83. Денис

    Сайшка, что именно не получилось?

  84. Moroz777

    ёмаё у мну тож палучилось))) http://my.mail.ru/mail/morozov-dedulya/app-canvas?appid=460207

  85. Moroz777

    Сашка, кщё важно кадры подписать!!..а не только мувики))

  86. Moroz777

    …ой, наврал!..кароче в панельке properties не забудь вписать имена

  87. Сашка

    извиняюсь, а какие именно имена ?))

  88. Сашка

    точнее как назвать их

  89. Pocifik

    Не могу понять как сделать символ, по подробее сам символ создал в него поместил символы left и right а как поместить его в монтажный кадр, кто нить может дать исходник

  90. Сашка

    ктонить дайте исходник плиз

  91. Лаки

    Пытаюсь придумать занос и следы от колёс.

Оставить комментарий