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,把学习这门语言作为我的阶段目标。
课程体会和建议
王志强老师上课很幽默,而且是一位很负责、敬业的老师,我很喜欢上王老师的课。
我觉得课程后面进度太快了,尽管课后可以看云班课上的文件,正则表达式开始就不太能够跟上,建议除了实验作业之外应该多多布置一些小作业来让我们自行练习。
还有就是下学期还能开这门课就更好了。