20202219 实验四《Python程序设计》实验报告

#20202219 《2022Python程序设计》实验四报告

课程:《Python程序设计》
班级: 2022
姓名: 吴坤泽
学号:20202219
实验教师:王志强
实验日期:2020年5月19日
必修/选修: 公选课

## 1.实验内容
  (一)Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。

  (二)实验要求:

  (1)程序能运行,功能丰富。(需求提交源代码,并建议录制程序运行的视频)10分
  (2)综合实践报告,要体现实验分析、设计、实现过程、结果等信息,格式规范,逻辑清晰,结构合理。10分。
  (3)在实践报告中,需要对全课进行总结,并写课程感想体会、意见和建议等。5分

  (4)如果没有使用华为云服务(ECS或者MindSpore均可),本次实践扣10分。


## 2. 实验过程及结果

  首先,我选择的是制作一个简单的植物大战僵尸的小游戏,因为没有过游戏开发的经历,所以先从网上找教程先看。了解到需要pygame这个包来开发游戏,所以就先在Pycharm里安装pygame这个包,方便后续开发:

 

 

   

  安装好这个包之后,要尽量做出植物大战僵尸的效果的话,初步设计的框架如下:

   当然,除了主程序调用这些类之外,每个子类里都还要从文件夹里调用各自的贴图,有各自的属性。这个简单的植物大战僵尸的游戏我就只先设计了三种植物和两种僵尸,植物分别是:向日葵,豌豆射手和坚果墙;僵尸是普通僵尸和橄榄球僵尸。然后需要植物大战僵尸摆放植物的背景,所需植物和僵尸的图片,产生阳光的图片,这些图片(png格式)或者动态图片(gif格式)我从https://www.aigei.com/网站上找到了素材,并下载下来(gif图片在pycharm里调用的时候好像只能显示图片的第一帧,解决办法后面在叙述),图片保存在一个文件夹里:     ps.坚果的图片我稍微p了一下

   找好需要的图片后,根据框架图,需要创建一个主程序,然后一个Nust类,一个Peashoot类,一个SunFlower类,一个Zoombie类,一个FootballZoombie类然后考虑到向日葵要产生太阳,豌豆射手种植下来后要发射子弹,所以就还需要定义两个类:Sun类和Bullet类。创建好如下:

   然后考虑到游戏不能一直运行,需要胜利的条件,这里我将收集阳光数量到多少作为胜利条件,当收集的阳光到达5000,那么游戏胜利。

  大致的构思如上,期间遇到的难点及解决方法在下面介绍程序时介绍。

  然后开始编辑程序:

   improt pygame这个包后,先要pygame.init()初始化程序,因为需要将阳光的数值做成贴图放在背景图上,这时候需要用到电脑的R,G,B配色格式,黑色为(0,0,0),所以定义BLACK = (0,0,0),然后根据我想放置的背景图的大小,定义一个back_size = (1100,600),来放置背景图片。

BLACK = (0,0,0)
back_size =(1100,600)

screen = pygame.display.set_mode(back_size)
pygame.display.set_caption('植物大战僵尸')

   然后在其上面放置背景图片:   ps.这里的.convert_alpha()是为了防止图片出现锯齿。

#背景图片路径
backimages_path = 'material/background1.jpg'
backimages_objet = pygame.image.load(backimages_path).convert_alpha()

   然后我定义了初始的阳光值,为200,sun_num_object就是一个贴图对象了,后面根据背景图和种子银行的位置调像素,使其在合适地位置:

text = '200'
sun_font = pygame.font.SysFont('arial',25)
sun_num_object = sun_font.render(text,True,BLACK)

   然后开始def main:因为游戏一直在进行,所以可以用一个while循环来控制,可以先定义一个running变量 = Ture,while running就会一直运行,当游戏胜利或者点击退出之后,running = False,那么循环就会停止。但是在IDLE中有一个bug,如果一个Pygame程序在调用pygame.quit()之前就终止了,将会导致IDLE挂起。所以后面我就采用了sys.exit()来关闭窗口。

