JavaScript 游戏中的 if 语句未按预期工作以允许碰撞检测

if statement in JavaScript game not working as desired to allow for collision detection

我正在通过 HTML、CSS 和 JScript 游戏中的一些基本步骤来获得非常简单的 碰撞检测 在 CHARACTER 和一个敌人。

我正在寻找足够简单的东西来向 8 - 11 岁的 children 解释。

如果角色和敌人发生碰撞则“游戏结束”。我尝试了各种方法,但需要一些代码方面的帮助和 getComputedStyle 方法的解释以及它获得的属性,以便我有效地创建主 if 语句。

这是相关的if函数:

if(
        characterTop==enemyLeft //have tried characterRight==enemyLeft didn't work
    )
    {
        enemy.style.animation="none"; //remove the animation
        enemy.style.display="none";
        alert("Game Over");
        
    } 
},10);

这是 setInterval 函数,其中声明了变量(我在 if 函数中使用)。我已经基于 varcharacterTop 变量和 enemyLeft 创建了 var CharacterRight 变量,但它似乎不起作用,或者我不确定我是否以正确的方式进行处理。

在当前设置中发生了一些奇怪的事情。如果我离开角色并且不移动它,那么在(敌人的)5 次弹跳之后游戏就结束了,尽管根据 if 函数,characterTop 根本没有改变。那么那里发生了什么?

在回答中,请:

a) 根据我现有的代码提出碰撞检测的建议解决方案

b) GetComputedStyle 和 getProperties 的说明及其文档。例如,如果 characterTop 没有改变(如果我不移动角色)它怎么会突然输出“游戏结束”这表明 characterTop 是 == enemyLeft.

c) 简单碰撞检测的最佳实践(对于绝对初学者的学习概念并提出最简单的可能解决方案,给定现有代码)

var checkDead =setInterval(function(){
    var characterTop = parseInt(window.getComputedStyle(character).getPropertyValue("top"));
    var enemyLeft = parseInt(window.getComputedStyle(enemy).getPropertyValue("left"));
    //ADD VARIABLE TO FIND CHARACTER RIGHT -if it collides with enemy left, you are out
    //remove the condition that the enemy has to be in the first 30 pixels of the game (left side)
    var characterRight =parseInt(window.getComputedStyle(character).getPropertyValue("right"));

为了完整性,这里是完整的代码:

HTML

<!DOCTYPE html>

<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <link rel="stylesheet" href="style.css">
    
</head>
<body>
  <h1>Game</h1>
 
   
   
   <div id="game">
        <div id="sky"></div>
       <div id="ground"></div>
        <div id="enemy"></div>
       <div id="character"></div>
   </div>
   
<script src="script.js"></script>
</body>

</html>

CSS

*{
    padding:0;
    margin:22;
}

#game{
    width:500px;
    height:500px;
    border:4px solid #171918;
}

#character{
    width:30px;
    height:120px;
    background-color:green;
    position:relative;
    top:320px;
    border-radius:20px;
    /*animation: jump 300ms */
    
}

/* new class called animate */
.animate{
    animation: jump 500ms;
}


#enemy{
    width:60px;
    height:60px;
    background-color:red;
    border-radius:14px;
    position:relative;
    top:320px;
    left:440px;
    animation: moveenemy 1s infinite linear;
    
}

@keyframes moveenemy{
    0%{left:440px;}
    50%{top:58px;}
    100%{left:0px; top:320x;}
}

@keyframes jump{
    0%{top:380px;}
    30%{top:50px;}
    50%{top:40px;}
    100%{top:380px;}
}





/* adding sky*/
#sky{
    width:500px;
    height:340px;
    background-color:skyblue;
    position:absolute;
    top:118px;
}

/* adding ground */
#ground{
    width:500px;
    height:170px;
    background-color:bisque;
    position:absolute;
    top:450px;
}

JavaScript

var character = document.getElementById("character");
var enemy = document.getElementById("enemy");    
function jump(){
    if(character.classlist!="animate"){
    character.classList.add("animate");
    }
    setTimeout(function(){
        character.classList.remove("animate");
    },500);
    
}

//right movement

function right() {
  var leftVal =  parseInt(window.getComputedStyle(character).getPropertyValue("left"))
  character.style.left = (leftVal + 30) + "px";

}

//left movement
function left() {

  var leftVal =  parseInt(window.getComputedStyle(character).getPropertyValue("left"))
  character.style.left = (leftVal - 30) + "px";

}

var checkDead =setInterval(function(){
    var characterTop = parseInt(window.getComputedStyle(character).getPropertyValue("top"));
    var enemyLeft = parseInt(window.getComputedStyle(enemy).getPropertyValue("left"));
    //ADD VARIABLE TO FIND CHARACTER RIGHT -if it collides with enemy left, you are out
    //remove the condition that the enemy has to be in the first 30 pixels of the game (left side)
    var characterRight =parseInt(window.getComputedStyle(character).getPropertyValue("right"));
    
    console.log(characterRight);
    console.log(enemyLeft)
  
    if(
        characterTop==enemyLeft //have tried characterRight==enemyLeft didn't work
    )
    {
        enemy.style.animation="none"; //remove the animation
        enemy.style.display="none";
        alert("Game Over");
        
    } 
},10);


//left
addEventListener("keydown", function(e) {
    if(e.keyCode == 37) left()
})

//jump (up)
addEventListener("keydown", function(e) {
  if (e.keyCode === 38) {
    jump()
  }
})

