Python —— 给女儿写个雷霆战机

Posted 程序猿知秋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python —— 给女儿写个雷霆战机相关的知识,希望对你有一定的参考价值。

最终程序图

程序分析——精灵对象与功能分析

  • 基本精灵对象,继承 pygame.sprite.Sprite

    • 属性:加载图片、设置初始速度

    • 功能:纵向更新速度

程序对象代码

import random
import pygame

SCREEN_PRO = pygame.Rect(0, 0, 512, 768)

# 自定义派生精灵子类,继承pygame.sprite.Sprite
class GameSprites(pygame.sprite.Sprite):
    """游戏精灵基类"""

    def __init__(self, img_name, speed=1):
        # 调用父类的初始化方法
        super().__init__()

        if img_name is None:
            return

        # 加载图像
        self.image = pygame.image.load(img_name)
        # 设置尺寸; get_rect()可以获取图像的原始大小
        self.rect = self.image.get_rect()
        # 设置速度
        self.speed = speed

    def update(self):
        # 默认在屏幕上垂直方向移动
        self.rect.y += self.speed
 
  • 背景图对象(继承精灵基类)

    • 属性:背景图片、背景音乐

    • 位置:从屏幕0,0 开始绘制(屏幕大小与背景图一样大小)

    • 功能:更新图片纵向移动,当移出屏幕后重置到屏幕上方(需要两张背景图,不断交替纵向下移动,表现出飞机不停飞的现象)

程序对象代码

class BackGround(GameSprites):
    """背景精灵"""

    # 初始化背景图片
    def __init__(self, is_alternate=False):
        super().__init__("./img/bg2.jpg")
        # 加载背景音乐
        pygame.mixer.music.load("./music/bg.mp3")
        # 设置音量
        pygame.mixer.music.set_volume(0.1)
        # 设置播放次数, -1 表示无限循环
        pygame.mixer.music.play(-1)

        # 如果是交替图,初始位置则在屏幕上方
        if is_alternate:
            self.rect.bottom = SCREEN_PRO.y

    def update(self):
        # 调用父类更新
        super().update()

        # 当图片移出屏幕外时,将图片设置到屏幕上方
        if self.rect.top >= SCREEN_PRO.height:
            self.rect.bottom = SCREEN_PRO.y

  • 英雄战机对象

    • 英雄图片

    • x轴在屏幕中间,y轴距离屏幕底部200个像素

    • 横向移动,不能移出屏幕。发射子弹,发射子弹音乐

程序对象代码

class Hero(GameSprites):
    """英雄战机精灵"""

    def __init__(self):
        super().__init__("./img/hero.png")

        # 初始化英雄的位置
        self.rect.centerx = SCREEN_PRO.centerx
        self.rect.y = SCREEN_PRO.height - 200

    def update(self, speed=1):
        self.rect.x += speed
        # 控制边界
        if self.rect.left <= 0:
            self.rect.left = 0
        elif self.rect.right >= SCREEN_PRO.right:
            self.rect.right = SCREEN_PRO.right

    def fire(self, bulletGroup):
        # 英雄发射子弹
        for i in range(1, 2):
            bullet = Bullet(-2)
            bullet.rect.centerx = self.rect.centerx
            bullet.rect.y = self.rect.top - 30 * i
            bulletGroup.add(bullet)

            # 播放子弹音乐
            bullet.bulletMusic.play()
 
  • 两种类型的敌机对象

    • 一群普通敌机

      • 属性:敌机图片

      • 位置:从屏幕上方纵向移动到屏幕中

      • 功能:从上往下,纵向移动。移动屏幕后,销毁敌机对象

    • 一群雷霆敌机

      • 功能同上,敌机图片不同

程序对象代码

