【问题标题】:Javascript settimeouts on html whack a mole gamehtml 中的 Javascript settimeout 打鼹鼠游戏
【发布时间】:2016-12-22 12:32:30
【问题描述】:

我一直在尝试创建一个 html 打鼹鼠游戏,其中鼹鼠以特定间隔添加了一个类,然后触发另一个超时功能,让用户有 3 秒的时间单击鼹鼠并删除该类在进行检查以确定该痣是否仍然具有附加到它的类之前。

这是我的游戏的 jsfiddle:https://jsfiddle.net/gko9puqf/1/,下面是我的 javascript。

var score = 0;
var numberofpipes = 9;
var lastnum = 0;
var intervalseconds;
var interval;
var haslost = false;
var checkpipetimer;
var timeoutfunc;
var timeoutinit;
var timers = [];
var burstingpipes = {};
var timeoutinit = setTimeout(startaburst, 3000);
$('#scorecontainer').text(score);
//starts a bursting pipe
function startaburst() {
  clearTimeout(timeoutinit);
  if (score < 10) {
    intervalseconds = 2;
  } else if (score >= 10 && score < 25) {
    intervalseconds = 1.5;
  } else if (score >= 25 && score < 40) {
    intervalseconds = 1;
  } else if (score >= 40 && score < 60) {
    intervalseconds = 0.5;
  } else if (score >= 60) {
    intervalseconds = 0.25;
  } else if (score > 100) {
    intervalseconds = 0.1;
  }
  interval = intervalseconds * 1000;
  burstingpipe();
  //creating a loop with the new timeout value as the game gets harder.
  //also assigning it to the timeoutfunc variable so i can cancel the loop later.
  timeoutfunc = setTimeout(startaburst, interval);
}

//adds the bursting pipe attributes to the pipe intersections
function burstingpipe() {
  randomnum = Math.floor(Math.random() * 9) + 1;
  //cant be the same twice in case of overlapping
  if ((randomnum == lastnum) || $("." + randomnum).hasClass("burstingpipe")) {
    //if the random num is still valid after -1, -1
    if (((randomnum - 1) >= 0) && !($("." + (randomnum - 1)).hasClass("burstingpipe"))) {
      randomnum = (randomnum - 1);
      //add one to the random number
    } else if (((randomnum + 1) <= (numberofpipes)) && !($("." + (randomnum + 1)).hasClass("burstingpipe"))) {
      randomnum = (randomnum + 1);
    } else {
      burstingpipe();
    }
  }
  //make the lastnum the current number so we dont get 2 in a row
  lastnum = randomnum;
  randomdiv = $("." + randomnum);
  console.log(randomdiv.hasClass("burstingpipe"));
  //adds shake animation and red glow
  console.log(randomnum);
  randomdiv.addClass("burstingpipe");

  //setting a timeout of 3 seconds, so th user has 3 seconds to press each 
  //bursting pipe before it bursts.
  checkpipetimer = setTimeout(haspipeburst.bind(this, randomdiv), 3000);
}

//function to check if the pipe has burst.
function haspipeburst(pipecheck) {
  console.log(pipecheck);
  console.log(pipecheck.hasClass("burstingpipe"));
  //checking to see if the pipe still has the class attached after 3 seconds
  //and if the user has already lost.
  if (pipecheck.hasClass("burstingpipe")) {
    //if the pipe still has the class attached - game over.
    haslost = true;
    $("#result").text("you have lost");
    //stopping the loop.
    clearTimeout(timeoutfunc);
    //changing the background color to make it look like the pipe has broken.
    //(will possibly change to image in future)
    //$(".hitpoint").removeClass("burstingpipe");
    $(pipecheck).css("background-color", "#49c1e2");
  }
}

//when the user clicks a hitpoint the class is removed and they gain a point.
$(document).on('click', '.hitpoint', function() {
  if ($(this).hasClass("burstingpipe") && haslost == false) {
    $(this).removeClass("burstingpipe");
    score++;
    $("#scorecontainer").text(score);
  }
});

它按预期工作,直到超时显着缩短(大约 40 分)并且痣出现故障,就好像超时被忽略了一样。

我已经盯着代码看了好几个小时了,但进展甚微,所以我希望你能帮助我!我认为这与未正确完成超时有关。

非常感谢任何帮助,谢谢。

【问题讨论】:

  • settimeout 不会像您使用的那样有问题
  • 是的,同意对不起,这是我关于堆栈溢出的第一篇文章,我的意思是我使用它们的方式,显然某处存在缺陷。

标签: javascript jquery html settimeout


【解决方案1】:

添加的有点晚,但在其他任务之间做了一些工作。如前所述,启动多个计时器的一个问题是您需要记住特定的计时器,而不仅仅是最后一个。在下面的代码中,这是通过在具有自己的计时器的单个类(函数)中保留一个“爆破管道”来完成的。

也许我有点过火了,但正如其他人所说,我喜欢你制作的游戏 :) 更改之一不是循环遍历所有管道以获得不会爆裂的管道,而是从可用管道中移除管道一旦爆发。这也消除了对 div 进行编号的需要。更多细节在 code-cmets。当然你可以完全忽略这段代码,但既然我已经完成了,我还是把它贴出来。

Fiddle

var score = 24; //set higher for testing purposes
var pipes = $('.hitpoint').toArray() ,
	last = null,
  haslost = false,
	interval = 2, //start interval
	thresholds = {10: 1.5, 25: 1 , 40: 0.5, 60:0.25, 100 :1}; //interval thresholds
setTimeout(startaburst, 3000); //intial timeout (doesn't need to be cleared, because it's fired once)

$('#scorecontainer').text(score);
//starts a bursting pipe
function startaburst() {
	if(haslost)return; //already lost
  
  if(pipes.length>0){ //pick a pipe to burst unless all pipes allready bursting
    var i;
    while(true){
      var p = pipes[i = Math.floor(Math.random() * pipes.length)]; //get random element from the available pipes
      if(p!==last || pipes.length === 1)break;
    }  
    pipes.splice(i,1); //remove pipe from available pipes
    last = p; //remember last to prevent reusing the same pipe twice
    new burstingPipe(p);
	}
  
  setTimeout(startaburst, interval * 1000); //wait until staring the new burst. interval is increased inside backInGame if the score increases
}

function burstingPipe(pipe){
	this.pipe = $(pipe);
  this.pipe.addClass("burstingpipe");  
  
  function checkBurst(){  
  	this.dispose();
  	if(haslost)return; //already lost on other pipe
    haslost = true;
    $("#result").text("you have lost");
    //changing the background color to make it look like the pipe has broken.
    //(will possibly change to image in future)    		
    this.pipe.css("background-color", "#49c1e2");
  };
  
  this.dispose=function(){
  	this.pipe.off('click'); //unbind click (no longer bursting or already burst)
  	this.pipe.removeClass("burstingpipe");    
  }
  
  function backInGame(){  	
  	clearTimeout(this.timer); //clear the burst timeout (specific for this pipe)
    this.dispose();
    pipes.push(this.pipe[0]); //make pipe available again (NB, because the array contains of DOM elements and not jquery objects, [0] is needed)
    var int = thresholds[++score]; //increase the score and check if interval should be increased for the new score
    if(int && int < interval){ 
    	//optional: some message or css that interval is increased
    	interval =int;
    }
    $("#scorecontainer").text(score);
  }
  
  this.pipe.click(backInGame.bind(this)); //bind the click
  this.timer =setTimeout(checkBurst.bind(this), 3000);
}
@keyframes shake {
  5%,
  15%,
  25%,
  35%,
  45%,
  55%,
  65%,
  75%,
  85%,
  95% {
    left: 0;
    right: 1vh;
    outline: none;
    border-color: red;
    box-shadow: 0 0 10px red;
  }
  10%,
  20%,
  30%,
  40%,
  50%,
  60%,
  70%,
  80%,
  90%,
  100% {
    left: 1vh;
    right: 0;
    outline: none;
    border-color: red;
    box-shadow: 0 0 10px red;
  }
}

