部分修复
This commit is contained in:
339
frontend/smallgame/别踩白方块/game.js
Normal file
339
frontend/smallgame/别踩白方块/game.js
Normal file
@@ -0,0 +1,339 @@
|
||||
var c = document.getElementById("piano");
|
||||
var context = c.getContext("2d");
|
||||
var b = document.getElementById("background");
|
||||
var context_back = b.getContext("2d");
|
||||
var a = document.getElementById("score_bar");
|
||||
var context_score = a.getContext("2d");
|
||||
|
||||
|
||||
var numOfTiles = 5;
|
||||
var myScore = 0;
|
||||
var eachState = [false,false,false,false,false];
|
||||
var myTiles = [];
|
||||
|
||||
var intervalTmp;
|
||||
var geneTmp;
|
||||
var gameSpeed = 1; // 游戏速度倍数,初始为1倍
|
||||
var baseInterval = 5; // 基础更新间隔(毫秒)
|
||||
var baseGenerateInterval = 600; // 基础生成间隔(毫秒)
|
||||
|
||||
paintWindow();
|
||||
paintScoreBar();
|
||||
|
||||
// 添加全局鼠标和触摸事件监听
|
||||
c.addEventListener('click', function(e) {
|
||||
handleClick(e);
|
||||
});
|
||||
|
||||
c.addEventListener('touchstart', function(e) {
|
||||
e.preventDefault();
|
||||
handleTouch(e);
|
||||
});
|
||||
|
||||
document.getElementById('start_btn').addEventListener('click',function(e){
|
||||
var content = document.getElementById('start_btn');
|
||||
if(content.innerHTML == "开始游戏" || content.innerHTML == "继续游戏"){
|
||||
startGame();
|
||||
}
|
||||
else{
|
||||
pauseGame();
|
||||
}
|
||||
});
|
||||
|
||||
// 重新开始按钮事件
|
||||
document.getElementById('restart-btn').addEventListener('click', function(){
|
||||
restartGame();
|
||||
});
|
||||
|
||||
function startGame(){
|
||||
var content = document.getElementById('start_btn');
|
||||
updateGameSpeed();
|
||||
document.getElementById('music').play();
|
||||
content.innerHTML = "暂停游戏";
|
||||
content.className = "game-btn pause-btn";
|
||||
}
|
||||
|
||||
// 更新游戏速度
|
||||
function updateGameSpeed() {
|
||||
// 清除现有定时器
|
||||
if (intervalTmp) clearInterval(intervalTmp);
|
||||
if (geneTmp) clearInterval(geneTmp);
|
||||
|
||||
// 保持正常1倍速度,不加速
|
||||
gameSpeed = 1;
|
||||
|
||||
// 设置新的定时器,优化性能
|
||||
intervalTmp = setInterval(upDate, Math.max(baseInterval / gameSpeed, 3));
|
||||
geneTmp = setInterval(geneBlock, Math.max(baseGenerateInterval / gameSpeed, 200));
|
||||
}
|
||||
|
||||
function pauseGame(){
|
||||
var content = document.getElementById('start_btn');
|
||||
document.getElementById('music').pause();
|
||||
window.clearInterval(intervalTmp);
|
||||
window.clearInterval(geneTmp);
|
||||
content.innerHTML = "继续游戏";
|
||||
content.className = "game-btn start-btn";
|
||||
}
|
||||
|
||||
function gameOver(){
|
||||
document.getElementById('music').pause();
|
||||
window.clearInterval(intervalTmp);
|
||||
window.clearInterval(geneTmp);
|
||||
|
||||
// 显示最终得分和达到的最高速度
|
||||
document.getElementById('final-score-value').innerHTML = myScore;
|
||||
document.getElementById('final-speed-value').innerHTML = gameSpeed.toFixed(1);
|
||||
|
||||
// 显示游戏结束弹窗
|
||||
document.getElementById('game-over-modal').style.display = 'flex';
|
||||
}
|
||||
|
||||
function restartGame(){
|
||||
// 重置游戏状态
|
||||
myScore = 0;
|
||||
gameSpeed = 1; // 重置游戏速度
|
||||
eachState = [false,false,false,false,false];
|
||||
myTiles = [];
|
||||
|
||||
// 清空画布
|
||||
context.clearRect(0,0,300,600);
|
||||
context_back.clearRect(0,0,300,600);
|
||||
context_score.clearRect(0,0,300,60);
|
||||
|
||||
// 重新绘制背景
|
||||
paintWindow();
|
||||
paintScoreBar();
|
||||
|
||||
// 隐藏弹窗
|
||||
document.getElementById('game-over-modal').style.display = 'none';
|
||||
|
||||
// 重置按钮状态
|
||||
var content = document.getElementById('start_btn');
|
||||
content.innerHTML = "开始游戏";
|
||||
content.className = "game-btn start-btn";
|
||||
}
|
||||
function paintScoreBar(){
|
||||
// 清空画布
|
||||
context_score.clearRect(0,0,300,60);
|
||||
|
||||
// 绘制黑色背景
|
||||
context_score.fillStyle = "#333";
|
||||
context_score.fillRect(0,0,300,60);
|
||||
|
||||
// 更新HTML显示
|
||||
document.getElementById('score-value').textContent = myScore;
|
||||
document.getElementById('speed-value').textContent = gameSpeed.toFixed(1);
|
||||
}
|
||||
function geneBlock(){
|
||||
var myRand = Math.floor(Math.random()*numOfTiles);
|
||||
var i;
|
||||
var flag = true;
|
||||
for( i = 0; i < numOfTiles; ++i){
|
||||
if(!eachState[i]){
|
||||
flag = false;
|
||||
}
|
||||
}
|
||||
if(flag)return;//if mytiles array didn't have false element, then return
|
||||
|
||||
while(eachState[myRand])
|
||||
myRand = Math.floor(Math.random()*numOfTiles);
|
||||
myTiles[myRand] = new Block(myRand);
|
||||
|
||||
}
|
||||
function paintWindow(){
|
||||
// 清空背景
|
||||
context_back.clearRect(0,0,300,600);
|
||||
|
||||
// 绘制白色背景
|
||||
context_back.fillStyle = "white";
|
||||
context_back.fillRect(0,0,300,600);
|
||||
|
||||
// 绘制分隔线
|
||||
context_back.strokeStyle = "#ddd";
|
||||
context_back.lineWidth = 2;
|
||||
|
||||
// 垂直分隔线
|
||||
context_back.beginPath();
|
||||
context_back.moveTo(75,0);
|
||||
context_back.lineTo(75,600);
|
||||
context_back.stroke();
|
||||
|
||||
context_back.beginPath();
|
||||
context_back.moveTo(150,0);
|
||||
context_back.lineTo(150,600);
|
||||
context_back.stroke();
|
||||
|
||||
context_back.beginPath();
|
||||
context_back.moveTo(225,0);
|
||||
context_back.lineTo(225,600);
|
||||
context_back.stroke();
|
||||
|
||||
// 可点击区域警戒线
|
||||
context_back.strokeStyle = "#ff4444";
|
||||
context_back.lineWidth = 3;
|
||||
context_back.beginPath();
|
||||
context_back.moveTo(0,250);
|
||||
context_back.lineTo(300,250);
|
||||
context_back.stroke();
|
||||
|
||||
// 底部失败线
|
||||
context_back.strokeStyle = "#ff4444";
|
||||
context_back.lineWidth = 3;
|
||||
context_back.beginPath();
|
||||
context_back.moveTo(0,470);
|
||||
context_back.lineTo(300,470);
|
||||
context_back.stroke();
|
||||
}
|
||||
function Block(index){
|
||||
if(!eachState[index])
|
||||
eachState[index] = true;
|
||||
|
||||
this.index = index;
|
||||
this.appearPos = Math.floor(Math.random()*4);
|
||||
|
||||
this.width = 75;
|
||||
this.height = 120;
|
||||
this.color = "black";
|
||||
switch(this.appearPos){
|
||||
case 0:
|
||||
this.x = 0;
|
||||
this.y = -120;
|
||||
break;
|
||||
case 1:
|
||||
this.x = 75;
|
||||
this.y = -120;
|
||||
break;
|
||||
case 2:
|
||||
this.x = 150;
|
||||
this.y = -120;
|
||||
break;
|
||||
case 3:
|
||||
this.x = 225;
|
||||
this.y = -120;
|
||||
break;
|
||||
}
|
||||
context.fillStyle = this.color;
|
||||
context.fillRect(this.x,this.y,this.width,this.height);
|
||||
this.live = true;
|
||||
|
||||
window.addEventListener('keydown',function(e){
|
||||
myTiles[index].keyCode = e.keyCode;
|
||||
});
|
||||
window.addEventListener('keyup',function(e){
|
||||
myTiles[index].keyCode = false;
|
||||
});
|
||||
}
|
||||
function move(index){
|
||||
if(myTiles[index].live){
|
||||
myTiles[index].y += Math.ceil(gameSpeed);
|
||||
// 绘制逻辑已移到upDate函数中,避免重复绘制
|
||||
}
|
||||
}
|
||||
function afterRight(index){
|
||||
myScore++;
|
||||
// 清除方块(在upDate中统一处理绘制)
|
||||
myTiles[index].live = false;
|
||||
eachState[index] = false;
|
||||
|
||||
// 立即更新得分显示
|
||||
paintScoreBar();
|
||||
|
||||
// 每次得分都更新游戏速度,实现平滑渐进加速
|
||||
updateGameSpeed();
|
||||
}
|
||||
// 处理鼠标点击事件
|
||||
function handleClick(e) {
|
||||
var rect = c.getBoundingClientRect();
|
||||
var x = e.clientX - rect.left;
|
||||
var y = e.clientY - rect.top;
|
||||
|
||||
checkHit(x, y);
|
||||
}
|
||||
|
||||
// 处理触摸事件
|
||||
function handleTouch(e) {
|
||||
var rect = c.getBoundingClientRect();
|
||||
var touch = e.touches[0];
|
||||
var x = touch.clientX - rect.left;
|
||||
var y = touch.clientY - rect.top;
|
||||
|
||||
checkHit(x, y);
|
||||
}
|
||||
|
||||
// 检查点击/触摸是否命中方块
|
||||
function checkHit(x, y) {
|
||||
// 检查是否点击到黑色方块
|
||||
for (var i = 0; i < numOfTiles; i++) {
|
||||
if (eachState[i] && myTiles[i].live) {
|
||||
// 检查点击位置是否在方块范围内
|
||||
if (x >= myTiles[i].x && x <= myTiles[i].x + 75 &&
|
||||
y >= myTiles[i].y && y <= myTiles[i].y + 120) {
|
||||
// 检查方块是否在可点击区域(提高到130像素以上)
|
||||
if (myTiles[i].y + 120 > 130) {
|
||||
afterRight(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有点击到任何黑色方块,且点击位置在游戏区域内,则游戏结束
|
||||
if (y > 130 && y < 600) {
|
||||
gameOver();
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function upDate(){//check keyCode whether correct
|
||||
var i;
|
||||
|
||||
// 清空整个游戏区域,避免重叠
|
||||
context.clearRect(0, 0, 300, 600);
|
||||
|
||||
// 移动并重绘所有活跃的方块
|
||||
for(i = 0; i < numOfTiles; ++i){
|
||||
if(eachState[i]){
|
||||
myTiles[i].y += Math.ceil(gameSpeed); // 使用整数移动,避免模糊
|
||||
context.fillStyle = "black";
|
||||
context.fillRect(myTiles[i].x, myTiles[i].y, 75, 120);
|
||||
}
|
||||
}
|
||||
for(i = 0; i < numOfTiles; ++i){
|
||||
if( eachState[i] ){
|
||||
if(myTiles[i].y < 470 && myTiles[i].y >350){
|
||||
switch(myTiles[i].keyCode){
|
||||
case 65: //A
|
||||
if(myTiles[i].x == 0)
|
||||
afterRight(i);
|
||||
break;
|
||||
case 83: //S
|
||||
if(myTiles[i].x == 75)
|
||||
afterRight(i);
|
||||
break;
|
||||
case 68: //D
|
||||
if(myTiles[i].x == 150)
|
||||
afterRight(i);
|
||||
break;
|
||||
case 70: //F
|
||||
if(myTiles[i].x == 225)
|
||||
afterRight(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(myTiles[i].y > 470){
|
||||
// 方块到达底部,游戏结束
|
||||
myTiles[i].live = false;
|
||||
eachState[i] = false;
|
||||
gameOver();
|
||||
return; // 立即退出,避免继续处理
|
||||
}
|
||||
}
|
||||
else{//not alive
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user