class EnemyPlane(GameSprites):
    """敌机精灵"""

    def __init__(self):
        # 初始化敌机图像
        super().__init__("./img/enemy1.png")
        # 初始化 敌机随机速度
        self.speed = random.randint(2, 4)
        # 初始化 敌机随机位置,x轴的 最小位置是0,最大位置是屏幕宽度-敌机宽度
        maxSpeed = SCREEN_PRO.width - self.rect.width
        self.rect.bottom = SCREEN_PRO.y
        self.rect.x = random.randint(0, maxSpeed)

        # 初始化爆炸图片
        self.boomImg = pygame.image.load("./img/boom.png")

        # 初始化敌机销毁音乐
        self.boomMusic = pygame.mixer.Sound("./music/boom.mp3")
        self.boomMusic.set_volume(0.3)

    def update(self):
        # 调用父类更新敌机速度
        super().update()

        # 如果敌机飞出屏幕需要从精灵组中删除
        if self.rect.top >= SCREEN_PRO.height:
            # kill 方法可以让精灵从所有精灵组中移除,精灵会自动销毁(会默认调用 __del__ 方法)
            self.kill()

    def plan_die(self):
        # 播放音乐
        self.boomMusic.play()


class EnemyPlane2(GameSprites):
    """敌机精灵2-雷霆敌机"""

    def __init__(self):
        # 初始化敌机图像
        super().__init__("./img/enemy2.png")
        # 初始化 敌机随机速度
        self.speed = random.randint(2, 4)
        # 初始化 敌机随机位置,x轴的 最小位置是0,最大位置是屏幕宽度-敌机宽度
        maxSpeed = SCREEN_PRO.width - self.rect.width
        self.rect.bottom = SCREEN_PRO.y
        self.rect.x = random.randint(0, maxSpeed)

        # 初始化爆炸图片
        self.boomImg = pygame.image.load("./img/boom.png")

        # 初始化敌机销毁音乐
        self.boomMusic = pygame.mixer.Sound("./music/boom.mp3")
        self.boomMusic.set_volume(0.3)

    def update(self):
        # 调用父类更新敌机速度
        super().update()

        # 如果敌机飞出屏幕需要从精灵组中删除
        if self.rect.top >= SCREEN_PRO.height:
            # kill 方法可以让精灵从所有精灵组中移除,精灵会自动销毁(会默认调用 __del__ 方法)
            self.kill()

    def plan_die(self):
        # 播放音乐
        self.boomMusic.play()

  • 子弹图对象

    • 属性:子弹图片

    • 位置:在英雄敌机的正上方

    • 功能:子弹纵向移动,从下往上。移出屏幕后,子弹对象销毁

程序对象代码

class Bullet(GameSprites):
    """子弹精灵"""

    def __init__(self, speed):
        super().__init__("./img/bullet.png", speed)

        # 初始子弹发出音乐
        self.bulletMusic = pygame.mixer.Sound("./music/bullet2.wav")
        self.bulletMusic.set_volume(0.2)

    def update(self):
        super().update()

        # 子弹超出屏幕就销毁
        if self.rect.bottom <= 0:
            self.kill()

  • 计分器对象

    • 属性:计分器文字对象

    • 位置:初始位置在屏幕左上角,游戏结束时,在结束图片的中间

    • 功能:子弹销毁一个敌机,分值+1

程序对象代码

class FontSprites(GameSprites):
    """字体精灵"""

    def __init__(self, size=18):
        super().__init__(None)
        self.font = pygame.font.Font("./font/msyh.ttf", size)
        # 初始分值
        self.fontValue = 0
        self.textShow = self.font.render("分值:%d" % self.fontValue, True, (0, 255, 0))

    def update(self, color=(0, 255, 0)):
        # 第一个参数是写的文字;第二个参数是个布尔值,以为这是否开启抗锯齿,就是说True的话字体会比较平滑,不过相应的速度有一点点影响;
        # 第三个参数是字体的颜色;第四个是背景色,如果你想没有背景色(也就是透明),那么可以不加这第四个参数。
        self.textShow = self.font.render("分值:%d" % self.fontValue, True, color)

程序所需材料与监听事件

材料

  • 背景音乐材料

  • 子弹发出音乐材料

  • 敌机爆炸音乐材料

  • 敌机爆炸图片材料

  • 游戏结束图片材料、

  • 游戏重新开始图片材料