@-webkit-keyframes shake {
  5%,
  15%,
  25%,
  35%,
  45%,
  55%,
  65%,
  75%,
  85%,
  95% {
    left: 0;
    right: 1vh;
    outline: none;
    border-color: red;
    box-shadow: 0 0 10px red;
  }
  10%,
  20%,
  30%,
  40%,
  50%,
  60%,
  70%,
  80%,
  90%,
  100% {
    left: 1vh;
    right: 0;
    outline: none;
    border-color: red;
    box-shadow: 0 0 10px red;
  }
}

@-moz-keyframes shake {
  5%,
  15%,
  25%,
  35%,
  45%,
  55%,
  65%,
  75%,
  85%,
  95% {
    left: 0;
    right: 1vh;
    outline: none;
    border-color: red;
    box-shadow: 0 0 10px red;
  }
  10%,
  20%,
  30%,
  40%,
  50%,
  60%,
  70%,
  80%,
  90%,
  100% {
    left: 1vh;
    right: 0;
    outline: none;
    border-color: red;
    box-shadow: 0 0 10px red;
  }
}

@-o-keyframes shake {
  5%,
  15%,
  25%,
  35%,
  45%,
  55%,
  65%,
  75%,
  85%,
  95% {
    left: 0;
    right: 1vh;
    outline: none;
    border-color: red;
    box-shadow: 0 0 10px red;
  }
  10%,
  20%,
  30%,
  40%,
  50%,
  60%,
  70%,
  80%,
  90%,
  100% {
    left: 1vh;
    right: 0;
    outline: none;
    border-color: red;
    box-shadow: 0 0 10px red;
  }
}

html {
  height: 100%;
  width: 100%;
}

* {
  margin: 0;
  padding: 0;
}

body {
  height: 100%;
  width: 100%;
}

#gamecontainer {
  height: 100%;
  width: 100%;
  background-color: #49c1e2;
}

#gameinformation {
  height: 10%;
  display: flex;
  flex-direction: row;
  align-items: center;
  padding-left: 10%;
}

#pipecontainer {
  height: 80%;
  width: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
}

.pipe {
  height: 8vh;
  width: 100vw;
  background-color: #a5a5a5;
  display: flex;
  flex-direction: row;
  justify-content: space-around;
}

.hitpoint {
  height: 10vh;
  width: 10vh;
  background-color: #6d6d6d;
  border-radius: 2vh;
  position: relative;
  bottom: 1vh;
  cursor: pointer;
}

#scoretext {
  color: #fff;
  font-size: 6vh;
}

#scorecontainer {
  color: #fff;
  font-size: 6vh;
}

#statusupdate {
  color: #fff;
  font-size: 6vh;
}

.burstingpipe {
  animation-name: shake;
  animation-duration: 3s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="gamecontainer">
  <div id="gameinformation">
    <p id="scoretext">Score:&nbsp;</p>
    <div id="scorecontainer">
    </div>
  </div>
  <div id="pipecontainer">
    <div class="pipe">
      <div class="hitpoint"></div>
      <div class="hitpoint"></div>
      <div class="hitpoint"></div>
    </div>
    <div class="pipe">
      <div class="hitpoint"></div>
      <div class="hitpoint"></div>
      <div class="hitpoint"></div>
    </div>
    <div class="pipe">
      <div class="hitpoint"></div>
      <div class="hitpoint"></div>
      <div class="hitpoint"></div>
    </div>
  </div>
  <div id="statusupdate">
    <p id="result"></p>
  </div>
</div>

【讨论】:

  • 您好,感谢您花时间为我的问题寻找解决方案!我找到了一个不同的解决方案来给每个单独的管道一个唯一的超时,这是通过将超时存储在一个动态变量中(通过使用两个变量创建)“管道”+管道唯一编号。这样我可以在单击管道时清除各个超时。但是,您所做的方式看起来更干净并且使用的代码更少,因此我可能不得不重构我的解决方案!我也很高兴您喜欢我的游戏 :),再次感谢您抽出时间提供解决方案。
【解决方案2】:

我喜欢你的游戏:)

这是你的问题:当分数增加时,你正在减少超时间隔以同时拥有多个 shacked 区域。如果用户松动,要停止所有计时器,您正在使用这一行:

timeoutfunc = setTimeout(startaburst, interval);

然后

clearTimeout(timeoutfunc);

