用AI写游戏3——deepseek实现kotlin android studio greedy snake game 贪吃蛇游戏
项目下载
https://download.csdn.net/download/AnalogElectronic/90421306
项目结构
就是通过android studio 建空项目,改下MainActivity.kt的内容就完事了
ctrl+shift+alt+s 看项目结构如下
核心代码
MainActivity.kt
package com.example.snakegame1// MainActivity.kt
import android.content.ContentValues.TAG
import android.view.KeyEvent
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.focusable
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.key.*
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import java.util.*
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.input.pointer.pointerInput
import kotlin.math.abs
import kotlin.math.roundToInt// 游戏配置常量
const val CELL_SIZE = 30f // 每个网格单元大小
const val GRID_SIZE = 20 // 网格行列数
const val GAME_SPEED = 150L // 游戏刷新速度(毫秒)// 方向枚举类
enum class Direction { UP, DOWN, LEFT, RIGHT }// 坐标数据类
data class Point(val x: Int, val y: Int)class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {SnakeGame()}}
}@Composable
fun SnakeGame() {// 游戏状态控制var isPlaying by remember { mutableStateOf(true) }var score by remember { mutableStateOf(0) }Log.d(TAG, "游戏是否启动: $isPlaying")// 蛇的初始状态val snake = remember {mutableStateOf(Snake(body = listOf(Point(GRID_SIZE/2, GRID_SIZE/2)),direction = Direction.RIGHT))}// 食物位置var food by remember { mutableStateOf(generateFood(snake.value.body)) }// 游戏循环控制LaunchedEffect(key1 = isPlaying) {while (isPlaying) {delay(GAME_SPEED)snake.value = snake.value.move()// 检测是否吃到食物if (snake.value.body.first() == food) {score += 10food = generateFood(snake.value.body)snake.value = snake.value.grow()}// 检测碰撞if (checkCollision(snake.value.body)) {isPlaying = false}}}Column(modifier = Modifier.fillMaxSize().background(Color(0xFF2B2B2B)).pointerInput(Unit) {// 处理触摸或鼠标事件detectDragGestures { _, dragAmount ->// 根据拖动方向改变蛇的方向if (abs(dragAmount.x) > abs(dragAmount.y)) {if (dragAmount.x > 0) {snake.value = snake.value.turn(Direction.RIGHT)} else {snake.value = snake.value.turn(Direction.LEFT)}} else {if (dragAmount.y > 0) {snake.value = snake.value.turn(Direction.DOWN)} else {snake.value = snake.value.turn(Direction.UP)}}}}.focusable(),verticalArrangement = Arrangement.Center,horizontalAlignment = Alignment.CenterHorizontally) {// 游戏画布Canvas(modifier = Modifier.size((CELL_SIZE * GRID_SIZE).dp).background(Color.Black)) {// 绘制网格线for (i in 0..GRID_SIZE) {drawLine(color = Color.Gray.copy(alpha = 0.3f),start = Offset(i * CELL_SIZE, 0f),end = Offset(i * CELL_SIZE, size.height),strokeWidth = 1f)drawLine(color = Color.Gray.copy(alpha = 0.3f),start = Offset(0f, i * CELL_SIZE),end = Offset(size.width, i * CELL_SIZE),strokeWidth = 1f)}// 绘制食物drawCircle(color = Color.Red,center = Offset(food.x * CELL_SIZE + CELL_SIZE / 2,food.y * CELL_SIZE + CELL_SIZE / 2),radius = CELL_SIZE / 3)// 绘制蛇身snake.value.body.forEachIndexed { index, point ->val color = if (index == 0) Color.Green else Color(0xFF4CAF50)drawCircle(color = color,center = Offset(point.x * CELL_SIZE + CELL_SIZE / 2,point.y * CELL_SIZE + CELL_SIZE / 2),radius = CELL_SIZE / 2.5f,style = Stroke(width = 3f))}}// 重新开始按钮if (!isPlaying) {Button(onClick = {// 重置游戏状态isPlaying = truescore = 0snake.value = Snake(body = listOf(Point(GRID_SIZE/2, GRID_SIZE/2)),direction = Direction.RIGHT)food = generateFood(snake.value.body)},modifier = Modifier.padding(8.dp)) {Text("重新开始")}}}
}// 蛇类定义
class Snake(val body: List<Point>,val direction: Direction
) {// 移动方法fun move(): Snake {val head = body.first()val newHead = when (direction) {Direction.UP -> head.copy(y = head.y - 1)Direction.DOWN -> head.copy(y = head.y + 1)Direction.LEFT -> head.copy(x = head.x - 1)Direction.RIGHT -> head.copy(x = head.x + 1)}return copy(body = listOf(newHead) + body.dropLast(1))}// 转向方法fun turn(newDirection: Direction): Snake {// 禁止反向移动if ((direction == Direction.UP && newDirection == Direction.DOWN) ||(direction == Direction.DOWN && newDirection == Direction.UP) ||(direction == Direction.LEFT && newDirection == Direction.RIGHT) ||(direction == Direction.RIGHT && newDirection == Direction.LEFT)) {return this}return copy(direction = newDirection)}// 增长方法fun grow(): Snake {val tail = body.last()val newTail = when (direction) {Direction.UP -> tail.copy(y = tail.y + 1)Direction.DOWN -> tail.copy(y = tail.y - 1)Direction.LEFT -> tail.copy(x = tail.x + 1)Direction.RIGHT -> tail.copy(x = tail.x - 1)}return copy(body = body + newTail)}private fun copy(body: List<Point> = this.body,direction: Direction = this.direction) = Snake(body, direction)
}// 生成食物位置
fun generateFood(snakeBody: List<Point>): Point {val random = Random()while (true) {val newFood = Point(random.nextInt(GRID_SIZE),random.nextInt(GRID_SIZE))if (newFood !in snakeBody) return newFood}
}// 碰撞检测
fun checkCollision(body: List<Point>): Boolean {val head = body.first()return head.x < 0 || head.x >= GRID_SIZE ||head.y < 0 || head.y >= GRID_SIZE ||head in body.drop(1)
}
这段代码实现了一个经典的贪吃蛇游戏,使用Kotlin和Jetpack Compose来构建。让我逐步解释代码的功能和结构:
-
包和导入:
package com.example.snakegame1
:定义了应用的包名。- 导入了Android和Jetpack Compose的相关库,用于构建UI和处理输入事件。
-
MainActivity类:
- 继承自
ComponentActivity
,这是Compose支持的Activity基类。 onCreate
方法设置内容为SnakeGame
Composable函数,启动游戏。
- 继承自
-
SnakeGame Composable函数:
- 使用
remember
保存游戏状态,如isPlaying
(游戏是否进行)和score
(得分)。 - 定义了蛇的初始状态和食物的位置。
- 使用
-
游戏逻辑:
LaunchedEffect
用于启动游戏循环,当isPlaying
为true时持续运行。- 每隔
GAME_SPEED
毫秒更新一次蛇的位置。 - 检测蛇是否吃到食物,增加得分并生成新的食物。
- 检测碰撞,如果蛇撞到边界或自身,游戏结束。
-
UI绘制:
- 使用
Canvas
绘制游戏画面。 - 绘制网格线、食物和蛇的身体。
- 蛇的头部和身体部分使用不同的颜色,便于区分。
- 使用
-
输入控制:
- 使用
PointerInput
处理拖动事件,根据拖动方向改变蛇的移动方向。 - 禁止蛇反向移动,确保游戏逻辑正确。
- 使用
-
辅助函数和类:
generateFood
函数生成不在蛇身上的食物位置。Snake
类包含蛇的身体和方向,并有移动、转向和增长的方法。checkCollision
函数检测蛇是否撞到边界或自身。
总结:
这段代码通过Jetpack Compose构建了一个贪吃蛇游戏,涵盖了游戏循环、输入控制、碰撞检测和得分系统。对于Kotlin和Compose的初学者来说,这是一个很好的学习项目,可以帮助理解状态管理、UI绘制和游戏逻辑的实现。
实现效果