Python 玩出花兒了!一文教你用 Python 製作吃豆人遊戲! | 附代碼

2020-06-23     AI科技大本營

原標題:Python 玩出花兒了!一文教你用 Python 製作吃豆人遊戲! | 附代碼

作者 | 李秋鍵

責編 | Carol

封圖 | CSDN 下載自視覺中國

近幾年來Python語言得到了快速發展,而Pygame作為Python開發應用和遊戲必備的庫更是展現了Python的優越性。

而今天我們就將藉助Pygame建立吃豆人遊戲。

吃豆人是電子遊戲歷史上的經典街機遊戲,由Namco公司的岩谷徹設計並由Midway Games在1980年發行。Pac-Man被認為是80年代最經典的街機遊戲之一,遊戲的主角小精靈的形象甚至被作為一種大眾文化符號,或是此產業的代表形象。

而Pygame模塊是跨平台Python模塊,專為電子遊戲設計,包含圖像、聲音。建立在SDL基礎上,允許實時電子遊戲研發而無需被低級語言(如機器語言和彙編語言)束縛。

最終遊戲效果如下可見:

一、實驗前的準備

首先我們使用的python版本是3.6.5所用到的模塊是pygame模塊,用來創建遊戲框架。Random模塊用來隨機生成方向。

素材準備

首先我們將圖片放到images目錄下,背景音樂放到sounds目錄下。

如下圖可見:

遊戲搭建

1、定義一些精靈:

整體的類變量定義包括牆類,通過pygame的圖片填充作為牆類的加載;同理還包括食物類和角色。而怪物的隨機運動使用random產生隨機運動方向。

其對應的代碼如下:

import random

import pygame

'''牆類'''

classWall( pygame. sprite. Sprite):

def__init__( self, x, y, width, height, color, **kwargs) :

pygame.sprite.Sprite.__init_ _( self)

self.image = pygame.Surface([width, height])

self.image.fill(color)

self.rect = self.image.get_rect

self.rect.left = x

self.rect.top = y

'''食物類'''

classFood( pygame. sprite. Sprite):

def__init__( self, x, y, width, height, color, bg_color, **kwargs) :

pygame.sprite.Sprite.__init_ _( self)

self.image = pygame.Surface([width, height])

self.image.fill(bg_color)

self.image.set_colorkey(bg_color)

pygame.draw.ellipse( self.image, color, [ 0, 0, width, height])

self.rect = self.image.get_rect

self.rect.left = x

self.rect.top = y

'''角色類'''

classPlayer( pygame. sprite. Sprite):

def__init__( self, x, y, role_image_path) :

pygame.sprite.Sprite.__init_ _( self)

self.role_name = role_image_path.split( '/')[- 1].split( '.')[ 0]

self.base_image = pygame.image.load(role_image_path).convert

self.image = self.base_image.copy

self.rect = self.image.get_rect

self.rect.left = x

self.rect.top = y

self.prev_x = x

self.prev_y = y

self.base_speed = [ 30, 30]

self.speed = [ 0, 0]

self.is_move = False

self.tracks = []

self.tracks_loc = [ 0, 0]

'''改變速度方向'''

defchangeSpeed( self, direction) :

ifdirection[ 0] < 0:

self.image = pygame.transform.flip( self.base_image, True, False)

elif direction[ 0] > 0:

self.image = self.base_image.copy

elif direction[ 1] < 0:

self.image = pygame.transform.rotate( self.base_image, 90)

elif direction[ 1] > 0:

self.image = pygame.transform.rotate( self.base_image, - 90)

self.speed = [direction[ 0] * self.base_speed[ 0], direction[ 1] * self.base_speed[ 1]]

returnself.speed

'''更新角色位置'''

defupdate( self, wall_sprites, gate_sprites) :

ifnotself. is_move:

returnFalse

x_prev = self.rect.left

y_prev = self.rect.top

self.rect.left += self.speed[ 0]

self.rect.top += self.speed[ 1]

is_collide = pygame.sprite.spritecollide( self, wall_sprites, False)

ifgate_sprites is notNone:

ifnotis_collide:

is_collide = pygame.sprite.spritecollide( self, gate_sprites, False)

ifis_collide:

self.rect.left = x_prev

self.rect.top = y_prev

returnFalse

returnTrue

'''生成隨機的方向'''

defrandomDirection( self) :

returnrandom.choice([[- 0. 5, 0], [ 0. 5, 0], [ 0, 0. 5], [ 0, - 0. 5]])

2、遊戲關卡定義:

在這裡設置好了關卡一。關卡的定義必須包括牆的位置,不同關卡牆的位置和怪物的位置不同。更多關卡可以參照設置

對應代碼如下:

importpygame

fromSprites import*

NUMLEVELS = 1

'''關卡一'''

classLevel1:

def__init__(self):

