javascript游戏引擎中奇怪的碰撞检测行为。

时间:2014-04-12 23:32:24

标签: javascript html5 html5-canvas collision-detection game-engine

如果你玩“游戏”我已经设置了一会儿,你会发现当你跳到它上面时,化身会从第二个平台上掉下来。我简直无法理解为什么会这样。我知道这可能比应该发布的代码更多,但是我的智慧结束了,也许有人可以很快看到我做错了什么。 有问题的“游戏”。只需使用箭头键进行跑步和跳跃即可。

http://jsfiddle.net/QGB69/

//RequestAnimationFrame shim. 

window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;


//Initializing canvas and world

var canvas = document.getElementById('viewport');
var ctx = canvas.getContext('2d');
var keysDown = [];
var currentPlatform = 0;

//some helpful variables

var canvasHeight = $('#viewport').height();
var canvasWidth = $('#viewport').width();


//Add keycodes to 'keysDown' array

$(document).keydown(function (e) {
    if ($.inArray(e.which, keysDown) === -1) {
        keysDown.push(e.keyCode);
    }
});


//Remove keycodes from 'keysDown' array

$(document).keyup(function (e) {
    if ($.inArray(e.which, keysDown) > -1) {
        keysDown = $.grep(keysDown, function (n, i) {
            return n !== e.which;
        });
    }
});


//Avatar object, lots of attributes, great import!

var avatar = {};

avatar.xPos = 50;
avatar.yPos = 50;
avatar.accl = 0.55;
avatar.decel = 0.85;
avatar.jReduction = 1.25;
avatar.direction = null;
avatar.stopping = false;
avatar.avatarHeight = 50;
avatar.avatarWidth = 25;
avatar.fallTime = 0;
avatar.isGrounded = false;
avatar.isJumping = false;
avatar.endJump = false;
avatar.jump = 18;
avatar.j = avatar.jump;
avatar.jStrength = 0.55;
avatar.speed = 13;
avatar.prevXPos = 0;
avatar.xDelta = 0;
avatar.xVelocity = 0;
avatar.yVelocity = 0;
avatar.yBottom = 0;
avatar.xAlignment = 0;


avatar.collDetect = function (args) {

    avatar.yBottom = avatar.yPos + avatar.avatarHeight;
    avatar.xPosRight = avatar.xPos + avatar.avatarWidth;


    for (i = 0; i < arguments.length; i++) {
        if (avatar.yBottom > arguments[i].boxTop) {
            if (avatar.xPos > arguments[i].xPos) {
                if (avatar.direction === 'left' && avatar.xDelta > avatar.xPos - arguments[i].xPosRight) {
                    avatar.xPos = arguments[i].xPosRight;
                    avatar.xStop();
                } else if (avatar.direction === 'left' && avatar.xPos <= arguments[i].xPosRight) {
                    avatar.xPos = arguments[i].xPosRight;
                    avatar.xStop();
                }
            } else if (avatar.xPos < arguments[i].xPos) {
                if (avatar.direction === 'right' && avatar.xDelta > arguments[i].xPos - avatar.xPosRight) {
                    avatar.xPos = arguments[i].xPos - avatar.avatarWidth;
                    avatar.xStop();
                } else if (avatar.direction === 'right' && avatar.xPos >= arguments[i].xPos) {
                    avatar.xPos = arguments[i].xPos - avatar.avatarWidth;
                    avatar.xStop();
                }
            }
        }

        if (avatar.xPos > arguments[i].xPos - avatar.avatarWidth && avatar.xPos < arguments[i].xPos + arguments[i].boxWidth) {
            currentPlatform = arguments[i].boxHeight;
        } else {
            currentPlatform = 0;
        }
    }
};

avatar.xStop = function () {
    avatar.xVelocity = 0;
    avatar.xDelta = 0;
    avatar.stopping = false;
    avatar.direction = null;
};

//First obstacle. Good luck gettin' over this one, avatar! 

function Box(xPos, boxWidth, boxHeight, boxColor) {
    this.xPos = xPos;
    this.boxWidth = boxWidth;
    this.boxHeight = boxHeight;
    this.boxColor = boxColor;
    this.xPosRight = xPos + boxWidth;
    this.boxTop = canvasHeight - boxHeight;
}

function renderBoxes(n) {
    for (i = 0; i < arguments.length; i++) {
        ctx.fillStyle = arguments[i].boxColor;
        ctx.fillRect(arguments[i].xPos,
        canvasHeight - arguments[i].boxHeight,
        arguments[i].boxWidth,
        arguments[i].boxHeight);
    }
}

var box1 = new Box(100, 50, 100, 'gray');
var box2 = new Box(300, 50, 125, 'green');


//physics object. Properties of the world     

var physx = {};
physx.gravity = 1;
physx.colliding = false;
physx.fallTimeModifier = 0.5;


//Big movement function. The action's in here!

