python做游戲用什么軟件_用Python自制谷歌小游戲

谷歌流量器中有個很有名的彩蛋:當你網絡出現問題時,就會出現一個“小恐龍游戲”。

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

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

廢話不多說,讓我們愉快地開始吧~

開發工具:

Python版本:3.6.4

相關模塊:

pygame模塊;以及一些python自帶的模塊。

環境搭建

安裝Python并添加到環境變量,pip安裝需要的相關模塊即可。

先睹為快

在終端運行如下命令即可:

python Game7.py

效果如下:

代碼介紹

這里介紹一下游戲的實現原理。

首先,我們對游戲進行一些必要的初始化工作:

# 游戲初始化

pygame.init()

screen = pygame.display.set_mode(cfg.SCREENSIZE)

pygame.display.set_caption('T-Rex Rush —— Charles的皮卡丘')

# 導入所有聲音文件

sounds = {}

for key, value in cfg.AUDIO_PATHS.items():

sounds[key] = pygame.mixer.Sound(value)

接著,我們來考慮一下,游戲中有哪些游戲元素:小恐龍:由玩家控制以躲避路上的障礙物;

路面:游戲的背景;

云:游戲的背景;

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

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

記分板:記錄當前的分數和歷史最高分。

讓我們來依次定義一下這些游戲元素類。對于云,路面以及仙人掌來說,定義起來很簡單,我們只需要加載對應的游戲元素圖片:

然后寫兩個類內部方法update和draw就ok了。兩個方法分別用于將場景不斷向左移動以實現小恐龍不斷向前移動的動畫效果和將場景顯示在游戲界面的對應位置上。具體而言,代碼實現如下:

'''地板'''

class Ground(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

'''更新地板'''

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

'''將地板畫到屏幕'''

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)

# 導入圖片

self.image = pygame.image.load(imagepath)

self.rect = self.image.get_rect()

self.rect.left, self.rect.top = position

# 定義一些必要的參數

self.speed = -1

'''將云畫到屏幕上'''

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)

# 導入圖片

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

'''畫到屏幕上'''

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 Scoreboard(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)

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'

'''設置得分'''

def set(self, score):

self.score = str(score).zfill(5)

'''畫到屏幕上'''

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變量來區分該記分板是否用于記錄游戲最高分,還是只是記錄當前的分數,做該區分的原因是游戲最高分前面有HI標識,所以占的空間更大:

飛龍的定義就稍微復雜一些了,因為它不僅需要向左移動,還需要做出不停扇動翅膀的效果。具體而言,飛龍有兩張圖:

你需要做的就是每隔一段時間就切換一次當前的飛龍圖片,以實現飛龍扇動翅膀的效果:

'''飛龍'''

class Ptera(pygame.sprite.Sprite):

def __init__(self, imagepath, position, size=(46, 40), **kwargs):

pygame.sprite.Sprite.__init__(self)

# 導入圖片

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

'''畫到屏幕上'''

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

'''載入當前狀態的圖片'''

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)

最后,我們需要定義一下小恐龍類,也就是最復雜的一個游戲精靈類。它有低頭,跳躍,普通前進三種狀態。對于低頭來說:

你只需要和飛龍扇動翅膀一樣,不斷切換兩張低頭的圖片以實現小恐龍跑動的效果就可以了。對于普通狀態也是類似的:

對于跳躍狀態,我們則可以通過初中學的上拋和自由落體運動公式來建模,從而計算小恐龍在豎直方向上的位置。具體而言,代碼實現如下:

'''小恐龍'''

class Dinosaur(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])

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

'''將恐龍畫到屏幕'''

def draw(self, screen):

screen.blit(self.image, self.rect)

'''載入當前狀態的圖片'''

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

定義完游戲精靈類,我們就可以實例化他們:

# 定義一些游戲中必要的元素和變量

score = 0

score_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 = 0

score_timer = 0

然后寫游戲主循環啦:

# 游戲主循環

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)

# --隨機添加云

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))))

# --隨機添加仙人掌/飛龍

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

# --碰撞檢測

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)

# --將游戲元素畫到屏幕上

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)

# --游戲是否結束

if dino.is_dead:

break

游戲主循環的邏輯很簡單,即每幀游戲畫面,我們都需要檢測一下玩家的操作,如果玩家按下了空格鍵或者↑鍵,則小恐龍跳躍,如果玩家按下了↓鍵,則小恐龍低頭,否則小恐龍正常向前沖。

