Linux中國

在你的 Python 平台類遊戲中放一些獎勵

這是正在進行的關於使用 Python 3Pygame 模塊創建視頻遊戲的系列文章的第十部分。以前的文章有:

如果你已經閱讀了本系列的前幾篇文章,那麼你已經了解了編寫遊戲的所有基礎知識。現在你可以在這些基礎上,創造一個全功能的遊戲。當你第一次學習時,遵循本系列代碼示例,這樣的「用例」是有幫助的,但是,用例也會約束你。現在是時候運用你學到的知識,以新的方式應用它們了。

如果說,說起來容易做起來難,這篇文章展示了一個如何將你已經了解的內容用於新目的的例子中。具體來說,就是它涵蓋了如何使用你以前的課程中已經了解到的來實現獎勵系統。

在大多數電子遊戲中,你有機會在遊戲世界中獲得「獎勵」或收集到寶物和其他物品。獎勵通常會增加你的分數或者你的生命值,或者為你的下一次任務提供信息。

遊戲中包含的獎勵類似於編程平台。像平台一樣,獎勵沒有用戶控制,隨著遊戲世界的滾動進行,並且必須檢查與玩家的碰撞。

創建獎勵函數

獎勵和平台非常相似,你甚至不需要一個獎勵的類。你可以重用 Platform 類,並將結果稱為「獎勵」。

由於獎勵類型和位置可能因關卡不同而不同,如果你還沒有,請在你的 Level 中創建一個名為 loot 的新函數。因為獎勵物品不是平台,你也必須創建一個新的 loot_list 組,然後添加獎勵物品。與平台、地面和敵人一樣,該組用於檢查玩家碰撞:

    def loot(lvl,lloc):
        if lvl == 1:
            loot_list = pygame.sprite.Group()
            loot = Platform(300,ty*7,tx,ty, 'loot_1.png')
            loot_list.add(loot)

        if lvl == 2:
            print(lvl)

        return loot_list

你可以隨意添加任意數量的獎勵對象;記住把每一個都加到你的獎勵清單上。Platform 類的參數是獎勵圖標的 X 位置、Y 位置、寬度和高度(通常讓你的獎勵精靈保持和所有其他方塊一樣的大小最為簡單),以及你想要用作的獎勵的圖片。獎勵的放置可以和貼圖平台一樣複雜,所以使用創建關卡時需要的關卡設計文檔。

在腳本的設置部分調用新的獎勵函數。在下面的代碼中,前三行是上下文,所以只需添加第四行:

enemy_list = Level.bad( 1, eloc )
ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )
loot_list = Level.loot(1,tx,ty)

正如你現在所知道的,除非你把它包含在你的主循環中,否則獎勵不會被顯示到屏幕上。將下面代碼示例的最後一行添加到循環中:

    enemy_list.draw(world)
    ground_list.draw(world)
    plat_list.draw(world)
    loot_list.draw(world)

啟動你的遊戲看看會發生什麼。

![Loot in Python platformer](/data/attachment/album/202001/29/131252hahl80ckmu2p0hk4.jpg "Loot in Python platformer")

你的獎勵將會顯示出來,但是當你的玩家碰到它們時,它們不會做任何事情,當你的玩家經過它們時,它們也不會滾動。接下來解決這些問題。

滾動獎勵

像平台一樣,當玩家在遊戲世界中移動時,獎勵必須滾動。邏輯與平台滾動相同。要向前滾動獎勵物品,添加最後兩行:

        for e in enemy_list:
            e.rect.x -= scroll
        for l in loot_list:
            l.rect.x -= scroll

要向後滾動,請添加最後兩行:

        for e in enemy_list:
            e.rect.x += scroll
        for l in loot_list:
            l.rect.x += scroll

再次啟動你的遊戲,看看你的獎勵物品現在表現得像在遊戲世界裡一樣了,而不是僅僅畫在上面。

檢測碰撞

就像平台和敵人一樣,你可以檢查獎勵物品和玩家之間的碰撞。邏輯與其他碰撞相同,除了撞擊不會(必然)影響重力或生命值。取而代之的是,命中會導致獎勵物品會消失並增加玩家的分數。

當你的玩家觸摸到一個獎勵對象時,你可以從 loot_list 中移除該對象。這意味著當你的主循環在 loot_list 中重繪所有獎勵物品時,它不會重繪那個特定的對象,所以看起來玩家已經獲得了獎勵物品。

Player 類的 update 函數中的平台碰撞檢測之上添加以下代碼(最後一行僅用於上下文):

                loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False)
                for loot in loot_hit_list:
                        loot_list.remove(loot)
                        self.score += 1
                print(self.score)

        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)

當碰撞發生時,你不僅要把獎勵從它的組中移除,還要給你的玩家一個分數提升。你還沒有創建分數變數,所以請將它添加到你的玩家屬性中,該屬性是在 Player 類的 __init__ 函數中創建的。在下面的代碼中,前兩行是上下文,所以只需添加分數變數:

        self.frame = 0
        self.health = 10
        self.score = 0

