鸿蒙版(ArkTs) 贪吃蛇,包含无敌模式 最高分 暂停和继续功能;
效果图如下:
代码如下:
ts
// 所有import语句必须放在文件开头
import router from '@ohos.router';
import promptAction from '@ohos.promptAction';
// Add this import at the top with other imports
// Remove the problematic import
// import { Gradient, GradientDirection } from '@ohos.arkui.graphics';
// 在文件开头添加Preferences导入
import preferences from '@ohos.data.preferences';
// 移除@Entry装饰器
@Entry
@Component
struct Tsc {
@State snake: Array<[number, number]> = [[5, 5], [5, 6], [5, 7]];
@State food: [number, number] = [10, 10];
@State private _moveDirection: number = 3;
@State score: number = 0;
@State highScore: number = 0;
private prefs?: preferences.Preferences; // Use optional type instead of undefined
@State isInvincible: boolean = false;
@State foodColor: Color = Color.Red;
@State snakeHeadColor: Color = Color.Green;
private gridSize: number = 20;
private timer: number = 0;
@State isPlaying: boolean = false;
// 添加generateFood方法
generateFood() {
const gridCells = 12;
let newFood: [number, number] = [0, 0];
let validPositionFound = false;
const allPositions: Array<[number, number]> = [];
for (let x = 0; x < gridCells; x++) {
for (let y = 0; y < gridCells; y++) {
allPositions.push([x, y]);
}
}
allPositions.sort(() => Math.random() - 0.5);
for (const pos of allPositions) {
const isOverlap = this.snake.some(segment =>
segment[0] === pos[0] && segment[1] === pos[1]
);
if (!isOverlap) {
newFood = pos;
validPositionFound = true;
break;
}
}
this.food = newFood;
this.foodColor = Color.Red; // 设置默认食物颜色
}
// 重置游戏状态
resetGame() {
this.snake = [[5, 5], [5, 6], [5, 7]];
this._moveDirection = 3;
this.score = 0;
this.generateFood();
}
startGame() {
// 先清除之前的定时器
if (this.timer) {
clearInterval(this.timer);
}
this.resetGame();
this.isPlaying = true;
this.timer = setInterval(() => {
this.moveSnake();
}, 200);
}
// 添加生命周期方法
aboutToAppear() {
this.loadHighScore();
}
// 加载历史最高分
async loadHighScore() {
try {
this.prefs = await preferences.getPreferences(getContext(this), 'snakeGamePrefs');
const score = await this.prefs.get('highScore', 0);
this.highScore = Number(score);
} catch (err) {
console.error('Failed to load high score:', err);
}
}
// 保存历史最高分
async saveHighScore(score: number) {
try {
if (this.prefs) { // Add null check
await this.prefs.put('highScore', score);
await this.prefs.flush();
}
} catch (err) {
console.error('Failed to save high score:', err);
}
}
endGame() {
clearInterval(this.timer);
this.isPlaying = false;
// 更新历史最高分
if (this.score > this.highScore) {
this.highScore = this.score;
this.saveHighScore(this.highScore);
}
promptAction.showToast({
message: '游戏结束!',
duration: 2000
});
}
stopGame() {
clearInterval(this.timer);
this.isPlaying = false;
if (this.score > this.highScore) {
this.highScore = this.score;
this.saveHighScore(this.highScore);
}
}
moveSnake() {
if (!this.isPlaying) return;
let head: [number, number] = [this.snake[0][0], this.snake[0][1]];
switch (this._moveDirection) {
case 0: head[1] -= 1; break;
case 1: head[1] += 1; break;
case 2: head[0] -= 1; break;
case 3: head[0] += 1; break;
}
// 修正边界检测逻辑
const gridCells = 12; // 与显示区域保持一致
if (head[0] < 0 || head[0] >= gridCells ||
head[1] < 0 || head[1] >= gridCells) {
if (!this.isInvincible) {
this.endGame();
return;
}
head[0] = (head[0] + gridCells) % gridCells;
head[1] = (head[1] + gridCells) % gridCells;
}
if (head[0] === this.food[0] && head[1] === this.food[1]) {
this.score += 10;
this.generateFood();
// 吃到食物时,只添加新头部,不删除尾部
this.snake = [head, ...this.snake];
} else {
// 没吃到食物时,移动蛇身
this.snake.pop();
this.snake = [head, ...this.snake];
}
}
// 添加暂停游戏方法
@State isPaused: boolean = false; // 添加暂停状态
// 修改暂停游戏方法
pauseGame() {
clearInterval(this.timer);
this.isPlaying = false;
this.isPaused = true;
}
// 修改恢复游戏方法
resumeGame() {
this.isPlaying = true;
this.isPaused = false;
this.timer = setInterval(() => {
this.moveSnake();
}, 200);
}
build() {
Column() {
Button('返回首页')
.width(100)
.height(40)
.fontSize(16)
.alignSelf(ItemAlign.Start)
.margin(10)
.onClick(() => {
router.pushUrl({
url: 'pages/Index'
})
})
// 添加历史最高分显示
Row() {
Text(`当前得分: ${this.score}`)
.fontSize(20)
Text(`最高分: ${this.highScore}`)
.fontSize(20)
.margin({ left: 20 })
}
.margin({ bottom: 10 })
// 修改按钮布局
Row() {
if (!this.isPlaying && !this.isPaused) {
Button('开始游戏')
.width(100)
.height(35)
.fontSize(14)
.margin(5)
.onClick(() => {
this.startGame();
})
} else if (this.isPlaying) {
Button('暂停')
.width(100)
.height(35)
.fontSize(14)
.margin(5)
.onClick(() => {
this.pauseGame();
})
} else if (this.isPaused) {
Button('继续')
.width(100)
.height(35)
.fontSize(14)
.margin(5)
.onClick(() => {
this.resumeGame();
})
}
Button('重新开始')
.width(100)
.height(35)
.fontSize(14)
.margin(5)
.onClick(() => {
this.startGame();
})
Button('结束游戏')
.width(100)
.height(35)
.fontSize(14)
.margin(5)
.onClick(() => {
this.stopGame();
})
}
.margin({ top: 10 })
Stack() {
Circle({ width: this.gridSize, height: this.gridSize })
.fill(this.foodColor)
// 使用固定颜色描边
.stroke(Color.Gray)
.strokeWidth(2)
// 添加阴影效果模拟渐变
.shadow({
radius: 3,
color: Color.White,
offsetX: 1,
offsetY: 1
})
.position({
x: this.food[0] * this.gridSize,
y: this.food[1] * this.gridSize
})
ForEach(this.snake, (segment: [number, number], index: number) => {
if (index === 0) {
Rect({ width: this.gridSize, height: this.gridSize })
.fill(this.snakeHeadColor)
.radius(5)
.position({
x: segment[0] * this.gridSize,
y: segment[1] * this.gridSize
})
} else {
// 每节蛇身使用食物颜色
Circle({ width: this.gridSize, height: this.gridSize })
.fill(this.foodColor)
.position({
x: segment[0] * this.gridSize,
y: segment[1] * this.gridSize
})
}
})
}
.width(this.gridSize * 12)
.height(this.gridSize * 12)
.border({ width: 1, color: Color.Black })
.clip(true) // 添加裁剪确保内容不会超出边框
.margin({ bottom: 10 })
Column() {
Button('上')
.width(80)
.height(50)
.fontSize(18)
.margin(5)
.onClick(() => { this._moveDirection = 0; })
Row() {
Button('左')
.width(80)
.height(50)
.fontSize(18)
.margin(5)
.onClick(() => { this._moveDirection = 2; })
Button('右')
.width(80)
.height(50)
.fontSize(18)
.margin(5)
.onClick(() => { this._moveDirection = 3; })
}
Button('下')
.width(80)
.height(50)
.fontSize(18)
.margin(5)
.onClick(() => { this._moveDirection = 1; })
}
.margin({ top: 10 })
Row() {
Text('无敌模式:')
.fontSize(18)
.fontColor(this.isInvincible ? Color.Red : Color.Black)
.margin({ right: 10 })
Toggle({ type: ToggleType.Switch, isOn: this.isInvincible })
.width(40)
.height(24)
.onChange((isOn: boolean) => {
this.isInvincible = isOn;
})
Text(this.isInvincible ? '开启' : '关闭')
.fontSize(18)
.fontColor(this.isInvincible ? Color.Red : Color.Black)
.margin({ left: 10 })
}
.margin({ top: 20 })
.padding(10)
.borderRadius(10)
.backgroundColor('#f0f0f0')
.margin({ top: 10 })
}
.width('100%')
.height('100%')
.backgroundColor('#E0F7FA')
.onKeyEvent((event: KeyEvent) => {
if (event.type === KeyType.Down) {
switch (event.keyCode) {
case 19: if (this._moveDirection !== 1) this._moveDirection = 0; break;
case 20: if (this._moveDirection !== 0) this._moveDirection = 1; break;
case 21: if (this._moveDirection !== 3) this._moveDirection = 2; break;
case 22: if (this._moveDirection !== 2) this._moveDirection = 3; break;
}
}
})
}
}