广告
广告
推荐:
当前位置:主页 > 河南都市网 > 财经 > 正文

用Python实现谷歌的小恐龙游戏

点击数:搜狐网 作者:admin 时间2021-01-11 21:26
摘要:
用Python实现谷歌的小恐龙游戏来源:Charles的皮卡丘-白露未晞me理谷歌流量器中有个很有名的彩蛋:当你网络出现问题时,就会出现一个“小恐龙游戏”。(如果想要直接进行游戏,可以在地址栏

原标题:用Python实现谷歌的小恐龙游戏

来源: Charles的皮卡丘-白露未晞me理

谷歌流量器中有个很有名的彩蛋:当你网络出现问题时,就会出现一个“小恐龙游戏”。

(如果想要直接进行游戏,可以在地址栏输入:chrome://dino)

今天我们就来给大家演示下,用Python来自己做一个仿制的“小恐龙游戏”!

废话不多说,让我们愉快地开始吧~

开发工具:

Python版本:3.6.4

相关模块:

pygame模块;以及一些python自带的模块。

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

先睹为快

在终端运行如下命令即可:

pythonGame7.py

效果如下:

代码介绍

这里介绍一下游戏的实现原理。

先,我们对游戏进行一些必要的初始化工作:

# 游戏初始化 pygame.init screen = pygame.display.set_mode(cfg.SCREENSIZE) pygame.display.set_caption( 'T-Rex Rush —— Charles的皮卡丘') # 导入所有声音文件 sounds = {} forkey, valueincfg.AUDIO_PATHS.items: sounds[key] = pygame.mixer.Sound( value)

接着,我们来考虑一下,游戏中有哪些游戏元素:

  • 小恐龙: 由玩家控制以躲避路上的障碍物;
  • 路面: 游戏的背景;
  • 云: 游戏的背景;
  • 飞龙: 路上的障碍物之一,小恐龙碰上就会死掉;
  • 仙人掌: 路上的障碍物之一,小恐龙碰上就会死掉;
  • 记分板:记录当前的分数和历史最高分。

让我们来依次定义一下这些游戏元素类。对于云,路面以及仙人掌来说,定义起来很简单,我们只需要加载对应的游戏元素图片:

然后写两个类内部方法update和draw就ok了。两个方法分别用于将场景不断向左移动以实现小恐龙不断向前移动的动画效果和将场景显示在游戏界面的对应位置上。具体而言,代码实现如下:

'''地板''' classGround( pygame. sprite. Sprite): def__init__( self, imagepath, position, **kwargs) : pygame.sprite.Sprite.__init_ _( self) # 导入图片 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 # 定义一些必要的参数 self.speed = - 10 '''更新地板''' defupdate( self) : self.rect_ 0.left += self.speed self.rect_1.left += self.speed ifself.rect_ 0.right < 0: self.rect_ 0.left = self.rect_1.right ifself.rect_1.right < 0: self.rect_1.left = self.rect_ 0.right '''将地板画到屏幕''' defdraw( self, screen) : screen.blit( self.image_ 0, self.rect_ 0) screen.blit( self.image_1, self.rect_1)

'''云'''classCloud( pygame. sprite. Sprite): def__init__( self, imagepath, position, **kwargs) : pygame.sprite.Sprite.__init_ _( self) # 导入图片self.image = pygame.image.load(imagepath) self.rect = self.image.get_rect self.rect.left, self.rect.top = position # 定义一些必要的参数self.speed = - 1'''将云画到屏幕上'''defdraw( self, screen) : screen.blit( self.image, self.rect) '''更新云'''defupdate( self) : self.rect = self.rect.move([ self.speed, 0]) ifself.rect.right < 0: self.kill

'''仙人掌'''classCactus( pygame. sprite. Sprite): def__init__( self, imagepaths, position=( 600, 147) , sizes=[( 40, 40), ( 40, 40)], **kwargs): pygame.sprite.Sprite.__init_ _( self) # 导入图片self.images = [] image = pygame.image.load(imagepaths[ 0]) fori inrange( 3): self.images.append(pygame.transform.scale(image.subsurface((i* 101, 0), ( 101, 101)), sizes[ 0])) image = pygame.image.load(imagepaths[ 1]) fori inrange( 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'''画到屏幕上'''defdraw( self, screen) : screen.blit( self.image, self.rect) '''更新'''defupdate( self) : self.rect = self.rect.move([ self.speed, 0]) ifself.rect.right < 0: self.kill

记分板的定义也类似,只不过它不需要移动,但是需要实时地更新当前 的分数:

'''记分板'''classScoreboard( pygame. sprite. Sprite): def__init__( self, imagepath, position, size=( 11, 13) , is_highest=False, bg_color=None, **kwargs): pygame.sprite.Sprite.__init_ _( self) # 导入图片self.images = [] image = pygame.image.load(imagepath)fori inrange( 12): self.images.append(pygame.transform.scale(image.subsurface((i* 20, 0), ( 20, 24)), size)) ifis_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''''设置得分'''defset( self, score) : self.score = str(score).zfill( 5) '''画到屏幕上'''defdraw( self, screen) : self.image.fill( self.bg_color) foridx, digital inenumerate(list( self.score)): digital_image = self.images[int(digital)] ifself. 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)) ifself. 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变量来区分该记分板是否用于记录游戏最高分,还是只是记录当前的分数,做该区分的原因是游戏最高分前面有HI标识,所以占的空间更大:

飞龙的定义就稍微复杂一些了,因为它不仅需要向左移动,还需要做出不停扇动翅膀的效果。具体而言,飞龙有两张图:

你需要做的就是每隔一段时间就切换一次当前的飞龙图片,以实现飞龙扇动翅膀的效果:

'''飞龙'''classPtera( pygame. sprite. Sprite): def__init__( self, imagepath, position, size=( 46, 40) , **kwargs): pygame.sprite.Sprite.__init_ _( self) # 导入图片self.images = [] image = pygame.image.load(imagepath)fori inrange( 2): self.images.append(pygame.transform.scale(image.subsurface((i* 92, 0), ( 92, 81)), size)) self.image_idx = 0self.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 = - 10self.refresh_rate = 10self.refresh_counter = 0'''画到屏幕上'''defdraw( self, screen) : screen.blit( self.image, self.rect) '''更新'''defupdate( self) : ifself.refresh_counter % self.refresh_rate == 0: self.refresh_counter = 0self.image_idx = ( self.image_idx + 1) % len( self.images) self.loadImage self.rect = self.rect.move([ self.speed, 0]) ifself.rect.right < 0: self.kill self.refresh_counter += 1'''载入当前状态的图片'''defloadImage( 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)

最后,我们需要定义一下小恐龙类,也就是最复杂的一个游戏精灵类。它有低头,跳跃,普通前进三种状态。对于低头来说:

你只需要和飞龙扇动翅膀一样,不断切换两张低头的图片以实现小恐龙跑动的效果就可以了。

于普通状态也是类似的:

对于跳跃状态,我们则可以通过初中学的上抛和自由落体运动公式来建模,从而计算小恐龙在竖直方向上的位置。具体而言,代码实现如下:

'''小恐龙'''classDinosaur( pygame. sprite. Sprite): def__init__( self, imagepaths, position=( 40, 147) , size=[( 44, 47), ( 59, 47)], **kwargs): pygame.sprite.Sprite.__init_ _( self) # 导入所有图片self.images = [] image = pygame.image.load(imagepaths[ 0]) fori inrange( 5): self.images.append(pygame.transform.scale(image.subsurface((i* 88, 0), ( 88, 95)), size[ 0])) image = pygame.image.load(imagepaths[ 1]) fori inrange( 2): self.images.append(pygame.transform.scale(image.subsurface((i* 118, 0), ( 118, 95)), size[ 1])) self.image_idx = 0self.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 = 5self.refresh_counter = 0self.speed = 11.5self.gravity = 0. 6self.is_jumping = False self.is_ducking = False self.is_dead = False self.movement = [ 0, 0] '''跳跃'''defjump( self, sounds) : ifself.is_dead orself. is_jumping:returnsounds[ 'jump'].play self.is_jumping = True self.movement[ 1] = - 1* self.speed '''低头'''defduck( self) : ifself.is_jumping orself. is_dead:returnself.is_ducking = True '''不低头'''defunduck( self) : self.is_ducking = False '''死掉了'''defdie( self, sounds) : ifself. is_dead:returnsounds[ 'die'].play self.is_dead = True '''将恐龙画到屏幕'''defdraw( self, screen) : screen.blit( self.image, self.rect) '''载入当前状态的图片'''defloadImage( 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) '''更新小恐龙'''defupdate( self) : ifself. is_dead:self.image_idx = 4self.loadImage returnifself. is_jumping:self.movement[ 1] += self.gravity self.image_idx = 0self.loadImage self.rect = self.rect.move( self.movement) ifself.rect.bottom >= self.init_position[ 1]: self.rect.bottom = self.init_position[ 1] self.is_jumping = False elif self. is_ducking:ifself.refresh_counter % self.refresh_rate == 0: self.refresh_counter = 0self.image_idx = 5ifself.image_idx == 6else6self.loadImage else:ifself.refresh_counter % self.refresh_rate == 0: self.refresh_counter = 0ifself.image_idx == 1: self.image_idx = 2elif self.image_idx == 2: self.image_idx = 3else:self.image_idx = 1self.loadImage self.refresh_counter += 1

定义完游戏精灵类,我们就可以实例化他们:

# 定义一些游戏中必要的元素和变量score= 0score_board= Scoreboard(cfg.IMAGE_PATHS[ 'numbers'], position=( 534, 15), bg_color=cfg.BACKGROUND_COLOR) highest_score= highest_score highest_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

后写游戏主循环啦:

# 游戏主循环clock = pygame.time.ClockwhileTrue: foreventinpygame. event. get: ifevent.type == pygame.QUIT: pygame.quitsys.exitelif event.type == pygame.KEYDOWN: ifevent.key == pygame.K_SPACE or event.key == pygame.K_UP: dino.jump(sounds)elif event.key == pygame.K_DOWN: dino.duckelif event.type == pygame.KEYUP and event.key == pygame.K_DOWN: dino.unduckscreen.fill(cfg.BACKGROUND_COLOR)# --随机添加云iflen( 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)))) # --随机添加仙人掌/飞龙add_obstacle_timer += 1ifadd_obstacle_timer > random.randrange( 50, 150): add_obstacle_timer = 0random_value = random.randrange( 0, 10) ifrandom_value >= 5and 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.updateground.updatecloud_sprites_group.updatecactus_sprites_group.updateptera_sprites_group.updatescore_timer += 1ifscore_timer > (cfg.FPS //12):score_timer = 0score += 1score = min(score, 99999) ifscore > highest_score: highest_score = scoreifscore % 100== 0: sounds[ 'point'].play ifscore % 1000== 0: ground.speed -= 1foritem incloud_sprites_group: item.speed -= 1foritem incactus_sprites_group: item.speed -= 1foritem inptera_sprites_group: item.speed -= 1# --碰撞检测foritem incactus_sprites_group: ifpygame.sprite.collide_mask(dino, item): dino.die(sounds)foritem inptera_sprites_group: ifpygame.sprite.collide_mask(dino, item): dino.die(sounds)# --将游戏元素画到屏幕上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.updateclock.tick(cfg.FPS)# --游戏是否结束ifdino.is_dead: break

戏主循环的逻辑很简单,即每帧游戏画面,我们都需要检测一下玩家的操作,如果玩家按下了空格键或者↑键,则小恐龙跳跃,如果玩家按下了↓键,则小恐龙低头,否则小恐龙正常向前冲。

然后在游戏中,我们随机产生云,飞龙和仙人掌这些游戏场景和障碍物,并且和路面一起以相同的速度向左移动,从而实现小恐龙向右移动的视觉效果。在移动的过程中,我们需要对小恐龙和仙人掌,小恐龙和飞龙进行碰撞检测,当小恐龙碰到这些障碍物时,小恐龙就死掉了,本局游戏也随之结束。

要注意的是我们应该使用collide_mask函数来进行更为精确的碰撞检测,而不是之前的collide_rect函数:

即当两个目标的最小外接矩形有重叠时,collide_rect就会判定两个目标有碰撞,这显然是不合理的,会给玩家带来较差的游戏体验。

另外,当分数每提高一千分,我们就和原版的游戏一样增加一点场景和障碍物向左移动的速度(也就是增加小恐龙向右移动的速度)。

最后,把当前所有的游戏元素绑定到屏幕上并更新当前的屏幕就ok了。

大概就是这样,大功告成~完整源代码详见相关文件呗~

GitHub地址:https://github.com/CharlesPikachu/Games/tree/master/Game7返回搜狐,查看更多

责任编辑:

注:本站上发表的所有内容均为原作者的观点,不代表[本网站]的立场,也不代表[本网站]的价值判断。
广告

用Python实现谷歌的小恐龙游戏

admin
摘要:
用Python实现谷歌的小恐龙游戏来源:Charles的皮卡丘-白露未晞me理谷歌流量器中有个很有名的彩蛋:当你网络出现问题时,就会出现一个“小恐龙游戏”。(如果想要直接进行游戏,可以在地址栏

原标题:用Python实现谷歌的小恐龙游戏

来源: Charles的皮卡丘-白露未晞me理

谷歌流量器中有个很有名的彩蛋:当你网络出现问题时,就会出现一个“小恐龙游戏”。

(如果想要直接进行游戏,可以在地址栏输入:chrome://dino)

今天我们就来给大家演示下,用Python来自己做一个仿制的“小恐龙游戏”!

废话不多说,让我们愉快地开始吧~

开发工具:

Python版本:3.6.4

相关模块:

pygame模块;以及一些python自带的模块。

环境搭建

安装Python并添加到环境变量,pip安装需要的相关模块即可。

先睹为快

在终端运行如下命令即可:

pythonGame7.py

效果如下:

代码介绍

这里介绍一下游戏的实现原理。

先,我们对游戏进行一些必要的初始化工作:

# 游戏初始化 pygame.init screen = pygame.display.set_mode(cfg.SCREENSIZE) pygame.display.set_caption( 'T-Rex Rush —— Charles的皮卡丘') # 导入所有声音文件 sounds = {} forkey, valueincfg.AUDIO_PATHS.items: sounds[key] = pygame.mixer.Sound( value)

接着,我们来考虑一下,游戏中有哪些游戏元素:

让我们来依次定义一下这些游戏元素类。对于云,路面以及仙人掌来说,定义起来很简单,我们只需要加载对应的游戏元素图片:

然后写两个类内部方法update和draw就ok了。两个方法分别用于将场景不断向左移动以实现小恐龙不断向前移动的动画效果和将场景显示在游戏界面的对应位置上。具体而言,代码实现如下:

'''地板''' classGround( pygame. sprite. Sprite): def__init__( self, imagepath, position, **kwargs) : pygame.sprite.Sprite.__init_ _( self) # 导入图片 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 # 定义一些必要的参数 self.speed = - 10 '''更新地板''' defupdate( self) : self.rect_ 0.left += self.speed self.rect_1.left += self.speed ifself.rect_ 0.right < 0: self.rect_ 0.left = self.rect_1.right ifself.rect_1.right < 0: self.rect_1.left = self.rect_ 0.right '''将地板画到屏幕''' defdraw( self, screen) : screen.blit( self.image_ 0, self.rect_ 0) screen.blit( self.image_1, self.rect_1)

'''云'''classCloud( pygame. sprite. Sprite): def__init__( self, imagepath, position, **kwargs) : pygame.sprite.Sprite.__init_ _( self) # 导入图片self.image = pygame.image.load(imagepath) self.rect = self.image.get_rect self.rect.left, self.rect.top = position # 定义一些必要的参数self.speed = - 1'''将云画到屏幕上'''defdraw( self, screen) : screen.blit( self.image, self.rect) '''更新云'''defupdate( self) : self.rect = self.rect.move([ self.speed, 0]) ifself.rect.right < 0: self.kill

'''仙人掌'''classCactus( pygame. sprite. Sprite): def__init__( self, imagepaths, position=( 600, 147) , sizes=[( 40, 40), ( 40, 40)], **kwargs): pygame.sprite.Sprite.__init_ _( self) # 导入图片self.images = [] image = pygame.image.load(imagepaths[ 0]) fori inrange( 3): self.images.append(pygame.transform.scale(image.subsurface((i* 101, 0), ( 101, 101)), sizes[ 0])) image = pygame.image.load(imagepaths[ 1]) fori inrange( 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'''画到屏幕上'''defdraw( self, screen) : screen.blit( self.image, self.rect) '''更新'''defupdate( self) : self.rect = self.rect.move([ self.speed, 0]) ifself.rect.right < 0: self.kill

记分板的定义也类似,只不过它不需要移动,但是需要实时地更新当前 的分数:

'''记分板'''classScoreboard( pygame. sprite. Sprite): def__init__( self, imagepath, position, size=( 11, 13) , is_highest=False, bg_color=None, **kwargs): pygame.sprite.Sprite.__init_ _( self) # 导入图片self.images = [] image = pygame.image.load(imagepath)fori inrange( 12): self.images.append(pygame.transform.scale(image.subsurface((i* 20, 0), ( 20, 24)), size)) ifis_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''''设置得分'''defset( self, score) : self.score = str(score).zfill( 5) '''画到屏幕上'''defdraw( self, screen) : self.image.fill( self.bg_color) foridx, digital inenumerate(list( self.score)): digital_image = self.images[int(digital)] ifself. 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)) ifself. 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变量来区分该记分板是否用于记录游戏最高分,还是只是记录当前的分数,做该区分的原因是游戏最高分前面有HI标识,所以占的空间更大:

飞龙的定义就稍微复杂一些了,因为它不仅需要向左移动,还需要做出不停扇动翅膀的效果。具体而言,飞龙有两张图:

你需要做的就是每隔一段时间就切换一次当前的飞龙图片,以实现飞龙扇动翅膀的效果:

'''飞龙'''classPtera( pygame. sprite. Sprite): def__init__( self, imagepath, position, size=( 46, 40) , **kwargs): pygame.sprite.Sprite.__init_ _( self) # 导入图片self.images = [] image = pygame.image.load(imagepath)fori inrange( 2): self.images.append(pygame.transform.scale(image.subsurface((i* 92, 0), ( 92, 81)), size)) self.image_idx = 0self.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 = - 10self.refresh_rate = 10self.refresh_counter = 0'''画到屏幕上'''defdraw( self, screen) : screen.blit( self.image, self.rect) '''更新'''defupdate( self) : ifself.refresh_counter % self.refresh_rate == 0: self.refresh_counter = 0self.image_idx = ( self.image_idx + 1) % len( self.images) self.loadImage self.rect = self.rect.move([ self.speed, 0]) ifself.rect.right < 0: self.kill self.refresh_counter += 1'''载入当前状态的图片'''defloadImage( 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)

最后,我们需要定义一下小恐龙类,也就是最复杂的一个游戏精灵类。它有低头,跳跃,普通前进三种状态。对于低头来说:

你只需要和飞龙扇动翅膀一样,不断切换两张低头的图片以实现小恐龙跑动的效果就可以了。

于普通状态也是类似的:

对于跳跃状态,我们则可以通过初中学的上抛和自由落体运动公式来建模,从而计算小恐龙在竖直方向上的位置。具体而言,代码实现如下:

'''小恐龙'''classDinosaur( pygame. sprite. Sprite): def__init__( self, imagepaths, position=( 40, 147) , size=[( 44, 47), ( 59, 47)], **kwargs): pygame.sprite.Sprite.__init_ _( self) # 导入所有图片self.images = [] image = pygame.image.load(imagepaths[ 0]) fori inrange( 5): self.images.append(pygame.transform.scale(image.subsurface((i* 88, 0), ( 88, 95)), size[ 0])) image = pygame.image.load(imagepaths[ 1]) fori inrange( 2): self.images.append(pygame.transform.scale(image.subsurface((i* 118, 0), ( 118, 95)), size[ 1])) self.image_idx = 0self.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 = 5self.refresh_counter = 0self.speed = 11.5self.gravity = 0. 6self.is_jumping = False self.is_ducking = False self.is_dead = False self.movement = [ 0, 0] '''跳跃'''defjump( self, sounds) : ifself.is_dead orself. is_jumping:returnsounds[ 'jump'].play self.is_jumping = True self.movement[ 1] = - 1* self.speed '''低头'''defduck( self) : ifself.is_jumping orself. is_dead:returnself.is_ducking = True '''不低头'''defunduck( self) : self.is_ducking = False '''死掉了'''defdie( self, sounds) : ifself. is_dead:returnsounds[ 'die'].play self.is_dead = True '''将恐龙画到屏幕'''defdraw( self, screen) : screen.blit( self.image, self.rect) '''载入当前状态的图片'''defloadImage( 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) '''更新小恐龙'''defupdate( self) : ifself. is_dead:self.image_idx = 4self.loadImage returnifself. is_jumping:self.movement[ 1] += self.gravity self.image_idx = 0self.loadImage self.rect = self.rect.move( self.movement) ifself.rect.bottom >= self.init_position[ 1]: self.rect.bottom = self.init_position[ 1] self.is_jumping = False elif self. is_ducking:ifself.refresh_counter % self.refresh_rate == 0: self.refresh_counter = 0self.image_idx = 5ifself.image_idx == 6else6self.loadImage else:ifself.refresh_counter % self.refresh_rate == 0: self.refresh_counter = 0ifself.image_idx == 1: self.image_idx = 2elif self.image_idx == 2: self.image_idx = 3else:self.image_idx = 1self.loadImage self.refresh_counter += 1

定义完游戏精灵类,我们就可以实例化他们:

# 定义一些游戏中必要的元素和变量score= 0score_board= Scoreboard(cfg.IMAGE_PATHS[ 'numbers'], position=( 534, 15), bg_color=cfg.BACKGROUND_COLOR) highest_score= highest_score highest_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

后写游戏主循环啦:

# 游戏主循环clock = pygame.time.ClockwhileTrue: foreventinpygame. event. get: ifevent.type == pygame.QUIT: pygame.quitsys.exitelif event.type == pygame.KEYDOWN: ifevent.key == pygame.K_SPACE or event.key == pygame.K_UP: dino.jump(sounds)elif event.key == pygame.K_DOWN: dino.duckelif event.type == pygame.KEYUP and event.key == pygame.K_DOWN: dino.unduckscreen.fill(cfg.BACKGROUND_COLOR)# --随机添加云iflen( 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)))) # --随机添加仙人掌/飞龙add_obstacle_timer += 1ifadd_obstacle_timer > random.randrange( 50, 150): add_obstacle_timer = 0random_value = random.randrange( 0, 10) ifrandom_value >= 5and 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.updateground.updatecloud_sprites_group.updatecactus_sprites_group.updateptera_sprites_group.updatescore_timer += 1ifscore_timer > (cfg.FPS //12):score_timer = 0score += 1score = min(score, 99999) ifscore > highest_score: highest_score = scoreifscore % 100== 0: sounds[ 'point'].play ifscore % 1000== 0: ground.speed -= 1foritem incloud_sprites_group: item.speed -= 1foritem incactus_sprites_group: item.speed -= 1foritem inptera_sprites_group: item.speed -= 1# --碰撞检测foritem incactus_sprites_group: ifpygame.sprite.collide_mask(dino, item): dino.die(sounds)foritem inptera_sprites_group: ifpygame.sprite.collide_mask(dino, item): dino.die(sounds)# --将游戏元素画到屏幕上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.updateclock.tick(cfg.FPS)# --游戏是否结束ifdino.is_dead: break

戏主循环的逻辑很简单,即每帧游戏画面,我们都需要检测一下玩家的操作,如果玩家按下了空格键或者↑键,则小恐龙跳跃,如果玩家按下了↓键,则小恐龙低头,否则小恐龙正常向前冲。

然后在游戏中,我们随机产生云,飞龙和仙人掌这些游戏场景和障碍物,并且和路面一起以相同的速度向左移动,从而实现小恐龙向右移动的视觉效果。在移动的过程中,我们需要对小恐龙和仙人掌,小恐龙和飞龙进行碰撞检测,当小恐龙碰到这些障碍物时,小恐龙就死掉了,本局游戏也随之结束。

要注意的是我们应该使用collide_mask函数来进行更为精确的碰撞检测,而不是之前的collide_rect函数:

即当两个目标的最小外接矩形有重叠时,collide_rect就会判定两个目标有碰撞,这显然是不合理的,会给玩家带来较差的游戏体验。

另外,当分数每提高一千分,我们就和原版的游戏一样增加一点场景和障碍物向左移动的速度(也就是增加小恐龙向右移动的速度)。

最后,把当前所有的游戏元素绑定到屏幕上并更新当前的屏幕就ok了。

大概就是这样,大功告成~完整源代码详见相关文件呗~

GitHub地址:https://github.com/CharlesPikachu/Games/tree/master/Game7返回搜狐,查看更多

责任编辑: