20212115朱時鴻 《python程式設計》實驗四報告

  • 2022 年 5 月 29 日
  • 筆記

課程:《Python程式設計》
班級: 2121
姓名: 朱時鴻
學號:20212115
實驗教師:王志強
實驗日期:2022年5月28日
必修/選修: 公選課

 

1.實驗內容

Python綜合應用:爬蟲、數據處理、可視化、機器學習、神經網路、遊戲、網路安全等。
註:在華為ECS伺服器(OpenOuler系統)和物理機(Windows/Linux系統)上使用VIM、PDB、IDLE、Pycharm等工具編程實現。

2,實驗過程及結果

(一)實驗內容

編寫一個塔防遊戲,類似於保衛蘿蔔以及明日方舟那種。

(二)選題理由

因為本人對塔防遊戲情有獨鍾,所以自己想編寫一個塔防遊戲,但由於對python的學習空間剩餘的還很大,所以在網上找了許多的參考資料並且學習參考了教學影片才勉強完成,雖然不太完美,但對於自己來說也是一個挑戰自己的機會。

(三)實驗過程

1.首先購買一個華為雲伺服器

 

 

 

 

 

 

 

 這個步驟我在本專業的C語言課程中其實已提前完成,所以沒有花掉我多少的時間

2.下載pygame

 

 這個步驟我是通過在網上找找資料,然後根據熱心網友的回答解決的,但是在這個步驟的實現的過程我遇見了一個挺大的麻煩,就是明明我已經下載了pygame我在pycharm上運行時卻會顯示說我沒安裝pygame,這個問題困擾我很久,但好在課代表熱心能力有強,幫我解決了這個問題,原因是我的電腦里下列三個python

但是只有一個python是有pygame的,最終幫我換了一個編譯環境後解決了問題。(真的感謝課代表,我自己弄不知道要多久)

3.配置遠程桌面

這個步驟也是在課代表的提醒下弄得,課代表在群里說需要下載這個才可以在華為雲伺服器上運行,不然會報錯

 

 

 

首先在linux系統

在 Linux 系統安裝 X11 轉發的必要軟體包:

# yum install -y xauth
# yum install -y xclock

下載xterm和xauth,EularOS用如下命令

yum install xterm

yum install xauth
用vim編輯器打開(vi是vim的簡寫)網路設置,注意xming與putty之間是通過ssh協議通訊的

vi /etc/ssh/sshd_config
設置X11Forwarding yes
在vim編輯器中按i進入編輯模式,按Esc退出編輯,按:輸入wq退出vim
完成後退出putty

xming下載並安裝好後,在菜單欄找到xlaunch,一直點下一步至完成即可。之後打開putty輸入xterm即可看見窗口了。

 

 設置X11Forwarding yes

 

 下載xming

 

 

 

 最後為了成功運行xterm花了不少時間,通過上網查找教程和群里的文件,最終自己獨立完成,但運行成功出現自己的理想中的結果時,有點成就感

4.編寫程式碼過程及思路

首先塔防遊戲需要涉及地圖

# map1=[(50,14),(86,14),(135,14),(175,14),(180,47),(180,92),(215,92),(260,92),\
#       (302,94),(305,135),(306,174),(344,174),(392,174),(430,180),(430,139),\
#       (430,90),(430,51),(475,52),(516,52),(560,52),(560,94),(560,131),(560,166),\
#       (560,205),(560,247),(560,273),(560,307),(513,305),(469,305),(432,305),\
#       (387,305),(349,305),(300,305),(250,305),(200,305)]

#用分段函數來表示路徑,t從55開始
# def get_path(t):
#       if t<203 and t>50:
#             x=t
#             y=14
#             return [x,y]
#       elif t<286:
#             x=182
#             y=t-203+14
#             return [x,y]
#       elif t<403:
#             x=t-286+203
#             y=116
#             return [x,y]
#       elif t<487:
#             x=320
#             y=t-403+116
#             return [x,y]
#       elif t<633:
#             x=t-487+320
#             y=200
#             return [x,y]
#       elif t<770:
#             x=466
#             y=-(t-633)+200
#             return [x,y]
#       elif t<884:
#             x=t-770+466
#             y=63
#             return [x,y]
#       elif t<1277:
#             x=580
#             y=t-884+63
#             return [x,y]
#       elif t<1647:
#             x=-(t-1277)+580
#             y=330
#             return [x,y]
#       else:
#             pass#意思是不在路徑上