def main():
    running = True
    index = 0
    while running:

        #这个if循环防止因为这个whlie是死循环,只要不点击关闭窗口,index就会无限大,导致溢出
        if index >+ 3743:
            index = 0

        clock.tick(12)

        screen.blit(backimages_objet,(0,0))
        screen.blit(seadbank_object,(250,0))
        screen.blit(sun_num_object,(270,60))  #阳光数量
        screen.blit(pearshoot_card,(381,5))
        screen.blit(sunflower_card,(325,5))
        screen.blit(nust_card,(437,5))

        index += 1
        for event in pygame.event.get():  # 退出,
            if event.type == GEN_SUN_EVENT:  #生成阳光,用太阳事件
                for spirst in sunflowerGroup:
                    now = time.time()
                    if now - spirst.lasttime >= 8:
                        sun = Sun(spirst.rect)  # 将太阳花的位置属性传给Sun函数
                        sunList.add(sun)
                        spirst.lasttime = now

            if event.type == GEN_BULLET_EVENT:  #生成子弹,用子弹事件
                for spirst in pearshootGroup:
                    bullet = Bullet(spirst.rect, back_size)
                    bulletGroup.add(bullet)

            if event.type == GEN_ZOOMBIE_EVENT:  #生成僵尸事件
                zombie = Zoombie()
                zoombieGroup.add(zombie)

            if event.type == GEN_FOOTBALLZOOMBIN_EVENT:  #生成橄榄球僵尸事件
                footballzoombie = FootballZoombie()
                zoombieGroup.add(footballzoombie)

            if event.type == pygame.QUIT:
                sys.exit()

   这里已经涉及到精灵组了,因为一开始我也不太清楚怎么让我的这些植物和僵尸动起来,然后去网上找资料,了解到,精灵组是pygame自带的,可以存储所有

精灵变量,也就是我的植物和僵尸,然后让精灵组在每个循环都更新一下,屏幕上的画面也更新一下,那么图片就可以动起来。所以我还定义了一个index的变量,每次循环加一。加这一行代码clock.tick(12)是为了控制1秒刷新此数为12,也就是帧率12,如果不限制的话,我的电脑测试的峰值是5000fps,那么我的植物和僵尸就会抖动地很厉害。下图是一开始在测试pygame的时候编的ceshi程序,顺便测了一下电脑fps峰值

 

 

  下面是一开始初步测试的时候,如果没有限制帧率,就会抖得很厉害,限制后,就正常了:可以看到,这时只是将这个豌豆射手贴图固定在一个位置,并不能进行发射豌豆以及鼠标拖动进行种植。

  同时说到精灵组,如果让所有植物和僵尸都在同一个精灵组的话,那么后面进行碰撞检测的话就比较麻烦,因为需要从精灵组里面用for循环遍历精灵,那么就不好区分是否是植物和僵尸碰撞上了,也就不好进行后面僵尸停下进行啃食植物的操作和植物扣血的操作。所以我定义了以下的精灵组:在子类需要继承精灵类。

#定义精灵组对象(因为太阳点击需要消失,所以单独再定义一个太阳精灵组)

bulletGroup = pygame.sprite.Group() #子弹精灵组
zoombieGroup = pygame.sprite.Group() #僵尸精灵组
nustGroup = pygame.sprite.Group() #坚果精灵组
pearshootGroup = pygame.sprite.Group() #豌豆射手精灵组
sunflowerGroup = pygame.sprite.Group() #太阳花精灵组
sunList = pygame.sprite.Group()

   再说到上面一开始说到的问题,直接调用gif图片,图片并不能做到动起来,所以我竟gif图片放进ps,一帧一帧地导出来,再根据while循环每次更新屏幕内容时播放下一张,依次循环,如果播放到最后一张,就要播放第一张,就可以用取模运算实现。下图是一开始测试直接放的僵尸地gif图,运动并不能显示走路地=的样子:

   后面按上诉方法改动之后就可以了。

  然后开始编辑子类:

SunFlower类:

import pygame

class SunFlower(pygame.sprite.Sprite) :
    def __init__(self,lasttime):
        super(SunFlower,self).__init__()
        self.image = pygame.image.load('material/SunFlower00.png').convert_alpha()
        self.images = [pygame.image.load('material/SunFlower{:02d}.png'.format(i)).convert_alpha() for i in range(0,17)]   #这里实现了图片的动态


        self.rect = self.images[0].get_rect()
        self.lasttime = lasttime
        self.energy = 2*15
        self.zombies = set()

    def update(self, *args):
        for zombie in self.zombies:
            if zombie.isAlive == False:
                continue
            self.energy -= 1

        if self.energy <= 0:
            for zombie in self.zombies:
                zombie.isMeetnust = False
            self.kill()

        self.image = self.images[args[0] % len(self.images)]

 Sun类:

import pygame
import random

class Sun(pygame.sprite.Sprite) :
    def __init__(self,rect): #定义一个rect是为了多一个位置属性??(用来接收放置的太阳花的位置)
        super(Sun,self).__init__()
        self.images = pygame.image.load('material/Sun00.png').convert_alpha()
        self.images = [pygame.image.load('material/Sun{:02d}.png'.format(i)).convert_alpha() for i in range(0,10)]

        self.rect = self.images[0].get_rect()

        #定义一个偏移量,增加随机性,因为太阳要从太阳花的周围随机产生
        offsetTop = random.randint(-50,50)
        offsetLeft = random.randint(-50,50)

        self.rect.top = rect.top + offsetTop
        self.rect.left = rect.left + offsetLeft

    def update(self, *args):
        self.image = self.images[args[0] % len(self.images)]

   因为太阳花和太阳联系比较紧密,如果种植了太阳花,那么就应该会过一段时间生成太阳,所以定义Sun类的时候,会有传进来一个参数,就是太阳花种植的像素位置,以此来对生成太阳的位置进行定位。上面我采用了random,因为太阳生成是在太阳花周围生成,所以定义偏移量,然后再定义self.rect.top和left来接收位置。SunFlower类中定义了update函数,用来啥和进行各种判定的实现,里面有对其血量时候该减少的判断。

Peashoot类:

import pygame

class Peashoot((pygame.sprite.Sprite)) :
    def __init__(self):
        super(Peashoot,self).__init__()
        self.image = pygame.image.load('material/pearshoot00.png').convert_alpha()
        self.images = [pygame.image.load('material/pearshoot{:02d}.png'.format(i)).convert_alpha() for i in range(0,12)]


        self.rect = self.images[0].get_rect()
        #self.rect.top = 85
        #self.rect.left = 250
        self.energy = 3*15
        self.zombies = set()

    def update(self, *args):
        for zombie in self.zombies:
            if zombie.isAlive == False:
                continue
            self.energy -= 1

        if self.energy <= 0:
            for zombie in self.zombies:
                zombie.isMeetnust = False
            self.kill()

        self.image = self.images[args[0] % len(self.images)]

Bullet类:

import pygame

class Bullet(pygame.sprite.Sprite) :
    def __init__(self,peashoot_rect,screen_size):
        super(Bullet,self).__init__()
        self.image = pygame.image.load('material/Bullet.png').convert_alpha()
self.rect = self.image.get_rect() #定义子弹的初始化位置 self.rect.left = peashoot_rect[0] + 50 #因为传进来是一个元组,元组的第0位就是left,同样,下面那行代码就是传进来的top self.rect.top = peashoot_rect[1] + 4 self.width = screen_size[0] #定义子弹的射程,因为就只能屏幕那么宽 self.speed = 8 def update(self, *args): if self.rect.right < self.width: self.rect.left += self.speed else: self.kill()

Zoombie类:

import pygame
import random

class Zoombie((pygame.sprite.Sprite)) :
    def __init__(self):
        super(Zoombie,self).__init__()
        self.image = pygame.image.load('material/zombin1.png').convert_alpha()
        self.images = [pygame.image.load('material/zombin{}.png'.format(i)).convert_alpha() for i in range(1,23)]
        self.dieimages = [pygame.image.load('material/ZombieDie{:02d}.png'.format(i)).convert_alpha() for i in range(0,10)]
        self.attack_images = [pygame.image.load('material/ZombieAttact{:02d}.png'.format(i)).convert_alpha() for i in range(0,21)]


        self.rect = self.images[0].get_rect()
        self.rect.top = 50 + random.randrange(0,5)*90 #随机生成僵尸在任意一行
        self.rect.left = 1000
        self.speed = 1  #僵尸行走速度
        self.energy = 6 #僵尸血量
        self.dietimes = 0 #可以看成帧数
        self.isMeetnust = False
        self.isAlive = True


    def update(self, *args):
        if self.energy > 0:
            if self.isMeetnust:
                self.image = self.attack_images[args[0] % len(self.attack_images)]
            else:
                self.image = self.images[args[0] % len(self.images)]

            if self.rect.left > 250 and not self.isMeetnust:
                self.rect.left -= self.speed
        else:
            if self.dietimes < 10:
                self.image = self.dieimages[self.dietimes]
                self.dietimes += 1
            else:
                if self.dietimes > 24 :
                    self.isAlive = False
                    self.kill()
                else:
                    self.dietimes += 1

 FootballZoombie类:

import pygame
import random
from Zoombie import Zoombie

class FootballZoombie(Zoombie) :
    def __init__(self):
        super(FootballZoombie,self).__init__()
        self.image = pygame.image.load('material/FootballZombie00.png').convert_alpha()
        self.images = [pygame.image.load('material/FootballZombie{:02d}.png'.format(i)).convert_alpha() for i in range(0,11)]
        self.dieimages = [pygame.image.load('material/FootballZoombieDie{:02d}.png'.format(i)).convert_alpha() for i in range(0, 7)]

        # self.rect = self.images[0].get_rect()
        self.rect.top = 40 + random.randrange(0,5)*80 #随机生成僵尸在任意一行
        # self.rect.left = 1000
        self.energy = 15
        self.speed = 2  #僵尸行走速度


    def update(self, *args):
        if self.energy > 0:
            self.image = self.images[args[0] % len(self.images)]
            if self.rect.left > 250 and not self.isMeetnust:
                self.rect.left -= self.speed
        else:
            if self.dietimes < 7:
                self.image = self.dieimages[self.dietimes]
                self.dietimes += 1
            else:
                if self.dietimes > 20 :
                    self.kill()
                else:
                    self.dietimes += 1

   因为橄榄球僵尸和普通僵尸有一定的相似性,所以就用了继承,如果自身变量有不一样的,再在子类中重新定义就好

Nust类:

import pygame


class Nust(pygame.sprite.Sprite) :
    def __init__(self):
        super(Nust,self).__init__()
        self.image = pygame.image.load('material/nust00.png').convert_alpha()
        self.images = [pygame.image.load('material/nust{:02d}.png'.format(i)).convert_alpha() for i in range(0,15)]
        self.crackedImage = [pygame.transform.smoothscale(pygame.image.load('material/nust00.png').convert_alpha(),(self.image.get_rect().width,self.image.get_rect().height)),
                             pygame.transform.smoothscale(pygame.image.load('material/Wallnut_cracked1.png').convert_alpha(),(self.image.get_rect().width,self.image.get_rect().height)),
                             pygame.transform.smoothscale(
                                 pygame.image.load('material/Wallnut_cracked2.png').convert_alpha(),
                                 (self.image.get_rect().width, self.image.get_rect().height))]

        self.rect = self.images[0].get_rect()
        self.energy = 8*15   #坚果血量
        self.zombies = set()

    def update(self, *args):
        for zombie in self.zombies:
            if zombie.isAlive == False:
                continue
            self.energy -= 1

        if self.energy <= 0:
            for zombie in self.zombies:
                zombie.isMeetnust = False

            self.kill()

        if 6*15<self.energy<=8*15:
            self.image = self.images[args[0] % len(self.images)]
        elif 4*15<self.energy<=6*15:
            self.image = self.crackedImage[1]
        else:
            self.image = self.crackedImage[2]

   僵尸类和坚果类联系比较紧密,因为如果坚果挡住了僵尸行进,那么僵尸就要从走路变成停下来啃食坚果,同时坚果也开始扣血,如果血量少到一定程度那么坚果会变破损(就相当于要换贴图),所以就定义self.energy来赋予植物和僵尸血量,然后根据碰撞检测,来判定是不是僵尸被子弹击中扣血,还是植物被咬扣血。僵尸类中的dietimes可以让死去的动画根据数值变慢,不然直接动画变成倒下的动画太快了。

  子类定义完了,现在来看主函数:

import pygame
from pygame.locals import *
import os
import tkinter
import threading
import time
import sys
from Peashoot import Peashoot
from SunFlower import SunFlower
from Nust import Nust
from Sun import Sun
from Zoombie import Zoombie
from Bullet import Bullet
from FootballZombie import FootballZoombie


pygame.init()

BLACK = (0,0,0)
back_size =(1100,600)

screen = pygame.display.set_mode(back_size)
pygame.display.set_caption('植物大战僵尸')

#初始化音乐模块
pygame.mixer.init()
pygame.mixer.music.load('material/s.mp3')#加载音乐

#背景图片路径
backimages_path = 'material/background1.jpg'
backimages_objet = pygame.image.load(backimages_path).convert_alpha()