//right
addEventListener("keydown", function(e) {
  if (e.keyCode === 39) {
    right()
  }
})

我看过这个文档,但它似乎没有提到 objects。 https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle

把提出的点按顺序排列:

a) 根据我现有的代码提出碰撞检测的建议解决方案

您不能在此处使用 getComputedStyle(参见 b 点)。下面是使用带有碰撞检测的 getBoundingClientRect 的代码(即当敌人和角色完全重叠时)

b) GetComputedStyle 和 getProperties 的说明及其文档。例如,如果 characterTop 没有改变(如果我不移动角色)它怎么会突然输出“游戏结束”这表明 characterTop is == enemyLeft.

getComputedStyle 就是这样做的,它遍历所有样式设置并合并它们,以便您获得元素的当前样式。例如参见 [​​=12=]

The Window.getComputedStyle() method returns an object containing the values of all CSS properties of an element, after applying active stylesheets and resolving any basic computation those values may contain.

我们在这种情况下遇到的问题是,它不是我们所追求的计算样式,而是此时此刻元素的实际位置,该元素正在 window 周围飞行 CSS动画。因此使用 getBoundingClientRect 获取元素的实际当前 x 和 ys。

原作中角色上部对着敌人左侧的测试并没有告诉你任何信息。但偶尔它们可能会匹配,所以你会游戏结束。

c)简单碰撞检测的最佳实践(初学者学习概念)

老实说,我不认为我可以在这方面自以为是,因为我不知道学生们已经有多少 geometry/algebra 等等。下面使用的代码检测敌人是否完全位于角色上方,反之亦然,如果不是,则是否完全位于另一个敌人的左侧。否则它们会重叠。

这是完整的代码。不幸的是,SO 的代码片段系统似乎没有响应按键事件,因此我无法在此处将其作为可运行的代码片段呈现。

<!DOCTYPE html>

<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
    *{
    padding:0;
    margin:22;
}

#game{
    width:500px;
    height:500px;
    border:4px solid #171918;
}

#character{
    width:30px;
    height:120px;
    background-color:green;
    position:relative;
    top:320px;
    border-radius:20px;
    /*animation: jump 300ms */
    
}

/* new class called animate */
.animate{
    animation: jump 500ms;
}


#enemy{
    width:60px;
    height:60px;
    background-color:red;
    border-radius:14px;
    position:relative;
    top:320px;
    left:440px;
    animation: moveenemy 1s infinite linear;    
}

@keyframes moveenemy{
    0%{left:440px;}
    50%{top:58px;}
    100%{left:0px; top:320x;}
}

@keyframes jump{
    0%{top:380px;}
    30%{top:50px;}
    50%{top:40px;}
    100%{top:380px;}
}





/* adding sky*/
#sky{
    width:500px;
    height:340px;
    background-color:skyblue;
    position:absolute;
    top:118px;
}

/* adding ground */
#ground{
    width:500px;
    height:170px;
    background-color:bisque;
    position:absolute;
    top:450px;
}
</style>    
</head>
<body>
  <h1>Game</h1>
 
   
   
   <div id="game">
        <div id="sky"></div>
       <div id="ground"></div>
        <div id="enemy"></div>
       <div id="character"></div>
   </div>
   
<script>
var character = document.getElementById("character");
var enemy = document.getElementById("enemy");    
function jump(){
    if(character.classlist!="animate"){
    character.classList.add("animate");
    }
    setTimeout(function(){
        character.classList.remove("animate");
    },500);
    
}

//right movement

function right() {
  var leftVal =  parseInt(window.getComputedStyle(character).getPropertyValue("left"))
  character.style.left = (leftVal + 30) + "px";

}

//left movement
function left() {

  var leftVal =  parseInt(window.getComputedStyle(character).getPropertyValue("left"))
  character.style.left = (leftVal - 30) + "px";

}

var checkDead = setInterval(function(){
       
    // Get the positions of the top, left and bottom, right of the enemy and the character    
    let enemyPos = enemy.getBoundingClientRect() // this will give us the left, right, top and bottom positions of the enemy
    let characterPos = character.getBoundingClientRect() // this will give us the left, right, top and bottom positions of the character

    // now let's see if there is any overlap between the enemy and the character

   // we are going to check whether one of them is to the left of the other.
   // For example if the left side of the enemy is bigger than the right side of the character then the enemy is to the right of the character
    if (enemyPos.left >= characterPos.right || characterPos.left >= enemyPos.right) {
       // Now we know they don't overlap as either the enemy is to the right of the character or vice versa so do nothing
    }
    
       // if we still don't know, we see whether the character is above the enemy or vice versa
    else if (enemyPos.bottom <= characterPos.top || characterPos.bottom <= enemyPos.top) {
       // Now we know they don't overlap as either the enemy is above the character or vice versa so do nothing
    }
      
      // neither of them is totally to the left or totally above the other so they must overlap somewhere- GOTCHA!
    else {
        enemy.style.animation="none"; //remove the animation
        enemy.style.display="none";
        alert("Game Over");
        clearInterval(checkDead); //I've added this but you may want to start again completely or....
    }        
  },10 );


//left
addEventListener("keydown", function(e) {
    if(e.keyCode == 37) left()
})

//jump (up)
addEventListener("keydown", function(e) {
  if (e.keyCode === 38) {
    jump()
  }
})

//right
addEventListener("keydown", function(e) {
  if (e.keyCode === 39) {
    right()
  }
})
</script>

</body>

</html>