def get_path(t):
      if t<203 and t>50:
            x=t
            y=34
            return [x,y]
      elif t<286:
            x=203
            y=t-203+34
            return [x,y]
      elif t<403:
            x=t-286+203
            y=116
            return [x,y]
      elif t<487:
            x=320
            y=t-403+116
            return [x,y]
      elif t<633:
            x=t-487+320
            y=200
            return [x,y]
      elif t<770:
            x=466
            y=-(t-633)+200
            return [x,y]
      elif t<884:
            x=t-770+466
            y=63
            return [x,y]
      elif t<1177:
            x=580
            y=t-884+63
            return [x,y]
      elif t<1647:
            x=-(t-1177)+580
            y=330
            return [x,y]
      else:
            return [40,40]#意思是不在路徑上

然後再遊戲中也是需要音樂的,不然會讓遊玩者感到枯燥,所以加入了背景音樂

然後找了幾張防禦物,小怪物,地圖的圖來呈現

首先在塔防遊戲中,防禦物是需要攻擊怪物的,所以我們首先編寫攻擊物間的程式碼

import math
import random
import pygame
”’子彈類”’
class bullet1(pygame.sprite.Sprite):
    def __init__(self,pos_x,pos_y,angle):
        pygame.sprite.Sprite.__init__(self)
        #載入子彈的圖片
        image0 = pygame.image.load(‘./resource/imgs/game/arrow1.png’).convert_alpha()
        self.image1= pygame.transform.scale(image0,(24,24))
        #self.image=pygame.transform.rotate(self.image1,math.pi/3)
        #self.image=pygame.transform.rotate(self.image1,math.radians(45))

        self.image2 = pygame.transform.rotate(self.image1,45)
        self.image = pygame.transform.rotate(self.image2,-180*angle/math.pi)
        self.rect = self.image.get_rect()
        self.position = pos_x,pos_y
        self.begin_pos=pos_x,pos_y
        #self.begin_pos = self.position
        self.rect.left, self.rect.top = self.position
        # 與水平向左的直線所成的夾角, 順時針為正
        self.angle = angle#子彈的射擊角度
        self.speed=50#子彈的移動速度
        self.scope=400#子彈的射擊範圍
        self.attack_power=9#子彈的殺傷力

    ”’不停移動”’
    def move(self):

        self.rect.left = self.rect.left – self.speed * math.cos(self.angle)
        self.rect.top=self.rect.top – self.speed * math.sin(self.angle)
        #self.rect.left, self.rect.top = self.position
    ”’重置子彈的位置”’
    # def reset(self, position, angle=None):
    #   if angle is None:
    #       angle = random.random() * math.pi * 2
    #   self.position = position
    #   self.angle = angle
    #   self.rect = self.image.get_rect()
