【问题标题】:Simple Javascript collision detection?简单的Javascript碰撞检测?
【发布时间】:2016-12-24 14:21:39
【问题描述】:

我正在尝试使用 jquery、javascript、html 和 css 制作一个简单的游戏。我一直卡在碰撞检测上。

代码:

var map = [
[0,1,0,0,0,1,0,0,],
[0,1,0,0,0,1,0,0,],
[0,1,0,0,0,1,0,0,],
[0,1,1,1,0,1,0,0,],
[0,0,0,0,0,0,0,2,]  
];

function DrawMap() {

    for(var i=0; i < map.length; i++){
        for(var j=0; j < map[i].length; j++){
            if(parseInt(map[i][j]) == 0){
            $("#container").append("<div class='air'></div>");
            }
            if(parseInt(map[i][j]) == 1){
            $("#container").append("<div class='block'></div>");
            }
            if(parseInt(map[i][j]) == 2){
            $("#container").append("<div class='spike'></div>");
            }
        }
    }

}

window.onload=function() {
    DrawMap();

}

更多代码:

var guy=document.getElementById('guy');

var up = 0;
var guyLeft = 0;
var health = 100;



function anim(e){



if(e.keyCode==83){
   up +=10;
   guy.style.top = up + 'px';
   if(up >=400){
     up -=10;
   }

 }

if(e.keyCode==87){
   up -=10;
   guy.style.top = up + 'px';
if(up <=0){
     up +=10;
   }  
}




 if(e.keyCode==68){
   guyLeft +=10;
   guy.style.left = guyLeft + 'px';
     if(guyLeft >= 700){
     guyLeft -= 10;
   }d
 }

if(e.keyCode==65){
   guyLeft -=10;
   guy.style.left = guyLeft + 'px';
 if(guyLeft <= 0){
     guyLeft += 10;
   }
}

}

document.onkeydown=anim;im;

【问题讨论】:

  • document.onkeydown=anim;im;应该是 document.onkeydown=anim;我认为?你也可以在这里添加你的html代码吗?
  • 从根本上说,您可能想要采取的方法是跟踪该人的位置,不仅以像素为单位,而且以map[i][j] 坐标为单位。然后您可以检查该人将进入的下一个单元格以确定他是否应该碰撞。事实上,最好只在 i、j 坐标中跟踪人的位置,然后使用函数将它们映射到显示坐标。
  • 您可以先测试if (up &lt;= 0) { up = 0; },然后指定样式。
  • 旁注: 在你的 if 子句中,改用这个:if(e.keyCode==83){up+=10; if(up&gt;400){up-=10;} guy.style.top=up+'px';}(点击链接)。这就是 Nina Scholz 在上述评论中的意思。
  • 只是一个提示:如果你已经在使用 jQuery,那就全力以赴。它会让你的生活变得更轻松。因此,请使用所有普通 JS 的 jQuery 等效项,例如 $(window).load(function(){...}); 代替 window.onload = function(){...};,以及 $(document).keydown(function(){...}); 代替 document.onkeydown=function(){...}; 等...

标签: javascript jquery html collision-detection


【解决方案1】:

简答:使用document.elementFromPoint(x,y); 来检测播放器所在位置的元素。

长答案:看看下面的代码 sn-p。

现在,我意识到我对您的代码进行了很多更改,包括对功能的不必要更改。抱歉,这是因为最初我只是为自己玩,但现在它正在工作,它可能对某人有用。
(您可能不知道使用的某些语法,请参阅底部我的帖子有一些解释。)