self.info = 'level1'

'''創建牆'''

defsetupWalls(self, wall_color):

self.wall_sprites = pygame.sprite.Group

wall_positions = [[ 0, 0, 6, 600],

[ 0, 0, 600, 6],

[ 0, 600, 606, 6],

[ 600, 0, 6, 606],

[ 300, 0, 6, 66],

[ 60, 60, 186, 6],

[ 360, 60, 186, 6],

[ 60, 120, 66, 6],

[ 60, 120, 6, 126],

[ 180, 120, 246, 6],

[ 300, 120, 6, 66],

[ 480, 120, 66, 6],

[ 540, 120, 6, 126],

[ 120, 180, 126, 6],

[ 120, 180, 6, 126],

[ 360, 180, 126, 6],

[ 480, 180, 6, 126],

[ 180, 240, 6, 126],

[ 180, 360, 246, 6],

[ 420, 240, 6, 126],

[ 240, 240, 42, 6],

[ 324, 240, 42, 6],

[ 240, 240, 6, 66],

[ 240, 300, 126, 6],

[ 360, 240, 6, 66],

[ 0, 300, 66, 6],

[ 540, 300, 66, 6],

[ 60, 360, 66, 6],

[ 60, 360, 6, 186],

[ 480, 360, 66, 6],

[ 540, 360, 6, 186],

[ 120, 420, 366, 6],

[ 120, 420, 6, 66],

[ 480, 420, 6, 66],

[ 180, 480, 246, 6],

[ 300, 480, 6, 66],

[ 120, 540, 126, 6],

[ 360, 540, 126, 6]]

forwall_position inwall_positions:

wall = Wall(*wall_position, wall_color)

self.wall_sprites.add(wall)

returnself.wall_sprites

'''創建門'''

defsetupGate(self, gate_color):

self.gate_sprites = pygame.sprite.Group

self.gate_sprites.add(Wall( 282, 242, 42, 2, gate_color))

returnself.gate_sprites

'''創建角色'''

defsetupPlayers(self, hero_image_path, ghost_images_path):

self.hero_sprites = pygame.sprite.Group

self.ghost_sprites = pygame.sprite.Group

self.hero_sprites.add(Player( 287, 439, hero_image_path))

foreach inghost_images_path:

role_name = each.split( '/')[ -1].split( '.')[ 0]

ifrole_name == 'Blinky':

player = Player( 287, 199, each)

player.is_move = True

player.tracks = [[ 0, -0.5, 4], [ 0.5, 0, 9], [ 0, 0.5, 11], [ 0.5, 0, 3], [ 0, 0.5, 7], [ -0.5, 0, 11], [ 0, 0.5, 3],

[ 0.5, 0, 15], [ 0, -0.5, 15], [ 0.5, 0, 3], [ 0, -0.5, 11], [ -0.5, 0, 3], [ 0, -0.5, 11], [ -0.5, 0, 3],

[ 0, -0.5, 3], [ -0.5, 0, 7], [ 0, -0.5, 3], [ 0.5, 0, 15], [ 0, 0.5, 15], [ -0.5, 0, 3], [ 0, 0.5, 3],

[ -0.5, 0, 3], [ 0, -0.5, 7], [ -0.5, 0, 3], [ 0, 0.5, 7], [ -0.5, 0, 11], [ 0, -0.5, 7], [ 0.5, 0, 5]]

self.ghost_sprites.add(player)

elifrole_name == 'Clyde':

player = Player( 319, 259, each)

player.is_move = True

player.tracks = [[ -1, 0, 2], [ 0, -0.5, 4], [ 0.5, 0, 5], [ 0, 0.5, 7], [ -0.5, 0, 11], [ 0, -0.5, 7],

[ -0.5, 0, 3], [ 0, 0.5, 7], [ -0.5, 0, 7], [ 0, 0.5, 15], [ 0.5, 0, 15], [ 0, -0.5, 3],

[ -0.5, 0, 11], [ 0, -0.5, 7], [ 0.5, 0, 3], [ 0, -0.5, 11], [ 0.5, 0, 9]]

self.ghost_sprites.add(player)

elifrole_name == 'Inky':

player = Player( 255, 259, each)

player.is_move = True

player.tracks = [[ 1, 0, 2], [ 0, -0.5, 4], [ 0.5, 0, 10], [ 0, 0.5, 7], [ 0.5, 0, 3], [ 0, -0.5, 3],

[ 0.5, 0, 3], [ 0, -0.5, 15], [ -0.5, 0, 15], [ 0, 0.5, 3], [ 0.5, 0, 15], [ 0, 0.5, 11],

[ -0.5, 0, 3], [ 0, -0.5, 7], [ -0.5, 0, 11], [ 0, 0.5, 3], [ -0.5, 0, 11], [ 0, 0.5, 7],

[ -0.5, 0, 3], [ 0, -0.5, 3], [ -0.5, 0, 3], [ 0, -0.5, 15], [ 0.5, 0, 15], [ 0, 0.5, 3],

[ -0.5, 0, 15], [ 0, 0.5, 11], [ 0.5, 0, 3], [ 0, -0.5, 11], [ 0.5, 0, 11], [ 0, 0.5, 3], [ 0.5, 0, 1]]

