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半年,做这个游戏磕磕绊绊。花费了很多时间,最后还是有一些瑕疵。素材是从另一位博主那下载的。
素材下载地址:
地址
二、相关技术
- 了解什么是线程,进程,多线程,并发线程
- 了解线程寿命以及线程的控制
- 了解线程安全问题,处理游戏中出现的线程安全问题
- 了解Java中的list类以及它的底层实现
- 音乐文件的读取与播放
- 了解键盘监听
- 缓冲区(解决屏幕闪烁问题)
三、功能介绍及讲解
(一)功能简介
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血量调高一些,发射子弹的方式调一下。
(三)关键算法
碰撞判断
先看一张图
碰撞无外乎就是上面四种情况,所以,我们可以有很多种方法去实现它,你可以通过判断两张图片中心点之间的距离,你也可以通过遍历我方飞机的四个点,是否有一个点在敌方飞机或子弹的范围内即可。
四、我这个项目明显的缺点
- 所有我方子弹,敌方飞机,敌方子弹都是一个新线程,游戏进行中同时运行了成百上千的线程。造成电脑卡顿,资源浪费。解决方法,移动的线程不必每次创建子弹和飞机时都启动一个线程,用一个移动线程就能控制。
- 图片因为是四四方方的一张图片,有一部分留白,所以在写碰撞函数时无法兼顾所有图片,存在一定视觉上的误差(明明打中了却穿过去了,或者明明看上去没打中,但实际上却打中了)
- 游戏难度设置不合理(啊哈哈哈哈,因为我没有考虑玩家感受,在打boss的时候我试了一下,基本很难过关)。
- 游戏程序稳定性不好,遇到部分不容易出现的bug 会卡死。
- 存在一定闪烁问题(我加了缓冲功能,但是因为程序占用了太多资源,执行起来还是有一定的闪烁)。
最后的最后,附上我源代码的链接:
源码
以上是关于Python —— 给女儿写个雷霆战机的主要内容,如果未能解决你的问题,请参考以下文章