用SpriteKit实现的 Slither.io (中文: 贪吃蛇大作战), 学习工作之余可以用来放松, 单机版无需联网
实现的功能:
- 玩家移动(镜头控制)
- 平滑的转弯
- 双击高速移动
- 吃到食物增长
- 碰撞检测
- 每条蛇与其他蛇的碰撞判断
- 每条蛇与地图边界的碰撞判断
- 每条蛇的蛇头与食物的碰撞判断
- 装饰组件
- 眼睛👀跟踪手指
- 阴影 (高速移动时会闪烁)
- AI bot
- 自动寻找食物
- 自动避障
- 参数为随机生成
- 得分与计分榜
与原版的主要区别:
- 原版为多人联机对战, 此处为单机版, 敌人都是AI
-
[] 开始菜单场景 MainMenu
-
游戏中场景 GameScene
-
Snake
- 贪吃蛇基类-
root: SKNode
- 内含sections, detector, label等, 用于渲染 -
sections: SKNode
- 包含蛇身所有节点, 包括head -
head: SKSpriteNode
- 蛇头节点 -
label: SKLabelNode
- 名字的标签, 始终位于蛇头上方 -
eyes: EyePair
- 贪吃蛇的眼睛 -
shadow: SKNode
- 阴影 -
update()
- 状态更新
-
-
BotSnake: Snake
- AI控制的蛇-
careness: CGFloat
-
distcareness: CGFloat
-
anglecareness: CGFloat
-
worldBoundCareness: CGFloat
-
boundTurnTrend1: CGFloat
-
boundTurnTrend2: CGFloat
-
trendRotation: CGFloat
-
-
GameScene: SKScene
-
worldSize: CGSize
- 地图大小 -
camera: CGSize
- 地图大小 -
snakes: [Snake]
- 地图上的所有蛇 -
foodNode: SKNode
- 所有食物的容器 -
createSnake()
- 创建一条蛇-
将蛇对象加入snakes中, 将蛇的所有节点(body节点)加到scene中
-
使用空间四叉树
GKQuadtree
来防止新生成的蛇和其他蛇距离过近
-
-
createFood()
- 创建一个食物-
在地图上随机生成一颗食物
-
同样维护了一棵空间四叉树
GKQuadtree
来记录所有食物的位置, 供AI算法使用
-
-
(override) update()
- 更新界面, 依次更新所有蛇, 检查是否需要创建新的食物/蛇
-
蛇的平滑转弯实现:
let thisPos = self.head.position
let rot = self.head.zRotation
if let touchPos = self.scene.touchPos {
let targetDirect = CGVector(dx: touchPos.x - thisPos.x, dy: touchPos.y - thisPos.y)
var diff = atan2(targetDirect.dy, targetDirect.dx) - rot
if diff > CGFloat.pi {
diff -= 2 * CGFloat.pi
}
else if diff < -CGFloat.pi {
diff += 2 * CGFloat.pi
}
self.head.physicsBody?.angularVelocity = diff * Snake.rotateSpeed // 不断调整角速度以达到平滑转弯的效果
if self.scene.tapCount > 1 {
self.speed = Snake.fastSpeed
} else {
self.speed = Snake.slowSpeed
}
} else {
self.head.physicsBody?.angularVelocity = 0
self.speed = Snake.slowSpeed
}
-
线速度:velocity
-
角度:zRotation
-
角速度:angularVelocity
SKScene
SKNode
- 背景组SKTileMapNode
SKTileMapNode
SKTileMapNode
- ......
SKCameraNode
- 摄像头节点SKNode
- 食物组SKSpriteNode(phy)
- 一个食物SKSpriteNode(phy)
- 一个食物SKSpriteNode(phy)
- 一个食物- .......
SKNode
- 玩家SKLabelNode
- 名字标签SKNode
- 蛇身SKSpriteNode(phy)
- 蛇头SKSpriteNode
- 眼睛1SKSpriteNode
- 眼睛2SKSpriteNode(phy)
- 碰撞探测器
SKSpriteNode(phy)
- 蛇身1SKSpriteNode(phy)
- 蛇身2- ......
SKNode
- 蛇1SKLabelNode
- 名字标签SKNode
- 蛇身SKSpriteNode
- 蛇头SKSpriteNode
- 眼睛1SKSpriteNode
- 眼睛2SKSpriteNode
- 碰撞探测器
SKSpriteNode
- 蛇身1SKSpriteNode
- 蛇身2- ......
SKNode
- 蛇2SKNode
- 蛇3
size表示在父坐标系下的尺寸
scale表示对父坐标系的伸缩变化
修改scale的时候会同时修改size
修改size的时候不会修改scale
-
判断一定范围内有没有食物
-
判断最近的敌人的位置
-
判断是否靠近边界
-
随意选择一个感兴趣方向进行探索