Программное движение автомобиля во флеш - теперь с прицепом
25.07.2008, автор Stormit, рубрики: ActionScript, Flash игрыЭто продолжение дорожных приключений. Тогда попросили сделать вариант с прицепом. Я понимаю желание сделать “побырику” flash-игру типа “Парковка” имея под рукой готовый код, поэтому дальше описан пример как это сделать. И не один прицеп, а целый поезд.
Честно говоря, задача резко усложняется из-за возможных обратных связей при движении автомобиля назад. В этом случае прицеп поворачивается и мешает движению, а также является точкой опоры для вращения автомобиля.
В жизни, на колеса действует множество сил, и машина с прицепом - сложная система для расчетов. На решение такой задачи может претендовать какой-нибуть физический движок. У меня же нет точных расчетов и все что можно - имитируется. Поэтому, если ваш вариант будет вести себя не совсем корректно, некоторые параметры нужно будет изменить по ситуации. Я не часто вижу как ездят автомобили с прицепом, поэтому все настраивал интуитивно. Прошу оценить реализм
От предыдущего примера код почти не отличается. Добавилось несколько новых клипов и одна функция в коде.
- Добавился клип прицепа trailer. Также, как в машине так и в прицепе появились 2 круглых символа. Они нужны чтобы считывать с них координаты и присоединять по этим точкам прицеп. Чтобы точка была не видна, внутри клипа можно прописать:
_visible = false;
- На той же временной линейке, где находятся клипы car и trailer,в кадре пишем такой код:
WIDTH = zone._width; HEIGHT = zone._height; LEFT = zone._x; TOP = zone._y; RIGHT = LEFT + WIDTH; BOTTOM = TOP + HEIGHT; speed = 0; speedLimit = 8; speedStep = .5; rotLimit = 35; rotStep = 3; trailerRotLimit = 55 / 180 * Math.PI; processKey = function () { if (Key.isDown(Key.CONTROL) || Key.isDown(Key.SPACE)) { car.kovsh.play(); } 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; } }; 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); } }; 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; } function correctTrailer(slave, master){ if(speed){ //Пересчитываем точку в родительскую систему координат var masterDot = {x:master.dotOut._x, y:master.dotOut._y}; master.localToGlobal(masterDot); globalToLocal(masterDot); var dx = masterDot.x - slave._x; var dy = masterDot.y - slave._y; //Угол между прицепом и машиной var aRad = Math.atan2(dy, dx); //Угол поворота самой машины var masterRotRad = master._rotation / 180 * Math.PI; //Разница между ними var dAngle = masterRotRad - aRad; //Коррекция перехода 180/-180 градусов if (dAngle > Math.PI) { dAngle = -Math.PI*2 + dAngle; } else if (dAngle < -Math.PI) { dAngle = Math.PI*2 + dAngle; } if(speed < 0) { //Выполняется только при движении назад //Ограничение на поворот и торможение из-за прицепа if(dAngle >= trailerRotLimit) { aRad = masterRotRad - trailerRotLimit; speed *= .8; } else if(dAngle <= -trailerRotLimit) { aRad = masterRotRad + trailerRotLimit; speed *= .8; } //Обратная связь на машину в результате торможения //Коэффициенты .5 и 3 подбираются вручную if(dAngle >= trailerRotLimit * .5) { master._rotation += speed / speedLimit * 3; } else if(dAngle <= -trailerRotLimit * .5) { master._rotation -= speed / speedLimit * 3; } } //Убираем паразитную скорость (погрешность округления чисел) if(Math.abs(speed) < speedStep && !Key.isDown(Key.DOWN)) { speed = 0; } //Поворачиваем прицеп к машине var a = aRad / Math.PI * 180; slave._rotation = a; //Пододвигаем прицеп чтобы была стыковка slave._x = masterDot.x - Math.cos(aRad) * slave.dotIn._x; slave._y = masterDot.y - Math.sin(aRad) * slave.dotIn._x; } } onEnterFrame = function() { processKey(); move(); checkCycle(); correctTrailer(trailer, car); }
За прицеп отвечает функция correctTrailer(прицеп, куда_цеплять);
- Управление стрелками.
- Можно пойти дальше.
Добавим в клип прицепа точку с именем dotOut. - Я специально вынес код прицепа в отдельную функцию. Теперь, передавая параметрами что и куда цеплять, можно сделать небольшой паровозик. Тогда в обработчике enterFrame, одна строка заменится на эти три:
correctTrailer(trailer1, car); correctTrailer(trailer2, trailer1); correctTrailer(trailer3, trailer2);
Я отключил здесь зацикленность движения, так что не уезжайте далеко за границы флэшки.
Один минус - в расчетах не учитывается масса объектов. На это можно повлиять коэффициентами, но все равно прицепы при заднем ходе дергаются слишком резко.
А может это мне кажется… Что думаете?
Возвращаясь к flash-игре типа “Припаркуй авто”, мне кажется что столкновение проще определять путем расстановки точек по периметру машины и прицепа. Брать в цикле их координаты и проверять на hitTest() с окружающими объектами. Нет громоздкого физического движка и не нужно ломать голову над проекцией векторов.
Интересно на 30%




Общий принцип с прицепом такой: мы его поворачиваем так, чтобы его центр, точка прицепа и точка автомобиля лежали на одной прямой. Затем двигаем прицеп, чтобы эти точки совместились. И так каждый кадр. Сложности с обратной связью, когда прицеп должен воздействовать на машину.
Хм, потрясающе. Вот так смотришь, раньше на написание подобного уходили недели на С, а сейчас пару часов. Я вот тоже хочу небольшую штучку написать ан флеш. Разумеется писать буду сам, но, если такое возможно, хотелось бы заручиться вашей поддержкой, если она понадобиться.
Чем смогу - помогу
Здрасте, спасибо за пример. Для меня - это одна из лучших хитростей на этом сайте. Денис, ты мегакрут
А не по такому принципу делается “змейка”?
Можно и по такому, если возможен поворот на случайный градус, только там движения назад нет. А самые примитивные змейки делаются путем гашения/подсвечивания клеточки.
Черт, я не удержался и сделал мини-гейм “Парковка” =)
Супер!!! Такого,если не ошибаюсь,я ещё нигде не видел.Тоже с удовольствием поигрался в парковку,а учитывая прицеп,игра стала поинтересней )))
>>Черт, я не удержался и сделал мини-гейм “Парковка” =)
Блин, я так и знал ))
Cууууупееееррр!Можете мне прислать на coolcub.3dn@mail.ru саму игру на флеш, или хотябы готовый код чтобы добавить к себе на сайт.

