幽泉流霜关注
0.1942018.12.02 13:01:02字数 1,656阅读 1,375
自从开始学习编程后 ,就一直想着能够写一个自己的游戏,这大概是每一个男孩子的梦想吧!
这次我们使用python语言 ,调用pygame库 来写一个简单的小游戏
就拿最经典的游戏 贪吃蛇 作为我的第一个游戏!
看一下最终效果为
tanchishe.gif
我们先分一下步骤!
创建背景--写入蛇头食物--蛇的移动以及控制--蛇体算法--碰撞检测--食物随机生成--死亡判定--细节完善--源码
着急的小伙伴可以直接拉到最后看源码
先导入要用的库吧
import pygame
import random
from pygame.locals import *
第一个当然是必须要用到的pygame
随机生成食物点的时候要用到随机库
最后一个是导入pygame的上下左右键盘输入
一 、创建背景
这个是pygame的一个基本用法
我们先拿一个简单的例子来说
pygame.init()
window = pygame.display.set_mode((640,480),0,32)
pygame.display.set_caption("标题")
pygame.init()用语pygame的初始化
set_mode函数会返回一个Surface对象,代表了在桌面上出现的那个窗口,三个参数第一个为元祖,代表分 辨率(必须);第二个是一个标志位,具体意思见下表,如果不用什么特性,就指定0;第三个为色深。
set_caption顾名思义是用来设置标题的
这时候我们运行程序就会出现一个一闪而过的黑框
它就是我们的游戏窗体啦
那么如果要让黑框一直存在怎么办呢
肯定要用到一个while 循环
while True:
pygame.draw.rect(window,bk_color,(0,0,w,h))
pygame.display.update()
这样子我们的黑框就会一直存在
draw.rect是pygame带的一个画矩形的函数它一共有四个参数
第一个是对象 就是你要画的位置
第二个是颜色 矩形的色彩
第三个 是一个tuple 代表矩形的位置和大小
tuple里面一共四个参数 前面两个代表矩形的左上角坐标,后两个分别是宽和高
但是现在问题又来我们会发现 无法关闭掉这个窗口 或者说卡主
我们可以先定义一个
quit = True
while quit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = False
这里我们引入了pygame的事件概念
pygame.event.gey()可以获取目前的所有事件
import pygame
from pygame.locals import *
from sys import exit
pygame.init()
SCREEN_SIZE = (640, 480)
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
font = pygame.font.SysFont("arial", 16);
font_height = font.get_linesize()
event_text = []
while True:
event = pygame.event.wait()
event_text.append(str(event))
#获得时间的名称
event_text = event_text[-SCREEN_SIZE[1]//font_height:]
#这个切片操作保证了event_text里面只保留一个屏幕的文字
if event.type == QUIT:
exit()
screen.fill((255, 255, 255))
y = SCREEN_SIZE[1]-font_height
#找一个合适的起笔位置,最下面开始但是要留一行的空
for text in reversed(event_text):
screen.blit( font.render(text, True, (0, 0, 0)), (0, y) )
#以后会讲
y-=font_height
#把笔提一行
pygame.display.update()
运行以上代码 就可以看到我们的所有事件了
通过上面的说明我们已经可以让一个黑框完整的出现了!
为了方便
我们可以把贪吃蛇的背景看成一个表格
我们先定义了一个600*800的一个分辨率
然后分别设置行数和列数
代码如下
w = 800
h = 600
ROW = 30
COL = 40
size = (w, h)
direct = "left" #我们下面会讲
window = pygame.display.set_mode(size)
pygame.display.set_caption("贪吃蛇")
二、写入蛇头、食物
为了方便坐标的表示
我们写一个简单的坐标类
class Point:
row = 0
col = 0
def __init__(self,row,col):
self.row = row
self.col = col
我们要画一个蛇头 当然要用到draw.rect的函数
于是需要一个蛇头的颜色和坐标
食物也同样如此
head = Point(ROW / 2,COL / 2)
food = Point(10,10)
head_color = (0, 128, 128)
food_color = (255, 255, 0)
然后再在循环中用rect函数把我们的蛇头和食物画上
运行后效果如图所示
Snipaste_2018-12-01_19-17-04.png
三、蛇的移动以及控制
如何让蛇自动前进
这里我们先引入一个时间的概念
clock =pygame.time.Clock()
clock.tick(20)
当我们把这个clock.tick(20)加入到游戏的主循环后
就代表的画面每秒刷新20次 也就是20帧的意思
我们通过这个刷新次数来控制蛇的移动速度
当然 这是一个比较low的控制方法..
因为他并不稳定 和你的电脑配置是有关系的
那么如何让蛇来自动移动呢
方法很简单
那就是每次刷新的时候
如果方向向左那么让它的列数-1
同理其他方向
if direct == "left":
head.col -= 1
if direct == "down":
head.row += 1
if direct == "up":
head.row -= 1
if direct == "right":
head.col += 1
那改变蛇头方向怎么做呢
当我们按下键盘的时候 pygame会检测到这个事件
用if来判断不同的事件 同时控制direct的方向
if event.type == pygame.KEYDOWN:
print(event)
if event.key == K_LEFT:
direct = "left"
elif event.key == K_RIGHT:
direct = "right"
elif event.key == K_UP:
direct = "up"
elif event.key == K_DOWN:
direct = "down"
四、蛇体算法
我们先假设蛇头和蛇身体的坐标为:
head=(14,7)
l=[
(14,8)
(14,9)
(15,9)
(15,10)
(15,11)
(15,12)
(16,12)
(17,12)
]
移动:
1.把原来的头插到前面
2.把原来的尾删掉
head'=(14,6)
l'=[
(14,7) <-原来的头
(14,8)
(14,9)
(15,9)
(15,10)
(15,11)
(15,12)
(16,12)
del (17,12) <-原来的尾
]
所以本质上说一共就两步
1 把蛇头插入到身体的第一个位置
2 删除尾巴
还有一个问题 因为我们需要保存原先的蛇头位置
因为需要再在类中定义一个 copy
class Point:
row = 0
col = 0
def __init__(self,row,col):
self.row = row
self.col = col
def copy(self):
return Point(self.row, self.col)
snakes =[Point(head.row,head.col+1),
Point(head.row, head.col+2),
Point(head.row, head.col+3)]
#在循环上方定义一个身体 snake
snakes.insert(0,head.copy()) #插入旧蛇头
snakes.pop() #删除蛇尾
到这一步我们就可以简单的控制小蛇移动啦
五、碰撞检测
嘛。。听起来很高级的一个名词
但是我们这里并不需要很复杂的算法
只要检测蛇头的位置和食物的位置是否一样
如果一样
小蛇身体变长且食物新生成
所以还是很简单的
eat =(head.row == food.row and head.col == food.col)
snakes.insert(0,head.copy())
if eat:
food = food_exist() #食物生成
else:
snakes.pop()
六、食物随机生成
这一步肯定要用到random库拉
food = Point(random.randint(0,ROW-1),random.randint(0, COL-1))
这一句话就搞定了
七、死亡判定
死亡时无非是两种情况
1吃到墙了
2吃到自己
那么我们只要判断蛇头的位置死亡位置就好了
dead = False
if (head.row < 0 or head.col< 0 or head.row>ROW or head.col >COL):
print("你死了")
dead = True
for snake in snakes:
if(head.row == snake.row and head.col == snake.col):
print("你死了")
dead = True
if dead ==True:
break
在主循环中加入这段代码即可
先给予dead ==False 假设它一直不死
一旦玩家触发死亡 dead变为True 并且输出了一个 你死了
退出循环
到这里我们的贪吃蛇已经初步完成了 但是还有一些小小的细节需要优化
八、细节优化
1.我们的贪吃蛇是可以直接由左边转向右边 由上面转向下面 ,这显然是非常不科学的。
2.食物随机生成位置可能出现在蛇的身体或者头部上
先对第一点解决
为了避免这个问题 我们可以在转向前进行判定 只有在上下方向感才可以进行左右转
左右转的时候同理
if event.key == K_LEFT:
if (direct == "up" or direct == "down"):
direct = "left"
elif event.key == K_RIGHT:
if (direct == "up" or direct == "down"):
direct = "right"
elif event.key == K_UP:
if (direct == "right" or direct == "left"):
direct = "up"
elif event.key == K_DOWN:
if (direct == "right" or direct == "left"):
direct = "down"
第二点
也就是需要在生成食物前
进行判定食物的位置和蛇头位置,蛇身体位置
如果重复,就重新生成
def food_exist():
is_in =False
while True:
pos = Point(random.randint(0,ROW-1),random.randint(0, COL-1))
if (pos.row ==head.row and pos.col == head.col):
is_in =True
for snake in snakes:
if(pos.row == snake.row and pos.col == snake.col):
is_in = True
if is_in == False:
break
return pos
和死亡判定差不多
先定义一个is_in =False假设不会生成到蛇头和蛇身体位置
一旦 ...就重新生成
好了 到这里 我们简陋的贪吃蛇就全部完成了
九、源码
import pygame
import random
from pygame.locals import *
class Point:
row = 0
col = 0
def __init__(self,row,col):
self.row = row
self.col = col
def copy(self):
return Point(self.row, self.col)
pygame.init()
w = 800
h = 600
ROW = 30
COL = 40
size = (w, h)
direct = "left"
window = pygame.display.set_mode(size)
pygame.display.set_caption("贪吃蛇")
def rect(point, color):
w_cell = w/COL
h_cell = h/ROW
left = point.col*w_cell
top = point.row*h_cell
pygame.draw.rect(window,color,(left,top,w_cell,h_cell))
def food_exist():
is_in =False
while True:
pos = Point(random.randint(0,ROW-1),random.randint(0, COL-1))
if (pos.row ==head.row and pos.col == head.col):
is_in =True
for snake in snakes:
if(pos.row == snake.row and pos.col == snake.col):
is_in = True
if is_in == False:
break
return pos
quit = True
clock =pygame.time.Clock()
head = Point(ROW / 2,COL / 2)
snakes =[Point(head.row,head.col+1),
Point(head.row, head.col+2),
Point(head.row, head.col+3)]
food = food_exist()
head_color = (0, 128, 128)
food_color = (255, 255, 0)
bk_color = (255, 255, 255)
snake_color = (200,200,200)
while quit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit = False
elif event.type == pygame.KEYDOWN:
print(event)
if event.key == K_LEFT:
if (direct == "up" or direct == "down"):
direct = "left"
elif event.key == K_RIGHT:
if (direct == "up" or direct == "down"):
direct = "right"
elif event.key == K_UP:
if (direct == "right" or direct == "left"):
direct = "up"
elif event.key == K_DOWN:
if (direct == "right" or direct == "left"):
direct = "down"
dead = False
if (head.row < 0 or head.col< 0 or head.row>ROW or head.col >COL):
print("你死了")
dead = True
for snake in snakes:
if(head.row == snake.row and head.col == snake.col):
print("你死了")
dead = True
if dead ==True:
break
eat =(head.row == food.row and head.col == food.col)
snakes.insert(0,head.copy())
if eat:
food = food_exist()
else:
snakes.pop()
if direct == "left":
head.col -= 1
if direct == "down":
head.row += 1
if direct == "up":
head.row -= 1
if direct == "right":
head.col += 1
pygame.draw.rect(window,bk_color,(0,0,w,h))
rect(head,head_color)
rect(food,food_color)
#生成蛇身体
for snake in snakes:
rect(snake,snake_color)
pygame.display.update()
clock.tick(20)
感谢大家的阅读。
第一次写游戏
也参考了网上的一些教程
有问题欢迎大家讨论纠正
相关知识
py人类与宠物模拟世界
通过python
基于python
Python笔试题
python通过cython编译成可执行文件方式
编写宠物dog类python
Python之函数
深度学习宠物行为识别代码教程
099基于深度学习的动物声音分类
CNN鸟类图片识别教程:从数据集到模型训练
网址: 【py】python https://m.mcbbbk.com/newsview657249.html
上一篇: 今日可以扫舍吗 2024年8月2 |
下一篇: 使用python pygame库 |