function moveIt() {

    //Jump!

    if ($.inArray(38, keysDown) > -1) {

        if (avatar.j > 0) {
            avatar.isGrounded = false;
            avatar.isJumping = true;
            avatar.yPos -= avatar.j;
            avatar.yVelocity = avatar.j;
            avatar.j -= avatar.jStrength;
        } else if (avatar.j <= 0) {
            avatar.isJumping = false;
        }
    }

    //End Jump, initiated when the user lets off the jump key mid-jump.

    if (avatar.endJump === true) {

        if (avatar.j > 0) {
            avatar.j -= avatar.jReduction;
            avatar.yPos -= avatar.j;
        } else if (avatar.j <= 0) {
            avatar.isJumping = false;
            avatar.endJump = false;
        }

    }

    $(document).keyup(function (e) {
        if (e.which === 38 && avatar.isJumping === true) {
            avatar.endJump = true;
        }
    });

    //Accounting for deceleration when avatar stops.

    if (avatar.stopping === true) {

        if ((avatar.xVelocity - avatar.decel) <= 0) {
            avatar.xStop();
            return;
        }

        if (avatar.direction === 'right') {
            avatar.xPos += avatar.xVelocity;
            avatar.xVelocity -= avatar.decel;
            avatar.xDelta = avatar.xVelocity;
        }

        if (avatar.direction === 'left') {
            avatar.xPos -= avatar.xVelocity;
            avatar.xVelocity -= avatar.decel;
            avatar.xDelta = avatar.xVelocity
        }
    }


    //Correcting glitchy stopping behavior when conflicting left/right keycodes present in 'keysDown' array

    if ($.inArray(37, keysDown) > -1 && $.inArray(39, keysDown) > -1) {
        avatar.stopping = true;
    }

    //right

    if ($.inArray(39, keysDown) > -1) {

        if (avatar.stopping === false) {
            avatar.direction = 'right';
            if (avatar.xVelocity >= avatar.speed) {
                avatar.xPos += avatar.speed;
                avatar.xDelta = avatar.speed;
            } else {
                avatar.xPos += avatar.xVelocity;
                avatar.xVelocity += avatar.accl;
                avatar.xDelta = avatar.xVelocity;
            }
        }
    }


    //left

    if ($.inArray(37, keysDown) > -1) {

        if (avatar.stopping === false) {
            avatar.direction = 'left';
            if (avatar.xVelocity >= avatar.speed) {
                avatar.xPos -= avatar.speed;
                avatar.xDelta = avatar.speed;
            } else {
                avatar.xPos -= avatar.xVelocity;
                avatar.xVelocity += avatar.accl;
                avatar.xDeta = avatar.xVelocity;
            }
        }
    }


    //Set avatar.isStopping to true when 

    $(document).keyup(function (e) {
        if (e.which === 39 || e.which === 37) {
            avatar.stopping = true;
        }
    });
}

//Gravity function. Keep him on the dang ground!

function grav() {

    if (avatar.isJumping) {
        return;
    }

    if (avatar.yPos >= (canvasHeight - currentPlatform) - avatar.avatarHeight) {
        avatar.isGrounded = true;
        avatar.fallTime = 0;
    } else {
        if ((avatar.fallTime * physx.gravity) > (((canvasHeight - currentPlatform) - avatar.avatarHeight) - avatar.yPos)) {
            avatar.yPos = (canvasHeight - currentPlatform) - avatar.avatarHeight;
            avatar.isGrounded = true;
            avatar.j = avatar.jump;
            avatar.fallTime = 0;
        } else {
            avatar.yPos += avatar.fallTime * physx.gravity;
            avatar.fallTime += physx.fallTimeModifier;
        }
    }
}


//Render the dang thing, ya dingus!

function render() {

    ctx.clearRect(0, 0, canvasWidth, canvasHeight);
    renderBoxes(box1, box2);
    avatar.collDetect(box2, box1);
    grav();
    ctx.fillStyle = 'red';
    ctx.fillRect(avatar.xPos,
    avatar.yPos,
    avatar.avatarWidth,
    avatar.avatarHeight);
    moveIt();

谢谢!

1 个答案:

答案 0 :(得分:0)

看起来你几乎想通了这个,因为我注意到你已经颠倒了碰撞检测调用中的方框顺序。不过,我会继续告诉你它在哪里。

if (avatar.xPos > arguments[i].xPos - avatar.avatarWidth && avatar.xPos < arguments[i].xPos + arguments[i].boxWidth) {
            currentPlatform = arguments[i].boxHeight;

        } else {
            currentPlatform = 0;
        }

所以这里的这个位于循环内部。因为你使用if / else,所以它总是只适用于第二个框。意思是,即使第一次通过循环设置currentPlatform = X,第二次传递也会设置currentPlatform = 0.。

对于此特定问题,请尝试

if (avatar.xPos > arguments[i].xPos - avatar.avatarWidth && avatar.xPos < arguments[i].xPos + arguments[i].boxWidth) {
            currentPlatform = arguments[i].boxHeight;
            break; // <-- here

        } else {
            currentPlatform = 0;
        }