监听事件

  • 点击关闭窗口程序退出事件

  • 敌机随机出现事件

  • 鼠标点击重新开始游戏事件

  • 子弹发出事件

程序分析——主方法分析

  • 初始化

    • 初始化pygame模块

    • 初始化英雄生命

    • 初始化开始菜单图片位置

    • 初始化游戏窗口

    • 初始化游戏时钟

    • 初始化爆炸敌机对象

    • 初始化各个精灵及精灵组对象

    • 初始化 创建敌机定时器(每700毫秒创建一架敌机)

    • 初始化 创建子弹定时器 (每500毫秒创建一颗子弹)

  • 游戏循环

    • 检测如果敌机爆炸了,让爆炸效果最多持续1秒

    • 设置刷新频率,每秒刷新60次

    • 监听事件

      • 监听鼠标点击关闭窗口退出游戏事件

      • 监听创建敌机事件

      • 监听发射子弹事件

      • 监听鼠标点击重新开始游戏事件

      • 监听键盘按住向左或向右移动英雄战机事件

    • 判断英雄战机,如果死亡则不再向下更新,直到点击重新开始,或者关闭游戏

    • 碰撞检测

      • 检测子弹精灵组与敌机精灵组碰撞,一旦有碰撞,则相应的敌机与子弹都销毁,并播放敌机爆炸声音,加载爆炸图片、分值加+1

      • 检测英雄战机与敌机精灵组碰撞,一旦有碰撞,英雄战机阵亡,游戏结束,弹出游戏结束界面。停止全部音乐,加载最终分值

    • 更新精灵组

      • 更新与绘制背景图

      • 更新与绘制敌机精灵组,如果有爆炸的敌机,需要绘制爆炸图

      • 绘制英雄战机

      • 更新与绘制子弹 

      • 绘制分值

      • 如果英雄战机销毁,则调用结束方法

    • 更新屏幕显示

程序代码

from plane_sprites import *
# 设置游戏时钟(刷新频率)
TICK_TIMES = 60

# 设置敌机事件、创建敌机所需时间
EVENT_ENEMY=pygame.USEREVENT
CREATE_ENEMY_TIME=700

# 设置子弹事件、创建子弹所需时间
EVENT_BULLET=pygame.USEREVENT+1
CREATE_BULLET_TIME=500

# 总分值
TOTAL_SCORE=0

