第十二章 【pygame】 做一架能射子弹的小飞船

  基本上是按照课本给的路线和代码。


一:安装pip:点击打开链接    点击里面的getpip.py。则出来get-pip.py的代码在浏览器里面,复制代码到编辑器中运行则pip安装完成。


二:安装pygame:点击打开链接  找到pygame一系列 我的电脑是win10 64位 则下载 pygame-1.9.3-cp36-cp36m-win_amd64.whl   下载到项目文件夹中 运行cmd 用python pip运行 

    输入:python -m pip install --user pygame-1.9.3-cp36-cp36m-win_amd64.whl

    不出意外安装完成,出了意外 可能是pygame的版本不对,或者pip安装失败。


三:开始游戏项目

1:创建空屏幕

    

import sys #用以退出程序
import pygame #import库

def run_game():
	pygame.init() #初始化
	screen = pygame.display.set_mode((1000,800)) #返回一个屏幕 此时出现一个窗口
	pygame.display.set_caption("ship") #设置窗口的标题
	while True:#死循环
		for event in pygame.event.get():#检测用户的键盘鼠标等输入
			if event.type == pygame.QUIT:#此处仅检测是否退出
				sys.exit()#退出

	pygame.display.flip()#绘制一个新屏幕 并擦去旧屏幕 以形成平滑移动
run_game()

利用pygame  终于能够不再黑框框里面运行程序了。

当初写个贪吃蛇写出来的效果巨差。。。

简单的解释 pygame.display.set_mode((int,int))返回一个屏幕  screen就是这个屏幕 ,两个参数是屏幕的长宽

                pygame.display.filp()是刷新屏幕

2:设置背景颜色

 bg_color = (230,230,230)

screen.fill(bg_color)

screen是屏幕,fill是填充颜色。也就是改变背景色。

此处需要注意,该条代码应该在显示其它元素的前面,否则其他元素会被覆盖。

在pygame中,颜色是用RGB(red,green,blue)指定的。详细可参考百度百科:点击打开链接

    

3: 加载飞船

#import pygame
class Ship():
	def __init__(self,screen):

		self.screen = screen  
		self.image = pygame.image.load('images/ship.bmp')
		self.rect = self.image.get_rect()
		self.screen_rect = screen.get_rect()
		self.rect.x = self.screen_rect.centerx
		self.rect.y = self.screen_rect.bottom

	def blitme(self):
		self.screen.blit(self.image,self.rect)	

windows环境下pygame默认加载bmp,想要加载别的格式类型需要一定的操作,暂时还没学会。

不过可以将jpg,png等图片格式转化为bmp。

简单的解释:  pygame.image.load(路径)  是加载一个bmp图片。

                     self.image.get_rect() 返回这个bmp图片的矩形

                     self.rect.x/y是该矩形的x,y轴坐标。注意,pygame中左上角为(0,0) 右下角为(∞,∞)

                     screen_rect.centerx 是screen这个矩形(屏幕就是个矩形)的中间的坐标

                     screen_rect.bottom 类似,是底部的坐标

                     这样ship这个飞船的图片就定义好了,下面在screen中绘制出来即可

                     函数blitme目的是绘制该图片,

                     screen.blit(self.image,self.rect) 第一个参数是 之前加载的bmp图片,第二个参数是之前设置好的x,y轴。该函数会在指定位置绘制指定图片。

ship = Ship(screen)

ship.blitme()

在主函数中调用相应函数就可以绘制出飞船图片。

4:重构函数

    重构函数的具体内容不多赘述,因为不涉及到python或者pygame内容,而是全部编程语言共同的点。在此只是提示要进行重构函数~~~


5:移动飞船

    移动飞船的过程就是通过按键,不断移动图片,并重新绘制屏幕的过程。

    首先按一下→,向右移动一下:

    

for event in pygame.event.get():
		if event.type == pygame.QUIT:
			sys.exit()
		elif event.type == pygame.KEYDOWM:
			if event.key == pygame.K_RIGHT:
				ship.rect.x +=1 

在之前的检测按键和鼠标模块中,添加部分代码即可

简单的解释:  event.type是检测到的按键的类型,如果检测到是QUIT就退出,

                    当然最经典的是pygame.KEYDOWN和pygame.KEYUP。   这里检测的是按下 而不是松开  。

                  如果检测到按下就比较按下的是什么按键 也就是event.key()的值 pygame.K_RIGHT 就是方向右键  类似的有K_LEFT K_SPACE K_UP K_DOWN。

                    如果检测到按下方向右键 那么飞船的矩形的x轴坐标+1  ,那么在重新绘制屏幕的时候就可以看到飞船向右移动了一格。在感官效果上就实现了移动飞船