當在主循環中調用 update 函數時,需要包括 loot_list

        player.gravity()
        player.update()

如你所見,你已經掌握了所有的基本知識。你現在要做的就是用新的方式使用你所知道的。

在下一篇文章中還有一些提示,但是與此同時,用你學到的知識來製作一些簡單的單關卡遊戲。限制你試圖創造的東西的範圍是很重要的,這樣你就不會埋沒自己。這也使得最終的成品看起來和感覺上更容易完成。

以下是迄今為止你為這個 Python 平台編寫的所有代碼:

#!/usr/bin/env python3
# draw a world
# add a player and player control
# add player movement
# add enemy and basic collision
# add platform
# add gravity
# add jumping
# add scrolling

# GNU All-Permissive License
# Copying and distribution of this file, with or without modification,
# are permitted in any medium without royalty provided the copyright
# notice and this notice are preserved.  This file is offered as-is,
# without any warranty.

import pygame
import sys
import os

'''
Objects
'''

class Platform(pygame.sprite.Sprite):
    # x location, y location, img width, img height, img file    
    def __init__(self,xloc,yloc,imgw,imgh,img):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join('images',img)).convert()
        self.image.convert_alpha()
        self.rect = self.image.get_rect()
        self.rect.y = yloc
        self.rect.x = xloc