class PlaneGame:
    """飞机大战主类"""

    def __init__(self):
        # 初始化pygame模块
        pygame.init()

        # 初始化英雄生命
        self.life=True
        # 初始化开始菜单图片位置
        self.startImgRect=pygame.Rect(0,0,0,0)

        # 初始化游戏窗口
        self.screen = pygame.display.set_mode(SCREEN_PRO.size)
        # 初始化游戏时钟
        self.clock = pygame.time.Clock()
        # 初始化爆炸敌机对象
        self.boomEnemy= "boomEnemy":None,"times":0
        # 初始化精灵及精灵组相关
        self.__create_sprites()
        # 初始化 创建敌机定时器
        pygame.time.set_timer(EVENT_ENEMY,CREATE_ENEMY_TIME)
        # 初始化 创建子弹定时器
        pygame.time.set_timer(EVENT_BULLET,CREATE_BULLET_TIME)


    def __create_sprites(self):
        # 创建背景精灵
        bg1 = BackGround()
        bg2 = BackGround(True)
        # 创建精灵组,并放入背景精灵
        self.bgGroup = pygame.sprite.Group(bg1, bg2)

        # 创建敌机精灵组
        self.enemyGroup=pygame.sprite.Group()

        # 创建英雄战机
        self.hero=Hero()
        self.heroGroup=pygame.sprite.Group(self.hero)

        # 创建子弹精灵组
        self.bulletGroup=pygame.sprite.Group()

        # 创建分值
        self.font=FontSprites()
        self.fontGroup=pygame.sprite.Group(self.font)

    def start_game(self):
        # 游戏循环开始
        while True:
            # 爆炸图片持续1秒
            self.__enemy_boom()
            # 设置刷新频率
            self.clock.tick(TICK_TIMES)
            # 监听事件
            self.__event_handler()

            if not self.life:
                continue
            # 碰撞检测
            self.__check_collide()
            # 更新精灵组
            self.__update_group()
            # 更新屏幕
            pygame.display.update()

    def __enemy_boom(self):
        # 爆炸图片持续1秒
        if self.boomEnemy["boomEnemy"] is not None:
            enemyTimes = self.boomEnemy["times"]
            self.boomEnemy["times"] = enemyTimes + 1
            if enemyTimes > TICK_TIMES:
                self.boomEnemy["boomEnemy"] = None
                self.boomEnemy["times"] = 0

    def __event_handler(self):
        global TOTAL_SCORE
        for event in pygame.event.get():
            # 判断退出游戏
            if event.type==pygame.QUIT:
                PlaneGame.game_over()

            # 监听鼠标点击开始游戏
            if event.type == pygame.MOUSEBUTTONDOWN:
                x, y = event.pos
                print("鼠标点击了...x:%d ,y:%d,原始图片位置,x:%d,y:%d"%(x,y,self.startImgRect.x,self.startImgRect.y))
                if self.startImgRect.collidepoint(x, y):
                    self.life = True
                    TOTAL_SCORE=0

                    pygame.quit()
                    PlaneGame().start_game()

            # 监听英雄死亡
            if not self.life:
                continue


            # 监听到创建敌机
            if event.type==EVENT_ENEMY:
                enemy=EnemyPlane()
                enemy2 = EnemyPlane2()
                self.enemyGroup.add(enemy)
                self.enemyGroup.add(enemy2)

            # 监听子弹
            if event.type == EVENT_BULLET:
                self.hero.fire(self.bulletGroup)

        keyPressed=pygame.key.get_pressed()
        if keyPressed[pygame.K_RIGHT]:
            self.hero.update(3)
        if keyPressed[pygame.K_LEFT]:
            self.hero.update(-3)

    def __update_group(self):
        # 绘制背景
        self.bgGroup.update()
        self.bgGroup.draw(self.screen)

        # 绘制敌机
        self.enemyGroup.update()
        self.enemyGroup.draw(self.screen)
        boomEnemy=self.boomEnemy["boomEnemy"]
        if boomEnemy:
            # 绘制爆炸图片
            self.screen.blit(boomEnemy.boomImg,(boomEnemy.rect.x,boomEnemy.rect.y))

        # 绘制英雄
        self.heroGroup.draw(self.screen)

        # 绘制子弹
        self.bulletGroup.update()
        self.bulletGroup.draw(self.screen)

        # 绘制分值
        self.fontGroup.update()
        self.screen.blit(self.font.textShow,(0,0))

        # 更新游戏结束
        if not self.life:
            self.load_game_over()

    def __check_collide(self):
        global TOTAL_SCORE
        # 子弹碰撞敌机,都销毁
        dictG=pygame.sprite.groupcollide(self.bulletGroup,self.enemyGroup,True,True)
        if dictG:
            self.font.kill()
            # 分值加1
            TOTAL_SCORE += 1
            self.font=FontSprites()
            self.font.fontValue=TOTAL_SCORE
            self.fontGroup.add(self.font)

            # 爆炸敌机对象
            enemy=list(dictG.values())[0][0]
            # 将爆炸的敌机记录
            self.boomEnemy["boomEnemy"]=enemy
            # 播放音乐
            enemy.plan_die()

        # # 敌机碰撞英雄战机,都销毁
        spriteList=pygame.sprite.spritecollide(self.hero,self.enemyGroup,True)
        # 碰撞的敌机列表
        if len(spriteList)>0:
            # self.hero.kill()
            self.life=False
            self.load_game_over()

    def load_game_over(self):
        # 背景音乐停止
        pygame.mixer.music.stop()
        # 停止全部音效
        pygame.mixer.stop()
        # 加载游戏结束
        img = pygame.image.load("./img/gameover1.png")
        self.screen.blit(img, (0, 30))
        # 加载开始菜单
        startImg = pygame.image.load("./img/restart.png")
        self.startImgRect=self.screen.blit(startImg, (150,img.get_rect().height+30))

        # 加载文字
        gameOverFont=FontSprites(40)
        gameOverFont.fontValue=TOTAL_SCORE
        gameOverFont.update((255,0,0))
        self.screen.blit(gameOverFont.textShow,(200,250))


    @staticmethod
    def game_over():
        print("游戏结束!!!!")
        # 游戏退出
        pygame.quit()
        exit()


