python打飞机小程序

游戏框架的搭建

安装框架包pygame

pip install pygame

搜索图片资源

教程里是有的,可我觉得太单调了
本来想搜索雷霆战机的,不太好找,便下载的全民飞机大战的素材包,但是发现这个素材包和教程里的不太一样,教程里的都是一个一个的,素材包里有很多一堆图片挤在一个图片里的,估计还需要额外学习。
这里写图片描述

plist文件相关

本来在网上找到一个可以直接根据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没有黑背景,尴尬。。。

关于飞机显示的努力

一直不想用教程里的图,便想办法自己从大图里面扣
大图

ps里的.gif

幸好大图里的图都非常好扣,但是移动到程序里的图一直有黑底,很烦,网上教程说应该存gif格式的,这样才能透明,可是在ps里没找到gif格式。然后上网搜索才知道应该选择那个存为web格式的才有gif格式。
gif格式的
存储完成后,到程序中显示,虽然周围确实是透明了,但是为什么图片内一些偏白的地方也透明了???
这里写图片描述
我还以为我抠图扣错了,又试了几遍,还是不行
(╯‵□′)╯︵┴─┴

png

但是我在抠图的时候发现其实大图里的背景也应该是透明的,因为我在抠图过程中发现这些图并没有背景,所以我觉得应该png格式也是可以保存透明背景的,经过搜索,证实了我的想法,那就用png格式的喽
结果经过ps处理后的png文件根本无法在ubuntu中打开,可能是由于我在存储中没有选择压缩?或者是交错
经过搜索,网上提供的另外一种奇怪的方法解决了我的一部分问题。
那就是 把扩展名删掉。但是不幸的是拿到系统里的图片还是不知道为什么挂了这里写图片描述
但是,待在共享文件夹里的文件还是好的
这里写图片描述
但是调用共享文件夹里的文件依然在程序中显示为黑底,由此,我推断:
一定是这个轮子不够圆!!!
当然我也不想自己去造个轮子,或者找一个更圆的轮子,因为我还可以老老实实的用教程里的图片(我屈服了QAQ)
这里写图片描述
另外,我发现,去掉后缀之后即使再加上后缀也不影响显示了,我本来是想截个无法打开的png图的,但是加上后缀后依然可以打开,而且就是把它删掉再扔进来一个新的依然可以显示,这算什么?开窍了吗?
这里写图片描述

思路

飞机类定义

  1. 创建一个飞机类
  2. 各种属性

    1. 本身的图片相关,如图片路径,图片尺寸

      #获取图片及相关信息
      self.imageName = "./feiji/hero.gif" #100x124
      self.img = Image.open(self.imageName)
      self.imgWidth = self.img.width 
      self.imgHeight = self.img.height 
      
    2. 用于显示图片的屏幕相关,背景屏幕是谁,背景屏幕的尺寸(由于我将屏幕也定义了一个类,所以只传一个参数)

      #获取背景屏幕
      self.bScreen = bgScreen
      
    3. 以及初始显示位置。x,y坐标,具体数值由背景屏幕尺寸及图片尺寸决定

      #设置飞机默认位置
      self.x = bgScreen.x/2 - self.imgWidth/2
      self.y = bgScreen.y - self.imgHeight
      
    4. 其它,待添加

  3. 各种方法

    1. 显示飞机,根据如何显示一个图片,显示在默认位置

      #显示飞机
      def display(self):
          self.bScreen.screen.blit(self.heroimage,(self.x,self.y))
      
    2. 移动飞机,根据如何显示一个图片,根据指令调整图片位置,同时设定边界,禁止移动飞机移出边界,边界数值由背景屏幕尺寸及图片尺寸决定。

      #向左
      def movLeft(self):
          if self.x > (0 - self.imgWidth/2):
                  self.x -=10
          else:
                  self.x = 0 - self.imgWidth/2
      
    3. 其它,待添加

飞机类显示

  1. 创建一个实例并应用
    1. 将显示飞机方法放到屏幕显示中
    2. 将移动飞机的方法与按键命令相结合

可以攻击的飞机

即显示我方子弹及我方子弹移动

思路

子弹类定义

  1. 定义一个子弹类
  2. 各种属性
    1. 本身的图片相关,如图片路径,图片尺寸
    2. 用于显示图片的屏幕相关,背景屏幕是谁,背景屏幕的尺寸
    3. 以及初始显示位置。x,y坐标,具体数值由背景屏幕尺寸,图片尺寸及飞机位置决定(所以在定义时需要传入飞机参数或只传入相关参数)
    4. 其它,待添加
  3. 各种方法
    1. 显示子弹,根据如何显示一个图片,显示于默认位置
    2. 移动子弹,根据如何显示一个图片,由于目前子弹只需要竖直移动(修改y值),所以一个函数足以。
    3. 其它,待添加

全部子弹显示及移动

由于子弹一般不会只有一颗,所以需要将全部子弹生成一个列表并显示。列表存放在哪呢?存放在发射子弹的飞机中不错(飞机炸了怎么办…子弹清完再清除飞机?还是将子弹放于飞机类中?)

  1. 在飞机类中定义全部子弹的显示方法,将列表中的子弹一一显示出来
  2. 在显示的时候对每一个子弹修改y值,即可完成移动
  3. 设定边界,在子弹出界后移除(即从列表中删除)

tips:列表删除相关

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                

抽取基类

可以看到有许多代码都是重复的,将基类抽取出来,化简代码

一些小心得

类内的变量

在整合基类的过程中,发现在子类的初始化中,其实不用把参数一层层传到父类,父类的__init__也是能调用到对应的变量的(只要定义了)
而self.imageName 这个参数由于在初始化过程中还需要调用,如果在子类没有定义会导致出错(虽然正常来讲不会出现未定义的情况)。便想写一个函数使它在未定义的时候进行定义一个参数。
最初想判断self.imageName == None,报错,说不存在self.imageName 这个东西,想了想,是啊,未定义呢
后来想试试缺省参数。结果由于def xxx后面忘了加冒号导致一直报错,后来发现了以后,测试一下好像也不行
上网搜索方法
1. 调用hasattr方法
2. 使用dir方法
3. 使用locals().has_key(‘var’)方法
4. 以及捕捉异常方法
由于之前并未怎么接触过捕捉异常的写法(只是学习了),导致并不喜欢捕捉异常的方法,但是其它方法都在报错,想了想,应该是在调用self.imageName时就直接报错了,无法进行判断,最后

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)
  • 26
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值