Прямое столкновение 2d круга и отражение не работает - PullRequest
0 голосов
/ 26 мая 2018

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

Проблема в новом векторе после столкновения.

Я заставляю функцию circleRectGetCollisionNormal () возвращать вектор (-1,0) что я считаю нормальным для этого случая (мяч движется в правильном направлении).Мяч начинается с градусов и меняется просто на вектор, это отражение работало для 45 градусов, но когда я меняю угол на 10 градусов, шар перемещался в более светлые прямоугольники (называемые «открытыми»).

Вот какэто выглядит так (рисунок)

Я делаю так:

1 - проверьте, не столкнулся ли шар с более светлым прямоугольником, 2 - если он столкнулся, я хочу изменить направление так,Я возвращаю вектор, например, если правая сторона шара сталкивается с возвращением прямоугольника [-1,0] (я думаю, что это нормаль вертикальной линии и направление влево).

3 - вычисление движения нового шара Векториз этого уравнения: newMoveVector = oldMoveVector − (2 * dotProduct(oldMoveVector, normalVector) * normalVector)

Вот код для каждого шага:

1.

   circleRect(circlePos, circleSize, rectPos, rectSize) { 
//its rectRect collision but it doesnt matter because reflection surface is always horizontal or vertical
        let r1 = {
            left: circlePos.x - circleSize.x/2,
            right: circlePos.x + circleSize.x/2,
            top: circlePos.y - circleSize.y/2,
            bottom: circlePos.y + circleSize.y/2
        };
        let r2 = {
            left: rectPos.x,
            right: rectPos.x + rectSize.x,
            top: rectPos.y,
            bottom: rectPos.y + rectSize.y
        };  
    return !(r2.left > r1.right || 
        r2.right < r1.left || 
        r2.top > r1.bottom ||
        r2.bottom < r1.top);
    }

    isOnOpenTile(pos: Vector, size: Vector) {
        let openTiles = this.getTiles('open');
        let result = false;
        openTiles.forEach(element => {
            if( this.circleRect(pos,size,element.pos,element.size) ){
                 result = element;
                return;
            }
        });
        return result;
    }

2.

    circleRectGetCollisionNormal(c, r) {
        if(c.pos.y <= r.pos.y - (r.size.y/2)) return new Vector(0,-1);
        //Hit was from below the brick
        if(c.pos.y >= r.pos.y + (r.size.y/2)) return new Vector(0,1);
        //Hit was from above the brick
        if(c.pos.x < r.pos.x) return new Vector(1,0);
        //Hit was on left
        if(c.pos.x > r.pos.x) return new Vector(-1,0);
        //Hit was on right
        return false;
    }

3.

    getNewMoveVector(moveVector, normalVector) {
        normalVector = this.normalize(normalVector);
        let dot = (moveVector.x * moveVector.y) + (normalVector.x * normalVector.y);
        let dotProduct = new Vector(dot, dot);
        return moveVector.sub(dotProduct.mult(normalVector).mult(new Vector(2,2)));
    }

    normalize(v) {
        let length = Math.sqrt((v.x*v.x) + (v.y*v.y));
        return new Vector(v.x/length,v.y/length);
    }

И вот основная функция для этого

        getMoveVectorOnCollision(circle) {
        let coll = this.isOnOpenTile( circle.pos, circle.size );
        if( coll != false) {
            let vector = this.circleRectGetCollisionNormal(circle, coll);
            return this.getNewMoveVector(circle.moveVector, vector);
        } else return false;
    }

Объект Vector всегда содержит 2 значения, все функции (mult, sub, div, add) работают так, как здесь.

sub(vector: Vector) {
    return new Vector(this.x - vector.x, this.y - vector.y);
}

Пожалуйста, дайте мне совет, реальное решение или расскажите о другом способе сделать это отражение.Я потратил больше 3 дней, пытаясь решить эту проблему, я должен идти дальше.

1 Ответ

0 голосов
/ 26 мая 2018

Ваш точечный расчет продукта ошибочен.Измените эти строки:

let dot = (moveVector.x * moveVector.y) + (normalVector.x * normalVector.y);
let dotProduct = new Vector(dot, dot);

на эту одну строку:

let dotProduct = (moveVector.x * normalVector.x  + moveVector.y * normalVector.y);

Обратите внимание, что dotProduct это скалярное значение , а не вектор, поэтому вы должны сделатьвектор для вычитания как

subvec.x = 2 * dotProduct * normalVector.x
subvec.y = 2 * dotProduct * normalVector.y

и

return moveVector.sub(subvec);
...