Search code examples
javascriptfunctionfor-looprequestanimationframe

Why can't I use a function to do collision check in javascript?


I have a simple collision detection working that lets you jump off of blocks, and yet if I call a function that has the same code block in it. It will break.

call without the function:

    for(let i = 0; i < blocks.length; i++){
        if(blockCollision(sprite, blocks[i])){
            sprite.vy = 0;
            // sprite.vy += gravity;

            if(blockCollisionLeft(sprite, blocks[i])){
                sprite.vx = 0;
                sprite.x = blocks[i].x - sprite.w - offset;
            }
            if(blockCollisionRight(sprite, blocks[i])){
                sprite.vx = 0;
                sprite.x = blocks[i].x + blocks[i].w + offset;
            }

            if(blockCollisionTop(sprite, blocks[i])){
                sprite.y = blocks[i].y - sprite.h - offset;
                sprite.canJump = true;
            }else{
                // sprite.vy = 0;
                sprite.y = blocks[i].y + blocks[i].h + offset;
                sprite.vy += gravity;
            }
        }
    }

and the call with the function:

    for(let i = 0; i < blocks.length; i++){
         if(blockCollision(sprite, blocks[i])){
             checkCollisions(sprite, blocks[i]);
             break;
         }
    }

I'm not sure what to do at this point, the sprite block keeps jumping out of control, can't quite understand why a function call would do this.

const PI = Math.PI;
const offset = 1;
const gravity = .33;

function inCanvas(obj){
    if(obj.x - offset < 0 && obj.x + obj.w + offset > w
        && obj.y - offset < 0 && obj.y + obj.h + offset > h){
            return true;
        }
    return false;
}

function groundCollision(obj){
    if(obj.y + obj.h + offset == h){
        return true;
    }
    return false;
}

function blockCollision(obj, block){
    if(obj.x - offset < block.x + block.w && obj.x + obj.w + offset > block.x
        && obj.y - offset < block.y + block.h && obj.y + obj.h + offset > block.y){
            return true;
        }
    return false;
}

function blockCollisionTop(obj, block){    
    if(obj.y + obj.h + offset > block.y && obj.y + obj.h + offset < block.y + block.h){
        return true;
    }
    return false;
}

function blockCollisionLeft(obj, block){
    if(obj.x + obj.w + offset > block.x && obj.x + obj.w < block.x){
            return true;
        }
    return false;
}

function blockCollisionRight(obj, block){
    if(obj.x - offset < block.x + block.w && obj.x > block.x + block.w){
            return true;
        }
    return false;
}

function Sprite(_x, _y, _w, _h){
    this.x = _x;
    this.y = _y;
    this.w = _w;
    this.h = _h;

    this.vx = 0;
    this.vy = 0;
    this.jv = -11;

    this.canJump = false;

    // this.maxv = 3;
};

Sprite.prototype.draw = function(){
    ctx.fillRect(this.x, this.y, this.w, this.h);
};

Sprite.prototype.update = function(){
    this.x += this.vx;
    this.y += this.vy;
    this.vy += gravity;
    // this.yv -= gravity;
    // this.xv -= gravity;
    // this.xv += gravity;

    if(this.y + this.h + offset > h){
        this.y = h - this.h - offset;
    }
    if(this.y - offset < 0){
        this.y = offset;
    }
    if(this.x - offset < 0){
        this.x = offset;
    }
    if(this.x + this.w + offset > w){
        this.x = w - this.w - offset;
    }
};

Sprite.prototype.jump = function(){
    this.vy = this.jv;
};
function Block(_x, _y, _w, _h){
    this.x = _x;
    this.y = _y;
    this.w = _w;
    this.h = _h;

    this.steppedOn = false;
};

Block.prototype.draw = function(){
    ctx.fillRect(this.x, this.y, this.w, this.h);
};
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
const w = canvas.width = 600;
const h = canvas.height = 600;

var right = false,
    left = false,
    up = false;

var sprite = new Sprite(100, 200, 20, 40);
var box1 = new Block(w - 300, h - 80, 300, 10);
var blocks = [];

for(let i = 1; i <= 10; i++){
    blocks.push(new Block(Math.round(Math.random() * w), Math.round(Math.random() * h), w/4 + Math.round(Math.random() * (w)), 15));
}