self.ghost_sprites.add(player)

elifrole_name == 'Pinky':

player = Player( 287, 259, each)

player.is_move = True

player.tracks = [[ 0, -1, 4], [ 0.5, 0, 9], [ 0, 0.5, 11], [ -0.5, 0, 23], [ 0, 0.5, 7], [ 0.5, 0, 3],

[ 0, -0.5, 3], [ 0.5, 0, 19], [ 0, 0.5, 3], [ 0.5, 0, 3], [ 0, 0.5, 3], [ 0.5, 0, 3],

[ 0, -0.5, 15], [ -0.5, 0, 7], [ 0, 0.5, 3], [ -0.5, 0, 19], [ 0, -0.5, 11], [ 0.5, 0, 9]]

self.ghost_sprites.add(player)

returnself.hero_sprites, self.ghost_sprites

'''創建食物'''

defsetupFood(self, food_color, bg_color):

self.food_sprites = pygame.sprite.Group

forrow inrange( 19):

forcol inrange( 19):

if(row == 7orrow == 8) and(col == 8orcol == 9orcol == 10):

continue

else:

food = Food( 30*col+ 32, 30*row+ 32, 4, 4, food_color, bg_color)

is_collide = pygame.sprite.spritecollide(food, self.wall_sprites, False)

ifis_collide:

continue

is_collide = pygame.sprite.spritecollide(food, self.hero_sprites, False)

ifis_collide:

continue

self.food_sprites.add(food)

returnself.food_sprites

3、遊戲創建:

在通過關卡定義牆等位置後以及精靈自身屬性怪物運動、食物定義等後,通過調用已經創建好的類達到搭建遊戲的目的。

具體如下可見:

importos

importsys

importpygame

importLevels

'''定義一些必要的參數'''

BLACK = ( 0, 0, 0)

WHITE = ( 255, 255, 255)

BLUE = ( 0, 0, 255)

GREEN = ( 0, 255, 0)

RED = ( 255, 0, 0)

YELLOW = ( 255, 255, 0)

PURPLE = ( 255, 0, 255)

SKYBLUE = ( 0, 191, 255)

BGMPATH = os.path.join(os.getcwd, 'resources/sounds/bg.mp3')

ICONPATH = os.path.join(os.getcwd, 'resources/images/icon.png')

FONTPATH = os.path.join(os.getcwd, 'resources/font/ALGER.TTF')

HEROPATH = os.path.join(os.getcwd, 'resources/images/pacman.png')

BlinkyPATH = os.path.join(os.getcwd, 'resources/images/Blinky.png')

ClydePATH = os.path.join(os.getcwd, 'resources/images/Clyde.png')

InkyPATH = os.path.join(os.getcwd, 'resources/images/Inky.png')

PinkyPATH = os.path.join(os.getcwd, 'resources/images/Pinky.png')

'''開始某一關遊戲'''

defstartLevelGame(level, screen, font):

clock = pygame.time.Clock

SCORE = 0

wall_sprites = level.setupWalls(SKYBLUE)

gate_sprites = level.setupGate(WHITE)

hero_sprites, ghost_sprites = level.setupPlayers(HEROPATH, [BlinkyPATH, ClydePATH, InkyPATH, PinkyPATH])

food_sprites = level.setupFood(YELLOW, WHITE)

is_clearance = False

whileTrue:

forevent inpygame.event.get:

ifevent.type == pygame.QUIT:

sys.exit( -1)

pygame.quit

ifevent.type == pygame.KEYDOWN:

ifevent.key == pygame.K_LEFT:

forhero inhero_sprites:

hero.changeSpeed([ -1, 0])

hero.is_move = True

elifevent.key == pygame.K_RIGHT:

forhero inhero_sprites:

hero.changeSpeed([ 1, 0])

hero.is_move = True

elifevent.key == pygame.K_UP:

forhero inhero_sprites:

hero.changeSpeed([ 0, -1])

hero.is_move = True

elifevent.key == pygame.K_DOWN:

forhero inhero_sprites:

hero.changeSpeed([ 0, 1])

hero.is_move = True

ifevent.type == pygame.KEYUP:

if(event.key == pygame.K_LEFT) or(event.key == pygame.K_RIGHT) or(event.key == pygame.K_UP) or(event.key == pygame.K_DOWN):

hero.is_move = False

screen.fill(BLACK)

forhero inhero_sprites:

hero.update(wall_sprites, gate_sprites)

