2016-11-30 77 views
0

我正在創建一個簡單的平臺遊戲。我正在嘗試創建與對象的碰撞並能夠檢測這些碰撞。通過下面的代碼,我無法正確檢測碰撞,並在碰撞時阻止玩家移動。應該發生的是代碼應該檢查是否與level.Objects數組中的任何對象發生衝突。我現在的代碼沒有檢測到碰撞,並且你落入地下無限。我將如何創建一個函數來正確檢測碰撞並在碰撞的哪一側返回true?更好的2D畫布碰撞檢測

function runGame() { 
 
    var game = document.getElementById('game') 
 
    var ctx = game.getContext("2d") 
 
    var DonaldRest = document.getElementById('DonaldRest') 
 
    var GrassTile = document.getElementById('GrassTile') 
 
    var gravity = 0.5 
 
    var momentum = 0; 
 
    var momentumDown = 0; 
 
    var spacing = 64; 
 
    var speed = 2; 
 
    var maxSpeed = 2; 
 
    var jumpHeight = 3; 
 
    var levels = [{ 
 
    Name: "Level 1", 
 
    Objects: [{ 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: 0, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 1, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 2, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 3, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 4, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 5, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 6, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 7, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 8, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 9, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 10, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 11, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 12, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 13, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 14, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 15, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 16, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 17, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 18, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 19, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 20, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 21, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 22, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 23, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 24, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 25, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 26, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 27, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 28, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, { 
 
     Type: "GrassFloor", 
 
     Location: { 
 
     x: spacing * 29, 
 
     y: 0 
 
     }, 
 
     Scale: { 
 
     x: 1, 
 
     y: 1 
 
     }, 
 
     Solid: true, 
 
     Height: 3 
 
    }, ] 
 
    }] 
 
    var player = { 
 
    position: { 
 
     x: 0, 
 
     y: 0 
 
    }, 
 
    Time: 0 
 
    } 
 
    ctx.canvas.width = window.innerWidth; 
 
    ctx.canvas.height = window.innerHeight; 
 
    var game = setInterval(function() { 
 
    ctx.imageSmoothingEnabled = false 
 
    ctx.clearRect(0, 0, window.innerWidth, window.innerHeight); 
 
    ctx.fillStyle = "#adfffa" 
 
    ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height) 
 
    ctx.drawImage(DonaldRest, ctx.canvas.width/2 - (96/2), ctx.canvas.height/2 - (96/2), 96, 96) 
 
    var Level = levels[0] 
 
    var Objects = Level.Objects 
 
    var OnGround = checkCollisions().Bottom 
 
    if (OnGround == false) { 
 
     if (momentumDown <= maxSpeed) { 
 
     momentumDown -= gravity; 
 
     player.position.y += momentumDown; 
 
     } else { 
 
     player.position.y += momentumDown; 
 
     } 
 
    } else { 
 
     momentumDown = 0; 
 
     console.log("collided") 
 
    } 
 
    for (var j = 0; j < Objects.length; j++) { 
 
     if (Objects[j].Type == "GrassFloor") { 
 
     ctx.drawImage(GrassTile, Objects[j].Location.x - player.position.x, (ctx.canvas.height - spacing + player.position.y) - (spacing * Objects[j].Height), spacing, spacing) 
 
     for (var i = -5; i < Objects[j].Height; i++) { 
 
      ctx.drawImage(DirtTile, Objects[j].Location.x - player.position.x, (ctx.canvas.height - spacing) - (i * spacing) + player.position.y, spacing, spacing) 
 
     } 
 
     } 
 
    } 
 
    }, 17); //17 
 

 
    $(document).keydown(function(e) { 
 
    if (e.which == 32) { 
 
     if (checkCollisions().Bottom == true) { 
 
     console.log(momentumDown); 
 
     momentumDown -= jumpHeight 
 
     console.log(momentumDown); 
 
     } 
 
    } 
 
    }) 
 

 
    function isTouchingFloor(e1, e2) { 
 
    return e1.x < (e2.x + e2.w) && (e1.x + e1.w) > e2.x && e1.y - momentumDown < (e2.y + e2.h) && (e1.y - momentumDown + e1.h) > e2.y; 
 
    } 
 

 
    function checkCollisions() { 
 
    var Objects = levels[0].Objects; 
 
    var Collision = { 
 
     Top: false, 
 
     Left: false, 
 
     Bottom: false, 
 
     Right: false 
 
    } 
 
    var GrassTileImg = new Image() 
 
    var o1 = { 
 
     y: player.position.y, 
 
     h: 96, 
 
     x: player.position.x, 
 
     w: 96 
 
    } 
 
    for (var i = 0; i < Objects.length; i++) { 
 
     var o2 = { 
 
     y: Objects[i].Location.y, 
 
     x: Objects[i].Location.x, 
 
     h: 64, 
 
     w: 64 
 
     } 
 
     if (isTouchingFloor(o1, o2) == true) { 
 
     Collision.Bottom == true; 
 
     } 
 
     console.log(Collision.Bottom) 
 
    } 
 
    return Collision 
 
    } 
 
}

