Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 53 additions & 8 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,24 @@
z-index: 10000;
padding: 5px;
}
.speed-btn {
display: inline-block;
padding: 5px 10px;
margin: 0 2px;
cursor: pointer;
border: 1px solid #ccc;
background-color: #f5f5f5;
border-radius: 3px;
font-size: 12px;
}
.speed-btn:hover {
background-color: #e0e0e0;
}
.speed-btn.active {
background-color: #4CAF50;
color: white;
border-color: #4CAF50;
}
</style>
<script>
function getTheme() {
Expand Down Expand Up @@ -106,14 +124,11 @@
</select>
</div>
<div style="display: inline-block; margin-right: 10px">
<span>Mode:</span>
<select id="selectMode">
<option value="100">Easy</option>
<option value="75" selected>Medium</option>
<option value="50">Hard</option>
<option value="25">Impossible</option>
<option value="110">Rush</option>
</select>
<span>速度:</span>
<button id="speed1" class="speed-btn active">1 倍速</button>
<button id="speed2" class="speed-btn">2 倍速</button>
<button id="speed3" class="speed-btn">3 倍速</button>
<button id="speed5" class="speed-btn">5 倍速</button>
</div>
<button id="go_full_screen">Full Screen</button>
<br />
Expand All @@ -127,6 +142,36 @@
<script type="text/javascript">
document.getElementById('select').addEventListener('change', getTheme);

// 速度控制按钮逻辑
function changeSpeed(speedMultiplier) {
const baseSpeed = 300; // 1倍速 = 300ms
const newSpeed = Math.round(baseSpeed / speedMultiplier);

// 更新按钮状态
document.querySelectorAll('.speed-btn').forEach(btn => {
btn.classList.remove('active');
});
document.getElementById('speed' + speedMultiplier).classList.add('active');

// 更新游戏速度
if (mySnakeBoard && mySnakeBoard.setSpeed) {
mySnakeBoard.setSpeed(newSpeed);
}

// 焦点返回到游戏区域,确保可以继续控制蛇
setTimeout(function() {
document.getElementById('game-area').focus();
}, 10);
}

// 绑定速度按钮事件
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('speed1').addEventListener('click', function() { changeSpeed(1); });
document.getElementById('speed2').addEventListener('click', function() { changeSpeed(2); });
document.getElementById('speed3').addEventListener('click', function() { changeSpeed(3); });
document.getElementById('speed5').addEventListener('click', function() { changeSpeed(5); });
});

function go_full_screen() {
const elem = document.documentElement;
try {
Expand Down
69 changes: 30 additions & 39 deletions src/js/snake.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const MOVE_RIGHT = 1;
const MIN_SNAKE_SPEED = 25;
const RUSH_INCR = 5;

const DEFAULT_SNAKE_SPEED = 80;
const DEFAULT_SNAKE_SPEED = 300; // 1倍速 = 300ms

const BOARD_NOT_READY = 0;
const BOARD_READY = 1;
Expand Down Expand Up @@ -146,7 +146,7 @@ SNAKE.Snake =

const me = this;
const playingBoard = config.playingBoard;
const growthIncr = 5;
const growthIncr = 1;
const columnShift = [0, 1, 0, -1];
const rowShift = [-1, 0, 1, 0];
let prevNode;
Expand All @@ -159,27 +159,7 @@ SNAKE.Snake =
isDead = false,
isPaused = false;

const modeDropdown = document.getElementById("selectMode");
if (modeDropdown) {
modeDropdown.addEventListener("change", function (evt) {
evt = evt || {};
let val = evt.target
? parseInt(evt.target.value)
: DEFAULT_SNAKE_SPEED;

if (isNaN(val)) {
val = DEFAULT_SNAKE_SPEED;
} else if (val < MIN_SNAKE_SPEED) {
val = DEFAULT_SNAKE_SPEED;
}

snakeSpeed = val;

setTimeout(function () {
document.getElementById("game-area").focus();
}, 10);
});
}

// ----- public variables -----
me.snakeBody = {};
Expand Down Expand Up @@ -381,6 +361,29 @@ SNAKE.Snake =
newHead.col = oldHead.col + columnShift[lastMove];
newHead.row = oldHead.row + rowShift[lastMove];

// 穿墙效果:在游戏活动区域边界实现穿墙(限定在没有文字的界面内)
// 网格的结构:边界为2,内部活动区域为1到numRows-2,1到numCols-2
const numRows = grid.length;
const numCols = grid[0].length;
const minCol = 1; // 最左活动列(避开左边界)
const maxCol = numCols - 2; // 最右活动列(避开右边界)
const minRow = 1; // 最上活动行(避开上边界)
const maxRow = numRows - 2; // 最下活动行(避开下边界和文字区域)

// 检查列边界(左右)- 限定在活动区域内
if (newHead.col < minCol) {
newHead.col = maxCol; // 从左边穿出,从右边进入
} else if (newHead.col > maxCol) {
newHead.col = minCol; // 从右边穿出,从左边进入
}

// 检查行边界(上下)- 限定在活动区域内
if (newHead.row < minRow) {
newHead.row = maxRow; // 从上方穿出,从下方进入
} else if (newHead.row > maxRow) {
newHead.row = minRow; // 从下方穿出,从上方进入
}

if (!newHead.elmStyle) {
newHead.elmStyle = newHead.elm.style;
}
Expand All @@ -399,7 +402,8 @@ SNAKE.Snake =
setTimeout(function () {
me.go();
}, snakeSpeed);
} else if (grid[newHead.row][newHead.col] > 0) {
} else if (grid[newHead.row][newHead.col] === 1) {
// die if hitting snake body (value 1)
me.handleDeath();
} else if (
grid[newHead.row][newHead.col] === playingBoard.getGridFoodValue()
Expand Down Expand Up @@ -448,18 +452,6 @@ SNAKE.Snake =
return false;
}

//Checks if the current selected option is that of "Rush"
//If so, "increase" the snake speed
const selectDropDown = document.getElementById("selectMode");
const selectedOption =
selectDropDown.options[selectDropDown.selectedIndex];

if (selectedOption.text.localeCompare("Rush") == 0) {
if (snakeSpeed > MIN_SNAKE_SPEED + RUSH_INCR) {
snakeSpeed -= RUSH_INCR;
}
}

return true;
};

Expand All @@ -468,9 +460,8 @@ SNAKE.Snake =
* @method handleDeath
*/
me.handleDeath = function () {
//Reset speed
const selectedSpeed = document.getElementById("selectMode").value;
snakeSpeed = parseInt(selectedSpeed);
//Reset speed to default (1x speed = 300ms)
snakeSpeed = DEFAULT_SNAKE_SPEED;

handleEndCondition(playingBoard.handleDeath);
};
Expand Down Expand Up @@ -1197,7 +1188,7 @@ SNAKE.Board =
col === numBoardCols - 1 ||
row === numBoardRows - 1
) {
me.grid[row][col] = 1; // an edge
me.grid[row][col] = 2; // an edge (changed from 1 to support wall passing)
} else {
me.grid[row][col] = 0; // empty space
}
Expand Down