P.S.Я просто в этом не разбираюсь
Спасибо, пост действительно толково написан и по делу, есть что почерпнуть.
Класс! То, что надо.
Отличная статья.Респект автору.
Автор, поясни пожалуйста действии конструкции ? :
Пример твоего кода ниже:
speed += (speed 0)? -speedStep : 0;
Вообще-то там такой код:
speed += (speed < speedLimit)? speedStep : 0;
Раз вы выделили конструкцию, то наверное знаете. Я так понимаю:
(если_тру)? тогда_это : иначе_это
В моем случае - если скорость меньше предельной, немного ее увеличим, иначе прибавим 0.
Спасибо!
люфта на сцепках нет, а так всё супер !
почемуто невыходит прицепить 2 и более прицепов, делаю всё по инструкции в итоге 2й прицеп стоит наместе и реагирует только на езду назад
У меня прицеп почему то едет на некотором расстоянии от машины. В чем дело?
Я давно искал и нашел. Только я искал не прицеп а регдолл. Наверно и регдолл можно сделать на основе этого? Принцип тот же, только добавить гравитацию и столкновения.
Там другой принцип, там всё построено на реальной физике (попробуйте Box2DFlashAS3).
Здесь создаётся только видимость физики путём ручной подгонки и определённым устройством символов.
Ага. Кстати говоря, соседние темы - создание человечков, палящих по курсору - это, например, я давно умею. Так что я все искал инструкцию по созданию регдолла.
Ну типа круто но тележко спокойно может залезьть на машинку
а как сделать так чтоб при отпускании кнопки мыши колёса вставали в начальное положение
Привет! Супер!
Спасибо за урок. Очень интересно и полезно