#种子银行路径
seadbank_path = 'material/seadbank.png'
seadbank_object = pygame.image.load(seadbank_path).convert_alpha()
#定义卡片
sunflower_card = pygame.image.load('material/sunflower_card.png')
nust_card = pygame.image.load('material/nust_card.png')
pearshoot_card = pygame.image.load('material/pearshoot_card.png')

#定义太阳花图片类型
sunflower_image = pygame.image.load('material/SunFlower00.png').convert_alpha()
#定义坚果墙图片类型
nust_image = pygame.image.load('material/nust00.png').convert_alpha()
#定义豌豆射手图片类型
pearshoot_image = pygame.image.load('material/pearshoot00.png').convert_alpha()

#定义初始阳光
text = '200'
sun_font = pygame.font.SysFont('arial',25)
sun_num_object = sun_font.render(text,True,BLACK)


#定义时钟,不然刷新太快豌豆抖得厉害
clock = pygame.time.Clock()

#定义精灵组对象(因为太阳点击需要消失,所以单独再定义一个太阳精灵组)
bulletGroup = pygame.sprite.Group() #子弹精灵组
zoombieGroup = pygame.sprite.Group() #僵尸精灵组
nustGroup = pygame.sprite.Group() #坚果精灵组
pearshootGroup = pygame.sprite.Group() #豌豆射手精灵组
sunflowerGroup = pygame.sprite.Group() #太阳花精灵组
#spirtGroup.add(pearshoot)
#spirtGroup.add(sunflower)
#spirtGroup.add(nust)
#spirtGroup.add(zoombins)

sunList = pygame.sprite.Group()

GEN_SUN_EVENT = pygame.USEREVENT + 1 #定义阳光事件
pygame.time.set_timer(GEN_SUN_EVENT,1000) #7000就是7秒

GEN_BULLET_EVENT =pygame.USEREVENT + 2 #定义射出子弹事件
pygame.time.set_timer(GEN_BULLET_EVENT,1000)

GEN_ZOOMBIE_EVENT =pygame.USEREVENT + 3 #定义僵尸出现事件
pygame.time.set_timer(GEN_ZOOMBIE_EVENT,7000)

GEN_FOOTBALLZOOMBIN_EVENT =pygame.USEREVENT + 4 #定义橄榄球僵尸出现事件
pygame.time.set_timer(GEN_FOOTBALLZOOMBIN_EVENT,17000)

choose = 0