hero_sprites.draw(screen)

forhero inhero_sprites:

food_eaten = pygame.sprite.spritecollide(hero, food_sprites, True)

SCORE += len(food_eaten)

wall_sprites.draw(screen)

gate_sprites.draw(screen)

food_sprites.draw(screen)

forghost inghost_sprites:

# 幽靈隨機運動(效果不好且有BUG)

'''

res = ghost.update(wall_sprites, None)

while not res:

ghost.changeSpeed(ghost.randomDirection)

res = ghost.update(wall_sprites, None)

'''

# 指定幽靈運動路徑

ifghost.tracks_loc[ 1] < ghost.tracks[ghost.tracks_loc[ 0]][ 2]:

ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[ 0]][ 0: 2])

ghost.tracks_loc[ 1] += 1

else:

ifghost.tracks_loc[ 0] < len(ghost.tracks) - 1:

ghost.tracks_loc[ 0] += 1

elifghost.role_name == 'Clyde':

ghost.tracks_loc[ 0] = 2

else:

ghost.tracks_loc[ 0] = 0

ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[ 0]][ 0: 2])

ghost.tracks_loc[ 1] = 0

ifghost.tracks_loc[ 1] < ghost.tracks[ghost.tracks_loc[ 0]][ 2]:

ghost.changeSpeed(ghost.tracks[ghost.tracks_loc[ 0]][ 0: 2])

else:

ifghost.tracks_loc[ 0] < len(ghost.tracks) - 1:

loc0 = ghost.tracks_loc[ 0] + 1

elifghost.role_name == 'Clyde':

loc0 = 2

else:

loc0 = 0

ghost.changeSpeed(ghost.tracks[loc0][ 0: 2])

ghost.update(wall_sprites, None)

ghost_sprites.draw(screen)

score_text = font.render( "Score: %s"% SCORE, True, RED)

screen.blit(score_text, [ 10, 10])

iflen(food_sprites) == 0:

is_clearance = True

break

ifpygame.sprite.groupcollide(hero_sprites, ghost_sprites, False, False):

is_clearance = False

break

pygame.display.flip

clock.tick( 10)

returnis_clearance

'''顯示文字'''

defshowText(screen, font, is_clearance, flag=False):

clock = pygame.time.Clock

msg = 'Game Over!'ifnotis_clearance else'Congratulations, you won!'

positions = [[ 235, 233], [ 65, 303], [ 170, 333]] ifnotis_clearance else[[ 145, 233], [ 65, 303], [ 170, 333]]

surface = pygame.Surface(( 400, 200))

surface.set_alpha( 10)

surface.fill(( 128, 128, 128))

screen.blit(surface, ( 100, 200))

texts = [font.render(msg, True, WHITE),

font.render( 'Press ENTER to continue or play again.', True, WHITE),

font.render( 'Press ESCAPE to quit.', True, WHITE)]

whileTrue:

forevent inpygame.event.get:

ifevent.type == pygame.QUIT:

sys.exit

pygame.quit

ifevent.type == pygame.KEYDOWN:

ifevent.key == pygame.K_RETURN:

ifis_clearance:

ifnotflag:

return

else:

main(initialize)

else:

main(initialize)

elifevent.key == pygame.K_ESCAPE:

sys.exit

pygame.quit

foridx, (text, position) inenumerate(zip(texts, positions)):

screen.blit(text, position)

pygame.display.flip

clock.tick( 10)

'''初始化'''

definitialize:

pygame.init

icon_image = pygame.image.load(ICONPATH)

pygame.display.set_icon(icon_image)

screen = pygame.display.set_mode([ 606, 606])

pygame.display.set_caption( '吃豆人')

returnscreen

'''主函數'''

defmain(screen):

pygame.mixer.init

pygame.mixer.music.load(BGMPATH)

pygame.mixer.music.play( -1, 0.0)

pygame.font.init

font_small = pygame.font.Font(FONTPATH, 18)

font_big = pygame.font.Font(FONTPATH, 24)

fornum_level inrange( 1, Levels.NUMLEVELS+ 1):

ifnum_level == 1:

level = Levels.Level1

is_clearance = startLevelGame(level, screen, font_small)

ifnum_level == Levels.NUMLEVELS:

showText(screen, font_big, is_clearance, True)

else:

showText(screen, font_big, is_clearance)

最終運行程序結果如下:

源碼地址:

https://pan.baidu.com/s/128id8L-PDPgGOPuH-5uHDg

提取碼:rj9f

作者簡介:

李秋鍵,CSDN博客專家,CSDN達人課作者。碩士在讀於中國礦業大學,開發有taptap競賽獲獎等等。

文章來源: https://twgreatdaily.com/zh-tw/TGFd4nIBd4Bm1__YcYnH.html










CSDN湘苗培優

2020-12-24