html上的Javascript settimeouts重击鼹鼠游戏

时间:2016-12-22 12:32:31

标签: javascript jquery html settimeout

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

这是我游戏的一个方面: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分),并且鼹鼠出现故障,好像忽略了超时。

我现在已经盯着代码几个小时并且进展不大,所以我希望你能帮助我!我相信它与未正确完成的超时有关。

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

2 个答案:

答案 0 :(得分:4)

有点迟到了,但是在这个中间的其他任务上工作了一点。如上所述,启动多个计时器的问题是您需要记住特定的计时器而不仅仅是最后一个计时器。在下面的代码中,通过保持&#39;爆破管道来完成。在单个类(函数)内部有自己的计时器。

也许我有点过火,但正如其他人所说,我喜欢你制作的游戏:)其中一个变化是没有循环通过所有管道来获得一个没有破裂的管道,但删除了一旦它破裂就从可用管道中取出管道。这也消除了对div编号的需要。代码注释中的更多细节。当然,你完全可以完全忽略这些代码,但是因为我已经完成了它,所以无论如何都要发布它。

Fiddle

&#13;
&#13;
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);
}
&#13;
@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;
}
&#13;
<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>
&#13;
&#13;
&#13;

答案 1 :(得分:3)

我喜欢你的游戏:)

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

  

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