回答

0

這是我在做檢查的碰撞一組項目,我使用的代碼片段。本質上我們做一個函數來檢查兩個物體和相應側面之間的碰撞。

衝突功能

/** 
 
* Checks for a collision of two objects. Moves objectA if side is a string with the word move. 
 
* @param objectA The object that needs to move. 
 
* @param objectB The object that needs to block. 
 
* @param side If true, makes return a string. If "move", moves objectA. 
 
* @returns {*} String if side evaluates to true, otherwise boolean. 
 
*/ 
 
function checkCollision(objectA, objectB, side) { 
 
    if (side) { 
 
    var vx = objectA.centerX() - objectB.centerX(), 
 
     vy = objectA.centerY() - objectB.centerY(), 
 

 
     combinedHalfWidths = objectA.halfWidth() + objectB.halfWidth(), 
 
     combinedHalfHeights = objectA.halfHeight() + objectB.halfHeight(), 
 

 
     collisionSide = ""; 
 

 
    if (Math.abs(vx) < combinedHalfWidths && Math.abs(vy) < combinedHalfHeights) { 
 
     var overlapX = combinedHalfWidths - Math.abs(vx), 
 
     overlapY = combinedHalfHeights - Math.abs(vy); 
 

 
     if (overlapX > overlapY) { 
 
     if (vy > 0) { 
 
      if (side === "move") { 
 
      objectA.vy = objectB.vy; 
 
      objectA.y += overlapY; 
 
      } 
 

 
      collisionSide = "top"; 
 
     } else { 
 
      if (side === "move") { 
 
      objectA.vy = objectB.vy; 
 
      objectA.y -= overlapY; 
 
      } 
 

 
      collisionSide = "bottom"; 
 
     } 
 
     } else { 
 
     if (vx > 0) { 
 
      if (side === "move") { 
 
      objectA.vx = objectB.vx; 
 
      objectA.x += overlapX; 
 
      } 
 

 
      collisionSide = "left"; 
 
     } else { 
 
      if (side === "move") { 
 
      objectA.vx = objectB.vx; 
 
      objectA.x -= overlapX; 
 
      } 
 

 
      collisionSide = "right"; 
 
     } 
 
     } 
 
    } 
 
    return collisionSide; 
 
    } else { 
 
    return !(objectA.x + objectA.width < objectB.x || 
 
     objectB.x + objectB.width < objectA.x || 
 
     objectA.y + objectA.height < objectB.y || 
 
     objectB.y + objectB.height < objectA.y); 
 
    } 
 
}

該功能確實爲我們在水平已加載的所有對象的檢查。

碰撞檢查

