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

 

posted @ 2022-05-29 15:36  弦masamasa  阅读(331)  评论(0编辑  收藏  举报