20212109施鋮哲 《Python程式設計》實驗四 Python綜合實踐實驗報告
課程:《Python程式設計》
班級: 2121
姓名: 施鋮哲
學號: 20212109
實驗教師:王志強
實驗日期:2022年5月28日
必修/選修:公選課
一、實驗題目:
Python綜合應用:爬蟲、資料處理、視覺化、機器學習、神經網路、遊戲、網路安全等。
這裡我選擇根據飛機大戰相似的模式自制遊戲。
二、實驗過程:
2.1製作目標
2.1.1靈感來源
基於B站教學視訊製作魔改遊戲,發現飛機大戰很好玩,就想根據這個做自己的垃圾大戰
2.1.2遊戲介紹
把自己操控的飛機改為回收站,把敵方飛機改為pycharm圖示,pycharm會不斷射出名為python的資料夾和steam的圖示,回收站碰到steam圖示會掛,而碰到python資料夾可以加分,一次加十分。
操控由鍵盤的上下左右完成,敵方pycharm會自動左右移動。
如果直接用回收站撞pycharm的話,解鎖同歸於盡結局,獲得500000000000000分。
2.2製作過程
2.2.1我在B站學python
由於上課處於比較懵的狀態,類的知識學的還是不紮實的,所以決定跟著B站飛機大戰教程重新學習。
但是由於遊戲內容相似但不一樣,所以我參考了一部分程式碼,而自己完成了一部分。
2.2.2製作流程
製作遊戲必需pycharm,終端下載
先在主函式裡面編寫,建立視窗,後面新增類
就是這個背景
視窗這裡需要注意(542,830)與新增的圖片規格一致
先載入圖片,然後blit新增,然後display展示
Hero玩家類
使用鍵盤監聽來實現操控,而監聽同時需要在while True迴圈裡面出現,否則只會響應一下無法連續響應
而新增入迴圈之後又有速度太快的問題,這時候需要time.sleep控制
Enemy敵人類
基本與Hero類一樣,但是把鍵盤監聽改成自動move,新增自動fire的方法
這裡auto_move的範圍即介面寬度減去自身圖片寬度
auto_fire使用random.randint(1,40)來實現隨機開火,這一方法會用在兩種子彈中,而根據遊戲難度兩種子彈生成的概率設定是不一樣的
敵人子彈類(一個是加分的python,一個是會死的steam)
bullet1
bullet2
使用矩形rect的方法(pygame自帶),kill()即消滅自身
rect方法下的座標
爆炸類
檢測回收站和python、steam兩種子彈以及pycharm圖示之間的矩形碰撞,並載入動畫
(動畫就是這兩個圖片來回切換幾次)
注意這一類並不能完全實現功能,還需要管理類中主函式方法的while迴圈進行控制,從而實現碰撞後圖片的清除和分數的記錄
管理類
用於管理前面數個類的方法
由於很長,中間略,下面會放原始碼
主函式
最後執行主函式
執行效果
死亡動畫(沒法放視訊,截了一下中間的圖片)
撞到pycharm之後的結局(加500000000000000分)
2.3相關知識
2.3.1類
初始化
例項化物件時可以傳入引數,這些引數會傳入__init__()方法中,可以通過重寫這個方法來定義物件的初始化操作
加pygame.sprite.Sprite.__init__(self)是為了主要矩形rect的方法呼叫
self
通常需要將函式的第一個引數定義成self,而self指向物件本身
之後在這個類裡面寫都要在前面加self,表示自己的引數和函式方法
然後呼叫別的類中的就是寫別的類的名稱(例如此處的Enemy.enemy_bullets)
父類和子類繼承
此處pygame.sprite.Sprite就是父類,位於pygame模組中,所以不用自己寫。
而Enemy就是自己建立的子類
呼叫父類,繼承函式方法
2.3.2pygame的函式
影象和矩形(上面講過了)
Group()
用於裝子彈,使用起來相當於列表list
退出模組
字型
事件判斷
碰撞用到的方法
重新整理介面(安了兩個)
time
pygame.time.set_timer()
功能:在事件佇列上重複建立事件
2.3.3文字
分數面板的製作需要用到文字,不難但是比較特殊
在定義函式之後,設定內容、兩個顏色和字型,然後導成矩形貼到介面上
2.4原始碼
import random
import time
import pygame
class Hero(pygame.sprite.Sprite):
def __init__(self,screen):
pygame.sprite.Sprite.__init__(self)
self.image=pygame.image.load("./python/11.png")
self.rect=self.image.get_rect()
self.rect.topleft=[480/2-50,600]
self.speed=10
self.screen=screen
self.bullets=pygame.sprite.Group()
def key_control(self):
#監聽
key_pressed=pygame.key.get_pressed()
if key_pressed[pygame.K_w] or key_pressed[pygame.K_UP]:
self.rect.top-=self.speed
if key_pressed[pygame.K_s] or key_pressed[pygame.K_DOWN]:
self.rect.bottom+=self.speed
if key_pressed[pygame.K_d] or key_pressed[pygame.K_RIGHT]:
self.rect.right+=self.speed
if key_pressed[pygame.K_a] or key_pressed[pygame.K_LEFT]:
self.rect.left-=self.speed
if key_pressed[pygame.K_SPACE]:
bullet=Bullet(self.screen,self.rect.left,self.rect.top)
self.bullets.add(bullet)
def update(self):
self.key_control()
self.display()
def display(self):
self.screen.blit(self.image,self.rect)
self.bullets.update()
self.bullets.draw(self.screen)
class Bullet(pygame.sprite.Sprite):
def __init__(self,screen,x,y):
pygame.sprite.Sprite.__init__(self)
self.image=pygame.image.load("./python/22.png")
self.rect=self.image.get_rect()
self.rect.topleft=[x+50,y-22]
self.screen=screen
self.speed=10
def update(self):
self.rect.top-=self.speed
if self.rect.top<-22:
self.kill()
class Enemy(pygame.sprite.Sprite):
enemy_bullets1=pygame.sprite.Group()
enemy_bullets2=pygame.sprite.Group()
def __init__(self,screen):
pygame.sprite.Sprite.__init__(self)
self.image=pygame.image.load("./python/33.png")
self.rect=self.image.get_rect()
self.rect.topleft=[0,0]
self.speed=10
self.screen=screen
self.bullets1=pygame.sprite.Group()
self.bullets2=pygame.sprite.Group()
self.direction='right'
def display(self):
#貼飛機圖
self.screen.blit(self.image,self.rect)
self.bullets1.update()
self.bullets2.update()
self.bullets1.draw(self.screen)
self.bullets2.draw(self.screen)
def update(self):
self.auto_move()
self.auto_fire()
self.display()
def auto_move(self):
if self.direction == 'right':
self.rect.right+=self.speed
elif self.direction == 'left':
self.rect.right-=self.speed
if self.rect.right>=542:
self.direction='left'
elif self.rect.right<=57:
self.direction='right'
def auto_fire(self):
random_num=random.randint(1,40)
if random_num>37:
bullet1=EnemyBullet1(self.screen,self.rect.left,self.rect.top)
self.bullets1.add(bullet1)
Enemy.enemy_bullets1.add(bullet1)
if random_num<=1:
bullet2=EnemyBullet2(self.screen,self.rect.left,self.rect.top)
self.bullets2.add(bullet2)
Enemy.enemy_bullets2.add(bullet2)
class EnemyBullet1(pygame.sprite.Sprite):
def __init__(self,screen,x,y):
pygame.sprite.Sprite.__init__(self)
self.image=pygame.image.load("./python/python.png")
self.rect=self.image.get_rect()
self.rect.topleft=[x+20,y+20]
self.screen=screen
self.speed=10
def update(self):
self.rect.top+=self.speed
if self.rect.top>830:
self.kill()
class EnemyBullet2(pygame.sprite.Sprite):
def __init__(self,screen,x,y):
pygame.sprite.Sprite.__init__(self)
self.image=pygame.image.load("./python/steam.png")
self.rect=self.image.get_rect()
self.rect.topleft=[x+20,y+20]
self.screen=screen
self.speed=10
def update(self):
self.rect.top+=self.speed
if self.rect.top>830:
self.kill()
class Bomb(object):
def __init__(self,screen,type):
self.screen=screen
if type=='enemy':
self.mImage=[pygame.image.load
("./python/4"+str(v)+".png") for v in range(1,5)]
else:
self.mImage=[pygame.image.load
("./python/4"+str(v)+".png") for v in range(1,5)]
self.mIndex=0
self.mPos=[0,0]
self.mVisible=False
def action(self,rect):
self.mPos[0]=rect.left
self.mPos[1]=rect.top
self.mVisible=True
def draw(self):
if not self.mVisible:
return
self.screen.blit(self.mImage[self.mIndex],(self.mPos[0],self.mPos[1]))
self.mIndex+=1
if self.mIndex>=len(self.mImage):
self.mIndex=0
self.mVisible=False
class Manager(object):
bg_size=(542,830)
game_over_id=11 #1-32中任意一個
is_game_over=False
is_game_up=False
game_up_id=11
score=0
def __init__(self):
pygame.init()
self.screen=pygame.display.set_mode((542,830),0,32)
#視窗
self.background=pygame.image.load("./python/1.png")
#背景
self.players=pygame.sprite.Group()
#裝玩家精靈的group
self.enemys=pygame.sprite.Group()
#裝敵機精靈的group
self.player_bomb=Bomb(self.screen,'player')
#玩家爆炸物件
self.enemy_bomb=Bomb(self.screen,'enemy')
#敵機爆炸物件
def exit(self):
print('退出')
pygame.quit()
exit()
def new_player(self):
player=Hero(self.screen)
self.players.add(player)
def new_enemy(self):
enemy=Enemy(self.screen)
self.enemys.add(enemy)
def drawText(self,score:int,x,y,textHeight=30,fontColor=(100,200,0),backgroundColor=None):
self.word = f"Score: {score}"
font_obj=pygame.font.Font('./python/方.TTF',textHeight)
text_obj=font_obj.render(self.word,True,fontColor,backgroundColor)
text_rect=text_obj.get_rect()
text_rect.topleft=(x,y)
self.screen.blit(text_obj,text_rect)
def main(self):
self.new_player()
self.new_enemy()
while True:
self.screen.blit(self.background,(0,0))
self.drawText(Manager.score,0,0)
for event in pygame.event.get():
#判斷
if event.type==pygame.QUIT:
self.exit()
self.player_bomb.draw()
self.enemy_bomb.draw()
if self.players.sprites():
isover=pygame.sprite.spritecollide(self.players.sprites()[0],Enemy.enemy_bullets2,True)
if isover:
Manager.is_game_over=True
pygame.time.set_timer(Manager.game_over_id,1000)
print('中彈')
print('遊戲結束了')
self.player_bomb.action(self.players.sprites()[0].rect)
self.players.remove(self.players.sprites()[0])
if self.players.sprites():
isup=pygame.sprite.spritecollide(self.players.sprites()[0],Enemy.enemy_bullets1,True)
if isup:
Manager.is_game_up=True
pygame.time.set_timer(Manager.game_up_id,10)
print('獲取')
Enemy.enemy_bullets1.remove(Enemy.enemy_bullets1.sprites()[0])
Manager.score += 10
print(Manager.score)
iscollide=pygame.sprite.groupcollide(self.players,self.enemys,True,True)
if iscollide:
items=list(iscollide.items())[0]
print(items)
x=items[0]
y=items[1][0]
self.player_bomb.action(x.rect)
self.enemy_bomb.action(y.rect)
Manager.score+=500000000000000
self.players.update()
self.enemys.update()
pygame.display.flip()
pygame.display.update()
time.sleep(0.01)
if __name__=='__main__':
manager=Manager()
manager.main()
def main():
#視窗
screen=pygame.display.set_mode((542,830),0,32)
#背景
background=pygame.image.load("./python/1.png")
player=Hero(screen)
enemy=Enemy(screen)
while True:
screen.blit(background,(0,0))
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.qiut()
exit()
player.key_control()
player.display()
enemy.display()
enemy.auto_move()
enemy.auto_fire()
pygame.display.update()
time.sleep(0.01)
if __name__=='__main__':
main()
三、伺服器上執行:
3.1配置伺服器
由於C語言課程也需要用到華為雲伺服器,所以直接使用上次已經購買好的伺服器,就不再進行購買和配置。
3.2在 Linux 系統安裝 X11 轉發的必要軟體包
由於伺服器沒有自帶圖形介面,所以首先安裝遊戲執行所需介面(xming)
# yum install -y xauth
# yum install -y xclock
其中”xauth”用於 X11 轉發認證,而”xclock”是一個十分簡單的 GUI 程式,用於驗證 X11 轉發是否成功。
在伺服器端vi /etc/ssh/sshd_config,(用vim編輯器開啟sshd_config檔案)
新增一行:X11Forwarding yes(按i進入編輯模式,按Esc退出編輯,按: 輸入wq退出vim)
重啟sshd
systemctl restart sshd.service --重啟
3.3下載 Xming
由於華為伺服器沒有自帶的彈出介面,安裝xming來提供linux圖形介面
安裝好xming之後,啟動”xlaunch”工具,預設安裝位置為”C:\Program Files (x86)\Xming\XLaunch.exe”,會見到如下配置選擇介面:
在ssh的x11中勾選enable x11 forwarding
3.4 ECS環境執行
嘗試執行慘遭失敗
詢問課代表解決問題,更換為另一個伺服器成功執行~
在xming介面中運行遊戲
成功啦~(雖然超級卡根本沒法玩)
四、遇到的問題和解決辦法
1.視窗剛開啟就閃退
解決方案:是因為執行一次之後就結束了,要把screen加到while True迴圈裡面,使其一直執行
2..寫到子彈類發現無法執行,視窗剛彈出就消失
解決方法:發現呼叫Group函式的時候忘記在後面寫(),相當於沒有執行這個函式,加上括號之後就可以成功射出子彈了
3.計分板一直為0,無法重新整理
解決方案:開始以為問題出在沒有把score呼叫好,把score在Manager的開頭定義,然後在def main()中呼叫Manager.score,但是還是不行。後來我把判斷if isup==True:改成了if isup:,即可成功使計分板重新整理。
4.在華為伺服器執行python檔案時沒有畫面,且會報錯
解決方案:通過課代表在群裡的提醒後,下載了一個xming,並根據群裡發的參考連結,結合課代表的熱心幫助,最終解決了這個問題
5.執行找不到圖片
解決方案:圖片路徑是原來本地資料夾的,而沒有改為當前伺服器資料夾。改寫為./xxx.png之後成功執行(./指當前資料夾)
五、課程小結
課程總結與感想:
在學習程式設計之前,我一直對C語言和python這些是有“學習障礙”的。說是“學習障礙”,其實只是我不善於理解那些語法知識,而出現一下子無法解決的錯誤就覺得很心累,想要放棄。在現在學習的一個學期的程式設計的我看來,這都是很正常的現象,儘管當時真的對於那些很難理解的東西都感到絕望了,但是隨著不斷的堅持和時間的積累,自己的水平和技能一定會提高。我認為學習程式設計就是這樣,暫時無法理解的東西,會隨著學習的深入而自然瓦解。
python這門課的學習也是如此。在剛開課的時候,我對於python這種語言的理解就是“簡潔”,定義一個量不需要像C語言那樣寫上變數型別,而是隻要寫等號就行了。然後之後課上演示運行了input和print函式也很容易,後面講了for和while的迴圈,continue、break、pass也很好理解記憶,那時候的我還是遊刃有餘的。但是隨著課程的推進,序列list、元組Tuple、字典Dictionary等知識讓我覺得這門課忽然變得有些難度,相關的排序、訪問什麼什麼的操作也不太能記得住,後面的正則表示式、類(面向物件程式設計)、socket(套接字)等知識更是使我在課上反應不過來,根據自己的理解就是檢索替換之類的功能、程式分類封裝使用、伺服器建立連線吧,只能心累地跟著老師做。反思一下,其實我在課後練習的時間也不夠,所以才會產生這樣的惡行迴圈。
但是結課之後,我通過做遊戲潛心學習了python的類和函式呼叫等知識,儘管自己寫程式還很吃力,但我逐漸理解了序列的使用和麵向物件程式設計的優勢和強大,原本無法理解、讓我絕望的知識也不過是邏輯框架下設定的工具而已,而且python本就是很方便使用的工具,我現在覺得很有自信繼續學好python這門語言了。所以我說“暫時無法理解的東西,會隨著學習的深入而自然瓦解”,就是這樣的道理。
然而經過一個學期的學習,我的收穫相對於老師的付出來說還是少了,但是我決定在假期、在之後的學期裡自行學習python,把學習這門語言作為我的階段目標。
課程體會和建議
王志強老師上課很幽默,而且是一位很負責、敬業的老師,我很喜歡上王老師的課。
我覺得課程後面進度太快了,儘管課後可以看雲班課上的檔案,正則表示式開始就不太能夠跟上,建議除了實驗作業之外應該多多佈置一些小作業來讓我們自行練習。
還有就是下學期還能開這門課就更好了。
參考資料:
[1]: 超適合小白練手的python小遊戲專案【飛機大戰】手把手教學
[2]:軟體開發|新增計分到你的 Python 遊戲 (linux.cn)
[3]:(18條訊息) Python 類的定義與使用_區域性最優解的部落格-CSDN部落格_python類的定義與使用
[4]:https://www.linuxidc.com/Linux/2017-01/139241.htm
[5]:https://www.freesion.com/article/73691086600/
[7]:https://www.jianshu.com/p/23ba123ee874
參考資料:
[1]: 超適合小白練手的python小遊戲專案【飛機大戰】手把手教學
[2]:軟體開發|新增計分到你的 Python 遊戲 (linux.cn)
[3]:(18條訊息) Python 類的定義與使用_區域性最優解的部落格-CSDN部落格_python類的定義與使用
[4]:https://www.linuxidc.com/Linux/2017-01/139241.htm
[5]:https://www.freesion.com/article/73691086600/
[7]:https://www.jianshu.com/p/23ba123ee874
[8]:Linux終端如何執行py檔案【python程式碼檔案】_pythonlamb的部落格-CSDN部落格_linux執行py檔案