class Player(pygame.sprite.Sprite):
    '''
    Spawn a player
    '''
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.movex = 0
        self.movey = 0
        self.frame = 0
        self.health = 10
        self.collide_delta = 0
        self.jump_delta = 6
        self.score = 1
        self.images = []
        for i in range(1,9):
            img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
            img.convert_alpha()
            img.set_colorkey(ALPHA)
            self.images.append(img)
            self.image = self.images[0]
            self.rect  = self.image.get_rect()

    def jump(self,platform_list):
        self.jump_delta = 0

    def gravity(self):
        self.movey += 3.2 # how fast player falls

        if self.rect.y > worldy and self.movey >= 0:
            self.movey = 0
            self.rect.y = worldy-ty

    def control(self,x,y):
        '''
        control player movement
        '''
        self.movex += x
        self.movey += y

    def update(self):
        '''
        Update sprite position
        '''

        self.rect.x = self.rect.x + self.movex
        self.rect.y = self.rect.y + self.movey

        # moving left
        if self.movex < 0:
            self.frame += 1
            if self.frame > ani*3:
                self.frame = 0
            self.image = self.images[self.frame//ani]

        # moving right
        if self.movex > 0:
            self.frame += 1
            if self.frame > ani*3:
                self.frame = 0
            self.image = self.images[(self.frame//ani)+4]

        # collisions
        enemy_hit_list = pygame.sprite.spritecollide(self, enemy_list, False)
        for enemy in enemy_hit_list:
            self.health -= 1
            #print(self.health)

        loot_hit_list = pygame.sprite.spritecollide(self, loot_list, False)
        for loot in loot_hit_list:
            loot_list.remove(loot)
            self.score += 1
            print(self.score)

        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
        for p in plat_hit_list:
            self.collide_delta = 0 # stop jumping
            self.movey = 0
            if self.rect.y > p.rect.y:
                self.rect.y = p.rect.y+ty
            else:
                self.rect.y = p.rect.y-ty

        ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
        for g in ground_hit_list:
            self.movey = 0
            self.rect.y = worldy-ty-ty
            self.collide_delta = 0 # stop jumping
            if self.rect.y > g.rect.y:
                self.health -=1
                print(self.health)

        if self.collide_delta < 6 and self.jump_delta < 6:
            self.jump_delta = 6*2
            self.movey -= 33  # how high to jump
            self.collide_delta += 6
            self.jump_delta    += 6

class Enemy(pygame.sprite.Sprite):
    &apos;&apos;&apos;
    Spawn an enemy
    &apos;&apos;&apos;
    def __init__(self,x,y,img):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(os.path.join(&apos;images&apos;,img))
        self.movey = 0
        #self.image.convert_alpha()
        #self.image.set_colorkey(ALPHA)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.counter = 0

    def move(self):
        &apos;&apos;&apos;
        enemy movement
        &apos;&apos;&apos;
        distance = 80
        speed = 8

        self.movey += 3.2

        if self.counter >= 0 and self.counter <= distance:
            self.rect.x += speed
        elif self.counter >= distance and self.counter <= distance*2:
            self.rect.x -= speed
        else:
            self.counter = 0

        self.counter += 1

        if not self.rect.y >= worldy-ty-ty:
            self.rect.y += self.movey

        plat_hit_list = pygame.sprite.spritecollide(self, plat_list, False)
        for p in plat_hit_list:
            self.movey = 0
            if self.rect.y > p.rect.y:
                self.rect.y = p.rect.y+ty
            else:
                self.rect.y = p.rect.y-ty

        ground_hit_list = pygame.sprite.spritecollide(self, ground_list, False)
        for g in ground_hit_list:
            self.rect.y = worldy-ty-ty

class Level():
    def bad(lvl,eloc):
        if lvl == 1:
            enemy = Enemy(eloc[0],eloc[1],&apos;yeti.png&apos;) # spawn enemy
            enemy_list = pygame.sprite.Group() # create enemy group
            enemy_list.add(enemy)              # add enemy to group

        if lvl == 2:
            print("Level " + str(lvl) )

        return enemy_list

    def loot(lvl,tx,ty):
        if lvl == 1:
            loot_list = pygame.sprite.Group()
            loot = Platform(200,ty*7,tx,ty, &apos;loot_1.png&apos;)
            loot_list.add(loot)

        if lvl == 2:
            print(lvl)

        return loot_list

    def ground(lvl,gloc,tx,ty):
        ground_list = pygame.sprite.Group()
        i=0
        if lvl == 1:
            while i < len(gloc):
                ground = Platform(gloc[i],worldy-ty,tx,ty,&apos;ground.png&apos;)
                ground_list.add(ground)
                i=i+1

        if lvl == 2:
            print("Level " + str(lvl) )

        return ground_list

    def platform(lvl,tx,ty):
        plat_list = pygame.sprite.Group()
        ploc = []
        i=0
        if lvl == 1:
            ploc.append((20,worldy-ty-128,3))
            ploc.append((300,worldy-ty-256,3))
            ploc.append((500,worldy-ty-128,4))

            while i < len(ploc):
                j=0
                while j <= ploc[i][2]:
                    plat = Platform((ploc[i][0]+(j*tx)),ploc[i][1],tx,ty,&apos;ground.png&apos;)
                    plat_list.add(plat)
                    j=j+1
                print(&apos;run&apos; + str(i) + str(ploc[i]))
                i=i+1

        if lvl == 2:
            print("Level " + str(lvl) )

        return plat_list

&apos;&apos;&apos;
Setup
&apos;&apos;&apos;
worldx = 960
worldy = 720

fps = 40 # frame rate
ani = 4  # animation cycles
clock = pygame.time.Clock()
pygame.init()
main = True

BLUE  = (25,25,200)
BLACK = (23,23,23 )
WHITE = (254,254,254)
ALPHA = (0,255,0)

world = pygame.display.set_mode([worldx,worldy])
backdrop = pygame.image.load(os.path.join(&apos;images&apos;,&apos;stage.png&apos;)).convert()
backdropbox = world.get_rect()
player = Player() # spawn player
player.rect.x = 0
player.rect.y = 0
player_list = pygame.sprite.Group()
player_list.add(player)
steps = 10
forwardx = 600
backwardx = 230

eloc = []
eloc = [200,20]
gloc = []
#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]
tx = 64 #tile size
ty = 64 #tile size

i=0
while i <= (worldx/tx)+tx:
    gloc.append(i*tx)
    i=i+1

enemy_list = Level.bad( 1, eloc )
ground_list = Level.ground( 1,gloc,tx,ty )
plat_list = Level.platform( 1,tx,ty )
loot_list = Level.loot(1,tx,ty)

&apos;&apos;&apos;
Main loop
&apos;&apos;&apos;
while main == True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit(); sys.exit()
            main = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT or event.key == ord(&apos;a&apos;):
                print("LEFT")
                player.control(-steps,0)
            if event.key == pygame.K_RIGHT or event.key == ord(&apos;d&apos;):
                print("RIGHT")
                player.control(steps,0)
            if event.key == pygame.K_UP or event.key == ord(&apos;w&apos;):
                print(&apos;jump&apos;)

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == ord(&apos;a&apos;):
                player.control(steps,0)
            if event.key == pygame.K_RIGHT or event.key == ord(&apos;d&apos;):
                player.control(-steps,0)
            if event.key == pygame.K_UP or event.key == ord(&apos;w&apos;):
                player.jump(plat_list)

            if event.key == ord(&apos;q&apos;):
                pygame.quit()
                sys.exit()
                main = False

    # scroll the world forward
    if player.rect.x >= forwardx:
        scroll = player.rect.x - forwardx
        player.rect.x = forwardx
        for p in plat_list:
            p.rect.x -= scroll
        for e in enemy_list:
            e.rect.x -= scroll
        for l in loot_list:
            l.rect.x -= scroll

    # scroll the world backward
    if player.rect.x <= backwardx:
        scroll = backwardx - player.rect.x
        player.rect.x = backwardx
        for p in plat_list:
            p.rect.x += scroll
        for e in enemy_list:
            e.rect.x += scroll
        for l in loot_list:
            l.rect.x += scroll

    world.blit(backdrop, backdropbox)    
    player.gravity() # check gravity
    player.update()
    player_list.draw(world) #refresh player position
    enemy_list.draw(world)  # refresh enemies
    ground_list.draw(world)  # refresh enemies
    plat_list.draw(world)   # refresh platforms
    loot_list.draw(world)   # refresh loot

    for e in enemy_list:
        e.move()
    pygame.display.flip()
    clock.tick(fps)

via: https://opensource.com/article/20/1/loot-python-platformer-game

作者:Seth Kenlon 選題:lujun9972 譯者:heguangzhi 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國