使用python制作钻地小子demo
相信应该不少90后的伙伴,多少玩过这款GBA游戏
接下来我是用python来制作一款钻地小子的游戏demo
直接上开发完成的游戏
说实话有背景音乐还是很带劲的
效果就如下一个小demo还有写细节没有完全做完,先这样以后有空再做
实现玩法
- 设计好游戏主界面
- 设计好游戏地图,方块随机的
- 制作角色、移动
- 可以实现钻地下掉
OK闲话少说开干
实现思路
- 从网上下载好素材图片、音乐等
- 通过python的pygame库来实现游戏demo
- 具体实现
项目结构
Graph是保存了游戏中的所有素材图片
Sound存了所有的音效
gd.py 就是写demo的主程序
大概效果图:
Graph内容如下
所有的图片都归类好了
Sound内容如下
开发阶段
1.制作游戏框架
首先导入所有需要用到的包
# -*- coding:utf-8 -*-
import pygame,os
from sys import exit
from random import randint as ri
from pygame.locals import *
pygame.init()
我们需要绘制地图上所有方块的坐标,传入一个关卡id,函数代码如下:
#地图方块绘制
def LEVEL_POSITION(level):
level_pos = []
if level == 1:#第一关
for j in range(7,45+7):#45
for i in range(11):
level_pos.append([ i*(32), j*(32),ri(1, 495+1)])
#填充最后的纯绿色
for j in range(7):
for i in range(11):
level_pos.append([ i*(32), 1632+32+j*(32),-1])
return level_pos
制作好测试每个方块代号的颜色表,函数代码如下:
#测试方块的颜色
def colorTYPE(leP):
if 1<=leP<=110: #红色
return 'r'
elif 111<=leP<=220:#蓝色
return 'b'
elif 221<=leP<=330:#绿色
return 'g'
elif 331<=leP<=440:#黄色
return 'y'
elif 441<=leP<=487:#棕色
return 'Br'
elif 488<=leP<=495:#气囊
return 'AIR'
elif leP == -1: #绘制最后的关卡结束方块 纯绿色
return 'cG'
创建要给main方法,然后成为主方法,在main方法里面写入按键检测事件,代码块如下:
#---------------------行走动画效果和坠落动画效果------------------------
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
#在主界面的时候 等于 false
if gameing == False:
if event.key == K_SPACE:
gameing = True #可以开始游戏了
else:#可以开始游戏的行为了------------------------------
接下来是主调main函数的入口,代码如下:
if __name__ == '__main__':
trs = True
level = 1
argc = False
while trs:
trs = main(argc,level)
level+=1
接下来定义好所有游戏中使用的变量和资源加载,代码如下:
def main(gameing_argc,level_argc):
w,h = 510,480
recSIZE = 350
timer = 30
patth = 0
score = 0
life = 1
screen = pygame.display.set_mode([w,h],0,32)
caption = pygame.display.set_caption("钻地小子")
screen.fill([0,0,0]);
pygame.display.flip()
pygame.key.set_repeat(1,100)
#背景
bg = pygame.image.load('Graph/Title/Bg.jpg').convert_alpha()
bg = pygame.transform.scale(bg, (int(bg.get_width()*0.75), int(bg.get_height()*0.75)))
#载入声音
pygame.mixer_music.load('Sound/bgm/Airman.mp3')
pygame.mixer.music.play(-1,0,)
pygame.mixer.music.set_volume(0.5)
#please space 的按钮
spacebg = pygame.image.load('Graph/Common/PleasePushSpace.png').convert_alpha()
spacebg = pygame.transform.scale(spacebg, (int(spacebg.get_width()*0.7), int(spacebg.get_height()*0.7)))
spacetimer = 0 #空格闪烁定时器
gameing = gameing_argc #默认游戏还没开始
#左边壁纸
leftbg = pygame.image.load('Graph/Play/Bg.jpg').convert_alpha();
leftbg = pygame.transform.scale(leftbg,(int(leftbg.get_width()*0.145), int(leftbg.get_height()*0.2)))
#右边壁纸
rightbg = pygame.image.load('Graph/Play/UI.PNG').convert_alpha();
rightbg = pygame.transform.scale(rightbg,(int(rightbg.get_width()*0.6), int(rightbg.get_height()*0.7)))
#空气瓶条
air1 = pygame.image.load('Graph/Play/AirGauge1.png').convert_alpha()
air1 = pygame.transform.scale(air1, (100, int(air1.get_height()*0.4)))
fs = pygame.font.SysFont("arial", 30)
air_lifeV = 100 #气囊条血量 100代表100% 高度为:height == 26
air_timer = 0
#方块 32*32
blue1 = pygame.image.load('Graph/Play/blue1.png').convert_alpha()
blue1 = pygame.transform.scale(blue1,(32, 32))
brow1 = pygame.image.load('Graph/Play/brown1.png').convert_alpha()
brow1 = pygame.transform.scale(brow1,(32, 32))
green1 = pygame.image.load('Graph/Play/green1.png').convert_alpha()
green1 = pygame.transform.scale(green1,(32, 32))
green2 = pygame.image.load('Graph/Play/green2.png').convert_alpha()
green2 = pygame.transform.scale(green2,(32, 32))
red1 = pygame.image.load('Graph/Play/red1.png').convert_alpha()
red1 = pygame.transform.scale(red1,(32, 32))
yellow1 = pygame.image.load('Graph/Play/yellow1.png').convert_alpha()
yellow1 = pygame.transform.scale(yellow1,(32, 32))
#空气瓶
air = pygame.image.load('Graph/Play/air.png').convert_alpha()
air = pygame.transform.scale(air,(32, 32))
#角色坠落 fall
fall1 = pygame.image.load('Graph/Play/fall/fall1.png').convert_alpha()
fall1 = pygame.transform.scale(fall1, (32, 32))
fall_h = -50 #坠落高度
#角色移动 left
left1 = pygame.image.load('Graph/Play/leftm/walk_left1.png').convert_alpha()
left1 = pygame.transform.scale(left1, (32, 32))
left2 = pygame.image.load('Graph/Play/leftm/walk_left2.png').convert_alpha()
left2 = pygame.transform.scale(left2, (32, 32))
left3 = pygame.image.load('Graph/Play/leftm/walk_left3.png').convert_alpha()
left3 = pygame.transform.scale(left3, (32, 32))
left4 = pygame.image.load('Graph/Play/leftm/walk_left4.png').convert_alpha()
left4 = pygame.transform.scale(left4, (32, 32))
left5 = pygame.image.load('Graph/Play/leftm/walk_left5.png').convert_alpha()
left5 = pygame.transform.scale(left5, (32, 32))
#角色移动 right
right1 = pygame.image.load('Graph/Play/rightm/walk_right1.png').convert_alpha()
right1 = pygame.transform.scale(right1, (32, 32))
right2 = pygame.image.load('Graph/Play/rightm/walk_right2.png').convert_alpha()
right2 = pygame.transform.scale(right2, (32, 32))
right3 = pygame.image.load('Graph/Play/rightm/walk_right3.png').convert_alpha()
right3 = pygame.transform.scale(right3, (32, 32))
right4 = pygame.image.load('Graph/Play/rightm/walk_right4.png').convert_alpha()
right4 = pygame.transform.scale(right4, (32, 32))
right5 = pygame.image.load('Graph/Play/rightm/walk_right5.png').convert_alpha()
right5 = pygame.transform.scale(right5, (32, 32))
#上钻
upd = pygame.image.load('Graph/Play/upm/up.png').convert_alpha()
upd = pygame.transform.scale(upd, (32, 32))
#下钻
downd = pygame.image.load('Graph/Play/downm/down.png').convert_alpha()
downd = pygame.transform.scale(downd, (32, 32))
#关卡1 红 蓝 绿 黄 棕 气
# 110,110,110, 110, 47, 8
LEVEL = [1,0,0,0,0,0,0,0,0,0] #10个关卡
leveF = 1 #默认第一关标志 (用来测试随机生成第几关的地图标志)
level_pos = [] #关卡所有的方块坐标
Bindlist = [] #绑定的同色和在一块的方块数组
reducer = 0 #累减器
#角色状态
drc = 'sp'#默认炫富状态 sp 悬空 l 左 r右 st 静止
butup = False #按键松开判断
butup2 = False #松开按键判断
from_drc = drc #记录前一个方向
moveTimer = 0#移动定时器
P=[ 160 , 193 ]#角色默认位置
right_first_RECT = []#检测右边的方块坐标[ level_pos[0][0] , level_pos[0][1] ]
right_first_RECT2 = [] #钻机的右边的方块坐标
#棕色方块列表
color_brown = []
esc_stop = False #暂停游戏
循环往下掉的代码块如下:
#循环往下面掉----------
index = 0
ind_pos = []
ind_index = 0
for j in range(495):
if level_pos[index+11][2] == 0 and level_pos[index][2] != 0 and P[1] >= level_pos[index+11][1]:
ind_pos = level_pos[index+11]
ind_index = index+11
index += 1
#print(P,ind_pos)
ind_inde_ind = 0
while ind_index>0:
if level_pos[ind_index] == ind_pos and ind_pos[0]!=0 and ind_pos[1]!=0:
level_pos[ind_index-(ind_inde_ind+1)*11][1] = level_pos[ind_index-ind_inde_ind*11][1]-32
ind_inde_ind += 1
if level_pos[ind_index][2] == 0:
level_pos[ind_index-11][0] = level_pos[ind_index][0]
level_pos[ind_index-11][1] = level_pos[ind_index][1]
level_pos[ind_index][0] = 0
level_pos[ind_index][1] = 0
ind_index-=1
因为pygame这个游戏库没有动画的任何接口只能手动一个一个来码,所以我只能在这里手动实现序列帧的动画来设计角色,设计行走动画和坠落动画如下代码块:
--------------------行走动画效果和坠落动画效果------------------------
if drc == 'sp':
if fall_h < 193:
fall_h+=4
else:fall_h=193
screen.blit(fall1,(level_pos[5][0],fall_h))
elif drc == 'r':
moveTimer += 1
if moveTimer <= 2:
screen.blit(right1,P)
elif moveTimer <= 4:
screen.blit(right2,P)
elif moveTimer <= 6:
screen.blit(right3,P)
elif moveTimer <= 8:
screen.blit(right4,P)
elif moveTimer <= 10:
screen.blit(right5,P)
elif moveTimer <= 12:
moveTimer = 0
elif drc == 'l':
moveTimer += 1
if moveTimer <= 2:
screen.blit(left1,P)
elif moveTimer <= 4:
screen.blit(left2,P)
elif moveTimer <= 6:
screen.blit(left3,P)
elif moveTimer <= 8:
screen.blit(left4,P)
elif moveTimer <= 10:
screen.blit(left5,P)
elif moveTimer <= 12:
moveTimer = 0
elif drc == 'd':
if from_drc == 'l':
screen.blit(left1,P)
elif from_drc == 'r':
screen.blit(right1,P)
elif from_drc == 'd':
screen.blit(downd,P)
else:
screen.blit(downd,P)
elif drc == 'u':
if from_drc == 'l':
screen.blit(left1,P)
elif from_drc == 'r':
screen.blit(right1,P)
else:
screen.blit(upd,P)
#print(drc,from_drc)
添加按了ESC然后暂停游戏功能,使用Run变量来控制游戏的正常运行和停止,带代码如下:
def stopFun():
Run = True
pygame.mixer_music.load('Sound/effect/effect10.mp3')
pygame.mixer.music.play(1,0,)
pygame.mixer.music.set_volume(0.5)
pygame.display.flip()
while Run:
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
Run = False
pygame.display.update()
接下来是真正的最核心的代码块,实现了最终的行走动画和方块坠落、主角坠落的动画和逻辑,代码如下:
#---------------------行走动画效果和坠落动画效果------------------------
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
#在主界面的时候 等于 false
if gameing == False:
if event.key == K_SPACE:
gameing = True #可以开始游戏了
else:#可以开始游戏的行为了------------------------------
if fall_h >= 193:#坠落状态已经到达
#print('0-4坐标:',level_pos[3][0],level_pos[3][1])
#print('P:',P)
if event.key == K_ESCAPE:
stopFun()
if event.key == K_LEFT:
drc = 'l'
#-------------------------
#检测是不是最开始的状态,为了移动人物
if level_pos[0][1] > P[1] :
P[0]-=8
#elif True:
#print('begin_left')
else:
#左边移动判断撞到 方块的坐标
left_first_RECT = []#[ level_pos[0][0] , level_pos[0][1] ]#默认第一个方块
#检测和自己左边最近的方块坐标
left_indsss = 0
for reP in level_pos: #遍历是否撞到方块
if reP[0]<= P[0] and reP[1] <= P[1] and reP[0] >= P[0]-32 and reP[1] >= P[1]-32:
left_first_RECT = reP
#左边有最近的方块
try:
#print(left_first_RECT)
#pygame.draw.rect(screen, (255,0,0), (left_first_RECT[0],left_first_RECT[1],32,32))
if left_first_RECT[0]<=P[0] and left_first_RECT[1]<=P[1] and left_first_RECT[2]!=0:
#pygame.draw.rect(screen, (255,255,255), (left_first_RECT[0],left_first_RECT[1],32,32), 1)
#正在行走时...判断气囊是否在左边 是就吃掉加血
if colorTYPE(left_first_RECT[2]) == 'AIR':
indext = 0
for reP in level_pos:
if reP == left_first_RECT:
level_pos[indext][2] = 0
air_lifeV += 20
if air_lifeV >= 100:air_lifeV = 100
#print('yes qinang')
break
indext += 1
elif colorTYPE(left_first_RECT[2]) == 'Br':
#print('棕色')
air_lifeV -= 2
if air_lifeV<=0:air_lifeV = 0
try:
level_pos[left_indsss][2] = 0
except:pass
#没有最近的方块 是空格
elif left_first_RECT[2] == 0:
P[0]-=8
#print('DRECTION---left:',P[0])
except:pass#print('error1',left_first_RECT)
#-------------------------
#是否超出游戏最大盒子
if P[0]+32>recSIZE:P[0]=recSIZE-32
if P[0]<0:P[0]=0
if event.key == K_RIGHT:
drc = 'r'
#-------------------------
#检测是不是最开始的状态,为了移动人物
if level_pos[0][1] > P[1]:
P[0]+=8
#print('begin_right')
else:
#右边移动判断撞到 方块的坐标
right_first_RECT = [0,0,0]
right_indsss = 0
#检测和自己右边最近的方块坐标
#if reP[0]<= P[0] and reP[1] <= P[1] and reP[0] >= P[0]-32 and reP[1] >= P[1]-30:
for reP in level_pos: #遍历是否撞到方块
if reP[0]>=P[0]+32 and reP[0]+32<=P[0]+64 and reP[1] <= P[1] and reP[1] >= P[1]-30:
right_first_RECT = reP
right_indsss += 1
#------要到与自己平行的方块才被钻掉------
if(reP[1]+3)>=P[1] and (P[1]+32)>=(reP[1]+30):break
#------要到与自己平行的方块才被钻掉------
try:
#pygame.draw.rect(screen,(0,255,0), (right_first_RECT[0],right_first_RECT[1],32,32))
#右边有最近的方块
if right_first_RECT[0]>=P[0]+32 and right_first_RECT[1]<=P[1] and right_first_RECT[2]!=0:
#pygame.draw.rect(screen,(255,0,0), (right_first_RECT[0],right_first_RECT[1],32,32), 1)
#正在行走时...判断气囊是否在右边 是就吃掉加血
if colorTYPE(right_first_RECT[2]) == 'AIR':
indext = 0
for reP in level_pos:
if reP == right_first_RECT:
level_pos[indext][2] = 0
air_lifeV += 20
if air_lifeV >= 100:air_lifeV = 100
#print('yes qinang')
break
indext += 1
elif colorTYPE(right_first_RECT[2]) == 'Br':
#print('棕色')
air_lifeV -= 2
if air_lifeV<=0:air_lifeV=0
try:
level_pos[right_indsss][2] = 0
except:pass
#没有最近的方块 是空格
elif right_first_RECT[2] == 0:
P[0]+=8
#print('DRECTION---right:',P[0])
except:
print('error2',right_first_RECT)
#-------------------------
#是否产出游戏最大盒子
if P[0]+32>recSIZE:P[0]=recSIZE-32
if P[0]<0:P[0]=0
if event.key == K_DOWN:
from_drc = 'd'
drc = 'd'
right_indsss = 0
indes = 0
for i in range(495):
#p[0]+16是取角色的中心点坐标运算
if level_pos[indes][0]+32 >= P[0]+22 and P[0]+10 >= level_pos[indes][0] and \
P[1]+32 >= level_pos[indes][1] and level_pos[indes][2]!=0:
#print(level_pos[indes])
#print(P)
if level_pos[indes][0] >= P[0] and level_pos[indes][1]>= P[1]:
#红色'r'
#蓝色'b'
#绿色 'g'
#黄色'y'
#棕色'Br'
#气囊'AIR'
#纯绿色'cG'
if colorTYPE(level_pos[indes][2]) == 'Br':
#print('棕色')
air_lifeV -= 2
if air_lifeV<=0:air_lifeV=0
try:
if right_indsss!=0:
level_pos[right_indsss][2] = 0
except:pass
#break
indes += 1
if event.key == K_UP:
from_drc = 'u'
drc = 'u'
right_indsss = 0
indes = 0
for i in range(495):
#p[0]+16是取角色的中心点坐标运算
if level_pos[indes][0]+32 >= P[0]+22 and P[0]+10 >= level_pos[indes][0] and \
P[1] >= level_pos[indes][1] and level_pos[indes][2]!=0:
#print('up')
if level_pos[indes][0] >= P[0] and level_pos[indes][1]>= P[1]-32:
#红色'r'
#蓝色'b'
#绿色 'g'
#黄色'y'
#棕色'Br'
#气囊'AIR'
#纯绿色'cG'
if colorTYPE(level_pos[indes][2]) == 'Br':
#print('棕色')
air_lifeV -= 2
if air_lifeV<=0:air_lifeV = 0
try:
level_pos[right_indsss][2] = 0
except:pass
#break
indes += 1
if event.key == K_RETURN or event.key == K_KP_ENTER:
if drc == 'd':#开始钻机
indes = 0
for i in range(495):
#p[0]+16是取角色的中心点坐标运算
if level_pos[indes][0]+32 >= P[0]+22 and P[0]+10 >= level_pos[indes][0] and \
P[1]+32 >= level_pos[indes][1] and level_pos[indes][2]!=0:
#print(level_pos[indes])
#print(P)
if level_pos[indes][0] >= P[0] and level_pos[indes][1]>= P[1]:
patth += 1
score += patth+ri(1, 4)
#红色'r'
#蓝色'b'
#绿色 'g'
#黄色'y'
#棕色'Br'
#气囊'AIR'
#纯绿色'cG'
if colorTYPE(level_pos[indes][2]) == 'Br':
air_lifeV -= 2
if air_lifeV <=0:air_lifeV = 0
#BindTop(level_pos,level_pos[indes])
level_pos[indes][2] = 0#这个为空格方块
#break
indes += 1
if drc == 'u':#开始钻机
indes = 0
for i in range(495):
#p[0]+16是取角色的中心点坐标运算
if level_pos[indes][0]+32 >= P[0]+22 and P[0]+10 >= level_pos[indes][0] and \
P[1] >= level_pos[indes][1] and level_pos[indes][2]!=0:
#print('up')
if level_pos[indes][0] >= P[0] and level_pos[indes][1]>= P[1]-32:
patth += 1
score += patth*ri(1, 4)
if colorTYPE(level_pos[indes][2]) == 'Br':
air_lifeV -= 2
if air_lifeV <=0:air_lifeV = 0
level_pos[indes][2] = 0#这个为空格方块
break
indes += 1
if drc == 'l':#开始钻机
#-------------------------
#左边移动判断撞到 方块的坐标
left_first_RECT = []
#检测和自己左边最近的方块坐标 为了消除坐标方块
for reP in level_pos: #遍历是否撞到方块
if reP[0]<= P[0] and reP[1] <= P[1] and reP[2]!=0 \
and reP[0] >= P[0]-32 and reP[1] >= P[1]-30:
left_first_RECT = reP
#左边有最近的方块
try:
if left_first_RECT[0]<=P[0] and left_first_RECT[1]<=P[1] and left_first_RECT[2]!=0:
#level_pos[indes][2] = 0
index = 0
for reP in level_pos:
if reP == left_first_RECT:
#pygame.draw.rect(screen, (255,255,255), (left_first_RECT[0],left_first_RECT[1],32,32), 1)
patth += 1
score += patth*ri(1, 4)
if colorTYPE(level_pos[indes][2]) == 'Br':
air_lifeV -= 2
if air_lifeV <=0:air_lifeV = 0
level_pos[index][2] = 0
index += 1
except:pass
#-------------------------
if drc == 'r':#开始钻机
#-------------------------
#右边移动判断撞到 方块的坐标
#检测和自己右边最近的方块坐标
#and reP[1] <= P[1] and reP[1] >= P[1]-30
for reP in level_pos: #遍历是否撞到方块
if reP[0]>=P[0]+32 and reP[0]+32<=P[0]+64 and reP[2]!=0\
and reP[1] <= P[1] and reP[1] >= P[1]-30 :
right_first_RECT2 = reP
#---------要到与自己平行的方块才被钻掉-------------
if (reP[1]+3)>=P[1] and (P[1]+32)>=(reP[1]+30):break
#---------要到与自己平行的方块才被钻掉-------------
#右边有最近的方块
try:
#pygame.draw.rect(screen, (255,255,255), (right_first_RECT[0],right_first_RECT[1],32,32))
if right_first_RECT2[0]>=P[0] and right_first_RECT2[1]<=P[1] and right_first_RECT2[2]!=0:
index = 0
for reP in level_pos:
if reP == right_first_RECT2:
#pygame.draw.rect(screen, (255,255,255), (right_first_RECT2[0],right_first_RECT2[1],32,32), 1)
patth += 1
score += patth*ri(1, 4)
if colorTYPE(level_pos[indes][2]) == 'Br':#为棕色的方块
#print('棕色')
pass#level_pos[indes][2] = 0
else:
if colorTYPE(level_pos[indes][2]) == 'Br':
air_lifeV -= 2
if air_lifeV <=0:air_lifeV = 0
level_pos[index][2] = 0
#------要到与自己平行的方块才被钻掉------
if (reP[1]+3)>=P[1] and (P[1]+32)>=(reP[1]+30):break
#------要到与自己平行的方块才被钻掉------
index += 1
except:pass
#-------------------------
if event.type == KEYUP:
if fall_h >= 193:
if event.key == K_LEFT or event.key == K_RIGHT:
from_drc = drc #记录前一个方向
#drc = 'd'#成为静止状态
moveTimer = 0
if event.key == K_RETURN or event.key == K_KP_ENTER:
butup = True
butup2 = True
至此游戏全部代码量867行做完