然后要实现不断移动飞船,也就是按下方向右键之后不松开,飞船能不断移动。有点难懂,换句话说就简单了,按下右键就不断移动,松开右键就停止移动。

为了实现这个目标,需要添加一个flag,就是一个标志,设为moving_right  如果为真 就一直向右移动,如果为假就不移动

如果按下右键该标志就为真,如果松开右键该标志就为假。

到了这里思路就很清晰了。

for event in pygame.event.get():
		if event.type == pygame.QUIT:
			sys.exit()
		elif event.type == pygame.KEYDOWM:
			if event.key == pygame.K_RIGHT:
				ship.moving_right = True 
		elif event.type == pygame.KEYUP:#key up
			if event.key == pygame.K_RIGHT:
				ship.moving_right = False
		

在ship类中新增函数

	def update(self):
		if self.moving_right 
			self.rect.x += 1

并在更新屏幕的时候调用该函数。

	ship.update()	
	screen.fill(ai_settings.bg_color)
	pygame.display.flip()

到此为止,飞船就能一直向右移动,但是在实际操作中还有一个问题,飞船会一直飞一直飞,甚至会飞出屏幕。

这个问题加一行代码即可

	def update(self):
		if self.moving_right  and self.rect.right < self.screen_rect.right:
			self.rect.x += 1
self.rect.right是矩形的右边界,代码作用很显然。出界的时候不准出界。


到此为止,飞船就能完成向右移动的全部程序。其它三个方向完全同理。


6:控制飞船的移动速度

本来控制飞船的移动速度只需要更改每次调用函数的时候x坐标的幅度 从1变成2 ,2变成3,设置为一个变量,并控制即可,但是这样子不能够很细致的改变的飞船的移动,也就是2太快,1太慢,需要1.5    然而,pygame里面矩形的坐标只能够储存整数。

为了解决这个问题,可以引入中间变量

在ship类中新增变量设置为浮点数格式

		self.center_x=float(self.rect.centerx)
		self.center_y=float(self.rect.centerx)
                self.ship_speed_factor = 0.5

在更改x坐标的时候

		if self.moving_right and self.rect.right < self.screen_rect.right:
			self.center_x += self.ship_speed_factor
                self.rect.x = self.center_x

到这里,飞船能上下左右动,也能细腻的调整速度,那么飞船的内容就差不多了。


7.发射子弹

子弹的定义是什么呢?为了简单起见,应该是一个矩形,然后按空格(开火)会从飞船中间顶部出现,然后会一直向上移动,会有很多个子弹,到达顶部后删除该子弹(否则会造成使用内存boom),为了调整难度,还应该限制子弹数量。

也就是有那么几个要点:矩形图像/按空格出现/出现在飞船中间顶部/出现之后一直向上移动/移动到顶部被删除/子弹的数量应该有限制/

和飞船是有很多地方相似的

好的,一起来~

import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):#通过使用精灵,可以对对象进行编组,进而同时操作编组中的所有元素。
	def __init__(self , screen , ship):
		super().__init__()#超类的构造函数
		self.screen = screen
		self.width = 3
		self.height = 10
		self.rect = pygame.Rect(0,0,self.width,self.height)#定义左边为屏幕的左上角出现一个长宽固定的矩形
		self.rect.x = ship.rect.x + 29#
		self.rect.y = ship.rect.y - 3#更改坐标位置,让它出现在飞船那边

		self.y = float(self.rect.y)#为了能够细腻的移动子弹,采用浮点数,跟飞船同理
		self.color = 6,60,160 #设置颜色
		self.speed_factor = 1 #设置速度
		


	def update(self):
		self.y -= self.speed_factor
		self.rect.y = self.y #子弹向上移动  跟飞船类似

	def draw_bullet(self):
		pygame.draw.rect(self.screen,self.color,self.rect) #三个参数,屏幕,颜色,生成的矩形 便在指定位置绘制出一个矩形
                                                            

		



这是buttets类的内容,剩下的要在主函数和功能函数里面进行调度。

from pygame.sprite import Group   #需额外import


bullets = Group()#在主函数死循环外创造一个编组

在更新屏幕内容时记得绘制子弹

for i in bullets:
		i.update()
		i.draw_bullet()
同时记得让子弹向上运动


然后再检测键盘和鼠标输入的时候,类似于按方向右键,按下空格键即生成一个新的子弹在编组中,如果子弹数量太多,则不生成,便可以限制子弹的数量

elif event.key == pygame.K_SPACE:
    if len(bullets) < ship.bullets_allowed: 
	new_bullet = Bullet(screen , ship)
	bullets.add(new_bullet)

再随便写个函数删除掉子弹的y轴<0的子弹并调用

