samedi 26 mai 2018

2d circle rect collision with details

I have game with map builded by rectangles, darker rectangles (named "closed") mean its place where balls should be able to move, ball should reflect from the lighter rectangles(named "open") border. In future Ill add more balls and they will reflect from each other.

The problem is with new Vector after collision.

I force function circleRectGetCollisionNormal() to return vector(-1,0) what i think its normal for this case. Ball is starting with deegres and change it simply to vector, this reflection worked for 45 deegres but when I change angle to 10 deegres ball moved into lighter rectangles(named "open").

Here is how it looks like (Picture)

Im doing like this:

1-check is ball collid with lighter rectangle.

2-if it collid, i want to change direction so i return vector for example for right side of ball colliding with rectangle return [-1,0] (I think its normal of vertical line, and its pointing left direction).

3-calculate new ball move Vector from this equation: newMoveVector = oldMoveVector − (2 * dotProduct(oldMoveVector, normalVector) * normalVector)

Here is code for each step:

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);
    }

And here is main function for this

        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;
    }

Object Vector always contain 2 values all of function (mult, sub, div, add) work like here.

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

Please give me advice, actual solution or tell about different way to do this reflection. I waste more than 3 days trying to solve this, I have to move on.





Aucun commentaire:

Enregistrer un commentaire