经典的推箱子Sokoban是一个来自日本的古老游戏,目的是在训练你的逻辑思考能力。在一个狭小的仓库中,要求把木箱放到指定的位置,稍不小心就会出现箱子无法移动或者通道被堵住的情况,所以需要巧妙的利用有限的空间和通道,合理安排移动的次序和位置,才能顺利的完成任务。
下面将python+pygame实现推箱子小游戏的过程记录下来,以便学习。
零
基本逻辑是将箱子推到指定位置,虽然简单,但这个游戏其实很烧脑。开发实现时,计划为:
页面元素共有:推箱子的工人,箱子,外墙,终点
1、推箱子的工人class workerSprite,继承自pygame.sprite.Sprite,由于它和其他的页面元素有点不一样,它可以前后左右动,所以显示的图像不一样。它可以移动,还有就是要计算它在当前的位置和方向上的下一个位置能不能到达(这个要先判断),因此要返回下一个位置。
2、其他的页面元素(箱子box,外墙wall,终点target)class gameElementSprite,同样继承自pygame.sprite.Sprite,用elementtype来区别,只有box可以被移动,同时在移动之前,要判断在当前的位置和方向上的下一个位置能不能到达,因此要返回下一个位置。
3、游戏地图的构造及相关判断动作class gameMap,主要是加载地图上对应的元素,判断是否通关,判断1和2中计算出的位置是否可以到达。这里不涉及到pygame的应用,可以理解为就是个后端的服务。
4、游戏的界面展示class gameDisplay,主要完成关卡地图的读取,借助 3 来完成构造,同时draw到屏幕上。另外,有些地图较大,所以这里还会涉及到随着人物走动时的屏幕滚动的操作控制。
5、套娃结束,写主函数了。包含某一关的主循环(主要是键盘的控制),退出游戏及过渡附属页面。
注意:为方便起见,将程序用到的公共参数放在params.py文件中,这样:
'''
参数配置文件
'''
Params = {
'WIDTH': 650, #游戏界面宽度
'HEIGHT': 520, #游戏界面高度
'blockSize': 50, #每块大小
'levelsPath': './levels', #关卡文件夹
'resourcePath': './resource', #资源文件夹
'imgFolder': 'imgs', #图片文件夹
'fontFolder': 'font', #字体文件夹
'audioFolder': 'audios', #音乐文件夹
'bgColor': (38, 38, 38) #背景色
}
为方便查看,给出目录结构:
一
先从基本的class workerSprite写起,它继承自pygame.sprite.Sprite,
import os
import pygame
from params import Params
'''
推箱子的工人
'''
class workerSprite(pygame.sprite.Sprite):
def __init__(self,col,row):
pygame.sprite.Sprite.__init__(self)
self.imagepath = os.path.join(Params.get('resourcePath'), Params.get('imgFolder'), 'right.png')
self.image = pygame.image.load(self.imagepath).convert_alpha()
self.rect = self.image.get_rect()
self.col = col
self.row = row
'''
移动工人
'''
def move(self,direction):
if direction == 'up':
self.row -= 1
elif direction == 'down':
self.row += 1
elif direction == 'left':
self.col -= 1
elif direction == 'right':
self.col += 1
self.imagepath = os.path.join(Params.get('resourcePath'), Params.get('imgFolder')) + '\\' + direction + '.png'
self.image = pygame.image.load(self.imagepath).convert_alpha()
'''
获取下一个点的位置
'''
def getNextPos(self,direction):
if direction == 'up':
return self.col, self.row - 1
elif direction == 'down':
return self.col, self.row + 1
elif direction == 'left':
return self.col - 1, self.row
elif direction == 'right':
return self.col + 1, self.row
'''
画到屏幕上
'''
def draw(self,gamescreen):
self.rect.x = self.rect.width * self.col
self.rect.y = self.rect.height * self.row
gamescreen.blit(self.image, self.rect)
注解:
1、__init__中本质是在位置col,row上画图片,默认方向是right.png,convert_alpha()包含了透明度,用convert()也可以
2、move函数中,会根据其方向使用不同的图片,分别对应使用up.png,down.png,right.png,left.png
3、draw函数注意有个转换,人物占一格,所以要转换为像素,用Params中的blockSize也可以。
待续...