然後還需要設計被攻擊的怪物
import pygame
from maps import MAP
”’敵方類”’
class Monster1(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.image.load(‘./resource/imgs/game/monster.png’)
       
        self.rect = self.image.get_rect()
        self.t=55#已經走過的時間
        self.index1=0#目前所在路徑列表中的位置
        self.position = 60, 40
        self.rect.left, self.rect.top = self.position
        # 最大生命值
        self.max_life_value = 20
        # 當前生命值
        self.life_value = 20
        # 速度
        self.speed = 10
        # 擊殺獎勵
        self.reward = 70
        # 對大本營造成的傷害
        self.damage = 2

    def move(self):#移動怪物
        self.t+=self.speed
        self.rect.left,self.rect.top=MAP.get_path(self.t)[0]-20,MAP.get_path(self.t)[1]-20#修改位置
    def die(self):
         global monsters
         monsters = [monster for monster in monsters if monster.t>=1647]#列表中元素的刪除方式
         print(“monsters的類型是:”,type(monsters))
         print(len(monsters))

然後需要設計塔

import pygame
from sprites import Bullet
import math
import random

”’炮塔類”’
class Tower1(pygame.sprite.Sprite):

    def __init__(self,pos_x,pos_y,shot_angle,cooling_time):
                #shot_angle是射擊方向
        pygame.sprite.Sprite.__init__(self)
        #self.imgs = [‘./resource/imgs/game/basic_tower.png’, ‘./resource/imgs/game/med_tower.png’, ‘./resource/imgs/game/heavy_tower.png’]
        self.image = pygame.image.load(‘./resource/imgs/game/tower5.png’)
        self.rect = self.image.get_rect()
        self.cooling_time=cooling_time
        self.cooling_now=cooling_time#箭塔的冷卻時間
        self.shot_angle=shot_angle
        self.price=300#箭塔的價格
        self.position = pos_x,pos_y
        self.rect.left, self.rect.top = self.position
    ”’射擊”’
    def shot(self, position):#參數是子彈的位置和角度
        bullet = None
        #print(self.cooling_now)
        if self.cooling_now<=0:
            #angle = 2*math.pi*random.randint(0,360)/360#隨機生成箭的射擊方向
            #bullet=Bullet.bullet1(position[0],position[1],angle)
            #bullets.add(i.shot(i.position))
            self.cooling_now=self.cooling_time
            return 1
        else:
            self.cooling_now-=1
            return 0

    #   bullet = None
    #   if not self.is_cooling:
    #       bullet = Bullet.bullet1()#初始化一個子彈
    #       bullet.reset(position, angle)
    #       self.is_cooling = True#子彈重新進入冷卻時間
    #   if self.is_cooling:
    #       self.coolTime -= 1
    #       if self.coolTime == 0:#冷卻時間結束以後
    #           self.reset()
    #   return bullet
    ”’重置”’
    #def reset(self):
    #   self.price = 500
    #   # 射箭的冷卻時間
    #   self.coolTime = 30
    #   # 是否在冷卻期
    #   self.is_cooling = False

至此,最重要的幾個元素就設計完成了

 
然後完善來一下設計購買防置的金錢,自己家的生命值,怪物生命值等最大的框架
#隨機生成怪物
import pygame
from sprites import Monster
from sprites import Tower
from sprites import Bullet
from maps import MAP
import random
import os
from pygame.locals import*
from sys import exit
from random import*
import math
”’參數設置”’
WIDTH = 650
HEIGHT = 450
blood_color=(255,0,0)
blood_width=4
my_money=1000
monster_time=8#怪物出現的頻率
home_life_value=20#自己家的生命值
”’主函數”’
pygame.init()
pygame.mixer.init()
pygame.mixer.music.load(“./resource/music/back_ground_music.mp3”)
hit_sound = pygame.mixer.Sound(“./resource/music/s_hit.ogg”)
hit_sound.set_volume(0.1)
#pygame.mixer.music.load(“F:\defend_10\\td1_29\\resource\\music\\back_ground_music.mp3”)
#hit_sound = pygame.mixer.Sound(“F:\defend_10\\td1_29\\resource\\music\\s_hit.ogg”)#中箭的聲音
screen = pygame.display.set_mode((WIDTH, HEIGHT))
bg=(255,0,0)
background=pygame.image.load(‘./resource/imgs/game/map.jpg’).convert()#地圖
background0=pygame.image.load(‘./resource/imgs/game/ground0.JPG’).convert()#底色
pygame.display.set_caption(“塔防遊戲”)
clock = pygame.time.Clock()
#用列表存儲實例化以後的怪物,子彈,炮塔
monster=Monster.Monster1()
monsters =pygame.sprite.Group(monster)#建立怪物的精靈組
tower1=Tower.Tower1(200,200,2,3)
towers=pygame.sprite.Group(tower1)#建立一個箭塔精靈組
bullets=pygame.sprite.Group(Bullet.bullet1(200,200,3))#建立一個子彈的精靈組
font1 = pygame.font.SysFont(‘宋體’, 30, True)
def cal_dis(x1,y1,x2,y2):
    distance=math.sqrt(pow(x1-x2,2)+pow(y1-y2,2))
    return distance

def monster_move():
    for i in monsters:
        i.move()

def draw_blood():
    for i in monsters:
        start=(i.rect.left+10,i.rect.top-3)
        end=(i.rect.left+(i.life_value/i.max_life_value)*20+10,i.rect.top-3)
        pygame.draw.line(screen,blood_color,start,end,blood_width)

#碰撞檢測,檢測是否射中了怪物
def sprite_collide():
    global monsters
    global bullets
    global attack_power
    global my_money
    global home_life_value
    attack_power=10#默認的箭的殺傷力
    dict1=pygame.sprite.groupcollide(monsters, bullets, False,True, collided=None)
    for i in bullets:
        attack_power=i.attack_power
        if i.rect.top<0 or i.rect.left<0 or i.rect.top>HEIGHT or i.rect.left>WIDTH:
            bullets.remove(i)
            #hit_sound.play()
        else:
            pass

    for i in dict1:
        i.life_value-=attack_power
        hit_sound.play()
    for i in monsters:
        if i.life_value<=0:
            monsters.remove(i)
            my_money+=i.reward#殺死一個怪物獎勵一定的金錢
        elif i.rect.top>260 and i.rect.left<200:
            print(“怪物到達了你家”)
            home_life_value-=i.damage#對你家造成殺傷
            monsters.remove(i)
        else:
            pass
#在這裡面畫上當前金錢數,箭塔價格,城堡生命值
def draw_text():
    #screen.blit(surface1, [20, 20])
    #screen.blit(my_money,[400,400])
    screen.blit(font1.render(u’my money::%d’ % my_money, True, [255, 0, 0]), [350, 400])
    screen.blit(font1.render(u’home life_value::%d’ % home_life_value, True, [255, 0, 0]), [350, 430])

def move_bullet():
    global bullets
    for i in bullets:
        i.move()
        #判斷子彈是否超出射程,如果超出範圍就刪除這個子彈
        if cal_dis(i.position[0],i.position[1],i.begin_pos[0],i.begin_pos[1])>i.scope:
            bullets.remove(i)
        else:
            pass

def shot_bullet():
    for i in towers:
        k=i.shot(i.position)

        if k:
            angle = 2 * math.pi *randint(0, 360) / 360  # 隨機生成箭的射擊方向
            bullets.add(Bullet.bullet1(i.rect.left,i.rect.top,angle))
        else:
            pass

while True:
    for event in pygame.event.get():
        if event.type==pygame.QUIT:
            sys.exit()
        elif event.type == MOUSEMOTION:
            pos = pygame.mouse.get_pos()
            mouse_x = pos[0]
            mouse_y = pos[1]
        elif event.type==pygame.KEYDOWN:
            if event.key==pygame.K_d:
                #建立一個箭塔,在箭塔精靈組中添加一個箭塔
                if my_money>tower1.price:
                    towers.add(Tower.Tower1(mouse_x, mouse_y, math.pi, 7))
                    my_money -= tower1.price  # 建立一個箭塔消耗一定的金錢
                else:
                    print(“金錢不夠”)
            else:
                pass
                #建立一個箭塔,在滑鼠的當前位置
        else:
            pass
    if pygame.mixer.music.get_busy()==False:
        pygame.mixer.music.play()
    else:
        pass
    if randint(0,100)<monster_time:
        #產生一個怪物
        monsters.add(Monster.Monster1())
    else:
        pass
    monster_move()#移動精靈組
    shot_bullet()#射箭
    sprite_collide()
    move_bullet()
    monsters.update()
    towers.update()
    bullets.update()
    screen.blit(background0, (0, 0))
    screen.blit(background, (0, 0))
    draw_blood()
    draw_text()
    monsters.draw(screen)
    towers.draw(screen)
    bullets.draw(screen)

    clock.tick(4)
    pygame.display.update()
 
在ecs主機上運行
首先通過winscp上傳文件程式碼

 

 首先在本地運行

 

 然後是在ecs上面運行

 

 

 在這個上運行有點慢

(五)實驗中所遇到的問題及解決方法

1.在下載pygame後在本地運行是卻顯示沒有這個插件

解決方法:換了一個編譯環境,發現有三個不同的python,但是只有一個pygame所以換了那個有pygame插件的python

2.最開始在華為雲商運行時沒有畫面,且會報錯

解決方案:通過課代表在群里的提醒後,下載了一個xming,完美解決了這個問題

3.一開始將程式碼上傳後,但是會出錯

解決方案:再請教同學後,知道了不能上傳聲音,不然會出錯,然後將和聲音有關的程式碼全部屏蔽了,成功上傳

(六)實驗的感悟

通過本次實驗我明白了一個道理:沒有最好只有更好,每次解決了一個問題後,總會有另一個問題冒出來,這也間接證明我在知識點上面的欠缺。

在問題的發現解決中,我自己的能力也得到了許多的提升,在這個過程挺感謝課代表的幫助,相信通過這次的作業,我以後在編寫遊戲以及對華為雲的運用上面一定會更加的得心應手。

參考資料:B站教學影片

                課代表以及多位熱心同學的幫助

結課感想與體會

python是一門非常有潛力的高級語言,歷經多年的發展,其在編程上發揮著越來越大的作用。在這學期中,通過選修python課上的基礎知識學習,我對python也有了一定的認識。而且,在字元串上的處理,python相對於c語言也是給程式設計師極大的便利。而python不僅如此,它的庫也很多,正因為它強大的庫,讓編程變得不再艱難。但是,我認為python雖然在許多方面相對於c語言比較方便,但也有其相對於弱一點的方面,比如說for循環等方面。雖然一學期下來,我對python的學習也僅僅只是它的基礎方面,但python的強大,也是足足地吸引著我,希望自己能夠在不斷地學習中,將python學習的更加好。 python是一門非常有潛力的高級語言,歷經多年的發展,其在編程上發揮著越來越大的作用。在這學期中,通過選修python課上的基礎知識學習,我對python也有了一定的認識。

在學習python的第一節課上,其對我的最初的印象就是,相較於我學習過的c語言編程,它更加的簡潔。所有的變數都不需要像c語言編程那樣需要提前去定義,這樣給了編程者很大的自由空間與方便。如x=2,即可同時完成變數的定義與賦值。對於簡化程式的程式碼,起到了許多的作用。而且,在字元串上的處理,python相對於c語言也是給程式設計師極大的便利。在c語言中,只能用字元類的數組對字元串進行相應的操作,步驟也是相對於比較繁瑣的,而在python中,當我們需要創建一個字元串的時候,只需要在創建字元串的時候用”s=」就可以了。而python不僅如此,它的庫也很多,正因為它強大的庫,讓編程變得不再艱難。我們只需要調用庫中的函數,而對於函數的具體實現,也沒有特殊的需求。

但是,我認為python雖然在許多方面相對於c語言比較方便,但也有其相對於弱一點的方面,比如說for循環等方面。不過也依然不會影響到python的強大,而隨著近幾年來的發展,python的受歡迎度也越來越高,而它的運用的領域也是越來越多,比如人工智慧和大數據等領域,python都是在其中扮演者重要的角色。雖然一學期下來,我對python的學習也僅僅只是它的基礎方面,但python的強大,也是足足地吸引著我,希望自己能夠在不斷地學習中,將python學習的更加好。

在王老師的教導下,我覺得自己比起剛開始上課啥也不懂的小白可謂是強了不止一星半點,而且更為重要的是通過王老師得我教導,我對python的興趣更加的濃厚了

真的挺感謝王老師,教科好而且有責任心,您的課我覺得也非常風趣幽默,上起來沒有其他一些課的枯燥乏味,我知道python的學習還只是冰山一角,但相信通過王老師這一學期的引領,我在以後的學習中一定會得心應手,若果以後還有王老師的課,我一定還會選的(真)。