//console.log(blocks);

(function update(){
    ctx.clearRect(0, 0, w, h);

    sprite.draw();
    for(let i = 0; i < blocks.length; i++){
        blocks[i].draw();
    }
    box1.draw();
    sprite.update();

    // pOne.xv = left ? -2 : right ? 2 : 0;
    if(left && right){
        sprite.vx = 0;
    }
    else if(left){
        sprite.vx = -2;
    }
    else if(right){
        sprite.vx = 2;
    }
    else{
        sprite.vx = 0;
    }

    if(up && sprite.canJump){
        sprite.jump();
        sprite.canJump = false;
    }

    if(groundCollision(sprite)){
        sprite.canJump = true;
    }

    checkCollisions(sprite, box1);

    for(let i = 0; i < blocks.length; i++){
        if(blockCollision(sprite, blocks[i])){
            checkCollisions(sprite, blocks[i]);
             break;
         }
    }
    
    // if(blockCollision(sprite, box1)){
    //     // checkCollisions(sprite, box1);
    //     sprite.vy = 0;
    //     // sprite.vy += gravity;

    //     if(blockCollisionLeft(sprite, box1)){
    //         sprite.vx = 0;
    //         sprite.x = box1.x - sprite.w - offset;
    //     }
    //     if(blockCollisionRight(sprite, box1)){
    //         sprite.vx = 0;
    //         sprite.x = box1.x + box1.w + offset;
    //     }

    //     if(box1.steppedOn = blockCollisionTop(sprite, box1)){
    //         sprite.y = box1.y - sprite.h - offset;
    //         sprite.canJump = true;
    //     }else{
    //         // sprite.vy = 0;
    //         sprite.y = box1.y + box1.h + offset;
    //         sprite.vy += gravity;
    //     }
    // }

    window.addEventListener("keydown", (e)=>{
        // console.log(e.key);
        if(e.key == "a" || e.key == "ArrowLeft"){
            left = true;
        }
        if(e.key == "d" || e.key == "ArrowRight"){
            right = true;
        }
        if(e.key == " " || e.key == "ArrowUp"){
            up = true;
        }
    });

    window.addEventListener("keyup", (e)=>{
        if(e.key == "a" || e.key == "ArrowLeft"){
            left = false;
        }
        if(e.key == "d" || e.key == "ArrowRight"){
            right = false;
        }
        if(e.key == " " || e.key == "ArrowUp"){
            up = false;
        }
    });

    window.requestAnimationFrame(update);
}());

function checkCollisions(obj, block){
    if(blockCollision(obj, block)){
        obj.vy = 0;
        // obj.vy += gravity;

        if(blockCollisionLeft(obj, block)){
            obj.vx = 0;
            obj.x = block.x - obj.w - offset;
        }
        if(blockCollisionRight(obj, block)){
            obj.vx = 0;
            obj.x = block.x + block.w + offset;
        }

        if(block.steppedOn = blockCollisionTop(obj, block)){
            obj.y = obj.y - obj.h - offset;
            obj.canJump = true;
        }else{
            // obj.vy = 0;
            obj.y = block.y + block.h + offset;
            obj.vy += gravity;
        }
    }
}
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Block Jump</title>
    <style>
        *{margin:0; padding: 0;}
            #game{
                display:inherit;
                margin:30px auto;
                border:thin solid black;
            }
    </style>
</head>
<body>
    <canvas id="game"></canvas>
    <script src="JS/main.js"></script>
</body>


Solution

  • Your first two code snippets are not equivalent, you seem to have added a break statement in your example with a function. This will have the effect of terminating the for loop prematurely when blockCollision(sprite, blocks[i]) is true, which might be why you are seeing a difference between the two.

    edit: You also seem to have changed the third if-block slightly in your function. In your first code snippet that if-block is defined as:

    if(blockCollisionTop(sprite, blocks[i])){
        sprite.y = blocks[i].y - sprite.h - offset;
        sprite.canJump = true;
    }
    

    but in your function is defined as:

    if(block.steppedOn = blockCollisionTop(obj, block)){
        obj.y = obj.y - obj.h - offset;
        obj.canJump = true;
    }
    

    which is not equivalent because you have replaced blocks[i] with obj, but it should be block.