这不起作用,因为timeoutfunc 将只包含最后一次启动的超时,而不是所有启动的超时(请记住,虽然每 3 秒检查一次,但抖动超时将运行多次)。因此,您需要一个数组来保留所有间隔,然后将它们全部清除。

我更新了你的小提琴(也删除了一些不需要的行)

var score = 0;
var numberofpipes = 9;
var lastnum = 0;
var intervalseconds;
var interval;
var haslost = false;
var checkpipetimer;
var timeoutfunc = [];
var timers = [];
var burstingpipes = {};
setTimeout(startaburst, 3000);
$('#scorecontainer').text(score);
//starts a bursting pipe
function startaburst() {
  if (score < 10) {
    intervalseconds = 2;
  } else if (score >= 10 && score < 25) {
    intervalseconds = 1.5;
  } else if (score >= 25 && score < 40) {
    intervalseconds = 1;
  } else if (score >= 40 && score < 60) {
    intervalseconds = 0.5;
  } else if (score >= 60) {
    intervalseconds = 0.25;
  } else if (score > 100) {
    intervalseconds = 0.1;
  }
  interval = intervalseconds * 1000;
  burstingpipe();
  //creating a loop with the new timeout value as the game gets harder.
  //also assigning it to the timeoutfunc variable so i can cancel the loop later.

  timeoutfunc.push(setTimeout(startaburst, interval));
}

//adds the bursting pipe attributes to the pipe intersections
function burstingpipe() {
  randomnum = Math.floor(Math.random() * 9) + 1;
  //cant be the same twice in case of overlapping
  if ((randomnum == lastnum) || $("." + randomnum).hasClass("burstingpipe")) {
    //if the random num is still valid after -1, -1
    if (((randomnum - 1) >= 0) && !($("." + (randomnum - 1)).hasClass("burstingpipe"))) {
      randomnum = (randomnum - 1);
      //add one to the random number
    } else if (((randomnum + 1) <= (numberofpipes)) && !($("." + (randomnum + 1)).hasClass("burstingpipe"))) {
      randomnum = (randomnum + 1);
    } else {
      burstingpipe();
    }
  }
  //make the lastnum the current number so we dont get 2 in a row
  lastnum = randomnum;
  randomdiv = $("." + randomnum);
  console.log(randomdiv.hasClass("burstingpipe"));
  //adds shake animation and red glow
  console.log(randomnum);
  randomdiv.addClass("burstingpipe");

  //setting a timeout of 3 seconds, so th user has 3 seconds to press each 
  //bursting pipe before it bursts.
  checkpipetimer = setTimeout(haspipeburst.bind(this, randomdiv), 3000);
}

//function to check if the pipe has burst.
function haspipeburst(pipecheck) {
  console.log(pipecheck);
  console.log(pipecheck.hasClass("burstingpipe"));
  //checking to see if the pipe still has the class attached after 3 seconds
  //and if the user has already lost.
  if (pipecheck.hasClass("burstingpipe")) {
    //if the pipe still has the class attached - game over.
    haslost = true;
    $("#result").text("you have lost");
    //stopping the loop.
    for (var i = timeoutfunc.length - 1; i >= 0; i--) {
       clearTimeout(timeoutfunc[i]);
    }
    //changing the background color to make it look like the pipe has broken.
    //(will possibly change to image in future)
    //$(".hitpoint").removeClass("burstingpipe");
    $(pipecheck).css("background-color", "#49c1e2");
  }
}

//when the user clicks a hitpoint the class is removed and they gain a point.
$(document).on('click', '.hitpoint', function() {
  if ($(this).hasClass("burstingpipe") && haslost == false) {
    $(this).removeClass("burstingpipe");
    score++;
    $("#scorecontainer").text(score);
  }
});

【讨论】:

  • 您好,感谢您的浏览!但似乎问题仍然存在,是不是因为我在突发管道函数中的第二个超时函数也需要存储为数组?
  • 看起来像将第二批计时器添加到数组已修复它!谢谢你的帮助!!!!!!
猜你喜欢
  • 1970-01-01
  • 2020-03-14
  • 2011-03-14
  • 2014-01-23
  • 2023-03-21
  • 2013-06-28
  • 2011-05-30
  • 1970-01-01
  • 2016-09-28
相关资源
最近更新 更多