Jump to content
  • 0

Помогите с формулой


Odrin
 Share

Question

Добрый день!

Похоже школьные годы совсем забылись и мозг отказывается работать =)

Простая задача - объект (пусть это будет условно "мяч") падает с высоты h на поверхность, отскакивает, поднимается и снова падает. Силу трения и остальные внешние силы не учитываем, т.е. прыгает бесконечно.

С HTML все просто:

<body>
<div style="margin:0 auto; width: 802px;">
<canvas id="canvas" width="800" height="600" style="border:1px solid;"></canvas>
</div>
</body>

JS. Запускаем анимацию:

window.onload = function () {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var engine = new Engine(ctx);

var raf = window.requestAnimationFrame || window.msRequestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame;
var myRedrawFunc = function () {
engine.refresh();
raf(myRedrawFunc);
}
raf(myRedrawFunc);
}

Код "движка":

function Engine(ctx) {
this.width = 800;
this.height = 600;

this.ctx = ctx;
this.renderObjects = [];

this.refresh = function () {
this.ctx.clearRect(0, 0, this.width, this.height);
for (var i = 0; i < this.renderObjects.length; i++) {
this.renderObjects[i].draw(this.ctx);
}
}

this.addObject = function (obj) {
this.renderObjects.push(obj);
}
}

Ну и сам "мяч":

function RenderObject(x, y) {
this.x = x;
this.y = y;
this.vx = 0;
this.vy = 0;

this.width = 64;
this.height = 64;

this.img = new Image();
this.img.src = "/img/ball.png";

this._recalcPosition = function () {
// ???????
}

this.draw = function (ctx) {
this._recalPosition();
ctx.drawImage(this.img, this.x, this.y, this.width, this.height);
}
}

Тут все понятно. С равноускоренным падение так же все просто, Y = Y0 + V0 * T + (g * T * T) / 2. Т.е. зная начальную высоту и время создания объекта (запоминаем Date.now()) рассчитывается положение тела. Но далее встает вопрос о столкновении с поверхностью. Понятно, что нужно учитывать текущую скорость и изменение координаты и скорости за промежуток времени. А при столкновении умножать скорость на -1. Но вот как это формульно описать?

Edited by Odrin
Link to comment
Share on other sites

18 answers to this question

Recommended Posts

  • 0

Самое простое, это добавить условие:

if( this.vy < 0 && this.y <= 0 )this.vy = -1 * this.vy;

, которое нужно понимать так: Если скорость объекта направлена к нижней границе и координата объекта пересекла нижнюю границу, то скорость объекта должна изменить свой знак. Это соответствует абсолютно упругому отталкиванию от плоскости в направлении перпендикулярном плоскости, что следует из закона сохранения импульса.

Link to comment
Share on other sites

  • 0

nerv,

Совсем не то.

freeneutron,

Это и так понятно. "Формульно описать" я имел ввиду динамику движения. Со столкновением все просто.

У нас есть текущее состояние тела (для простоты будем только по оси Y). Координата - Y, скорость по оси Y - Vy, и дельта T (Date.now() - сохраненное время).

Соответственно первое, что приходит в голову:

this._recalcPosition = function () {
var now = Date.now();
var dt = (Date.now() - this.timestamp) / 1000;
this.y = this.y + this.vy * dt + g * dt * dt / 2;
this.vy = this.vy + g * dt;
this.timestamp = now;
}

Но мяч почему-то падает очень медленно.

Собственно вот как это выглядит.

:facepalmxd: Уж не потому ли это, что 1 м. != 1 px :rolleyes: А время я привожу к секундам, да и ускорение свободного падения в м/с?. Так все таки, как это правильно сделать-то?

Edited by Odrin
Link to comment
Share on other sites

  • 0

ball.vy - это скорость мячика по оси Y (т.е. вниз)

world.gravity - это гравитация (в реальном мире сила притяжения Земли равна 9.8 метров в секунду в квадрате), для игры и вообще для анимаций это слишком быстро, т.к. там масштабы мира дургие. Поэтому везде (ну может не везде - я в книгах читал) ставят гравитацию от балды. Я поставил 0.9, т.к. это выглядит реалистично.

