- pip install pygame
教程里是有的,可我觉得太单调了
本来想搜索雷霆战机的,不太好找,便下载的全民飞机大战的素材包,但是发现这个素材包和教程里的不太一样,教程里的都是一个一个的,素材包里有很多一堆图片挤在一个图片里的,估计还需要额外学习。
本来在网上找到一个可以直接根据 plist 文件分割大图的 py,但是我执行下来一直报错,经过我不断的搜索,最后发现可能是由于我下载的 plist 是加密的,所以。。。(mmp)
- #coding=utf-8
- import pygame
- if __name__ == "__main__":
- #1. 创建一个窗口,用来显示内容
- screen = pygame.display.set_mode((480,890),0,32)
- #2. 创建一个和窗口大小打图片,用来充当背景
- bgImageFile = "./fjdz/img_bg_logo.jpg"
- background = pygame.image.load(bgImageFile).convert()
- #3. 把背景图片放到窗口中
- while True:
- screen.blit(background,(0,0))
- pygame.display.update()
很尴尬的是在 while True 之后发现弹出来的窗口关不掉了,教程中是在 vi 模式编写,直接 Ctrl + c 关掉了,我是在 Sublime 中写了,Ctrl + c 不行,上网搜索杀死进程的方法使用 xkill 命令关掉了
图太长了好蛋疼,怎么才能显示全呢
大概只显示了三分之二的长度,也不能拉动边框
学习一下如何定义一个背景屏幕,以及如何显示一个图片。
- #coding=utf-8
- import pygame
- from pygame.locals import *
- if __name__ == "__main__":
- #1. 创建一个窗口,用来显示内容
- screen = pygame.display.set_mode((512,768),0,32)
- #2. 创建一个和窗口大小打图片,用来充当背景
- bgImageFile = "./fjdz/img_bg_logo.jpg"
- background = pygame.image.load(bgImageFile).convert()
- #3. 把背景图片放到窗口中
- while True:
- screen.blit(background,(0,0))
- for event in pygame.event.get():
- if event.type == QUIT:
- print "exit"
- exit()
- elif event.type == KEYDOWN:
- if event.key == K_a or event.key == K_LEFT:
- print "left"
- elif event.key == K_d or event.key == K_RIGHT:
- print "right"
- elif event.key == K_w or event.key == K_UP:
- print "up"
- elif event.key == K_s or event.key == K_DOWN:
- print "down"
- elif event.key == K_SPACE:
- print "space"
- pygame.display.update()
学习一下如何检测键盘
由于 plist 的原因,卡了许久,默默去下 ps,心塞。
只能先显示个飞机大阵了
(不只是飞机大阵,还有黑背景,只能先用教程里的图了)
只有教程里的 gif 没有黑背景,尴尬。。。
一直不想用教程里的图,便想办法自己从大图里面扣
幸好大图里的图都非常好扣,但是移动到程序里的图一直有黑底,很烦,网上教程说应该存 gif 格式的,这样才能透明,可是在 ps 里没找到 gif 格式。然后上网搜索才知道应该选择那个存为 web 格式的才有 gif 格式。
存储完成后,到程序中显示,虽然周围确实是透明了,但是为什么图片内一些偏白的地方也透明了???
我还以为我抠图扣错了,又试了几遍,还是不行
(╯‵□′)╯︵┴─┴
但是我在抠图的时候发现其实大图里的背景也应该是透明的,因为我在抠图过程中发现这些图并没有背景,所以我觉得应该 png 格式也是可以保存透明背景的,经过搜索,证实了我的想法,那就用 png 格式的喽
结果经过 ps 处理后的 png 文件根本无法在 ubuntu 中打开,可能是由于我在存储中没有选择压缩?或者是交错?
经过搜索,网上提供的另外一种奇怪的方法解决了我的一部分问题。
那就是 把扩展名删掉。但是不幸的是拿到系统里的图片还是不知道为什么挂了
但是,待在共享文件夹里的文件还是好的
但是调用共享文件夹里的文件依然在程序中显示为黑底,由此,我推断:
一定是这个轮子不够圆!!!
当然我也不想自己去造个轮子,或者找一个更圆的轮子,因为我还可以老老实实的用教程里的图片(我屈服了 QAQ)
另外,我发现,去掉后缀之后即使再加上后缀也不影响显示了,我本来是想截个无法打开的 png 图的,但是加上后缀后依然可以打开,而且就是把它删掉再扔进来一个新的依然可以显示,这算什么?开窍了吗?
- #获取图片及相关信息
- self.imageName = "./feiji/hero.gif" #100x124
- self.img = Image.open(self.imageName)
- self.imgWidth = self.img.width
- self.imgHeight = self.img.height
- #获取背景屏幕
- self.bScreen = bgScreen
- #设置飞机默认位置
- self.x = bgScreen.x/2 - self.imgWidth/2
- self.y = bgScreen.y - self.imgHeight
- #显示飞机
- def display(self):
- self.bScreen.screen.blit(self.heroimage,(self.x,self.y))
- #向左
- def movLeft(self):
- if self.x > (0 - self.imgWidth/2):
- self.x -=10
- else:
- self.x = 0 - self.imgWidth/2
即显示我方子弹及我方子弹移动
由于子弹一般不会只有一颗,所以需要将全部子弹生成一个列表并显示。列表存放在哪呢?存放在发射子弹的飞机中不错(飞机炸了怎么办… 子弹清完再清除飞机?还是将子弹放于飞机类中?)
- for bul in self.bullet:
- if bul.y > 0:
- self.bullet.remove(bul)
这种删除列表中的方法是错误的,当要删除的两个变量相邻时便会出错。
例:
原因嘛~
- #方法一
- nb = []
- for bul in self.bullet:
- if bul.y < 0:
- nb.append(bul)
- for bul in nb:
- self.bullet.remove(bul)
- #方法一
- nb = []
- for bul in self.bullet:
- if bul.y > 0:
- nb.append(bul)
- self.bullet = nb
教程中给的是方法一,自己写的方法二,不清楚会有什么后果(数据地址改变?)。
图片路径,初始位置 x,y 与普通飞机类不同,其余属性及方法通用
敌机的移由代码控制,需要编写相关代码
定义一个自动移动的方法。
显然需要随机数,即 random 模块。
相关代码:
- def autoMove(self):
- #如果上次的随机移动指令是否结束
- if self.amc <= 0:
- #若已结束,重新生成移动模式amm,移动次数amc
- self.amm = random.randint(1,3)
- self.amc = random.randint(5,20)
- else:
- #若未结束,移动次数减一
- self.amc -=1
- #是否移动到边缘
- if self.x <= 0 :
- #若移动到左边缘,剩余次数强制右移
- self.amm = 3
- elif self.x + self.imgWidth >= self.bScreen.x :
- #若移动到右边缘,剩余次数强制左移
- self.amm = 2
- #移动模式相关
- if self.amm == 1:
- #向前移,无论移动次数多少强制归0
- self.movDown()
- self.amc = 0
- elif self.amm == 2:
- #左移
- self.movLeft()
- elif self.amm == 3:
- #右移
- self.movRight()
看上去有些蠢,但是感觉也不太好化简了。
与我方子弹类基本相同,除了调用的图片路径不同。
显示也差不多,移动只要改下 y 变动的方向即可,删除也是
应该在敌机类中定义一个函数,生成一个随机数,满足一定条件即调用 shoot 函数。(我把自动攻击和子弹显示写在一起了)
- def autoShoot(self):
- nb = []
- n = random.randint(1,1000)
- if n < 100 :
- self.shoot()
- for bul in self.bullet:
- bul.display()
- bul.move(0,3)
- if bul.y > 0:
- nb.append(bul)
- self.bullet = nb
可以看到有许多代码都是重复的,将基类抽取出来,化简代码
在整合基类的过程中,发现在子类的初始化中,其实不用把参数一层层传到父类,父类的
也是能调用到对应的变量的(只要定义了) 而 self.imageName 这个参数由于在初始化过程中还需要调用,如果在子类没有定义会导致出错(虽然正常来讲不会出现未定义的情况)。便想写一个函数使它在未定义的时候进行定义一个参数。
- __init__
- class BaseImage(object):
- """docstring for BaseImage"""
- def __init__(self, bgScreen):
- try:
- self.imageName = self.imageName
- except AttributeError as e:
- #error: has not attribute
- self.imageName = "./feiji/bomb-2.gif"
很奇怪我将一个函数 display 从父类(Plane)放入更深的基类(BaseImage)时 heroPlane.display()便查找不到 display 函数了
(HeroPlane—>Plane—>BaseImage)
我把 display 函数粘贴在(BaseImage)中时,多缩进了一行,呵呵呵呵呵呵呵
子弹最后抽抽抽,凑成一个类了
教程到这就结束了。。。有空(猴年马月)再往下写吧
- #coding=utf-8
- import pygame
- from pygame.locals import *
- from PIL import Image
- import time
- import random
- class Screen(object):
- """定义一个背景屏幕"""
- def __init__(self,x,y):
- #背景屏幕的尺寸
- self.x = x
- self.y = y
- #生成背景屏幕
- self.screen = pygame.display.set_mode((self.x,self.y),0,32)
- #静态方法:获取键盘打值
- @staticmethod
- def getKey():
- for event in pygame.event.get():
- if event.type == QUIT:
- print "exit"
- exit()
- elif event.type == KEYDOWN:
- if event.key == K_a or event.key == K_LEFT:
- print "left"
- heroPlane.movLeft()
- elif event.key == K_d or event.key == K_RIGHT:
- print "right"
- heroPlane.movRight()
- elif event.key == K_w or event.key == K_UP:
- print "up"
- heroPlane.movUp()
- elif event.key == K_s or event.key == K_DOWN:
- print "down"
- heroPlane.movDown()
- elif event.key == K_SPACE:
- print "space"
- heroPlane.shoot()
- class BaseImage(object):
- """在背景屏幕打印一个图片打基础"""
- def __init__(self, bgScreenn):
- #判断是否有图片文件打路径传入
- try:
- self.imageName = self.imageName
- except AttributeError as e:
- #error: has not attribute
- self.imageName = "./feiji/bomb-2.gif"
- #打开图像文件,不想检测错误了
- self.img = Image.open(self.imageName)
- #获取图像的尺寸
- self.imgWidth = self.img.width
- self.imgHeight = self.img.height
- #s设置要显示内容打窗口
- self.bScreen = bgScreenn
- self.imageScreen = pygame.image.load(self.imageName).convert()
- #显示图片
- def display(self):
- self.bScreen.screen.blit(self.imageScreen,(self.x,self.y))
- #向左
- def movLeft(self, speed = 10):
- if self.x > (speed - 10 - self.imgWidth/2):
- self.x -= speed
- else:
- self.x = speed - 10 - self.imgWidth/2
- #向右
- def movRight(self, speed = 10):
- if self.x < (self.bScreen.x - speed - self.imgWidth/2 ):
- self.x += speed
- else:
- self.x = self.bScreen.x - speed - self.imgWidth/2
- #向上
- def movUp(self, speed = 10):
- if self.y > speed:
- self.y -= speed
- else:
- self.y = 0
- #向下
- def movDown(self, speed = 10):
- if self.y < (self.bScreen.y - self.imgHeight - speed):
- self.y += speed
- else:
- self.y = self.bScreen.y - self.imgHeight
- class Plane(BaseImage):
- """一个基础飞机类"""
- def __init__(self, bgScreen):
- super(Plane,self).__init__(bgScreen)
- #根据类型,设置飞机默认位置
- if self.planeType == "Hero" :
- self.x = bgScreen.x/2 - self.imgWidth/2
- self.y = bgScreen.y - self.imgHeight
- elif self.planeType == "Enemy" :
- self.x = 0
- self.y = 0
- #全部子弹
- self.bullet = []
- #射击
- def shoot(self):
- if self.planeType == "Hero":
- newBullet = Bullet(self.x+self.imgWidth/2-10,self.y,self.bScreen,self.planeType)
- elif self.planeType == "Enemy":
- newBullet = Bullet(self.x+self.imgWidth/2-10,self.y+self.imgHeight,self.bScreen,self.planeType)
- self.bullet.append(newBullet)
- #展示全部子弹
- def bulletDisplay(self,direction = "up", speed = 1):
- nb = []
- for bul in self.bullet:
- bul.display()
- bul.move(direction)
- if bul.y > 0 or bul.y < self.bgScreen.y:
- nb.append(bul)
- self.bullet = nb
- class HeroPlane(Plane):
- """基础英雄飞机类,可以视为工厂"""
- def __init__(self,bgScreen):
- #图片路径
- self.imageName = "./feiji/hero.gif" #100x124
- #self.imageName = "/mnt/share/Hero-1" #100x124
- #self.imageName = "./fjdz/Hero-1.gif" #100x124
- #飞机类型
- self.planeType = "Hero"
- super(HeroPlane,self).__init__(bgScreen)
- class EnemyPlane(Plane):
- """基础敌方飞机,可以视为工厂"""
- def __init__(self,bgScreen):
- #图片路径
- self.imageName = "./feiji/enemy-1.gif" #100x124
- #飞机类型
- self.planeType = "Enemy"
- super(EnemyPlane,self).__init__(bgScreen)
- #用于自动移动的移动次数及移动模式
- self.auMoNumofCycles = 0
- self.auMoType = 0
- #自动射击
- def autoShoot(self):
- n = random.randint(1,1000)
- if n < 100 :
- self.shoot()
- #自动移动
- def autoMove(self):
- #如果上次的随机移动指令是否结束
- if self.auMoNumofCycles <= 0:
- #若已结束,重新生成移动模式,移动次数
- self.auMoType = random.randint(1,3)
- self.auMoNumofCycles = random.randint(5,20)
- else:
- #若未结束,移动次数减一
- self.auMoNumofCycles -=1
- #判断是否移动到边缘
- if self.x <= 0 :
- #若移动到左边缘,剩余次数强制右移
- self.auMoType = 3
- elif self.x + self.imgWidth >= self.bScreen.x :
- #若移动到右边缘,剩余次数强制左移
- self.auMoType = 2
- #移动模式相关
- if self.auMoType == 1:
- #向前移,无论移动次数多少强制归0
- self.movDown()
- self.auMoNumofCycles = 0
- elif self.auMoType == 2:
- #左移
- self.movLeft()
- elif self.auMoType == 3:
- #友移
- self.movRight()
- #显示子弹(敌方)
- def bulletDisplay(self):
- super(EnemyPlane, self).bulletDisplay("down")
- class Bullet(BaseImage):
- """基础子弹类,可视为工厂"""
- def __init__(self,x,y,bgScreen, type):
- #生成子弹位置
- self.x = x
- self.y = y
- #根据类别选择子弹图片
- if type == "Hero":
- self.imageName = "./feiji/bullet-3.gif"
- elif type == "Enemy":
- self.imageName = "./feiji/bullet-1.gif"
- super(Bullet,self).__init__(bgScreen)
- #子弹的移动
- def move(self,direction,speed=1):
- if direction == "up":
- self.y -=speed
- elif direction == "down":
- self.y +=speed
- if __name__ == "__main__":
- #1. 创建一个窗口,用来显示内容
- bgScreen = Screen(512,700)
- #2. 创建一个和窗口大小打图片,用来充当背景
- #bgImageFile = "./fjdz/img_bg_logo.jpg"
- bgImageFile = "./fjdz/img_bg_level_1.jpg"
- background = pygame.image.load(bgImageFile).convert()
- #3.创建一个飞机对象
- heroPlane = HeroPlane(bgScreen)
- #4.创建一个敌方飞机
- enemyPlane = EnemyPlane(bgScreen)
- #5. 把全部图片放到窗口中
- while True:
- #背景图片
- bgScreen.screen.blit(background,(0,0))
- #我方飞机展示
- heroPlane.display()
- #我方子弹展示
- heroPlane.bulletDisplay();
- #敌方飞机展示
- enemyPlane.display()
- #敌方飞机自动移动
- enemyPlane.autoMove()
- #敌方飞机自动攻击
- enemyPlane.autoShoot()
- #敌方飞机子弹展示
- enemyPlane.bulletDisplay()
- #获取键值及相应操作
- Screen.getKey()
- #刷新显示
- pygame.display.update()
- #延迟
- time.sleep(0.05)
来源: http://blog.csdn.net/misaka_s/article/details/76668511