然后在游戲中,我們隨機產生云,飛龍和仙人掌這些游戲場景和障礙物,并且和路面一起以相同的速度向左移動,從而實現小恐龍向右移動的視覺效果。在移動的過程中,我們需要對小恐龍和仙人掌,小恐龍和飛龍進行碰撞檢測,當小恐龍碰到這些障礙物時,小恐龍就死掉了,本局游戲也隨之結束。

需要注意的是我們應該使用collide_mask函數來進行更為精確的碰撞檢測,而不是之前的collide_rect函數:

即當兩個目標的最小外接矩形有重疊時,collide_rect就會判定兩個目標有碰撞,這顯然是不合理的,會給玩家帶來較差的游戲體驗。

另外,當分數每提高一千分,我們就和原版的游戲一樣增加一點場景和障礙物向左移動的速度(也就是增加小恐龍向右移動的速度)。

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/277541.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/277541.shtml
英文地址,請注明出處:http://en.pswp.cn/news/277541.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用maven構建項目候,jar包錯誤的解決辦法

1、刪除架包&#xff0c;重新下載&#xff0c;右鍵項目點擊"run as"中的“maven clean”,然后再maven中找到Update Project 2、可以在代碼中&#xff0c;把鼠標放到報錯的架包上 點擊劃紅線部分&#xff0c;進行安裝 轉載于:https://www.cnblogs.com/qingqian/p/1099…

MySQL——通過EXPLAIN分析SQL的執行計劃

在MySQL中&#xff0c;我們可以通過EXPLAIN命令獲取MySQL如何執行SELECT語句的信息&#xff0c;包括在SELECT語句執行過程中表如何連接和連接的順序。下面分別對EXPLAIN命令結果的每一列進行說明&#xff1a;select_type:表示SELECT的類型&#xff0c;常見的取值有&#xff1a;…

python將argv作為參數_在jupyter / ipython notebook中將命令行參數傳遞給argv

經過大量的環顧后,我發現了非常繁瑣的自定義庫,但是用幾行代碼解決了它,我認為這些代碼很漂亮.我使用nbconvert最終得到一個html報告作為輸出,包含筆記本中的所有圖形和降價,但是通過最小的python包裝器接受命令行參數&#xff1a;python文件test_args.py(正常執行命令行參數)&…

模擬輸入(ADC-A0)

ESP8266具有內置的10位ADC&#xff0c;只有一個ADC通道(A0引腳)&#xff0c;即只有一個ADC輸入引腳可讀取來自外部器件的模擬電壓 ESP8266上的ADC通道和芯片供電電壓復用&#xff0c;也就是說我們可以將其設置為測量系統電壓或者外部電壓 測量外部電壓&#xff1a; analogRead(…

SQL Server 連接超時案例一則

原文:SQL Server 連接超時案例一則上周六&#xff0c;一工廠系統管理員反饋一數據庫連接不上&#xff0c;SSMS連接數據庫報“連接超時時間已到。在嘗試使用預登錄握手確認時超過了此超時時間.......”, 如下截圖所示&#xff1a; 另外遠程連接也連接不上&#xff0c;系統管理員…

mysql 刪除5天前 備份_mysql自動備份刪除5天前的備份

1、查看磁盤空間情況&#xff1a;df -h2、創建備份目錄&#xff1a;上面我們使用命令看出/home下空間比較充足&#xff0c;所以可以考慮在/home保存備份文件&#xff1b;cd /homemkdir backupcd backup3、創建備份Shell腳本:注意把以下命令中的DatabaseName換為實際的數據庫名稱…

個人作業-Alpha項目測試

這個作業屬于哪個課程https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2作業地址https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2/homework/3340團隊名稱腦闊疼https://www.cnblogs.com/chaserFF/p/10994338.html這個作業的目標完成班級項目互評…

深入理解brew link命令

來源&#xff1a;https://newsn.net/say/brew-link-php71.html brew是mac機上面程序猿非常常用的軟件包安裝方式&#xff0c;其中有兩組命令是需要大家知曉的。分別是&#xff1a;第一組&#xff1a;brew install和brew uninstall。第二組&#xff0c;brew link和brew unlink。…

scss2css vscode設置_VSCode下讓CSS文件完美支持SCSS或SASS語法方法

