使用 Pygame 模組來使你的 Python 平台開啟側滾效果,來讓你的玩家自由奔跑。
這是仍在進行中的關於使用 Pygame 模組來在 Python 3 中在建立電腦遊戲的第九部分。先前的文章是:
在這一系列關於使用 Pygame 模組來在 Python 3 中建立電腦遊戲的先前文章中,你已經設計了你的關卡設計布局,但是你的關卡的一些部分可能已近超出你的螢幕的可視區域。在平台類遊戲中,這個問題的普遍解決方案是,像術語“側滾”表明的一樣,捲動。
捲動的關鍵是當玩家精靈接近屏的幕邊緣時,使在玩家精靈周圍的平台移動。這樣給予一種錯覺,螢幕是一個在遊戲世界中穿梭追拍的攝像機
。
這個捲動技巧需要兩個在螢幕邊緣的絕對區域,在絕對區域內的點處,在世界捲動期間,你的化身靜止不動。
如果你希望你的玩家能夠後退,你需要一個觸發點來向前和向後。這兩個點僅僅是兩個變數。設定它們各個距各個螢幕邊緣大約 100 或 200 畫素。在你的設定部分中建立變數。在下面的程式碼中,前兩行用於上下文說明,所以僅需要新增這行後的程式碼:
player_list.add(player)steps = 10forwardX = 600backwardX = 230
在主迴圈中,檢視你的玩家精靈是否在 forwardx
或 backwardx
捲動點處。如果是這樣,向左或向右移動使用的平台,取決於世界是向前或向後移動。在下面的程式碼中,程式碼的最後三行僅供你參考:
# 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 # 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 ## scrolling code above world.blit(backdrop, backdropbox) player.gravity() # check gravity player.update()
啟動你的遊戲,並嘗試它。
捲動像預期的一樣工作,但是你可能注意到一個發生的小問題,當你捲動你的玩家和非玩家精靈周圍的世界時:敵人精靈不隨同世界捲動。除非你要你的敵人精靈要無休止地追逐你的玩家,你需要修改敵人程式碼,以便當你的玩家快速撤退時,敵人被留在後面。
在你的主迴圈中,你必須對捲軸平台為你的敵人的位置的應用相同的規則。因為你的遊戲世界將(很可能)有不止一個敵人在其中,該規則應該被應用於你的敵人列表,而不是一個單獨的敵人精靈。這是分組類似元素到列表中的優點之一。
前兩行用於上下文注釋,所以只需新增這兩行後面的程式碼到你的主迴圈中:
# 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
來滾向另一個方向:
# 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
再次啟動遊戲,看看發生什麼。
這裡是到目前為止你已經為這個 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 pygameimport sysimport 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 = xlocclass 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) 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): ''' Spawn an enemy ''' def __init__(self,x,y,img): pygame.sprite.Sprite.__init__(self) self.image = pygame.image.load(os.path.join('images',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): ''' enemy movement ''' 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],'yeti.png') # 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,lloc): print(lvl) 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,'ground.png') 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((0,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,'ground.png') plat_list.add(plat) j=j+1 print('run' + str(i) + str(ploc[i])) i=i+1 if lvl == 2: print("Level " + str(lvl) ) return plat_list'''Setup'''worldx = 960worldy = 720fps = 40 # frame rateani = 4 # animation cyclesclock = pygame.time.Clock()pygame.init()main = TrueBLUE = (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('images','stage.png')).convert()backdropbox = world.get_rect()player = Player() # spawn playerplayer.rect.x = 0player.rect.y = 0player_list = pygame.sprite.Group()player_list.add(player)steps = 10forwardx = 600backwardx = 230eloc = []eloc = [200,20]gloc = []#gloc = [0,630,64,630,128,630,192,630,256,630,320,630,384,630]tx = 64 #tile sizety = 64 #tile sizei=0while i <= (worldx/tx)+tx: gloc.append(i*tx) i=i+1enemy_list = Level.bad( 1, eloc )ground_list = Level.ground( 1,gloc,tx,ty )plat_list = Level.platform( 1,tx,ty )'''Main loop'''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('a'): print("LEFT") player.control(-steps,0) if event.key == pygame.K_RIGHT or event.key == ord('d'): print("RIGHT") player.control(steps,0) if event.key == pygame.K_UP or event.key == ord('w'): print('jump') if event.type == pygame.KEYUP: if event.key == pygame.K_LEFT or event.key == ord('a'): player.control(steps,0) if event.key == pygame.K_RIGHT or event.key == ord('d'): player.control(-steps,0) if event.key == pygame.K_UP or event.key == ord('w'): player.jump(plat_list) if event.key == ord('q'): 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 # 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 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 for e in enemy_list: e.move() pygame.display.flip() clock.tick(fps)