Скорость - это вектор, ускорение - тоже вектор. Получается что скорость мяча в начале анимации это вектор (0, 0), а сила притяжения (ускорение) это вектор (0, 0.9). По правилам сложения векторов нужно сложить их соответствующие компоненты. Т.е. допустим у нас есть 2 вектора - вектор А(x, y) и вектор B(x, y), чтобы их сложить надо сделать так:

A + B = (A.x + B.x, A.y + B.y)

Нас интересует только движение вниз, поэтому мы на координату X можем забить. Вот и получается, что скорость равна:

ball.vy = ball.vy + world.gravity;

или короче

ball.vy += world.gravity;

Ну а world.friction это коэффициент трения. Вообще он рассчитывается по разным формулам в зависимости от того трение о воздух у нас или трение качения или, например, трение скольжения. В целом для игр его тоже можно взять от балды :) Что я и сделал. Точные формулы расчета трения можно нагуглить - «коэффициент трения» в Google.. На этот коэффициент надо умножить вектор скорости. Сам коэффициент - это не вектор, а скаляр, т.е. просто число. Чтобы умножить вектор на скаляр надо умножить все его компоненты на скаляр:

A * number = (A.x * number, B.x * number)

Мы помним, что нас интересует только A.y (т.е. ball.vy), т.к. шар по горизонтали у нас не движется. Значит надо вектор скорости умножить на коэффициент:

ball.vy = ball.vy * world.friction;

или короче

ball.vy *= world.friction;

Кстати, я напортачил с трением :) Вот правильные расчеты: http://jsfiddle.net/qgm2G/1/ (если world.friction = 1, то трения нет, чем ближе world.friction к нулю, тем больше трение). Как по мне наиболее реалистично смотрится коэффициент 0.98

UPD:

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

  • Like 2
Link to comment
Share on other sites

  • 0

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

Link to comment
Share on other sites

  • 0

Great Rash,

Спасибо, все теперь понятно.

freeneutron,

Если решать эту задачу таким способом и, допустим, уже по двум осям с произвольным направлением движения, то при каждом столкновении высчитывается вектор скорости тела (значения Vx и Vy), timestamp заново сбрасывается на Date.now() и пускаем тело по формуле равноускоренного движения с новыми начальными значениями до следующего столкновения. Правильно?

  • Like 1
Link to comment
Share on other sites

  • 0

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

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

Great Rash,

Спасибо, все теперь понятно.

freeneutron,

Если решать эту задачу таким способом и, допустим, уже по двум осям с произвольным направлением движения, то при каждом столкновении высчитывается вектор скорости тела (значения Vx и Vy), timestamp заново сбрасывается на Date.now() и пускаем тело по формуле равноускоренного движения с новыми начальными значениями до следующего столкновения. Правильно?

Верно. Кстати, ppm - это количество пикселей в метре.

Link to comment
Share on other sites

  • 0

В игровых движках интегрирование по Эйлеру наверное вообще не используется. Гораздо интересней интгрирование Верле или Рунге-Кутта (я видел сравнительный анализ - Рунге-Кутта почти не дает погрешности). Однако я имел в виду, что Эйлера можно использовать для написания своей игры, т.к. он прост для понимания.

Link to comment
Share on other sites

  • 0

nerv,

Совсем не то.

ну-ну. Только почему-то в результате получилось то, что по приведенным мною ссылкам ;)

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

Edited by nerv
Link to comment
Share on other sites

  • 0
ну-ну. Только почему-то в результате получилось то, что по приведенным мною ссылкам

Все-таки там не совсем то. Да результат похож, но там скорее выражения для анимации чем для эмуляции именно физики.

Link to comment
Share on other sites

  • 0

ну-ну. Только почему-то в результате получилось то, что по приведенным мною ссылкам ;)

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

Уважаемый, Я далеко не новечек и перед тем как "однозначно заявлять НЕТ", я подробно изучил Ваши ссылки.

Edited by Odrin
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. See more about our Guidelines and Privacy Policy