def main():
    global sun_num_object  #指定成global才能修改全局变量

    global text,choose,zombie
    running = True
    index = 0
    while running:

        #这个if循环防止因为这个whlie是死循环,只要不点击关闭窗口,index就会无限大,导致溢出
        if index >+ 3743:
            index = 0

        clock.tick(12)
        if not pygame.mixer.music.get_busy():
            pygame.mixer.music.play()  #音乐播放

        for nust in nustGroup:             #坚果和僵尸碰撞检测
            for zombie in zoombieGroup:
                if pygame.sprite.collide_mask(nust,zombie):
                    nust.zombies.add(zombie)
                    zombie.isMeetnust = True



        for bullet in bulletGroup:          #子弹和僵尸碰撞检测
            for zombie in zoombieGroup:
                if pygame.sprite.collide_mask(bullet,zombie):
                    bulletGroup.remove(bullet)
                    zombie.energy -= 1

        for pearshoot in pearshootGroup:           #豌豆射手和僵尸碰撞检测
            for zombie in zoombieGroup:
                if pygame.sprite.collide_mask(pearshoot,zombie):
                    zombie.isMeetnust = True  #虽然这里是遇见坚果属性,但是这只是一个变量,让僵尸停下来
                    pearshoot.zombies.add(zombie)

        for sunflower in sunflowerGroup:           #太阳花和僵尸碰撞检测
            for zombie in zoombieGroup:
                if pygame.sprite.collide_mask(sunflower,zombie):
                    zombie.isMeetnust = True  #虽然这里是遇见坚果属性,但是这只是一个变量,让僵尸停下来
                    sunflower.zombies.add(zombie)

        screen.blit(backimages_objet,(0,0))
        screen.blit(seadbank_object,(250,0))
        screen.blit(sun_num_object,(270,60))  #阳光数量
        screen.blit(pearshoot_card,(381,5))
        screen.blit(sunflower_card,(325,5))
        screen.blit(nust_card,(437,5))

        #spirtGroup.update(index)
        #spirtGroup.draw(screen)

        sunList.update(index)
        sunList.draw(screen)

        zoombieGroup.update(index)
        zoombieGroup.draw(screen)

        bulletGroup.update(index)
        bulletGroup.draw(screen)

        nustGroup.update(index)
        nustGroup.draw(screen)

        pearshootGroup.update(index)
        pearshootGroup.draw(screen)

        sunflowerGroup.update(index)
        sunflowerGroup.draw(screen)

        (x,y) = pygame.mouse.get_pos()
        if choose == 1:
            screen.blit(sunflower_image,(x,y))
        elif choose == 3:
            screen.blit(nust_image,(x,y))
        elif choose == 2:
            screen.blit(pearshoot_image,(x,y))
        else:
            pass

        index += 1
        for event in pygame.event.get():  # 退出,
            if event.type == GEN_SUN_EVENT:  #生成阳光,用太阳事件
                for spirst in sunflowerGroup:
                    now = time.time()
                    if now - spirst.lasttime >= 8:
                        sun = Sun(spirst.rect)  # 将太阳花的位置属性传给Sun函数
                        sunList.add(sun)
                        spirst.lasttime = now

            if event.type == GEN_BULLET_EVENT:  #生成子弹,用子弹事件
                for spirst in pearshootGroup:
                    bullet = Bullet(spirst.rect, back_size)
                    bulletGroup.add(bullet)

            if event.type == GEN_ZOOMBIE_EVENT:  #生成僵尸事件
                zombie = Zoombie()
                zoombieGroup.add(zombie)

            if event.type == GEN_FOOTBALLZOOMBIN_EVENT:  #生成橄榄球僵尸事件
                footballzoombie = FootballZoombie()
                zoombieGroup.add(footballzoombie)

            if event.type == pygame.QUIT:
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN: #当鼠标按下的时候,获取鼠标按下键
                press_key = pygame.mouse.get_pressed()
                # print(press_key)  #等会儿可以注释掉
                if press_key[0] == 1:
                    pos = pygame.mouse.get_pos()  #得到鼠标按下的位置
                    print(pos)
                    x,y = pos
                    if 325<=x<=378 and 5<=y<=85 and int(text)>=50:
                        print("点中了太阳花卡片")
                        choose = 1
                    elif 381<=x<=434 and 5<=y<=85 and int(text)>=100:
                        print("点中了豌豆射手卡片")
                        choose = 2
                    elif 437<=x<=490 and 5<=y<=85 and int(text)>=50:
                        print("点中了坚果卡片")
                        choose = 3
                    elif 250<=x<=1100 and 70<=y<=580:
                        #种植植物:
                        if choose == 1:
                            current_time = time.time()
                            sunflower = SunFlower(current_time)
                            sunflower.rect.top = y
                            sunflower.rect.left = x
                            sunflowerGroup.add(sunflower)
                            choose = 0
                            #种植后,要扣除相应的分数
                            text = str(int(text) - 50)
                            sun_font = pygame.font.SysFont('arial', 25)
                            sun_num_object = sun_font.render(text, True, BLACK)
                        elif choose == 3:
                            nust = Nust()
                            nust.rect.top = y
                            nust.rect.left = x
                            nustGroup.add(nust)
                            choose = 0
                            #种植后,要扣除相应的分数
                            text = str(int(text) - 50)
                            sun_font = pygame.font.SysFont('arial', 25)
                            sun_num_object = sun_font.render(text, True, BLACK)
                        elif choose == 2:
                            pearshoot = Peashoot()
                            pearshoot.rect.top = y
                            pearshoot.rect.left = x
                            pearshootGroup.add(pearshoot)
                            choose = 0
                            text = str(int(text) - 100) #豌豆射手扣除100
                            sun_font = pygame.font.SysFont('arial', 25)
                            sun_num_object = sun_font.render(text, True, BLACK)

                    else:
                        pass

                    for sun in sunList:
                        if sun.rect.collidepoint(pos):  #太阳花和这个点击点冲突
                            sunList.remove(sun)    #就消除阳光
                            text = str(int(text)+50)
                            sun_font = pygame.font.SysFont('arial', 25)
                            sun_num_object = sun_font.render(text, True, BLACK)


        pygame.display.update()

        a = int(text)
        if a >= 5000:
            root = tkinter.Tk()
            root.title('Win')
            root['width'] = 400
            root['height'] = 300
            # 不允许改变窗口的大小
            root.resizable(False, False)

            richText = tkinter.Text(root, width=380)
            richText.place(x=10, y=10, width=380, height=230)
            richText.insert('0.0', '你赢啦!')

            lbTime = tkinter.Label(root, fg='red', anchor='w')
            lbTime.place(x=10, y=250, width=150)

            def autoClose():
                for i in range(2):
                    lbTime['text'] = '距离窗口关闭还有{}秒'.format(2 - i)
                    time.sleep(1)
                root.destroy()

            t = threading.Thread(target=autoClose)
            t.start()
            root.mainloop()
            pygame.quit()
            os._exit(0)