def remove_bullet(bullets):
	for i in bullets.copy():
		if i.rect.bottom <= 0:
			bullets.remove(i)

到这里,整个事情就做完了,核心思路是完善的,简单的,但是代码不完善,不过不要紧,所有代码如下:

Ship 类

import pygame
class Ship():
	def __init__(self,screen):

		self.screen = screen  
		self.image = pygame.image.load('images/ship.bmp')
		self.rect = self.image.get_rect()
		self.screen_rect = screen.get_rect()

		self.rect.x = self.screen_rect.centerx
		self.rect.y = self.screen_rect.bottom
		self.moving_right = False
		self.moving_left = False 
		self.moving_up = False
		self.moving_down = False 
		self.ship_speed_factor = 0.5
		self.bullets_allowed = 3 
		self.center_x=float(self.rect.centerx)
		self.center_y=float(self.rect.centerx)



	def blitme(self):
		self.screen.blit(self.image,self.rect)

	def update(self):
		if self.moving_right and self.rect.right < self.screen_rect.right:
			self.center_x += self.ship_speed_factor
		if self.moving_left and self.rect.left > self.screen_rect.left:
			self.center_x -= self.ship_speed_factor
		self.rect.x = self.center_x

		if self.moving_up and self.rect.top > self.screen_rect.top:
			self.center_y -= self.ship_speed_factor
		if self.moving_down and self.rect.bottom < self.screen_rect.bottom:
			self.center_y += self.ship_speed_factor
		self.rect.y = self.center_y
setting类 #没什么用,课本硬是有
class Settings():
    """A class to store all settings for Alien Invasion."""

    def __init__(self):
        """Initialize the game's settings."""
        # Screen settings.
        self.screen_width = 1000
        self.screen_height = 650
        self.bg_color = (230, 230, 230)

Bullet类

import pygame
from pygame.sprite import Sprite

class Bullet(Sprite):
	def __init__(self , screen , ship):
		super().__init__()
		self.screen = screen
		self.width = 3
		self.height = 10
		self.rect = pygame.Rect(0,0,self.width,self.height)
		self.rect.x = ship.rect.x + 29
		self.rect.y = ship.rect.y - 3

		self.y = float(self.rect.y)
		self.color = 6,60,160
		self.speed_factor = 1
		


	def update(self):
		self.y -= self.speed_factor
		self.rect.y = self.y

	def draw_bullet(self):
		pygame.draw.rect(self.screen,self.color,self.rect)


		


主代码

import sys
import pygame

from settings import Settings
from ship import Ship
import game_functions as gf 
from pygame.sprite import Group 

def run_game():
	pygame.init()
	ai_settings = Settings()
	screen = pygame.display.set_mode((ai_settings.screen_width,ai_settings.screen_height))
	pygame.display.set_caption("Alien Invasion")
	ship = Ship(screen)
	bullets = Group()
	while True:
		gf.check_events(ship , screen , bullets)
		gf.remove_bullet(bullets)
		gf.update_screen(ai_settings , screen , ship , bullets)
run_game()
功能函数类
import pygame
import sys
from bullet import Bullet

def check_events(ship , screen , bullets):
	for event in pygame.event.get():
		if event.type == pygame.QUIT:
			sys.exit()
		elif event.type == pygame.KEYDOWN:#key down
			if event.key == pygame.K_LEFT:
				ship.moving_left = True
			elif event.key == pygame.K_RIGHT:
				ship.moving_right = True 
			elif event.key == pygame.K_UP:
				ship.moving_up = True 
			elif event.key == pygame.K_DOWN:
				ship.moving_down = True 
			elif event.key == pygame.K_SPACE:
				if len(bullets) < ship.bullets_allowed:
					new_bullet = Bullet(screen , ship)
					bullets.add(new_bullet)
				
		elif event.type == pygame.KEYUP:#key up
			if event.key == pygame.K_RIGHT:
				ship.moving_right = False
			elif event.key == pygame.K_LEFT:
				ship.moving_left = False
			elif event.key == pygame.K_UP:
				ship.moving_up = False
			elif event.key == pygame.K_DOWN:
				ship.moving_down = False

def update_screen(ai_settings , screen , ship , bullets):
	
	ship.update()	
	screen.fill(ai_settings.bg_color)
	for i in bullets:
		i.update()
		i.draw_bullet()
	ship.blitme()
	pygame.display.flip()

def remove_bullet(bullets):
	for i in bullets.copy():
		if i.rect.bottom <= 0:
			bullets.remove(i)



运行结果~~~~ 第十二章 【pygame】 做一架能射子弹的小飞船_第1张图片




















你可能感兴趣的:(python)