冲突部分在function checkCollision() 中,if 子句在$(document).keydown 中:

  • 在 keydown if 子句中调用 checkCollision()else {tile = checkCollision(...);
  • 基本上我会检查播放器的前部(顶视图)是否会在即将到来的位置发生碰撞:
    (for (var i=corner1; i&lt;corner2; ++i) {...})。
    • 根据碰撞图块(“spike”或“block”),我要么生成警报 (console.log),要么将 checkTile 返回到调用 checkCollision() 的 if 子句。
  • 如果返回tile,则tile的位置用于确定player的位置:
    $(player).css("left",(tile?$(tile).offset().left+$(tile).width():x));

代码 sn-p:

//DOCUMENT-READY==========================
$(document).ready(function() {
  //VARS----------------------------------
  var step = 10;
  var health = 100;
  
  //MAP-----------------------------------
  var map = [
    [0,1,0,0,0,1,0,0],
    [0,1,0,0,0,1,0,0],
    [0,1,0,0,0,1,0,0],
    [0,1,1,1,0,1,0,0],
    [0,0,0,0,0,0,0,2]
  ];
  
  //DRAW MAP------------------------------
  (function() {
    var tile = "";
    for (var y=0,county=map.length; y<county; ++y) {
      $("#canvas").append('<div class="tile-row" id="row_'+(y+1)+'"></div>');
      for (var x=0,countx=map[y].length; x<countx; ++x) {
        switch (parseInt(map[y][x])) {
          case 0: tile="air"; break;
          case 1: tile="block"; break;
          case 2: tile="spike"; break;
          default: tile="error";
        }
        $("#row_"+(y+1)).append('<div class="tile '+tile+'"></div>');
      }
    }
  })();
  
  //SET BOUNDARIES------------------------
  var xMin=$("#canvas").offset().left, xMax=xMin+$("#canvas").width()-$("#player").width();
  var yMin=$("#canvas").offset().top, yMax=yMin+$("#canvas").height()-$("#player").height();
  
  //PLACE PLAYER--------------------------
  $("#player").css("left",xMin).css("top",yMin);
  
  //MOVE PLAYER---------------------------
  $(document).keydown(function(e){
    var player=document.getElementById("player"), tile=null;
    var x=$(player).offset().left, playerLeft=x, playerRight=playerLeft+$(player).width();
    var y=$(player).offset().top, playerTop=y, playerBottom=playerTop+$(player).height();
    
    function checkCollision(playerCorner1x, playerCorner1y, playerCorner2x, playerCorner2y) {
      var collisionTiles=["block","spike"];
      //check if the front of the player is colliding with the environment
      var front = (playerCorner1x==playerCorner2x?playerCorner1x:playerCorner1y);
      var corner1 = (front==playerCorner1x?playerCorner1y:playerCorner1x);
      var corner2 = (front==playerCorner1x?playerCorner2y:playerCorner2x);
      //check every pixel along the front for collision
      for (var i=corner1; i<corner2; ++i) {
        var checkTile = document.elementFromPoint((front==playerCorner1x?front:i), (front==playerCorner1y?front:i));
        if (collisionTiles.indexOf(checkTile.className.split(" ")[1]) != -1) {
          if ($(checkTile).hasClass("spike")) {console.log("YOU DEAD!");}
          else if ($(checkTile).hasClass("block")) {return checkTile;}
          break;
        }
      }
    }
    
    if(e.which==37 || e.which==65){ //LEFT,A
      x -= step;
      if (x <= xMin) {x = xMin;}
      else {tile = checkCollision(playerLeft-step,playerTop, playerLeft-step,playerBottom);}
      $(player).css("left",(tile?$(tile).offset().left+$(tile).width():x));
    }
    if(e.which==39 || e.which==68){ //RIGHT,D
      x += step;
      if (x >= xMax) {x = xMax;}
      else {tile = checkCollision(playerRight+step,playerTop, playerRight+step,playerBottom);}
      $(player).css("left",(tile?$(tile).offset().left-$(player).width():x));
    }
    if(e.which==38 || e.which==87){ //UP,W
      y -= step;
      if (y <= yMin) {y = yMin;}
      else {tile = checkCollision(playerLeft,playerTop-step, playerRight,playerTop-step);}
      $(player).css("top",(tile?$(tile).offset().top+$(tile).height():y));
    }
    if(e.which==40 || e.which==83){ //DOWN,S
      y += step;
      if (y >= yMax) {y = yMax;}
      else {tile = checkCollision(playerLeft,playerBottom+step, playerRight,playerBottom+step);}
      $(player).css("top",(tile?$(tile).offset().top-$(player).height():y));
    }
  });
});
div {margin:0; padding:0; border-style:none; box-sizing:border-box; overflow:hidden;}

/*CANVAS================*/
#canvas {display:inline-block;}

/*TILES=================*/
.tile-row {width:100%; height:40px;}
.tile {float:left; width:40px; height:100%;}
.tile.air {background-color:skyblue;}
.tile.block {background-color:sienna;}
.tile.spike {background-color:gray;}
.tile.error {background-color:red;}

/*PLAYER================*/
#player {position:absolute; width:15px; height:15px; background-color:black;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

<div id="canvas"></div>
<div id="player"></div>
jsfiddle:https://jsfiddle.net/Lqw9w06z/11/

解释/评论:

  • (function(){...})(); 是一个IIFE (Immediately Invoked Function Expression),它是一个自动执行的函数。
  • front==playerCorner1x?playerCorner1y:playerCorner1x 被称为 Conditional (ternary) Operator,它基本上是一个紧凑的 if 子句。
  • 图块的大小在 CSS 中设置:
    .tile-row {width:100%; height:40px;}.tile {width:40px; height:100%;}
    这决定了整个画布/游戏板的大小。
  • 我更改了您的 for-loop,以便将一行的所有图块包裹在包含 div 的内容中。

旁注:

由于某种原因,碰撞没有记录在一个特定的位置(见下文)。
如果有人可以向我解释为什么会在这个特定地点发生这种情况,我会很高兴!

【讨论】:

  • 这帮助我克服了最大的障碍,谢谢(尽管网站“建议”我不这样做。)
猜你喜欢
  • 1970-01-01
  • 2011-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多