簡體   English   中英

更好的2D畫布碰撞檢測

[英]Better 2D canvas collision detection

我正在創建一個簡單的平台游戲。 我試圖與對象創建碰撞並能夠檢測到這些碰撞。 使用下面提供的代碼,我無法正確檢測到碰撞並在碰撞時阻止玩家移動。 應該發生的是代碼應該檢查是否與level.Objects數組中的任何對象發生沖突。 我現在擁有的代碼無法檢測到沖突,因此您陷入了無窮無盡的困境。 我將如何創建一個能夠正確檢測碰撞並在碰撞的那一側返回true的函數?

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

這是我在進行團隊項目以檢查沖突時使用的代碼片段。 本質上,我們提供了一個功能來檢查兩個對象和相應側面之間的碰撞。

碰撞功能

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

抱歉,但是使用了許多不相關的屬性,例如速度限制等。但是它可以正常工作。

您可以在此處找到整個資源。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM