先上资源,图片资源,源代码及打包成的exe文件:
链接:https://pan.baidu.com/s/1jc8Yrr8XeknHLxicdRUzyw
提取码:j1ax
上效果gif,可解压上述百度云链接中的压缩包打开此沙雕游戏:
做一下说明:
一直想做一个游戏,现正好借熟悉python来写一个游戏,写着写着(边查资料)发现,这简直太难了,首先得学习下pygame,因为本来适用面较窄没有其他游戏引擎比如unity3D运用广泛,所以资料较少(相对而言),除此之外没有美工,图片得找,甚至还要自行PS(所以有时会显示出奇怪的字,动画也不连贯,水平有限啦),过于艰难,还要写底层逻辑,比如这个游戏需要判断是否与墙壁碰撞这些都是纯手工。基本入门之后,决定-->放弃。
源代码基本每一行都有注释,提供给初学者,这些都是什么意义。最开始通过教程学动画滚动啊等等,但是后来发现还是无法满足要求,建议:先构思游戏,再一步一步写,边写边查。
上述沙雕游戏步骤大致为:pygame游戏框架-->机器人动态,不同移动方向不同姿态-->引入背景及障碍物方块-->碰撞判断-->输赢判断及结束动画图-->构造迷宫二维List(之后改变该list则改变迷宫样式,接下来准备写点算法生成自动迷宫,给这个沙雕游戏一个ending)
机器人动态是相当于多个图片,图片如下(网上找的):
打包成exe时可参考上一篇文章https://blog.csdn.net/qq_36187544/article/details/86550376
算法自动生成迷宫pygame从入门到放弃(下)--迷宫游戏随机迷宫生成算法链接:https://blog.csdn.net/qq_36187544/article/details/87613346
这里由于涉及到图片,打包完成后会输出图片读取不到的问题,所以手动在exe同级目录下增加image文件夹,内含图片资源
源代码如下(这么简单的游戏200多行,放弃吧):
# -*- coding: cp936 -*-
import os, sys, pygame
from pygame.locals import *
size = (700, 700) # 对话框大小
white = (255, 255, 255) # 定义白色
block_group = [] # 障碍物组
isOver = False # 判断游戏是否结束
# 定义迷宫的二维list,0为可走为空,1为填充砖块处
background_group = [
[0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 0, 1, 1, 1, 1, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
[0, 1, 1, 1, 0, 1, 1, 0, 1, 0],
[0, 1, 0, 0, 0, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 1, 0, 1, 1, 1, 1],
[0, 1, 0, 1, 1, 0, 0, 0, 0, 1],
[0, 1, 0, 1, 1, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]
# 游戏主角是机器人android
class Android:
# 初始化类
def __init__(self, img, rect, speed):
# full_img 是整张图,imgs 是full_img的surface
# rect 是机器人的位置,speed则是移动速度
self.ful_img = img
self.imgs = [self.ful_img.subsurface(Rect((i * 64.5, 0), (70, 70)))
for i in range(11)]
self.rect = rect
self.speed = speed
self.num = 0
# 当按下键盘时,移动机器人
def update(self, screen, press_keys):
global isOver # 声明这是全局变量
# num是surface的编号,根据编号来轮流显示surface
self.num += 1
if self.num % 11 == 0:
self.num = 0
# 退出
if press_keys[K_ESCAPE]:
exit()
# 根据按下的方向键来移动机器人
if press_keys[K_LEFT]:
self.rect.left -= self.speed
# 如果碰壁则无法再移动
if self.rect.left <= 0:
self.rect.left = 0
# 判断是否碰撞,70是一个基数是障碍物方块边长
for n in range(len(block_group)-1): # block_group列表记录所有的方块,最后一位记录终点方块,判断胜利调用最后一位,除此之外不涉及最后一位
# 此后两个if判断与某一方块是否碰撞
if self.rect.top > block_group[n].rect.top - 70 and self.rect.bottom < block_group[n].rect.bottom + 70:
if self.rect.right > block_group[n].rect.right > self.rect.left:
self.rect.left += self.speed
break # 发生了碰撞则复原并跳出此For循环
# 接下来的if...else用于使机器人产生向左移动时的动画
if self.num % 3 == 1 or self.num % 3 == 0:
screen.blit(self.imgs[2], self.rect)
return 0
else:
screen.blit(self.imgs[0], self.rect)
return 0
if press_keys[K_RIGHT]:
self.rect.left += self.speed
# 如果碰壁则无法再移动
if self.rect.right >= 700:
self.rect.right = 700
# 判断是否碰撞,70是一个基数是障碍物方块边长
for n in range(len(block_group)-1):
if self.rect.top > block_group[n].rect.top - 70 and self.rect.bottom < block_group[n].rect.bottom + 70:
if self.rect.left < block_group[n].rect.left < self.rect.right:
self.rect.left -= self.speed
break
# 判断是否胜利
if self.rect.top > block_group[len(block_group) - 1].rect.top - 70 and self.rect.bottom < block_group[len(block_group) - 1].rect.bottom + 70:
if self.rect.left < block_group[len(block_group) - 1].rect.left < self.rect.right:
isOver = True
# 接下来的if...else用于使机器人产生向右移动时的动画
if self.num % 3 == 1 or self.num % 3 == 0:
screen.blit(self.imgs[1], self.rect)
return 0
else:
screen.blit(self.imgs[0], self.rect)
return 0
if press_keys[K_UP]:
self.rect.top -= self.speed
# 如果碰壁则无法再移动
if self.rect.top <= 0:
self.rect.top = 0
# 判断是否碰撞,70是一个基数是障碍物方块边长
for n in range(len(block_group)-1):
if self.rect.left > block_group[n].rect.left - 70 and self.rect.right < block_group[n].rect.right + 70:
if self.rect.bottom > block_group[n].rect.bottom > self.rect.top:
self.rect.top += self.speed
break
# 接下来的if...else用于使机器人产生向上移动时的动画
if self.num % 3 == 1 or self.num % 3 == 0:
screen.blit(self.imgs[9], self.rect)
return 0
else:
screen.blit(self.imgs[0], self.rect)
return 0
if press_keys[K_DOWN]:
self.rect.top += self.speed
# 如果碰壁则无法再移动
if self.rect.bottom >= 700:
self.rect.bottom = 700
# 判断是否碰撞,70是一个基数是障碍物方块边长
for n in range(len(block_group)-1):
if self.rect.left > block_group[n].rect.left - 70 and self.rect.right < block_group[n].rect.right + 70:
if self.rect.top < block_group[n].rect.top < self.rect.bottom:
self.rect.top -= self.speed
break
# 判断是否胜利
if self.rect.left > block_group[len(block_group)-1].rect.left - 70 and self.rect.right < block_group[len(block_group)-1].rect.right + 70:
if self.rect.top < block_group[len(block_group)-1].rect.top < self.rect.bottom:
isOver = True
# 接下来的if...else用于使机器人产生向下移动时的动画
if self.num % 3 == 1 or self.num % 3 == 0:
screen.blit(self.imgs[3], self.rect)
return 0
else:
screen.blit(self.imgs[0], self.rect)
return 0
# 用于产生静止时的动画
if 3 >= self.num >= 0 or self.num > 7:
screen.blit(self.imgs[0], self.rect)
elif self.num == 5 or self.num == 4:
screen.blit(self.imgs[5], self.rect)
elif self.num == 6 or self.num == 7:
screen.blit(self.imgs[6], self.rect)
return 0
# 由于需要判断碰撞,所以无法简单绘制障碍物,需设置障碍物类
class Block:
def __init__(self, img, rect):
self.img = img
self.rect = rect
# 绘制障碍物方块
def draw(self, screen):
screen.blit(self.img, self.rect)
# 绘制背景方块
def drawBackground(screen):
# 清空列表,初始化
block_group.clear()
# 定义障碍物
block1_img = pygame.image.load('image/block1.png').convert()
# 通过background_group这个二维List进行迷宫的绘制
for i in range(10):
for j in range(10):
if background_group[i][j] == 1:
block = Block(block1_img, Rect(70*j, 70*i, 70, 70)) # 初始化障碍物方块
block.draw(screen) # 绘制障碍物方块
block_group.append(block) # 向列表中加入该方块
# 定义终点方块
block_final = Block(pygame.image.load('image/block2.png').convert(), Rect(630, 630, 70, 70))
block_final.draw(screen)
block_group.append(block_final)
def game():
# 使窗口居中
os.environ['SDL_VIDEO_CENTERED'] = '1'
# 定义机器人移动速度
speed_android = 5
# 定义间隔时间,没过一个间隔时间进行一次循环判断
dwTime = 6
# 定义机器人所占的空间,为一个矩形,Rect(左上角位置横坐标,左上角位置纵坐标,长,宽)
r_android = Rect(0, 0, 70, 70)
# 初始化pygame
pygame.init()
# 定义时钟
clock = pygame.time.Clock()
# 定义屏幕
screen = pygame.display.set_mode(size, 0, 32)
# 定义机器人图画
android = pygame.image.load('image/robot.png').convert_alpha()
# 定义背景
background1 = pygame.image.load('image/background1.jpg').convert()
# 定义一个Android
Andr = Android(android, r_android, speed_android)
# 设置窗口标题
pygame.display.set_caption("真是一个小游戏")
# 开始循环
while True:
# 判断游戏是否结束,结束则换另一套逻辑
if isOver:
screen.blit(pygame.image.load('image/over.jpg').convert(), (0, 0)) # 绘制胜利背景
pygame.display.update()
# 按任意键退出
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
exit()
clock.tick(1000)
continue
# 屏幕填充为白色
screen.fill(white)
# 屏幕填充为背景图
screen.blit(background1, (0, 0))
# 调用方法绘制背景障碍物方块
drawBackground(screen)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# 当有按键按下时调用机器人类进行更新
press_keys = pygame.key.get_pressed()
Andr.update(screen, press_keys)
# 更新展示
pygame.display.update()
# 定时装置
clock.tick(dwTime)
if __name__ == "__main__":
game()