超级玛丽之工具、环境的搭建
所用参考文档🐍
这里使用的还是官方的文档,里面涵盖所有的Pygame的方法使用和说明,写代码时打开在旁边非常方便:Pygame官方文档
项目搭建的目录列表🦋
本篇博客主要就是对这几个文件进行说明,后续当然会往里头增加内容,level.py在这里还没有写入噢,大家别急,level.py在后续就是真正的大BOSS啦,大家先处理好前面的封面等制作吧!😼
本次博客内容主要呈现的效果图展示🍬
这次要做的就是我们最重要的封面~~~~~~下面是效果 |
变态版本~~~
请把好帅,我要做出来打在评论区上(都有都有的下面都有,封面代码我都准备好啦,本身是动态的,等下面大家做完了就可以看到效果了,这个工程也是非常大的,大家要坚持住👩🦰)
文件代码分析🤾♀️
tools.py内容和说明😼
说明
tools这个文件是非常非常重要的,是后面所有的基础和工具,所以大家一定要搞定它🤺因为它用到了一个技能,最重要的一个就是“抠图”技能,下载了素材包的朋友一定发现了,很多东西都在一张图片里面,我们要的只是其中的几个而已,所以需要“抠”出来
代码
import pygame
import os
class Game:
def __init__(self, state_dict, start_state):
self.screen = pygame.display.get_surface() ##获取当前显示的Surface的对象
self.clock = pygame.time.Clock()
self.keys = pygame.key.get_pressed() # return bools(just a simple judges)
self.state_dict = state_dict # 状态转移字典 常用对象的字典来传递
self.state = self.state_dict[start_state] ##初始的状态 在这里-----‘main_mune’
def update(self): ##状态更新
if self.state.finished: ##判断目前的状态是否结束
game_info = self.state.game_info
next_state = self.state.next
self.state.finished = False
self.state = self.state_dict[next_state]
self.state.start(game_info) ##传给下一个阶段的start方法
self.state.update(self.screen, self.keys)
def run(self):
while True: ##event事件
for event in pygame.event.get(): ###pygame.event.get()从队列中获取事件
if event.type == pygame.QUIT:
pygame.display.quit()
quit()
elif event.type == pygame.KEYDOWN:
self.keys = pygame.key.get_pressed()
elif event.type == pygame.KEYUP:
self.keys = pygame.key.get_pressed()
self.update()
pygame.display.update()
self.clock.tick(40)
def load_graphics(path, accept=('.jpg', '.png', '.gif', '.bmp')):
graphics = {}
for pic in os.listdir(path):
name, ext = os.path.splitext(pic)
if ext.lower() in accept:
img = pygame.image.load(os.path.join(path, pic))
if img.get_alpha():
img = img.convert_alpha()
else:
img = img.convert()
graphics[name] = img
return graphics
def get_image(sheet, x, y, width, height, colorkey, scale):
image = pygame.Surface((width, height))
image.blit(sheet, (0, 0), (x, y, width, height)) ##绘制一个图像在另一个图像上方
image.set_colorkey(colorkey) # 扣图 set_colorkey(colorkey) 设置背景为透明
image = pygame.transform.scale(image, (int(width * scale), int(height * scale)))
return image
setup.py内容和说明
这个函数没有特别重要的作用,主要是为了辅助tools.py而创立
代码
import pygame as pg
from . import Invariant as I
from . import tools
pg.init()
SCREEN = pg.display.set_mode((I.SCREEN_W, I.SCREEN_H))##封装
GRAPHICS = tools.load_graphics('resources/graphics')
mainmenu.py内容和说明
代码
from state import tools, Invariant as I, setup
import pygame
from source import info
class MainMenu():
def __init__(self):
game_info = { ##设置初始的状态(可以自行修改哈哈哈哈)
'score': 0,
'coin': 0,
'lives': 3,
'player_state': 'small'
}
self.start(game_info)
def start(self, game_info): ##初始化封面内容
self.game_info = game_info
self.setup_background() ##设置背景、地图信息
self.setup_player()
self.setup_cursor()
self.info = info.Info('main_menu', self.game_info)
self.finished = False ##判断某一个状态是否结束
self.next = 'load_screen' ##下一个状态
def setup_background(self):
self.background = setup.GRAPHICS['level_1']
self.background_rect = self.background.get_rect()
self.background = pygame.transform.scale(self.background, (int(self.background_rect.width * I.BG_MULIT),
int(self.background_rect.height * I.BG_MULIT)))
self.viewport = setup.SCREEN.get_rect()
self.caption = tools.get_image(setup.GRAPHICS['title_screen'], 1, 60, 176, 88, (255, 0, 220), I.BG_MULIT)
def setup_player(self):
self.player_image = tools.get_image(setup.GRAPHICS['mario_bros'], 178, 32, 12, 16, (0, 0, 0), I.PLAYER_MULIT)
def setup_cursor(self): ## 设置光标的位置
self.cursor = pygame.sprite.Sprite()
self.cursor.image = tools.get_image(setup.GRAPHICS['item_objects'], 160, 48, 16, 16, (0,0,0), 1.5)
rect = self.cursor.image.get_rect()
rect.x, rect.y = (300, 360)
self.cursor.rect = rect
self.cursor.state = '1P' #状态机
def update_cursor(self, keys):
if keys[pygame.K_UP]:
self.cursor.state = '1P'
self.cursor.rect.y = 360
elif keys[pygame.K_DOWN]:
self.cursor.state = '2P'
self.cursor.rect.y = 405
elif keys[pygame.K_RETURN]:
self.reset_game_info() ##每次按下回车的时候 游戏的数据就又从最开始的数据开始游戏
if self.cursor.state == '1P':
self.finished = True
elif self.cursor.state == '2P':
self.finished = True
def update(self, surface, keys):## 画布
surface.blit(self.background, self.viewport)
surface.blit(self.caption, (300, 100))
surface.blit(self.cursor.image, self.cursor.rect)
surface.blit(self.player_image, (250, 490))
self.info.update()
self.info.draw(surface)
self.update_cursor(keys)
def reset_game_info(self):
self.game_info.update({ ##死亡之后重新回复的状态
'score': 0,
'coin': 0,
'lives': 3,
'player_state': 'small'
})
变态玛丽的代码(就只是这个多了些东西而已啦)
from state import tools, Invariant as I, setup
import pygame
from source import info
#先更新、后绘图的原则
class MainMenu:
def __init__(self): ##马里奥初始的各种设定
game_info = {
'score': 0,
'coin': 0,
'lives': 3,
'player_state': 'small'
}
self.start(game_info)
def start(self, game_info):
self.game_info = game_info ##传递初始的一些信息
self.setup_background()
self.setup_player()
self.setup_cursor()
self.info = info.Info('main_menu', self.game_info)
self.finished = False
self.next = 'load_screen'
def setup_background(self):
self.background = setup.GRAPHICS['level_2']
self.background_rect = self.background.get_rect()
self.background = pygame.transform.scale(self.background, (int(self.background_rect.width*I.BG_MULIT),
int(self.background_rect.height*I.BG_MULIT)))
self.viewport = setup.SCREEN.get_rect()
self.caption = tools.get_image(setup.GRAPHICS['title_screen'], 1, 60, 176, 88, (255, 0, 220), I.BG_MULIT)
def setup_player(self):
self.player_image = tools.get_image(setup.GRAPHICS['mario_bros'], 178, 32, 12, 16, (0, 0, 0), I.PLAYER_MULIT)
self.player_image_1 = tools.get_image(setup.GRAPHICS['mario_bros'], 192, 80, 16, 17, (0, 0, 0), I.PLAYER_MULIT)
self.player_image_2 = tools.get_image(setup.GRAPHICS['mario_bros'], 143, 127, 16, 16, (0, 0, 0), I.PLAYER_MULIT)
self.player_image_3 = tools.get_image(setup.GRAPHICS['mario_bros'], 78, 176, 16, 16, (0, 0, 0), I.PLAYER_MULIT)
self.player_image_4 = tools.get_image(setup.GRAPHICS['smb_enemies_sheet'], 85, 58, 23, 27, (0, 0, 0), I.PLAYER_MULIT)
self.player_image_5 = tools.get_image(setup.GRAPHICS['smb_enemies_sheet'], 0, 0, 19, 23, (0, 0, 0), I.PLAYER_MULIT)
self.player_image_6 = tools.get_image(setup.GRAPHICS['mario'], 463, 359, 29, 26, (239, 228, 176), I.PLAYER_MULIT)
self.player_image_7 = tools.get_image(setup.GRAPHICS['mario'], 289, 624, 22, 35, (239, 228, 176), I.PLAYER_MULIT)
self.player_image_8 = tools.get_image(setup.GRAPHICS['mario'], 15, 1254, 25, 26, (239, 228, 176), I.PLAYER_MULIT)
self.player_image_9 = tools.get_image(setup.GRAPHICS['mario'], 29, 1784, 19, 34, (239, 228, 176), I.PLAYER_MULIT)
self.player_image_10 = tools.get_image(setup.GRAPHICS['mario'], 565, 1077, 28, 19, (239, 228, 176), I.PLAYER_MULIT)
self.player_image_11 = tools.get_image(setup.GRAPHICS['mario'], 487, 1409, 18, 35, (239, 228, 176), I.PLAYER_MULIT)
self.player_image_12 = tools.get_image(setup.GRAPHICS['smb_custom_enemies'], 117, 475, 21, 30, (163, 73, 164), I.PLAYER_MULIT)
self.player_image_13 = tools.get_image(setup.GRAPHICS['smb_custom_enemies'], 444, 310, 48, 83, (163, 73, 164), I.PLAYER_MULIT)
self.player_image_14 = tools.get_image(setup.GRAPHICS['smb_custom_enemies'], 424, 832, 87, 68, (163, 73, 164), I.MARIO_P)
self.player_image_15 = tools.get_image(setup.GRAPHICS['smb_custom_enemies'], 95, 347, 18, 25, (163, 73, 164), I.PLAYER_MULIT)
self.player_image_15_flip = pygame.transform.flip(self.player_image_15, True, False)
self.skill = tools.get_image(setup.GRAPHICS['smb_custom_enemies'], 116, 353, 9, 9, (163, 73, 164), I.PLAYER_MULIT)
def setup_cursor(self): ## 设置光标的位置
self.cursor = pygame.sprite.Sprite()
self.cursor.image = tools.get_image(setup.GRAPHICS['item_objects'], 160, 48, 16, 16, (255, 255, 255), 1.5)
rect = self.cursor.image.get_rect()
rect.x, rect.y = (300, 360)
self.cursor.rect = rect
self.cursor.state = '1P' #状态机
def update_cursor(self, keys):
if keys[pygame.K_UP]:
self.cursor.state = '1P'
self.cursor.rect.y = 360
elif keys[pygame.K_DOWN]:
self.cursor.state = '2P'
self.cursor.rect.y = 405
elif keys[pygame.K_RETURN]:
self.reset_game_info() ##每次按下回车的时候 游戏的数据就又从最开始的数据开始游戏
if self.cursor.state == '1P':
self.finished = True
elif self.cursor.state == '2P':
self.finished = True
def update(self, surface, keys):
surface.blit(self.background, self.viewport)
surface.blit(self.caption, (300, 100))
surface.blit(self.cursor.image, self.cursor.rect)
surface.blit(self.player_image_4, (600, 460))
surface.blit(self.player_image_5, (700, 480))
surface.blit(self.player_image_6, (200, 200))
surface.blit(self.player_image_7, (150, 300))
surface.blit(self.player_image_8, (100, 200))
surface.blit(self.player_image_9, (40, 433))
surface.blit(self.player_image_10, (50, 100))
surface.blit(self.player_image_12, (850, 450))
surface.blit(self.player_image_13, (850, 200))
surface.blit(self.player_image_14, (300, 430))
surface.blit(self.player_image_15_flip, (770, 430))
surface.blit(self.skill, (730, 460))
self.info.update()
self.info.draw(surface)
self.update_cursor(keys)
def reset_game_info(self):
self.game_info.update({
'score': 0,
'coin': 0,
'lives': 3,
'player_state': 'small'
})
info.py内容说明
代码
import pygame
from state import tools, Invariant as I,setup
from source import coin
pygame.font.init() ##字体字体~~
class Info():
def __init__(self, state, game_info):
self.state = state
self.game_info = game_info
self.create_state_labels() #用来传递每个阶段特定的数值信息
self.create_info_labels() #用来传递特定的金币啊时间信息等信息
self.flash_coin = coin.FlashingCoin()
def create_state_labels(self):
self.state_labels = []
if self.state == 'main_menu':
self.state_labels.append((self.create_label('1 have fun'), (400, 360)))
self.state_labels.append((self.create_label('2 have fun'), (400, 405)))
self.state_labels.append((self.create_label('TOP - '), (410, 450)))
self.state_labels.append((self.create_label('000000'), (500, 450)))
elif self.state == 'load_screen':
self.state_labels.append((self.create_label('WORLD'), (380, 200)))
self.state_labels.append((self.create_label('1 -- 1'), (530, 200)))
self.state_labels.append((self.create_label('X {}'.format(self.game_info['lives'])), (480, 280)))
self.player_image = tools.get_image(setup.GRAPHICS['mario_bros'], 178, 32, 12, 16, (0, 0, 0), I.BG_MULIT)
elif self.state == 'game_over':
self.state_labels.append((self.create_label('Game Over'), (380, 300)))
def create_info_labels(self):
self.info_labels = []
self.info_labels.append((self.create_label('MARIO'), (75, 30)))
self.info_labels.append((self.create_label('WORLD'), (450, 30)))
self.info_labels.append((self.create_label('TIME'), (625, 30)))
self.info_labels.append((self.create_label('000000'), (75, 55)))
self.info_labels.append((self.create_label('x00'), (300, 55)))
self.info_labels.append((self.create_label('1 - 1'), (480, 55)))
def create_label(self, label, size=40, width_scale=1, height_scale=1):
font = pygame.font.SysFont(I.Font,size)
label_image = font.render(label, 1, (255, 255, 255))
rect = label_image.get_rect()
label_image = pygame.transform.scale(label_image, (int(rect.width*width_scale), int(rect.height*height_scale)))
return label_image
def update(self):
self.flash_coin.update()
def draw(self, surface):#用来显示
for label in self.state_labels:
surface.blit(label[0], label[1])
for label in self.info_labels:
surface.blit(label[0], label[1])
surface.blit(self.flash_coin.image, self.flash_coin.rect)
if self.state == 'load_screen':
surface.blit(self.player_image, (400, 270))
load_screen内容说明
代码
import pygame
from source import info
class LoadScreen:
def start(self, game_info):
self.game_info = game_info
self.finished = False
self.duration = 2000
self.timer = 0
self.info = info.Info('load_screen', self.game_info)
def update(self, surface, keys):
self.draw(surface)
if self.timer == 0:
self.timer = pygame.time.get_ticks()
elif pygame.time.get_ticks() - self.timer > self.duration:
self.finished = True
self.timer = 0
def draw(self, surface):
surface.fill((0, 0, 0))
self.info.draw(surface)
coin.py内容说明
代码
import pygame
from state import tools, Invariant as I, setup
class FlashingCoin(pygame.sprite.Sprite):
def __init__(self):
pygame.sprite.Sprite.__init__(self)
self.frames = []
self.frame_index = 0
frame_rects = [(1, 160, 5, 8), (9, 160, 5, 8), (17, 160, 5, 8), (9, 160, 5, 8)]
self.load_frames(frame_rects)
self.image = self.frames[self.frame_index]
self.rect = self.image.get_rect()
self.rect.x = 280
self.rect.y = 50
self.timer = 0
def load_frames(self, frame_rects):
sheet = setup.GRAPHICS['item_objects']
for frame_rect in frame_rects: ##加载每个图片
self.frames.append(tools.get_image(sheet, *frame_rect, (0, 0, 0), I.BG_MULIT))
def update(self):
self.current_time = pygame.time.get_ticks() #返回此时的时间
frame_durations = [325, 125, 125, 125] ##每个图片停留的时间
if self.timer == 0: #说明此时是起始状态
self.timer = self.current_time
elif self.current_time - self.timer > frame_durations[self.frame_index]:
self.frame_index += 1
self.frame_index %= 4 #循环
self.timer = self.current_time #更新
self.image = self.frames[self.frame_index]
Invariant.py内容和说明
就是存放常用的一些变量而已🥴
代码
SCREEN_W, SCREEN_H = 1000, 600
SCREEN_SIZE = (SCREEN_W, SCREEN_H)
GROUND_HEIGHT = SCREEN_H - 62
BG_MULIT = 2.68
BRICK_MULIT = 2.69
ENEMY_MULIT = 2.5
ENEMY_SPEED = 1
MG_MULIT =0.21
PLAYER_MULIT = 3
MONSTER = 0.8
Font = 'Fixedsys.ttf'##使用这个是因为这个和超级玛丽游戏的字体比较像,大家也可以使用其他的字体
MARIO_P = 1.6
GRAVITY = 1.0
ANTI_GRAVITY = 0.3
main.py内容和说明
代码
from state import tools, main_menu,load_screen
def main():
state_dict = {
'main_menu':main_menu.MainMenu(),
'load_screen': load_screen.LoadScreen(),
}
game = tools.Game(state_dict, 'main_menu')
game.run()
if __name__ == '__main__':
main()
最终效果展示
当然了,最后结束的时候是会有警告的,因为没有下一个状态了嘛,下一个就到了我们最重要的部分啦---->level.py~😆😆
我个人认为对于如果是pygame新手的话,会有一定的难度,里面很多细节的实现我会单独弄博客来说明,比如抠图是怎么实现的之类的,现在只是将主要的部分代码给大家,有任何问题欢迎私信,评论 |