VSCode下讓CSS文件完美支持SCSS或SASS語法方法習慣Webpack PostCSS后, 通常PostCSS都是直接對CSS文件進行處理, 但是大部分習慣SCSS/SASS/LESS的朋友也許不適應了. 我專門研究了一下, 在Visual Studio Code編輯器下如果配置相關代碼和設置達到CSS文件完美編寫SCSS的辦法, 其他…

第5章 初識JQuery

JQuery是對JavaScript的封裝&#xff0c;簡化了JS代碼&#xff0c;是主流框架的基礎(VUE,EasyUI,Bootstrap) 它是2006年推出的JQuery的優勢&#xff1a; 體積小&#xff0c;壓縮后只有100KB左右 強大的選擇器 出色的DOM封裝 可靠的事件處理機制 出色的瀏覽器兼容性 使用隱式迭代…

Jenkins的Pipeline腳本在美團餐飲SaaS中的實踐

2019獨角獸企業重金招聘Python工程師標準>>> 一、背景 在日常開發中&#xff0c;我們經常會有發布需求&#xff0c;而且還會遇到各種環境&#xff0c;比如&#xff1a;線上環境&#xff08;Online&#xff09;&#xff0c;模擬環境&#xff08;Staging&#xff09;&…

6.12交流

czy bzoj5424燒橋計劃 f[i][j]暴力&#xff0c;可以分兩段轉移&#xff0c;更近的一段單調隊列 發現&#xff0c;最多分成sqrt(n)段。 因為如果只有一段&#xff0c;ansn*2000 而如果多段&#xff0c;至少是∑i*1000&#xff0c;那么&#xff0c;i的上界是sqrt(n)級別的。 所以…

java橢圓_如何用java畫橢圓

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓利用java畫出橢圓。也就是鼠標一邊移動一邊顯示出橢圓&#xff0c;如何做到請大神指教這是我寫的(沒有達到我自己的要求)&#xff1a;import java.awt.*;import java.awt.Graphics;import java.awt.event.*;import javax.swing.*;i…

【springboot+easypoi】一行代碼搞定excel導入導出

原文&#xff1a;https://www.jianshu.com/p/5d67fb720ece 開發中經常會遇到excel的處理&#xff0c;導入導出解析等等&#xff0c;java中比較流行的用poi&#xff0c;但是每次都要寫大段工具類來搞定這事兒&#xff0c;此處推薦一個別人造好的輪子【easypoi】&#xff0c;下面…

用java編寫一個計算器_用java程序編寫一個計算器

展開全部給你一個參考&#xff0c;希望不62616964757a686964616fe58685e5aeb931333330343261要被百度吞了當晚餐import java.awt.BorderLayout;import java.awt.GridLayout;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.text.DecimalFor…

TypeScript基礎入門 - 接口 - 可索引的類型

轉載地址 TypeScript基礎入門 - 接口 - 可索引的類型 項目實踐倉庫 https://github.com/durban89/typescript_demo.git tag: 1.0.11 為了保證后面的學習演示需要安裝下ts-node&#xff0c;這樣后面的每個操作都能直接運行看到輸出的結果。 npm install -D ts-node 后面自己在練…

jquery中的ajax方法(備忘)

參考&#xff1a;https://www.cnblogs.com/tylerdonet/p/3520862.html w3school:http://www.w3school.com.cn/jquery/ajax_ajax.asp 1.url: 要求為String類型的參數&#xff0c;&#xff08;默認為當前頁地址&#xff09;發送請求的地址。 2.type: 要求為String類型的參數&…

java高級類_Java高級類特性(一)

權限類內同包不同包子類不同包非子類private√default√√protected√√√public√√√√四、super關鍵字的使用package com.test.java;/** super可以用來修飾屬性、方法、構造器* 1)當子類與父類中有同名的屬性時&#xff0c;可以通過"super.屬性"顯式的調用父類中聲…

Android.對話框(AlertDialog/Toast/Snackbar)

1、資料&#xff1a; 1.1、Android提醒微技巧&#xff0c;你真的了解Dialog、Toast和Snackbar嗎&#xff1f; - CSDN博客.html&#xff08;https://blog.csdn.net/guolin_blog/article/details/51336415&#xff09; 1.2、Android界面設計之對話框——定制Toast、AlertDialog -…

第4次作業

轉載于:https://www.cnblogs.com/wzh2920330283/p/11027254.html