<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          用Python實(shí)現(xiàn)谷歌的小恐龍游戲:p

          共 11854字,需瀏覽 24分鐘

           ·

          2020-12-17 23:03


          導(dǎo)

          語(yǔ)

          大家好,歡迎來(lái)到Crossin的編程教室!

          谷歌流量器中有個(gè)很有名的彩蛋:當(dāng)你網(wǎng)絡(luò)出現(xiàn)問(wèn)題時(shí),就會(huì)出現(xiàn)一個(gè)“小恐龍游戲

          (如果想要直接進(jìn)行游戲,可以在地址欄輸入:chrome://dino)

          今天我們就來(lái)給大家演示下,用Python來(lái)自己做一個(gè)仿制的“小恐龍游戲”!

          廢話(huà)不多說(shuō),讓我們愉快地開(kāi)始吧~



          開(kāi)

          發(fā)

          Python版本:3.6.4

          相關(guān)模塊:

          pygame模塊;

          以及一些python自帶的模塊。



          環(huán)

          安裝Python并添加到環(huán)境變量,pip安裝需要的相關(guān)模塊即可。



          在終端運(yùn)行如下命令即可:

          python?Game7.py

          效果如下:



          這里介紹一下游戲的實(shí)現(xiàn)原理。

          首先,我們對(duì)游戲進(jìn)行一些必要的初始化工作:

          # 游戲初始化pygame.init()screen = pygame.display.set_mode(cfg.SCREENSIZE)pygame.display.set_caption('T-Rex Rush —— Charles的皮卡丘')# 導(dǎo)入所有聲音文件sounds = {}for key, value in cfg.AUDIO_PATHS.items():  sounds[key] = pygame.mixer.Sound(value)

          接著,我們來(lái)考慮一下,游戲中有哪些游戲元素:

          • 小恐龍:由玩家控制以躲避路上的障礙物;

          • 路面:游戲的背景;

          • 云:游戲的背景;

          • 飛龍:路上的障礙物之一,小恐龍碰上就會(huì)死掉;

          • 仙人掌:路上的障礙物之一,小恐龍碰上就會(huì)死掉;

          • 記分板:記錄當(dāng)前的分?jǐn)?shù)和歷史最高分。

          讓我們來(lái)依次定義一下這些游戲元素類(lèi)。對(duì)于云,路面以及仙人掌來(lái)說(shuō),定義起來(lái)很簡(jiǎn)單,我們只需要加載對(duì)應(yīng)的游戲元素圖片:

          然后寫(xiě)兩個(gè)類(lèi)內(nèi)部方法updatedraw就ok了。兩個(gè)方法分別用于將場(chǎng)景不斷向左移動(dòng)以實(shí)現(xiàn)小恐龍不斷向前移動(dòng)的動(dòng)畫(huà)效果和將場(chǎng)景顯示在游戲界面的對(duì)應(yīng)位置上。具體而言,代碼實(shí)現(xiàn)如下:

          '''地板'''class Ground(pygame.sprite.Sprite):  def __init__(self, imagepath, position, **kwargs):    pygame.sprite.Sprite.__init__(self)    # 導(dǎo)入圖片    self.image_0 = pygame.image.load(imagepath)    self.rect_0 = self.image_0.get_rect()    self.rect_0.left, self.rect_0.bottom = position    self.image_1 = pygame.image.load(imagepath)    self.rect_1 = self.image_1.get_rect()    self.rect_1.left, self.rect_1.bottom = self.rect_0.right, self.rect_0.bottom    # 定義一些必要的參數(shù)    self.speed = -10  '''更新地板'''  def update(self):    self.rect_0.left += self.speed    self.rect_1.left += self.speed    if self.rect_0.right < 0:      self.rect_0.left = self.rect_1.right    if self.rect_1.right < 0:      self.rect_1.left = self.rect_0.right  '''將地板畫(huà)到屏幕'''  def draw(self, screen):    screen.blit(self.image_0, self.rect_0)    screen.blit(self.image_1, self.rect_1)
          '''云'''class Cloud(pygame.sprite.Sprite): def __init__(self, imagepath, position, **kwargs): pygame.sprite.Sprite.__init__(self) # 導(dǎo)入圖片 self.image = pygame.image.load(imagepath) self.rect = self.image.get_rect() self.rect.left, self.rect.top = position # 定義一些必要的參數(shù) self.speed = -1 '''將云畫(huà)到屏幕上''' def draw(self, screen): screen.blit(self.image, self.rect) '''更新云''' def update(self): self.rect = self.rect.move([self.speed, 0]) if self.rect.right < 0: self.kill()
          '''仙人掌'''class Cactus(pygame.sprite.Sprite): def __init__(self, imagepaths, position=(600, 147), sizes=[(40, 40), (40, 40)], **kwargs): pygame.sprite.Sprite.__init__(self) # 導(dǎo)入圖片 self.images = [] image = pygame.image.load(imagepaths[0]) for i in range(3): self.images.append(pygame.transform.scale(image.subsurface((i*101, 0), (101, 101)), sizes[0])) image = pygame.image.load(imagepaths[1]) for i in range(3): self.images.append(pygame.transform.scale(image.subsurface((i*68, 0), (68, 70)), sizes[1])) self.image = random.choice(self.images) self.rect = self.image.get_rect() self.rect.left, self.rect.bottom = position self.mask = pygame.mask.from_surface(self.image) # 定義一些必要的變量 self.speed = -10 '''畫(huà)到屏幕上''' def draw(self, screen): screen.blit(self.image, self.rect) '''更新''' def update(self): self.rect = self.rect.move([self.speed, 0]) if self.rect.right < 0: self.kill()

          記分板的定義也類(lèi)似,只不過(guò)它不需要移動(dòng),但是需要實(shí)時(shí)地更新當(dāng)前 的分?jǐn)?shù):

          '''記分板'''class Scoreboard(pygame.sprite.Sprite):  def __init__(self, imagepath, position, size=(11, 13), is_highest=False, bg_color=None, **kwargs):    pygame.sprite.Sprite.__init__(self)    # 導(dǎo)入圖片    self.images = []    image = pygame.image.load(imagepath)    for i in range(12):      self.images.append(pygame.transform.scale(image.subsurface((i*20, 0), (20, 24)), size))    if is_highest:      self.image = pygame.Surface((size[0]*8, size[1]))    else:      self.image = pygame.Surface((size[0]*5, size[1]))    self.rect = self.image.get_rect()    self.rect.left, self.rect.top = position    # 一些必要的變量    self.is_highest = is_highest    self.bg_color = bg_color    self.score = '00000'  '''設(shè)置得分'''  def set(self, score):    self.score = str(score).zfill(5)  '''畫(huà)到屏幕上'''  def draw(self, screen):    self.image.fill(self.bg_color)    for idx, digital in enumerate(list(self.score)):      digital_image = self.images[int(digital)]      if self.is_highest:        self.image.blit(digital_image, ((idx+3)*digital_image.get_rect().width, 0))      else:        self.image.blit(digital_image, (idx*digital_image.get_rect().width, 0))    if self.is_highest:      self.image.blit(self.images[-2], (0, 0))      self.image.blit(self.images[-1], (digital_image.get_rect().width, 0))    screen.blit(self.image, self.rect)

          上面代碼用is_highest變量來(lái)區(qū)分該記分板是否用于記錄游戲最高分,還是只是記錄當(dāng)前的分?jǐn)?shù),做該區(qū)分的原因是游戲最高分前面有HI標(biāo)識(shí),所以占的空間更大:

          飛龍的定義就稍微復(fù)雜一些了,因?yàn)樗粌H需要向左移動(dòng),還需要做出不停扇動(dòng)翅膀的效果。具體而言,飛龍有兩張圖:

          你需要做的就是每隔一段時(shí)間就切換一次當(dāng)前的飛龍圖片,以實(shí)現(xiàn)飛龍扇動(dòng)翅膀的效果:

          '''飛龍'''class Ptera(pygame.sprite.Sprite):  def __init__(self, imagepath, position, size=(46, 40), **kwargs):    pygame.sprite.Sprite.__init__(self)    # 導(dǎo)入圖片    self.images = []    image = pygame.image.load(imagepath)    for i in range(2):      self.images.append(pygame.transform.scale(image.subsurface((i*92, 0), (92, 81)), size))    self.image_idx = 0    self.image = self.images[self.image_idx]    self.rect = self.image.get_rect()    self.rect.left, self.rect.centery = position    self.mask = pygame.mask.from_surface(self.image)    # 定義一些必要的變量    self.speed = -10    self.refresh_rate = 10    self.refresh_counter = 0  '''畫(huà)到屏幕上'''  def draw(self, screen):    screen.blit(self.image, self.rect)  '''更新'''  def update(self):    if self.refresh_counter % self.refresh_rate == 0:      self.refresh_counter = 0      self.image_idx = (self.image_idx + 1) % len(self.images)      self.loadImage()    self.rect = self.rect.move([self.speed, 0])    if self.rect.right < 0:      self.kill()    self.refresh_counter += 1  '''載入當(dāng)前狀態(tài)的圖片'''  def loadImage(self):    self.image = self.images[self.image_idx]    rect = self.image.get_rect()    rect.left, rect.top = self.rect.left, self.rect.top    self.rect = rect    self.mask = pygame.mask.from_surface(self.image)

          最后,我們需要定義一下小恐龍類(lèi),也就是最復(fù)雜的一個(gè)游戲精靈類(lèi)。它有低頭,跳躍,普通前進(jìn)三種狀態(tài)。對(duì)于低頭來(lái)說(shuō):

          你只需要和飛龍扇動(dòng)翅膀一樣,不斷切換兩張低頭的圖片以實(shí)現(xiàn)小恐龍跑動(dòng)的效果就可以了。

          對(duì)于普通狀態(tài)也是類(lèi)似的:

          對(duì)于跳躍狀態(tài),我們則可以通過(guò)初中學(xué)的上拋和自由落體運(yùn)動(dòng)公式來(lái)建模,從而計(jì)算小恐龍?jiān)谪Q直方向上的位置。具體而言,代碼實(shí)現(xiàn)如下:

          '''小恐龍'''class Dinosaur(pygame.sprite.Sprite):  def __init__(self, imagepaths, position=(40, 147), size=[(44, 47), (59, 47)], **kwargs):    pygame.sprite.Sprite.__init__(self)    # 導(dǎo)入所有圖片    self.images = []    image = pygame.image.load(imagepaths[0])    for i in range(5):      self.images.append(pygame.transform.scale(image.subsurface((i*88, 0), (88, 95)), size[0]))    image = pygame.image.load(imagepaths[1])    for i in range(2):      self.images.append(pygame.transform.scale(image.subsurface((i*118, 0), (118, 95)), size[1]))    self.image_idx = 0    self.image = self.images[self.image_idx]    self.rect = self.image.get_rect()    self.rect.left, self.rect.bottom = position    self.mask = pygame.mask.from_surface(self.image)    # 定義一些必要的變量    self.init_position = position    self.refresh_rate = 5    self.refresh_counter = 0    self.speed = 11.5    self.gravity = 0.6    self.is_jumping = False    self.is_ducking = False    self.is_dead = False    self.movement = [0, 0]  '''跳躍'''  def jump(self, sounds):    if self.is_dead or self.is_jumping:      return    sounds['jump'].play()    self.is_jumping = True    self.movement[1] = -1 * self.speed  '''低頭'''  def duck(self):    if self.is_jumping or self.is_dead:      return    self.is_ducking = True  '''不低頭'''  def unduck(self):    self.is_ducking = False  '''死掉了'''  def die(self, sounds):    if self.is_dead:      return    sounds['die'].play()    self.is_dead = True  '''將恐龍畫(huà)到屏幕'''  def draw(self, screen):    screen.blit(self.image, self.rect)  '''載入當(dāng)前狀態(tài)的圖片'''  def loadImage(self):    self.image = self.images[self.image_idx]    rect = self.image.get_rect()    rect.left, rect.top = self.rect.left, self.rect.top    self.rect = rect    self.mask = pygame.mask.from_surface(self.image)  '''更新小恐龍'''  def update(self):    if self.is_dead:      self.image_idx = 4      self.loadImage()      return    if self.is_jumping:      self.movement[1] += self.gravity      self.image_idx = 0      self.loadImage()      self.rect = self.rect.move(self.movement)      if self.rect.bottom >= self.init_position[1]:        self.rect.bottom = self.init_position[1]        self.is_jumping = False    elif self.is_ducking:      if self.refresh_counter % self.refresh_rate == 0:        self.refresh_counter = 0        self.image_idx = 5 if self.image_idx == 6 else 6        self.loadImage()    else:      if self.refresh_counter % self.refresh_rate == 0:        self.refresh_counter = 0        if self.image_idx == 1:          self.image_idx = 2        elif self.image_idx == 2:          self.image_idx = 3        else:          self.image_idx = 1        self.loadImage()    self.refresh_counter += 1

          定義完游戲精靈類(lèi),我們就可以實(shí)例化他們:

          # 定義一些游戲中必要的元素和變量score = 0score_board = Scoreboard(cfg.IMAGE_PATHS['numbers'], position=(534, 15), bg_color=cfg.BACKGROUND_COLOR)highest_score = highest_scorehighest_score_board = Scoreboard(cfg.IMAGE_PATHS['numbers'], position=(435, 15), bg_color=cfg.BACKGROUND_COLOR, is_highest=True)dino = Dinosaur(cfg.IMAGE_PATHS['dino'])ground = Ground(cfg.IMAGE_PATHS['ground'], position=(0, cfg.SCREENSIZE[1]))cloud_sprites_group = pygame.sprite.Group()cactus_sprites_group = pygame.sprite.Group()ptera_sprites_group = pygame.sprite.Group()add_obstacle_timer = 0score_timer = 0

          然后寫(xiě)游戲主循環(huán)啦:

          # 游戲主循環(huán)clock = pygame.time.Clock()while True:  for event in pygame.event.get():    if event.type == pygame.QUIT:      pygame.quit()      sys.exit()    elif event.type == pygame.KEYDOWN:      if event.key == pygame.K_SPACE or event.key == pygame.K_UP:        dino.jump(sounds)      elif event.key == pygame.K_DOWN:        dino.duck()    elif event.type == pygame.KEYUP and event.key == pygame.K_DOWN:      dino.unduck()  screen.fill(cfg.BACKGROUND_COLOR)  # --隨機(jī)添加云  if len(cloud_sprites_group) < 5 and random.randrange(0, 300) == 10:    cloud_sprites_group.add(Cloud(cfg.IMAGE_PATHS['cloud'], position=(cfg.SCREENSIZE[0], random.randrange(30, 75))))  # --隨機(jī)添加仙人掌/飛龍  add_obstacle_timer += 1  if add_obstacle_timer > random.randrange(50, 150):    add_obstacle_timer = 0    random_value = random.randrange(0, 10)    if random_value >= 5 and random_value <= 7:      cactus_sprites_group.add(Cactus(cfg.IMAGE_PATHS['cacti']))    else:      position_ys = [cfg.SCREENSIZE[1]*0.82, cfg.SCREENSIZE[1]*0.75, cfg.SCREENSIZE[1]*0.60, cfg.SCREENSIZE[1]*0.20]      ptera_sprites_group.add(Ptera(cfg.IMAGE_PATHS['ptera'], position=(600, random.choice(position_ys))))  # --更新游戲元素  dino.update()  ground.update()  cloud_sprites_group.update()  cactus_sprites_group.update()  ptera_sprites_group.update()  score_timer += 1  if score_timer > (cfg.FPS//12):    score_timer = 0    score += 1    score = min(score, 99999)    if score > highest_score:      highest_score = score    if score % 100 == 0:      sounds['point'].play()    if score % 1000 == 0:      ground.speed -= 1      for item in cloud_sprites_group:        item.speed -= 1      for item in cactus_sprites_group:        item.speed -= 1      for item in ptera_sprites_group:        item.speed -= 1  # --碰撞檢測(cè)  for item in cactus_sprites_group:    if pygame.sprite.collide_mask(dino, item):      dino.die(sounds)  for item in ptera_sprites_group:    if pygame.sprite.collide_mask(dino, item):      dino.die(sounds)  # --將游戲元素畫(huà)到屏幕上  dino.draw(screen)  ground.draw(screen)  cloud_sprites_group.draw(screen)  cactus_sprites_group.draw(screen)  ptera_sprites_group.draw(screen)  score_board.set(score)  highest_score_board.set(highest_score)  score_board.draw(screen)  highest_score_board.draw(screen)  # --更新屏幕  pygame.display.update()  clock.tick(cfg.FPS)  # --游戲是否結(jié)束  if dino.is_dead:    break

          游戲主循環(huán)的邏輯很簡(jiǎn)單,即每幀游戲畫(huà)面,我們都需要檢測(cè)一下玩家的操作,如果玩家按下了空格鍵或者↑鍵,則小恐龍?zhí)S,如果玩家按下了↓鍵,則小恐龍低頭,否則小恐龍正常向前沖。

          然后在游戲中,我們隨機(jī)產(chǎn)生云,飛龍和仙人掌這些游戲場(chǎng)景和障礙物,并且和路面一起以相同的速度向左移動(dòng),從而實(shí)現(xiàn)小恐龍向右移動(dòng)的視覺(jué)效果。移動(dòng)的過(guò)程中,我們需要對(duì)小恐龍和仙人掌,小恐龍和飛龍進(jìn)行碰撞檢測(cè),當(dāng)小恐龍碰到這些障礙物時(shí),小恐龍就死掉了,本局游戲也隨之結(jié)束。

          需要注意的是我們應(yīng)該使用collide_mask函數(shù)來(lái)進(jìn)行更為精確的碰撞檢測(cè),而不是之前的collide_rect函數(shù):

          即當(dāng)兩個(gè)目標(biāo)的最小外接矩形有重疊時(shí),collide_rect就會(huì)判定兩個(gè)目標(biāo)有碰撞,這顯然是不合理的,會(huì)給玩家?guī)?lái)較差的游戲體驗(yàn)。

          另外,當(dāng)分?jǐn)?shù)每提高一千分,我們就和原版的游戲一樣增加一點(diǎn)場(chǎng)景和障礙物向左移動(dòng)的速度(也就是增加小恐龍向右移動(dòng)的速度)。

          最后,把當(dāng)前所有的游戲元素綁定到屏幕上并更新當(dāng)前的屏幕就ok了。

          大概就是這樣,大功告成~完整源代碼詳見(jiàn)相關(guān)文件唄~



          https://github.com/CharlesPikachu/Games/tree/master/Game7

          歡迎給個(gè)star



          作者:白露未晞me
          來(lái)源:Charles的皮卡丘


          _往期文章推薦_

          100行Python代碼做出魔性聲控游戲




          瀏覽 79
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  偷拍自拍色图 | 美女黄页网站 | 九九综合九九 | 北条麻妃视频在线观看 | 色婷婷1234区在线 |