if __name__ == '__main__':
    planGame = PlaneGame()
    planGame.start_game()

 

程序猿与投资生活实录已改名为  程序猿知秋,WX同款,欢迎关注! 

Java多线程游戏-雷霆战机

Java多线程游戏-雷霆战机

先来张效果图(结尾附上源码地址,欢迎交流)

一、总述

飞机大战大家童年的时候都玩过,前两天学了线程方面的知识后,决定写一个关于多线程雷霆战机的游戏(单机)。这里用到了许多有关线程,图片处理,音乐等的技术我刚接触Java半年,做这个游戏磕磕绊绊。花费了很多时间,最后还是有一些瑕疵。素材是从另一位博主那下载的。

素材下载地址:
地址

二、相关技术

  1. 了解什么是线程,进程,多线程,并发线程
  2. 了解线程寿命以及线程的控制
  3. 了解线程安全问题,处理游戏中出现的线程安全问题
  4. 了解Java中的list类以及它的底层实现
  5. 音乐文件的读取与播放
  6. 了解键盘监听
  7. 缓冲区(解决屏幕闪烁问题)

三、功能介绍及讲解

(一)功能简介
1.加载页面
2.菜单页面
3.弹窗提示
4.多重关卡(四关)
5.多种飞机(八种)
6.音效
7.地图动态滚动,爆炸动图
8.分数达到一定程度飞机升级
9.计时
10.暂停\\继续游戏(线程控制)
11.开始新游戏(清空原有数据与加载新数据)
12.道具栏与道具使用(刷新道具栏,使用道具,四种道具)
13.关卡boss

(二)功能讲解
1.加载页面的制作

关键点:进度条的使用

加载界面,无外乎就是个界面嘛,重要的可能就是那个加载条了吧。这个加载条你可以自己做,也可以用Java中的加载条,这里我用的是Java中自带的加载条。

		JProgressBar bar = new JProgressBar(1, 100);
		bar.setStringPainted(true); //描绘文字
		bar.setString("加载飞机和子弹中,请稍候,精彩马上开始");  //设置显示文字
		bar.setBackground(Color.ORANGE);  //设置背景色
		bar.setBounds(100, 800, 1000, 100);//设置大小和位置
		bar.setValue(20); //设置进度条值

2.菜单页面的制作

就是提供一些功能按键以及弹窗实现各功能的有序进行。

关键点:弹窗、按钮监听、焦点的获取

弹窗,无外乎也是个界面嘛,要么自己做一个窗口,要么使用Java中自带的弹窗类

JDialog cs=new JDialog();

弹窗的各项操作与窗体JFrame类是一致的。
这里要注意的就是因为后面要实现键盘的监听,所以焦点必须要注意他的位置。并注意获取焦点。

3.多重关卡
这个没啥好说的,我就只是找了四张地图而已。

4.多种飞机
这个比较麻烦,在设计类的时候,可以将各种飞机不同的属性用私有数据来进行初始化。在创建飞机对象的时候将各项数据传进去即可。
下面是我的飞机类代码;

英雄机

public class MyHeroPlane {
	private int Blood;
	private int speed;
	private ImageIcon image;
	public MyHeroPlane(int blood, int speed, ImageIcon image) {
		super();
		Blood = blood;
		this.speed = speed;
		this.image = image;
	}
	public int getBlood() {
		return Blood;
	}
	public int getSpeed() {
		return speed;
	}
	public ImageIcon getImage() {
		return image;
	}
	public void setBlood(int blood) {
		Blood = blood;
	}
	
}

敌机类

