优化结果
This commit is contained in:
BIN
InfoGenie-frontend/public/smallgame/别踩白方块/MUSIC.mp3
Normal file
BIN
InfoGenie-frontend/public/smallgame/别踩白方块/MUSIC.mp3
Normal file
Binary file not shown.
339
InfoGenie-frontend/public/smallgame/别踩白方块/game.js
Normal file
339
InfoGenie-frontend/public/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
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
251
InfoGenie-frontend/public/smallgame/别踩白方块/index.html
Normal file
251
InfoGenie-frontend/public/smallgame/别踩白方块/index.html
Normal file
@@ -0,0 +1,251 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
||||
<title>别踩白方块</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #f5f5f5;
|
||||
font-family: 'Arial', 'Microsoft YaHei', sans-serif;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
overflow: hidden;
|
||||
touch-action: manipulation;
|
||||
}
|
||||
|
||||
.game-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.game-title {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.score-display {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 60px;
|
||||
background: #333;
|
||||
border-radius: 8px 8px 0 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.game-container {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 600px;
|
||||
border: 3px solid #333;
|
||||
border-top: none;
|
||||
border-radius: 0 0 8px 8px;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.control-panel {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.game-btn {
|
||||
padding: 12px 30px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.start-btn {
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.start-btn:hover {
|
||||
background: #45a049;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.pause-btn {
|
||||
background: #ff9800;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.pause-btn:hover {
|
||||
background: #e68900;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.instructions {
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin-top: 10px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 游戏结束弹窗 */
|
||||
.game-over-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.7);
|
||||
display: none;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 15px;
|
||||
text-align: center;
|
||||
box-shadow: 0 20px 40px rgba(0,0,0,0.3);
|
||||
max-width: 300px;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #e74c3c;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.final-score, .final-speed {
|
||||
font-size: 18px;
|
||||
margin: 15px 0;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.final-speed {
|
||||
color: #666;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.modal-btn {
|
||||
padding: 10px 25px;
|
||||
margin: 5px;
|
||||
border: none;
|
||||
border-radius: 20px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.restart-btn {
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.restart-btn:hover {
|
||||
background: #45a049;
|
||||
}
|
||||
|
||||
/* 移动端适配 */
|
||||
@media (max-width: 768px) {
|
||||
.game-wrapper {
|
||||
padding: 15px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.game-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.game-container {
|
||||
width: 280px;
|
||||
height: 560px;
|
||||
}
|
||||
|
||||
.score-display {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.instructions {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.game-container {
|
||||
width: 260px;
|
||||
height: 520px;
|
||||
}
|
||||
|
||||
.score-display {
|
||||
width: 260px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="game-wrapper">
|
||||
<h1 class="game-title">别踩白方块</h1>
|
||||
|
||||
<div class="score-display">
|
||||
<canvas id="score_bar" width="300" height="60"></canvas>
|
||||
<div style="position: absolute; color: white; font-size: 14px; display: flex; justify-content: space-between; width: 260px; padding: 0 20px;">
|
||||
<span>得分: <span id="score-value">0</span></span>
|
||||
<span>速度: <span id="speed-value">1.0</span>x</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="game-container">
|
||||
<canvas id="background" width="300" height="600"></canvas>
|
||||
<canvas id="piano" width="300" height="600" style="position: absolute; top: 0; left: 0;"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="control-panel">
|
||||
<button id="start_btn" class="game-btn start-btn">开始游戏</button>
|
||||
<div class="instructions">
|
||||
<div>电脑端:使用 A S D F 键</div>
|
||||
<div>手机端:直接点击黑色方块</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 游戏结束弹窗 -->
|
||||
<div id="game-over-modal" class="game-over-modal">
|
||||
<div class="modal-content">
|
||||
<h2 class="modal-title">游戏结束</h2>
|
||||
<div class="final-score">最终得分: <span id="final-score-value">0</span></div>
|
||||
<div class="final-speed">最高速度: <span id="final-speed-value">1.0</span>x</div>
|
||||
<button id="restart-btn" class="modal-btn restart-btn">重新开始</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<audio id="music" src="MUSIC.mp3" loop></audio>
|
||||
<script src="game.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user