1. 程式人生 > 其它 >20212109施鋮哲 《Python程式設計》實驗四 Python綜合實踐實驗報告

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/

[6]:https://www.daehub.com/archives/9949.html#:~:text=%E5%85%B6%E4%B8%AD%20PuTTY%20%E6%98%AF%20SSH%20%E5%AE%A2%E6%88%B7%E7%AB%AF%EF%BC%8C%E8%80%8C,Xming%20%E5%88%99%E6%98%AF%20Windows%20%E5%B9%B3%E5%8F%B0%E7%9A%84%20X%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E3%80%82

[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/

[6]:https://www.daehub.com/archives/9949.html#:~:text=%E5%85%B6%E4%B8%AD%20PuTTY%20%E6%98%AF%20SSH%20%E5%AE%A2%E6%88%B7%E7%AB%AF%EF%BC%8C%E8%80%8C,Xming%20%E5%88%99%E6%98%AF%20Windows%20%E5%B9%B3%E5%8F%B0%E7%9A%84%20X%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E3%80%82

[7]:https://www.jianshu.com/p/23ba123ee874

[8]:Linux終端如何執行py檔案【python程式碼檔案】_pythonlamb的部落格-CSDN部落格_linux執行py檔案