Python实现打砖块小游戏代码实例


Posted in Python onMay 18, 2019

这次用Python实现的是一个接球打砖块的小游戏,需要导入pygame模块,有以下两条经验总结:

1.多父类的继承2.碰撞检测的数学模型

知识点稍后再说,我们先看看游戏的效果和实现:

一、游戏效果

Python实现打砖块小游戏代码实例

二、游戏代码

#导入模块
import pygame
from pygame.locals import *
import sys,random,time,math

class GameWindow(object):
	'''创建游戏窗口类'''
	def __init__(self,*args,**kw):		
		self.window_length = 600
		self.window_wide = 500
		#绘制游戏窗口,设置窗口尺寸
		self.game_window = pygame.display.set_mode((self.window_length,self.window_wide))
		#设置游戏窗口标题
		pygame.display.set_caption("CatchBallGame")
		#定义游戏窗口背景颜色参数
		self.window_color = (135,206,250)

	def backgroud(self):
		#绘制游戏窗口背景颜色
		self.game_window.fill(self.window_color)

class Ball(object):
	'''创建球类'''
	def __init__(self,*args,**kw):
		#设置球的半径、颜色、移动速度参数
		self.ball_color = (255,215,0)		
		self.move_x = 1
		self.move_y = 1
		self.radius = 10

	def ballready(self):
		#设置球的初始位置、
		self.ball_x = self.mouse_x
		self.ball_y = self.window_wide-self.rect_wide-self.radius
		#绘制球,设置反弹触发条件			
		pygame.draw.circle(self.game_window,self.ball_color,(self.ball_x,self.ball_y),self.radius)

	def ballmove(self):
		#绘制球,设置反弹触发条件			
		pygame.draw.circle(self.game_window,self.ball_color,(self.ball_x,self.ball_y),self.radius)		
		self.ball_x += self.move_x
		self.ball_y -= self.move_y
		#调用碰撞检测函数
		self.ball_window()
		self.ball_rect()
		#每接5次球球速增加一倍
		if self.distance < self.radius:
			self.frequency += 1
			if self.frequency == 5:
				self.frequency = 0
				self.move_x += self.move_x
				self.move_y += self.move_y
				self.point += self.point
		#设置游戏失败条件
		if self.ball_y > 520:
			self.gameover = self.over_font.render("Game Over",False,(0,0,0))
			self.game_window.blit(self.gameover,(100,130))
			self.over_sign = 1

