要使用Python实现《贪吃蛇大作战》游戏,以下是具体所需的工具:
- Python 3.8.0 或更高版本:用于编写游戏代码。
- Pygame:用于创建游戏界面和处理游戏逻辑。
- PyCharm 或 Visual Studio Code:用于编写和调试代码。
- Git:用于代码管理和协作。
四、主要技术
pygame 库
pygame 是一个开源的Python模块,专门用于编写视频游戏。它包含了图形、声音、事件处理等功能,非常适合用来开发2D游戏。使用 pygame,我们可以轻松创建游戏窗口、处理用户输入、绘制图形和动画,以及添加音效等。
安装:可以通过 pip 命令安装 pygame:
pip install pygame
主要功能:
- 创建游戏窗口和表面对象。
- 处理键盘和鼠标事件。
- 绘制图形和文本。
- 添加音效和背景音乐。
- 控制游戏循环和帧率。
numpy 库
numpy 是Python中用于科学计算的基础库,提供了强大的多维数组对象和各种用于操作这些数组的工具。在游戏中,我们可以使用 numpy 来处理蛇的身体结构和食物的随机生成位置。
安装:可以通过 pip 命令安装 numpy:
pip install numpy
主要功能:
- 创建和操作多维数组。
- 进行高效的数学运算。
- 生成随机数,用于食物的随机位置生成。
cocos2d
使用了 cocos2d-python 作为游戏引擎。如果要运行代码,需要安装 cocos2d 库。
pip install cocos2d
五、源码分享
地图:
import cocos
from cocos.director import director
import define
from snake import Snake
from dot import Dot
class Arena(cocos.layer.ColorLayer):
is_event_handler = True
def \_\_init\_\_(self):
super(Arena, self).__init__(250, 255, 255, 255, define.WIDTH, define.HEIGHT)
self.center = (director.get_window_size()[0] / 2, director.get_window_size()[1] / 2)
self.batch = cocos.batch.BatchNode()
self.add(self.batch)
self.snake = Snake()
self.add(self.snake, 10000)
self.snake.init_body()
self.enemies = []
for i in range(7):
self.add_enemy()
self.keys_pressed = set()
for i in range(50):
self.batch.add(Dot())
self.schedule(self.update)
def add\_enemy(self):
enemy = Snake(True)
self.add(enemy, 10000)
enemy.init_body()
self.enemies.append(enemy)
def update(self, dt):
self.x = self.center[0] - self.snake.x
self.y = self.center[1] - self.snake.y
def on\_key\_press(self, key, modifiers):
self.keys_pressed.add(key)
self.snake.update_angle(self.keys_pressed)
def on\_key\_release (self, key, modifiers):
self.keys_pressed.remove(key)
self.snake.update_angle(self.keys_pressed)
游戏脚本:负责创建和管理游戏场景、处理用户输入和游戏逻辑。通过Cocos引擎提供的类和方法,这个脚本实现了一个简单的游戏循环,包括游戏的开始、运行、结束和重新开始。
import cocos
import define
from arena import Arena
from gameover import Gameover
class HelloWorld(cocos.layer.Layer):
is_event_handler = True
def \_\_init\_\_(self):
super(HelloWorld, self).__init__()
self.arena = Arena()
self.add(self.arena)
self.score = cocos.text.Label('30',
font_name='Times New Roman',
font_size=24,
color=define.GOLD)
self.score.position = 20, 440
self.add(self.score, 99999)
self.gameover = Gameover()
self.add(self.gameover, 100000)
def update\_score(self):
self.score.element.text = str(self.arena.snake.score)
def end\_game(self):
self.gameover.visible = True
self.gameover.score.element.text = str(self.arena.snake.score)
def on\_mouse\_press(self, x, y, buttons, modifiers):
if self.gameover.visible:
self.gameover.visible = False
self.arena.unschedule(self.arena.update)
self.remove(self.arena)
self.arena = Arena()
self.add(self.arena)
self.update_score()
cocos.director.director.init(caption="Gluttonous Python")
cocos.director.director.run(cocos.scene.Scene(HelloWorld()))
snake.py贪吃蛇
# -\*- coding: utf-8 -\*-
import math
import random
import cocos
from cocos.sprite import Sprite
import define
from dot import Dot
class Snake(cocos.cocosnode.CocosNode):
no = 0
def \_\_init\_\_(self, is_enemy=False):
super(Snake, self).__init__()
self.is_dead = False
self.angle = random.randrange(360) # 目前角度
self.angle_dest = self.angle # 目标角度
self.color = random.choice(define.ALL_COLOR)
self.no = Snake.no
Snake.no += 1
if is_enemy:
self.position = random.randrange(300, 1300), random.randrange(200, 600)
if 600 < self.x < 1000:
self.x += 400
else:
self.position = random.randrange(700, 900), random.randrange(350, 450)
self.is_enemy = is_enemy
self.head = Sprite('circle.png', color=self.color)
self.scale = 1.5
eye = Sprite('circle.png')
eye.y = 5
eye.scale = 0.5
eyeball = Sprite('circle.png', color=define.BLACK)
eyeball.scale = 0.5
eye.add(eyeball)
self.head.add(eye)
eye = Sprite('circle.png')
eye.y = -5
eye.scale = 0.5
eyeball = Sprite('circle.png', color=define.BLACK)
eyeball.scale = 0.5
eye.add(eyeball)
self.head.add(eye)
self.add(self.head)
self.speed = 150
if not is_enemy:
self.speed = 180
self.path = [self.position] \* 100
self.schedule(self.update)
if self.is_enemy:
self.schedule_interval(self.ai, random.random() \* 0.1 + 0.05)
def add\_body(self):
b = Sprite('circle.png', color=self.color)
b.scale = 1.5
self.body.append(b)
if self.x == 0:
print(self.position)
b.position = self.position
try:
self.parent.batch.add(b, 999 + 100\*self.no - len(self.body))
except:
print(999 + 100\*self.no - len(self.body))
def init\_body(self):
self.score = 30
self.length = 4
self.body = []
for i in range(self.length):
self.add_body()
def update(self, dt):
self.angle = (self.angle + 360) % 360
arena = self.parent
if self.is_enemy:
self.check_crash(arena.snake)
for s in arena.enemies:
if s != self and not s.is_dead:
self.check_crash(s)
if self.is_dead:
return
if abs(self.angle - self.angle_dest) < 2:
self.angle = self.angle_dest
else:
if (0 < self.angle - self.angle_dest < 180) or (
self.angle - self.angle_dest < -180):
self.angle -= 500 \* dt
else:
self.angle += 500 \* dt
self.head.rotation = -self.angle
self.x += math.cos(self.angle \* math.pi / 180) \* dt \* self.speed
self.y += math.sin(self.angle \* math.pi / 180) \* dt \* self.speed
self.path.append(self.position)
lag = int(round(1100.0 / self.speed))
for i in range(len(self.body)):
idx = (i + 1) \* lag + 1
self.body[i].position = self.path[-min(idx,len(self.path))]
if self.body[i].x == 0:
print(self.body[i].position)
m_l = max(self.length \* lag \* 2, 60)
if len(self.path) > m_l:
self.path = self.path[int(-m_l \* 2):]
def update\_angle(self, keys):
x, y = 0, 0
if 65361 in keys: # 左
x -= 1
if 65362 in keys: # 上
y += 1
if 65363 in keys: # 右
x += 1
if 65364 in keys: # 下
y -= 1
directs = ((225, 180, 135), (270, None, 90), (315, 0, 45))
direct = directs[x + 1][y + 1]
if direct is None:
self.angle_dest = self.angle
else:
self.angle_dest = direct
def add\_score(self, s=1):
if self.is_dead:
return
self.score += s
l = (self.score - 6) / 6
if l > self.length:
self.length = l
self.add_body()
def ai(self, dt):
self.angle_dest = (self.angle_dest + 360) % 360
if (self.x < 100 and 90 < self.angle_dest < 270) or (
self.x > define.WIDTH - 100 and (
self.angle_dest < 90 or self.angle_dest > 270)
):
self.angle_dest = 180 - self.angle_dest
elif (self.y < 100 and self.angle_dest > 180) or (
self.y > define.HEIGHT - 100 and self.angle_dest < 180
):
self.angle_dest = -self.angle_dest
else:
arena = self.parent
self.collision_detect(arena.snake)
for s in arena.enemies:
if s != self:
self.collision_detect(s)
def collision\_detect(self, other):
if self.is_dead or other.is_dead:
return
for b in other.body:
d_y = b.y - self.y
d_x = b.x - self.x
if abs(d_x) > 200 or abs(d_y) > 200:
return
if d_x == 0:
if d_y > 0:
angle = 90
else:
angle = -90
else:
angle = math.atan(d_y / d_x) \* 180 / math.pi
if d_x < 0:
angle += 180
angle = (angle + 360) % 360
if abs(angle - self.angle_dest) < 5:
self.angle_dest += random.randrange(90, 270)
def check\_crash(self, other):
if self.is_dead or other.is_dead:
return
if (self.x < 0 or self.x > define.WIDTH) or (
self.y < 0 or self.y > define.HEIGHT
):
self.crash()
return
for b in other.body:
dis = math.sqrt((b.x - self.x) \*\* 2 + (b.y - self.y) \*\* 2)
if dis < 24:
self.crash()
return
def crash(self):
if not self.is_dead:
self.is_dead = True
self.unschedule(self.update)
self.unschedule(self.ai)
arena = self.parent
for b in self.body:
arena.batch.add(Dot(b.position, b.color))
arena.batch.add(Dot(b.position, b.color))
arena.batch.remove(b)
arena.remove(self)
arena.add_enemy()
del self.path
if self.is_enemy:
arena.enemies.remove(self)
del self.body
del self
else:
arena.parent.end_game()
游戏结束:
# -\*- coding: utf-8 -\*-
import cocos
from cocos.director import director
import define
class Gameover(cocos.layer.ColorLayer):
def \_\_init\_\_(self):
super(Gameover, self).__init__(200, 235, 235, 200, 400, 300)
self.position = (director.get_window_size()[0] / 2 - 200,
director.get_window_size()[1] / 2 - 150)
self.visible = False
self.score = cocos.text.Label('',
font_name='SimHei',
font_size=36,
color=define.MAROON)
self.score.position = 250, 200
self.add(self.score)
text = cocos.text.Label('SCORE: ',