效果演示
基础源码
1.基础设置(tools部分)
这个部分设置马里奥以及游戏中蘑菇等怪的的移动设置。
import os import pygame as pg keybinding = { 'action':pg.k_s, 'jump':pg.k_a, 'left':pg.k_left, 'right':pg.k_right, 'down':pg.k_down } class control(object): """control class for entire project. contains the game loop, and contains the event_loop which passes events to states as needed. logic for flipping states is also found here.""" def __init__(self, caption): self.screen = pg.display.get_surface() self.done = false self.clock = pg.time.clock() self.caption = caption self.fps = 60 self.show_fps = false self.current_time = 0.0 self.keys = pg.key.get_pressed() self.state_dict = {} self.state_name = none self.state = none def setup_states(self, state_dict, start_state): self.state_dict = state_dict self.state_name = start_state self.state = self.state_dict[self.state_name] def update(self): self.current_time = pg.time.get_ticks() if self.state.quit: self.done = true elif self.state.done: self.flip_state() self.state.update(self.screen, self.keys, self.current_time) def flip_state(self): previous, self.state_name = self.state_name, self.state.next persist = self.state.cleanup() self.state = self.state_dict[self.state_name] self.state.startup(self.current_time, persist) self.state.previous = previous def event_loop(self): for event in pg.event.get(): if event.type == pg.quit: self.done = true elif event.type == pg.keydown: self.keys = pg.key.get_pressed() self.toggle_show_fps(event.key) elif event.type == pg.keyup: self.keys = pg.key.get_pressed() self.state.get_event(event) def toggle_show_fps(self, key): if key == pg.k_f5: self.show_fps = not self.show_fps if not self.show_fps: pg.display.set_caption(self.caption) def main(self): """main loop for entire program""" while not self.done: self.event_loop() self.update() pg.display.update() self.clock.tick(self.fps) if self.show_fps: fps = self.clock.get_fps() with_fps = "{} - {:.2f} fps".format(self.caption, fps) pg.display.set_caption(with_fps) class _state(object): def __init__(self): self.start_time = 0.0 self.current_time = 0.0 self.done = false self.quit = false self.next = none self.previous = none self.persist = {} def get_event(self, event): pass def startup(self, current_time, persistant): self.persist = persistant self.start_time = current_time def cleanup(self): self.done = false return self.persist def update(self, surface, keys, current_time): pass def load_all_gfx(directory, colorkey=(255,0,255), accept=('.png', 'jpg', 'bmp')): graphics = {} for pic in os.listdir(directory): name, ext = os.path.splitext(pic) if ext.lower() in accept: img = pg.image.load(os.path.join(directory, pic)) if img.get_alpha(): img = img.convert_alpha() else: img = img.convert() img.set_colorkey(colorkey) graphics[name]=img return graphics def load_all_music(directory, accept=('.wav', '.mp3', '.ogg', '.mdi')): songs = {} for song in os.listdir(directory): name,ext = os.path.splitext(song) if ext.lower() in accept: songs[name] = os.path.join(directory, song) return songs def load_all_fonts(directory, accept=('.ttf')): return load_all_music(directory, accept) def load_all_sfx(directory, accept=('.wav','.mpe','.ogg','.mdi')): effects = {} for fx in os.listdir(directory): name, ext = os.path.splitext(fx) if ext.lower() in accept: effects[name] = pg.mixer.sound(os.path.join(directory, fx)) return effects
2.设置背景音乐以及场景中的文字(setup部分)
该部分主要设置场景中的背景音乐,以及字体的显示等设置。
import os import pygame as pg from . import tools from .import constants as c original_caption = c.original_caption os.environ['sdl_video_centered'] = '1' pg.init() pg.event.set_allowed([pg.keydown, pg.keyup, pg.quit]) pg.display.set_caption(c.original_caption) screen = pg.display.set_mode(c.screen_size) screen_rect = screen.get_rect() fonts = tools.load_all_fonts(os.path.join("resources","fonts")) music = tools.load_all_music(os.path.join("resources","music")) gfx = tools.load_all_gfx(os.path.join("resources","graphics")) sfx = tools.load_all_sfx(os.path.join("resources","sound"))
3.设置游戏规则(load_screen)
from .. import setup, tools from .. import constants as c from .. import game_sound from ..components import info class loadscreen(tools._state): def __init__(self): tools._state.__init__(self) def startup(self, current_time, persist): self.start_time = current_time self.persist = persist self.game_info = self.persist self.next = self.set_next_state() info_state = self.set_overhead_info_state() self.overhead_info = info.overheadinfo(self.game_info, info_state) self.sound_manager = game_sound.sound(self.overhead_info) def set_next_state(self): """sets the next state""" return c.level1 def set_overhead_info_state(self): """sets the state to send to the overhead info object""" return c.load_screen def update(self, surface, keys, current_time): """updates the loading screen""" if (current_time - self.start_time) < 2400: surface.fill(c.black) self.overhead_info.update(self.game_info) self.overhead_info.draw(surface) elif (current_time - self.start_time) < 2600: surface.fill(c.black) elif (current_time - self.start_time) < 2635: surface.fill((106, 150, 252)) else: self.done = true class gameover(loadscreen): """a loading screen with game over""" def __init__(self): super(gameover, self).__init__() def set_next_state(self): """sets next state""" return c.main_menu def set_overhead_info_state(self): """sets the state to send to the overhead info object""" return c.game_over def update(self, surface, keys, current_time): self.current_time = current_time self.sound_manager.update(self.persist, none) if (self.current_time - self.start_time) < 7000: surface.fill(c.black) self.overhead_info.update(self.game_info) self.overhead_info.draw(surface) elif (self.current_time - self.start_time) < 7200: surface.fill(c.black) elif (self.current_time - self.start_time) < 7235: surface.fill((106, 150, 252)) else: self.done = true class timeout(loadscreen): """loading screen with time out""" def __init__(self): super(timeout, self).__init__() def set_next_state(self): """sets next state""" if self.persist[c.lives] == 0: return c.game_over else: return c.load_screen def set_overhead_info_state(self): """sets the state to send to the overhead info object""" return c.time_out def update(self, surface, keys, current_time): self.current_time = current_time if (self.current_time - self.start_time) < 2400: surface.fill(c.black) self.overhead_info.update(self.game_info) self.overhead_info.draw(surface) else: self.done = true
4.设置游戏内菜单等(main_menu)
import pygame as pg from .. import setup, tools from .. import constants as c from .. components import info, mario class menu(tools._state): def __init__(self): """initializes the state""" tools._state.__init__(self) persist = {c.coin_total: 0, c.score: 0, c.lives: 3, c.top_score: 0, c.current_time: 0.0, c.level_state: none, c.camera_start_x: 0, c.mario_dead: false} self.startup(0.0, persist) def startup(self, current_time, persist): """called every time the game's state becomes this one. initializes certain values""" self.next = c.load_screen self.persist = persist self.game_info = persist self.overhead_info = info.overheadinfo(self.game_info, c.main_menu) self.sprite_sheet = setup.gfx['title_screen'] self.setup_background() self.setup_mario() self.setup_cursor() def setup_cursor(self): """creates the mushroom cursor to select 1 or 2 player game""" self.cursor = pg.sprite.sprite() dest = (220, 358) self.cursor.image, self.cursor.rect = self.get_image( 24, 160, 8, 8, dest, setup.gfx['item_objects']) self.cursor.state = c.player1 def setup_mario(self): """places mario at the beginning of the level""" self.mario = mario.mario() self.mario.rect.x = 110 self.mario.rect.bottom = c.ground_height def setup_background(self): """setup the background image to blit""" self.background = setup.gfx['level_1'] self.background_rect = self.background.get_rect() self.background = pg.transform.scale(self.background, (int(self.background_rect.width*c.background_multipler), int(self.background_rect.height*c.background_multipler))) self.viewport = setup.screen.get_rect(bottom=setup.screen_rect.bottom) self.image_dict = {} self.image_dict['game_name_box'] = self.get_image( 1, 60, 176, 88, (170, 100), setup.gfx['title_screen']) def get_image(self, x, y, width, height, dest, sprite_sheet): """returns images and rects to blit onto the screen""" image = pg.surface([width, height]) rect = image.get_rect() image.blit(sprite_sheet, (0, 0), (x, y, width, height)) if sprite_sheet == setup.gfx['title_screen']: image.set_colorkey((255, 0, 220)) image = pg.transform.scale(image, (int(rect.width*c.size_multiplier), int(rect.height*c.size_multiplier))) else: image.set_colorkey(c.black) image = pg.transform.scale(image, (int(rect.width*3), int(rect.height*3))) rect = image.get_rect() rect.x = dest[0] rect.y = dest[1] return (image, rect) def update(self, surface, keys, current_time): """updates the state every refresh""" self.current_time = current_time self.game_info[c.current_time] = self.current_time self.update_cursor(keys) self.overhead_info.update(self.game_info) surface.blit(self.background, self.viewport, self.viewport) surface.blit(self.image_dict['game_name_box'][0], self.image_dict['game_name_box'][1]) surface.blit(self.mario.image, self.mario.rect) surface.blit(self.cursor.image, self.cursor.rect) self.overhead_info.draw(surface) def update_cursor(self, keys): """update the position of the cursor""" input_list = [pg.k_return, pg.k_a, pg.k_s] if self.cursor.state == c.player1: self.cursor.rect.y = 358 if keys[pg.k_down]: self.cursor.state = c.player2 for input in input_list: if keys[input]: self.reset_game_info() self.done = true elif self.cursor.state == c.player2: self.cursor.rect.y = 403 if keys[pg.k_up]: self.cursor.state = c.player1 def reset_game_info(self): """resets the game info in case of a game over and restart""" self.game_info[c.coin_total] = 0 self.game_info[c.score] = 0 self.game_info[c.lives] = 3 self.game_info[c.current_time] = 0.0 self.game_info[c.level_state] = none self.persist = self.game_info
5.main()
from . import setup,tools from .states import main_menu,load_screen,level1 from . import constants as c def main(): """add states to control here.""" run_it = tools.control(setup.original_caption) state_dict = {c.main_menu: main_menu.menu(), c.load_screen: load_screen.loadscreen(), c.time_out: load_screen.timeout(), c.game_over: load_screen.gameover(), c.level1: level1.level1()} run_it.setup_states(state_dict, c.main_menu) run_it.main()
6.调用以上函数实现
import sys import pygame as pg from 小游戏.超级玛丽.data.main import main import cprofile if __name__=='__main__': main() pg.quit() sys.exit()