if __name__ == '__main__':
    main()

   主函数中,我定义了一些事件(这里需要注意一下,因为pygame中自带事件,所以自己定义的事件后面需要加一个数),下面运行的时候,会进行判定,例如,如果子弹发射事件开始,那么豌豆射手就会发射一个豌豆。同时,我也用到了pygame中.mouse方法,我用到的就是当鼠标点击的时候,可以判断是鼠标的左键、中键还是右键点击;也可以获得点击屏幕中像素坐标的位置(这里说明一下,游戏界面中,以向右为正,向下为正)。然后用到了上面说到的碰撞检测(在上面代码中main函数下面的四个for循环中),如果贴图碰在了一起(也就是说像素有重合),那么就会根据判断改变相应类中的变量的值,从而达到整个效果。

  还有在编程过程中,那个设的text变量,用来存储一开始的太阳数量,因为当你种植物或者点击太阳的时候,sun_num_object调用ttext就会报错,后面经过网上的查询,发现是这个变量不是global型不能改变,在main函数里面将其定义为global型就可以了。

然后购买华为云服务器:

  按照此配置购买华为云服务器:

  

  购买好后如图: 

   然后先用Winscp登录云服务器,登陆进去的页面如图:

   然后创建一个python文件夹。如上图,已创建。

  然后把代码整个文件夹传输过去(包括png,mp3等文件),传输好后如图:

 

 

   然后用Putty进入:

  然后输入python,发现已经自带python2.7.

  接下来就在云服务器上运行代码:

 在这里我遇到了一点问题,因为华为云服务器里调用pygame时要在屏幕输出,所以根据网上的解决办法,下载了Xming,然后在其上运行:

 

 

 

## 3. 实验过程中遇到的问题和解决过程
- 问题1:gif图在pycharm里只显示一帧
- 问题1解决方案:用ps将gif图每一帧保存,然后根据更新刷新
- 问题2:本次实验最大的难点:华为云服务器上运行代码的时候,不能屏幕输出游戏的画面
- 问题2解决方案:上网查找解决方案

 

## 其他(感悟、思考等)
  通过本次实验,我自学了python简单的游戏开发,也知道了pygame包的调用以及使用,同时也巩固了子类的继承。当游戏画面成功运行的时候,真的非常有成就感。

 

## 参考资料

- _tkinter.TclError: no display name and no $DISPLAY environment variable

  https://www.jianshu.com/p/23ba123ee874

- Putty+Xming远程登录Ubuntu 16.04图形界面

  https://www.linuxidc.com/Linux/2017-01/139241.htm

- Xming下载

  https://pan.baidu.com/s/1wMDA-8zqd8eiu6iGWGPqFQ?_at_=1653577595955

 

##结课感想与体会

  记得我第一次接触Python是在高三的寒假,当时还自己买了python的书自学。但因为高考的原因就没继续学下去,但在那个时候对编程的喜欢就已经在我心里发芽了。上了大学后,非常幸运能进入自己感兴趣的专业学习,也接触了各种各样的语言,在系统性地和老师学习了python后,我发现python比其它语言都要简洁方便,python功能非常强大,同时,它开发游戏这一块我也比较感兴趣。所以,在期末的实验中,我选择了制作一款小游戏。

  虽然制作的比较简陋,能实现的功能也不多,但是在自学过程中,我学会了先搭建整个游戏的框架,然后根据框架添砖加瓦,不断修改完善,也知道了python游戏开发的大致固定模式。

  同时,我也非常感谢王老师这一学期的辛苦付出,不仅把每个知识点都讲的很清楚,还很多次手把手一步一步敲代码给我们看,带着我们一起敲代码,让我收获颇丰。

  最后,希望我自己将这份对编程的热情带到所有科目的学习中,不断丰富自己!

posted @ 2022-05-28 00:46  吴坤泽20202219  阅读(309)  评论(0编辑  收藏  举报