class Rect(object):
	'''创建球拍类'''
	def __init__(self,*args,**kw):
		#设置球拍颜色参数
		self.rect_color = (255,0,0)
		self.rect_length = 100
		self.rect_wide = 10

	def rectmove(self):
		#获取鼠标位置参数
		self.mouse_x,self.mouse_y = pygame.mouse.get_pos()
		#绘制球拍,限定横向边界					
		if self.mouse_x >= self.window_length-self.rect_length//2:
			self.mouse_x = self.window_length-self.rect_length//2
		if self.mouse_x <= self.rect_length//2:
			self.mouse_x = self.rect_length//2
		pygame.draw.rect(self.game_window,self.rect_color,((self.mouse_x-self.rect_length//2),(self.window_wide-self.rect_wide),self.rect_length,self.rect_wide))

class Brick(object):
	def __init__(self,*args,**kw):
		#设置砖块颜色参数
		self.brick_color = (139,126,102)
		self.brick_list = [[1,1,1,1,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1]]
		self.brick_length = 80
		self.brick_wide = 20

	def brickarrange(self):		
		for i in range(5):
			for j in range(6):
				self.brick_x = j*(self.brick_length+24)
				self.brick_y = i*(self.brick_wide+20)+40
				if self.brick_list[i][j] == 1:
					#绘制砖块
					pygame.draw.rect(self.game_window,self.brick_color,(self.brick_x,self.brick_y,self.brick_length,self.brick_wide))					
					#调用碰撞检测函数
					self.ball_brick()										
					if self.distanceb < self.radius:
						self.brick_list[i][j] = 0
						self.score += self.point
		#设置游戏胜利条件
		if self.brick_list == [[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0]]:
			self.win = self.win_font.render("You Win",False,(0,0,0))
			self.game_window.blit(self.win,(100,130))
			self.win_sign = 1

class Score(object):
	'''创建分数类'''
	def __init__(self,*args,**kw):		
		#设置初始分数
		self.score = 0
		#设置分数字体
		self.score_font = pygame.font.SysFont('arial',20)
		#设置初始加分点数
		self.point = 1
		#设置初始接球次数
		self.frequency = 0

	def countscore(self):
		#绘制玩家分数			
		my_score = self.score_font.render(str(self.score),False,(255,255,255))
		self.game_window.blit(my_score,(555,15))

class GameOver(object):
	'''创建游戏结束类'''
	def __init__(self,*args,**kw):
		#设置Game Over字体
		self.over_font = pygame.font.SysFont('arial',80)
		#定义GameOver标识
		self.over_sign = 0

class Win(object):
	'''创建游戏胜利类'''
	def __init__(self,*args,**kw):
		#设置You Win字体
		self.win_font = pygame.font.SysFont('arial',80)
		#定义Win标识
		self.win_sign = 0

class Collision(object):
	'''碰撞检测类'''
	#球与窗口边框的碰撞检测
	def ball_window(self):
		if self.ball_x <= self.radius or self.ball_x >= (self.window_length-self.radius):
			self.move_x = -self.move_x
		if self.ball_y <= self.radius:
			self.move_y = -self.move_y

	#球与球拍的碰撞检测
	def ball_rect(self):
		#定义碰撞标识
		self.collision_sign_x = 0
		self.collision_sign_y = 0

		if self.ball_x < (self.mouse_x-self.rect_length//2):
			self.closestpoint_x = self.mouse_x-self.rect_length//2
			self.collision_sign_x = 1
		elif self.ball_x > (self.mouse_x+self.rect_length//2):
			self.closestpoint_x = self.mouse_x+self.rect_length//2
			self.collision_sign_x = 2
		else:
			self.closestpoint_x = self.ball_x
			self.collision_sign_x = 3

		if self.ball_y < (self.window_wide-self.rect_wide):
			self.closestpoint_y = (self.window_wide-self.rect_wide)
			self.collision_sign_y = 1
		elif self.ball_y > self.window_wide:
			self.closestpoint_y = self.window_wide
			self.collision_sign_y = 2
		else:
			self.closestpoint_y = self.ball_y
			self.collision_sign_y = 3
		#定义球拍到圆心最近点与圆心的距离
		self.distance = math.sqrt(math.pow(self.closestpoint_x-self.ball_x,2)+math.pow(self.closestpoint_y-self.ball_y,2))
		#球在球拍上左、上中、上右3种情况的碰撞检测
		if self.distance < self.radius and self.collision_sign_y == 1 and (self.collision_sign_x == 1 or self.collision_sign_x == 2):
			if self.collision_sign_x == 1 and self.move_x > 0:
				self.move_x = - self.move_x
				self.move_y = - self.move_y
			if self.collision_sign_x == 1 and self.move_x < 0:
				self.move_y = - self.move_y
			if self.collision_sign_x == 2 and self.move_x < 0:
				self.move_x = - self.move_x
				self.move_y = - self.move_y
			if self.collision_sign_x == 2 and self.move_x > 0:
				self.move_y = - self.move_y
		if self.distance < self.radius and self.collision_sign_y == 1 and self.collision_sign_x == 3:
			self.move_y = - self.move_y
		#球在球拍左、右两侧中间的碰撞检测
		if self.distance < self.radius and self.collision_sign_y == 3:
			self.move_x = - self.move_x

	#球与砖块的碰撞检测
	def ball_brick(self):
		#定义碰撞标识
		self.collision_sign_bx = 0
		self.collision_sign_by = 0

		if self.ball_x < self.brick_x:
			self.closestpoint_bx = self.brick_x
			self.collision_sign_bx = 1
		elif self.ball_x > self.brick_x+self.brick_length:
			self.closestpoint_bx = self.brick_x+self.brick_length
			self.collision_sign_bx = 2
		else:
			self.closestpoint_bx = self.ball_x
			self.collision_sign_bx = 3

		if self.ball_y < self.brick_y:
			self.closestpoint_by = self.brick_y
			self.collision_sign_by = 1
		elif self.ball_y > self.brick_y+self.brick_wide:
			self.closestpoint_by = self.brick_y+self.brick_wide
			self.collision_sign_by = 2
		else:
			self.closestpoint_by = self.ball_y
			self.collision_sign_by = 3
		#定义砖块到圆心最近点与圆心的距离
		self.distanceb = math.sqrt(math.pow(self.closestpoint_bx-self.ball_x,2)+math.pow(self.closestpoint_by-self.ball_y,2))
		#球在砖块上左、上中、上右3种情况的碰撞检测
		if self.distanceb < self.radius and self.collision_sign_by == 1 and (self.collision_sign_bx == 1 or self.collision_sign_bx == 2):
			if self.collision_sign_bx == 1 and self.move_x > 0:
				self.move_x = - self.move_x
				self.move_y = - self.move_y
			if self.collision_sign_bx == 1 and self.move_x < 0:
				self.move_y = - self.move_y
			if self.collision_sign_bx == 2 and self.move_x < 0:
				self.move_x = - self.move_x
				self.move_y = - self.move_y
			if self.collision_sign_bx == 2 and self.move_x > 0:
				self.move_y = - self.move_y
		if self.distanceb < self.radius and self.collision_sign_by == 1 and self.collision_sign_bx == 3:
			self.move_y = - self.move_y
		#球在砖块下左、下中、下右3种情况的碰撞检测
		if self.distanceb < self.radius and self.collision_sign_by == 2 and (self.collision_sign_bx == 1 or self.collision_sign_bx == 2):
			if self.collision_sign_bx == 1 and self.move_x > 0:
				self.move_x = - self.move_x
				self.move_y = - self.move_y
			if self.collision_sign_bx == 1 and self.move_x < 0:
				self.move_y = - self.move_y
			if self.collision_sign_bx == 2 and self.move_x < 0:
				self.move_x = - self.move_x
				self.move_y = - self.move_y
			if self.collision_sign_bx == 2 and self.move_x > 0:
				self.move_y = - self.move_y
		if self.distanceb < self.radius and self.collision_sign_by == 2 and self.collision_sign_bx == 3:
			self.move_y = - self.move_y
		#球在砖块左、右两侧中间的碰撞检测
		if self.distanceb < self.radius and self.collision_sign_by == 3:
			self.move_x = - self.move_x

class Main(GameWindow,Rect,Ball,Brick,Collision,Score,Win,GameOver):
	'''创建主程序类'''
	def __init__(self,*args,**kw):		
		super(Main,self).__init__(*args,**kw)
		super(GameWindow,self).__init__(*args,**kw)
		super(Rect,self).__init__(*args,**kw)
		super(Ball,self).__init__(*args,**kw)
		super(Brick,self).__init__(*args,**kw)
		super(Collision,self).__init__(*args,**kw)		
		super(Score,self).__init__(*args,**kw)
		super(Win,self).__init__(*args,**kw)
		#定义游戏开始标识
		start_sign = 0

		while True:			
			self.backgroud()
			self.rectmove()
			self.countscore()			
			
			if self.over_sign == 1 or self.win_sign == 1:
				break
			#获取游戏窗口状态
			for event in pygame.event.get():
				if event.type == pygame.QUIT:
					sys.exit()
				if event.type == MOUSEBUTTONDOWN:
					pressed_array = pygame.mouse.get_pressed()
					if pressed_array[0]:
						start_sign = 1
			if start_sign == 0:
				self.ballready()
			else:
				self.ballmove()

			self.brickarrange()

			#更新游戏窗口
			pygame.display.update()
			#控制游戏窗口刷新频率
			time.sleep(0.010)

if __name__ == '__main__':
	pygame.init()
	pygame.font.init()
	catchball = Main()

三、知识点1.多父类的继承

Python的继承方式分为深度优先和广度优先,Python2分经典类的深度优先搜索继承方式(class A:)、 新式类的广度优先搜索继承方式(class A(object):)2种,Python3经典类与新式类的继承方式与python2的新式类继承方式一致,都为广度优先的继承方式。

经典类的深度优先搜索继承方式:

Python实现打砖块小游戏代码实例

如图所示
class B(A)
class C(A)
class D(B,C)

(1)若D类有构造函数,则重写所有父类的继承
(2)若D类没有构造函数,B类有构造函数,则D类会继承B类的构造函数
(3)若D类没有构造函数,B类也没有构造函数,则D类会继承 A类的构造函数,而不是C类的构造函数
(4)若D类没有构造函数,B类也没有构造函数,A类也没有构造函数,则D类才会继承C类的构造函数

新式类的广度优先搜索继承方式:

Python实现打砖块小游戏代码实例

如图所示
class B(A)
class C(A)
class D(B,C)

(1)若D类有构造函数,则重写所有父类的继承
(2)若D类没有构造函数,B类有构造函数,则D类会继承B类的构造函数
(3)若D类没有构造函数,B类也没有构造函数,则D类会继承 C类的构造函数,而不是A类的构造函数
(4)若D类没有构造函数,B类也没有构造函数,C类也没有构造函数,则D类才会继承A类的构造函数

通过上面的分析,大家应该清楚了Python中类的继承顺序,那么问题来了,如果我不想重写父类的构造函数,要子类和父类的构造函数都生效怎么办?解决办法需要用到super关键字,对直接父类对象的引用,可以通过super来访问父类中被子类覆盖的方法或属性。

class A(object):
	def __init__(self,*args,**kw)
class B(A):
	def __init__(self,*args,**kw)
		super(B,self).__init__(*args,**kw)
class C(A):
	def __init__(self,*args,**kw)
		super(C,self).__init__(*args,**kw)
class D(B,C):
	def __init__(self,*args,**kw)
		super(D,self).__init__(*args,**kw)
		super(B,self).__init__(*args,**kw)

2.碰撞检测的数学模型

其实,编程问题到最后就是数学问题,这个游戏涉及到2D圆形与矩形的碰撞检测问题:

碰撞检测原理:通过找出矩形上离圆心最近的点,然后通过判断该点与圆心的距离是否小于圆的半径,若小于则为碰撞。

那如何找出矩形上离圆心最近的点呢?下面我们从 x 轴、y 轴两个方向分别进行寻找。为了方便描述,我们先约定以下变量:

(1)矩形上离圆心最近的点为变量:closestpoint = [x, y]
(2)矩形 rect = [x, y, l, w] 左上角与长宽 length,wide
(3)圆形 circle = [x, y, r] 圆心与半径

Python实现打砖块小游戏代码实例

首先是 x 轴:
如果圆心在矩形的左侧(if circle_x < rect_x),那么 closestpoint_x = rect_x。
如果圆心在矩形的右侧(elif circle_x > rect_x + rect_l),那么 closestpoint_x = rect_x + rect_l。
如果圆心在矩形的正上下方(else),那么 closestpoint_x = circle_x。

同理,对于 y 轴:
如果圆心在矩形的上方(if circle_y < rect_y),那么 closestpoint_y = rect_y。
如果圆心在矩形的下方(elif circle_y > rect_y + rect_w)),那么 closestpoint_y = rect_y + rect_w。
圆形圆心在矩形的正左右两侧(else),那么 closestpoint_y = circle_y。

因此,通过上述方法即可找出矩形上离圆心最近的点了,然后通过“两点之间的距离公式”得出“最近点”与“圆心”的距离,最后将其与圆的半径相比,即可判断是否发生碰撞。
distance=math.sqrt(math.pow(closestpoint_x-circle_x,2)+math.pow(closestpoint_y-circle_y,2))

if distance < circle.r :
return True ? 发生碰撞
else :
return False ? 未发生碰撞

以上所述是小编给大家介绍的Python打砖块小游戏详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
python使用新浪微博api上传图片到微博示例
Jan 10 Python
python中类的一些方法分析
Sep 25 Python
详解Python程序与服务器连接的WSGI接口
Apr 29 Python
Python编程中使用Pillow来处理图像的基础教程
Nov 20 Python
关于numpy中np.nonzero()函数用法的详解
Feb 07 Python
python 实现一个贴吧图片爬虫的示例
Oct 12 Python
python脚本实现验证码识别
Jun 07 Python
pandas.cut具体使用总结
Jun 24 Python
Python如何筛选序列中的元素的方法实现
Jul 15 Python
浅析PyTorch中nn.Module的使用
Aug 18 Python
python列表返回重复数据的下标
Feb 10 Python
python实现最短路径的实例方法
Jul 19 Python
如何在Python中实现goto语句的方法
May 18 #Python
OpenCV搞定腾讯滑块验证码的实现代码
May 18 #Python
Python3匿名函数lambda介绍与使用示例
May 18 #Python
python中数组和矩阵乘法及使用总结(推荐)
May 18 #Python
Python实现二叉树前序、中序、后序及层次遍历示例代码
May 18 #Python
python的内存管理和垃圾回收机制详解
May 18 #Python
Django处理多用户类型的方法介绍
May 18 #Python
You might like
window+nginx+php环境配置 附配置搭配说明
2010/12/29 PHP
php利用单例模式实现日志处理类库
2014/02/10 PHP
PHP实现简单搜歌的方法
2015/07/28 PHP
基于PHP实现数据分页显示功能
2016/05/26 PHP
Laravel中encrypt和decrypt的实现方法
2017/09/24 PHP
PHP面向对象程序设计继承用法简单示例
2018/12/28 PHP
Ajax+Jpgraph实现的动态折线图功能示例
2019/02/11 PHP
指定位置如果有图片显示图片,无图片显示广告的JS
2010/06/05 Javascript
Javascript模拟加速运动与减速运动代码分享
2014/12/11 Javascript
javascript将DOM节点添加到文档的方法实例分析
2015/08/04 Javascript
Bootstrap每天必学之表格
2015/11/23 Javascript
快速掌握Node.js之Window下配置NodeJs环境
2016/03/21 NodeJs
JavaScript的ExtJS框架中表格的编写教程
2016/05/21 Javascript
JavaScript实现图片轮播组件代码示例
2016/11/22 Javascript
angular.JS实现网页禁用调试、复制和剪切
2017/03/31 Javascript
基于wordpress的ajax写法详解
2018/01/02 Javascript
Angular2.0实现modal对话框的方法示例
2018/02/18 Javascript
vue单页缓存方案分析及实现
2018/09/25 Javascript
详解微信小程序与内嵌网页交互实现支付功能
2018/10/22 Javascript
ES6 更易于继承的类语法的使用
2019/02/11 Javascript
Layui 数据表格批量删除和多条件搜索的实例
2019/09/04 Javascript
基于axios 的responseType类型的设置方法
2019/10/29 Javascript
[01:12:53]完美世界DOTA2联赛PWL S2 Forest vs SZ 第一场 11.25
2020/11/26 DOTA
极简的Python入门指引
2015/04/01 Python
python结合opencv实现人脸检测与跟踪
2015/06/08 Python
20个常用Python运维库和模块
2018/02/12 Python
Python中如何导入类示例详解
2019/04/17 Python
python 并发编程 非阻塞IO模型原理解析
2019/08/20 Python
利用Pycharm + Django搭建一个简单Python Web项目的步骤
2020/10/22 Python
Jupyter notebook命令和编辑模式常用快捷键汇总
2020/11/17 Python
定义css设备类型-Media Queries图表简介及使用方法
2013/01/21 HTML / CSS
使用HTML5 Geolocation实现一个距离追踪器
2018/04/09 HTML / CSS
十佳护士先进事迹
2014/05/08 职场文书
庆祝三八妇女节标语
2014/10/09 职场文书
2015年安全工作总结范文
2015/04/02 职场文书
青年志愿者活动感想
2015/08/07 职场文书