public class EnemyPlane extends Thread{
	private int blood;
	private int x,y;
	private ImageIcon image;
	private int speed;
	private boolean islive;
	private int sore;
	private boolean suspend=false;
	public EnemyPlane(int blood, int x, int y, ImageIcon image,int speed,int sore) {
		super();
		this.blood = blood;
		this.x = x;
		this.y = y;
		this.image = image;
		this.speed=speed;
		this.islive=true;
		this.sore=sore;
	}
	public void run()
	{
		while(blood>=0&&islive)
		{
			while(suspend)
			{
				//暂停功能
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			y+=speed;
		}
	}
	public int getBlood() {
		return blood;
	}
	public int getX() {
		return x;
	}
	public int getY() {
		return y;
	}
	public ImageIcon getImage() {
		return image;
	}
	public int getSpeed() {
		return speed;
	}
	public boolean isIslive() {
		return islive;
	}
	public void setIslive(boolean islive) {
		this.islive = islive;
	}
	public void setBlood(int blood) {
		this.blood = blood;
	}
	public int getSore() {
		return sore;
	}
	public boolean isSuspend() {
		return suspend;
	}
	public void setSuspend(boolean suspend) {
		this.suspend = suspend;
	}
	
}

子弹类(我方,敌方子弹)
我方子弹类

public class MyHeroBullets extends Thread{
	private boolean islive=true;
	private int x;
	private int y;
	private int atk;
	private ImageIcon image;
	private int speed;
	private boolean suspend=false;
	public MyHeroBullets(int x, int y, int atk, ImageIcon image, int speed) {
		super();
		this.x = x;
		this.y = y;
		this.atk = atk;
		this.image = image;
		this.speed = speed;
	}

	public void run() {
		while(islive)
		{
			while(suspend)
			{
				//暂停功能
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			y-=speed;
		}
	}

	public boolean isIslive() {
		return islive;
	}

	public int getX() {
		return x;
	}

	public int getY() {
		return y;
	}

	public int getAtk() {
		return atk;
	}

	public ImageIcon getImage() {
		return image;
	}

	public int getSpeed() {
		return speed;
	}

	public void setIslive(boolean islive) {
		this.islive = islive;
	}

	public boolean isSuspend() {
		return suspend;
	}

	public void setSuspend(boolean suspend) {
		this.suspend = suspend;
	}
	
}

敌方子弹类

public class EnemyBullets extends Thread{
	private int atk;
	private ImageIcon image;
	private int speed;
	private boolean islive=true;
	private int x,y;
	private boolean suspend=false;
	public EnemyBullets(int atk, ImageIcon image, int speed, int x, int y) {
		super();
		this.atk = atk;
		this.image = image;
		this.speed = speed;
		this.x = x;
		this.y = y;
	}
	public void run() {
		while(islive)
		{
			while(suspend)
			{
				//暂停功能
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			y+=speed;
		}
	}
	public boolean isIslive() {
		return islive;
	}
	public void setIslive(boolean islive) {
		this.islive = islive;
	}
	public int getAtk() {
		return atk;
	}
	public ImageIcon getImage() {
		return image;
	}
	public int getSpeed() {
		return speed;
	}
	public int getX() {
		return x;
	}
	public int getY() {
		return y;
	}
	public boolean isSuspend() {
		return suspend;
	}
	public void setSuspend(boolean suspend) {
		this.suspend = suspend;
	}
	
}

这里我没有将子弹与飞机封装在一起,这个不太方便,各位可以采用封装在一起的方法来实现。

5.音效
话不多说,读取文件后播放,直接上代码。

public class GetMusic extends Thread{
	private String path;
	private boolean flag=true;
	private boolean whileplay;
	private double value ;