function doCollisionChecks() { 
 
    var checkPush = false; 
 
    player.isOnGround = false; 
 
    for (var i = 0; i < solids.length; i++) { 
 
    if (checkCollision(player, solids[i], "move") === "bottom") { 
 
     player.isOnGround = true; 
 
     player.state = player.STANDING; 
 
     if (solids[i].vx) { 
 
     if (solids[i].vx !== player.extraVX) { 
 
      player.extraVX = solids[i].vx 
 
     } 
 
     } else { 
 
     player.extraVX = 0; 
 
     } 
 
    } 
 
    } 
 
    for (i = 0; i < objects.length; i++) { 
 
    if (checkCollision(objects[i], player, true) === "right" || checkCollision(objects[i], player, true) === "left") { 
 
     player.speedLimit = scaleWidth(2); 
 
     objects[i].speedLimit = scaleWidth(2); 
 
     checkPush = true; 
 
    } 
 

 
    //Letting the player move boxes, while avoiding a "box hop" bug. 
 
    if (checkCollision(objects[i], player, true) === "top") { 
 
     player.y = objects[i].y - player.height; 
 
    } else if (checkCollision(objects[i], player, true) === "bottom") { 
 
     player.y = objects[i].y + objects[i].height; 
 
    } else if (player.centerY() > objects[i].y + objects[i].height * 0.1 && player.centerY() < objects[i].y + objects[i].height * 0.9) { 
 
     checkCollision(objects[i], player, "move"); 
 
    } 
 

 
    for (var j = 0; j < solids.length; j++) { 
 
     if (checkCollision(objects[i], solids[j], "move") === "bottom" && solids[j].vx) { 
 
     objects[i].extraVX = solids[j].vx; 
 
     } else { 
 
     objects[i].extraVX = 0; 
 
     } 
 
     checkCollision(objects[i], solids[j], "move"); 
 
    } 
 

 
    for (j = 0; j < objects.length; j++) { 
 
     if (j !== i) { 
 
     //Avoids boxes falling through one another. 
 
     if (checkCollision(objects[i], objects[j], true) === "top") { 
 
      checkCollision(objects[j], objects[i], "move"); 
 
     } else { 
 
      checkCollision(objects[i], objects[j], "move"); 
 
     } 
 
     } 
 
    } 
 

 
    if (checkCollision(player, objects[i], true) === "bottom") { 
 
     player.isOnGround = true; 
 
     player.state = player.STANDING; 
 
     player.extraVX = objects[i].extraVX; 
 
    } else if (checkCollision(player, objects[i], true) === "top") { 
 
     score -= 50; 
 
     gameState = OVER; 
 
    } 
 
    checkCollision(player, objects[i], "move"); 
 

 
    if (objects[i].y > c.height) { 
 
     if (objects[i].correct) { 
 
     score += 100; 
 
     objects.splice(i, 1); 
 
     checkWin(); 
 
     } else { 
 
     fRed = 0; 
 
     score -= 100; 
 
     objects.splice(i, 1); 
 
     } 
 
    } 
 
    } 
 

 
    for (i = 0; i < enemies.length; i++) { 
 
    if (checkCollision(enemies[i], player)) { 
 
     score -= 50; 
 
     gameState = OVER; 
 
    } 
 
    j = 0; 
 
    while (enemies[i] && j < objects.length) { 
 
     if (checkCollision(objects[j], enemies[i], true) === "bottom") { 
 
     score += 75; 
 
     objects[j].vy = -1 * scaleHeight(6); 
 
     enemies.splice(i, 1); 
 
     //score++ 
 
     } 
 
     j++; 
 
    } 
 
    } 
 
    if (checkCollision(player, powerUp)) { 
 
    score += 25; 
 
    activatePowerUp(); 
 
    } 
 
    if (!checkPush) { 
 
    player.speedLimit = scaleWidth(3); 
 
    for (i = 0; i < objects.length; i++) { 
 
     objects[i].speedLimit = scaleWidth(3); 
 
    } 
 
    } 
 
}

很抱歉,但有很多使用這種速度限制等無關的屬性,但它工作正常。

您可以找到全部來源here