	public GetMusic(String path,boolean whileplay,double value) {
		super();
		this.path = path;
		this.whileplay=whileplay;
		this.value=value;
	}
	public void run()
	{
		if(whileplay)
		{
			while(flag)
			{
				playMusic();
			}
		}
		else
			playMusic();
	}
	public void playMusic() {// 背景音乐播放
		 
		try {
			AudioInputStream ais = AudioSystem.getAudioInputStream(new File("music\\\\"+path));
			AudioFormat aif = ais.getFormat();
			final SourceDataLine sdl;
			DataLine.Info info = new DataLine.Info(SourceDataLine.class, aif);
			sdl = (SourceDataLine) AudioSystem.getLine(info);
			sdl.open(aif);
			sdl.start();
			FloatControl fc = (FloatControl) sdl.getControl(FloatControl.Type.MASTER_GAIN);
			// value可以用来设置音量,从0-2.0
			double value = 2;
			float dB = (float) (Math.log(value == 0.0 ? 0.0001 : value) / Math.log(10.0) * 20.0);
			fc.setValue(dB);
			int nByte = 0;
			int writeByte = 0;
			final int SIZE = 1024 * 64;
			byte[] buffer = new byte[SIZE];
			while (nByte != -1) {
				if(flag) {
					sdl.write(buffer, 0, nByte);
					nByte = ais.read(buffer, 0, SIZE);
				}else {
					
					nByte = ais.read(buffer, 0, 0);
					
				}
			}
			sdl.stop();
 
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	public boolean isFlag() {
		return flag;
	}
	public void setFlag(boolean flag) {
		this.flag = flag;
	}
}

6.飞机升级
这个挺好实现的,你在产生子弹的线程中多产生两路子弹就可以了。当然如果你有什么更好的想法,欢迎交流。
效果图:(达到4000分升级)

7.暂停\\重新开始
我在这里用的是在线程run方法中加入死循环,进入暂停时,所有线程进入死循环。当然这样也有缺点,就是对电脑资源占用较高。也可以采用对线程进行休眠与唤醒来实现,这种方法在我的程序中较为麻烦,就没采用。

8.开始新游戏
这个你可以用重新创建对象来实现,但是如果你之前创建对象使用的是static,那么,你就需要去手动清空所有数据。很不巧,我就是部分对象创建的是static,所以会稍微麻烦一些。

9.道具的使用
为了增加游戏的可玩性,你可以增加一些道具,例如,加血道具,护盾道具,僚机,强化子弹。。。。。
这个你可以自己设计。你可以通过我的源码看懂怎么设计的就不赘述了。上两张效果图。

护盾

僚机
强化子弹

10.关卡boss
这个和设计敌机一样,只是吧,你可把boss血量调高一些,发射子弹的方式调一下。

(三)关键算法
碰撞判断
先看一张图

碰撞无外乎就是上面四种情况,所以,我们可以有很多种方法去实现它,你可以通过判断两张图片中心点之间的距离,你也可以通过遍历我方飞机的四个点,是否有一个点在敌方飞机或子弹的范围内即可。

四、我这个项目明显的缺点

  1. 所有我方子弹,敌方飞机,敌方子弹都是一个新线程,游戏进行中同时运行了成百上千的线程。造成电脑卡顿,资源浪费。解决方法,移动的线程不必每次创建子弹和飞机时都启动一个线程,用一个移动线程就能控制。
  2. 图片因为是四四方方的一张图片,有一部分留白,所以在写碰撞函数时无法兼顾所有图片,存在一定视觉上的误差(明明打中了却穿过去了,或者明明看上去没打中,但实际上却打中了)
  3. 游戏难度设置不合理(啊哈哈哈哈,因为我没有考虑玩家感受,在打boss的时候我试了一下,基本很难过关)。
  4. 游戏程序稳定性不好,遇到部分不容易出现的bug 会卡死。
  5. 存在一定闪烁问题(我加了缓冲功能,但是因为程序占用了太多资源,执行起来还是有一定的闪烁)。

最后的最后,附上我源代码的链接:
源码

以上是关于Python —— 给女儿写个雷霆战机的主要内容,如果未能解决你的问题,请参考以下文章

C/C++游戏项目教程:《雷霆战机》

Java多线程游戏-雷霆战机

仿《雷霆战机》飞行射击手游开发--游戏的入口

仿《雷霆战机》飞行射击手游开发--项目总览

仿《雷霆战机》飞行射击手游开发--游戏对象

仿《雷霆战机》飞行射击手游开发--游戏简介