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实现将内容分行输出
Nov 05 Python
json跨域调用python的方法详解
Jan 11 Python
python下setuptools的安装详解及No module named setuptools的解决方法
Jul 06 Python
Python入门学习指南分享
Apr 11 Python
Python循环中else,break和continue的用法实例详解
Jul 11 Python
Python基于BeautifulSoup和requests实现的爬虫功能示例
Aug 02 Python
Tensorflow 实现分批量读取数据
Jan 04 Python
Python基于yaml文件配置logging日志过程解析
Jun 23 Python
python线性插值解析
Jul 05 Python
用python获取txt文件中关键字的数量
Dec 24 Python
python 使用xlsxwriter循环向excel中插入数据和图片的操作
Jan 01 Python
基于PyTorch实现一个简单的CNN图像分类器
May 29 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
php强制下载类型的实现代码
2011/04/21 PHP
thinkphp自带验证码全面解析
2016/09/18 PHP
Zend Framework常用校验器详解
2016/12/09 PHP
php smtp实现发送邮件功能
2017/06/22 PHP
yii2.0框架实现上传excel文件后导入到数据库的方法示例
2020/04/13 PHP
WordPress伪静态规则设置代码实例
2020/12/10 PHP
De facto standard 世界上不可思议的事实标准
2010/08/29 Javascript
用js实现控件的隐藏及style.visibility的使用
2013/06/14 Javascript
js点击更换背景颜色或图片的实例代码
2013/06/25 Javascript
js几秒以后倒计时跳转示例
2013/12/26 Javascript
javascript用函数实现对象的方法
2015/05/14 Javascript
jQuery表单验证插件解析(推荐)
2016/07/21 Javascript
Vue.js第一天学习笔记(数据的双向绑定、常用指令)
2016/12/01 Javascript
Angular2学习笔记——详解NgModule模块
2016/12/02 Javascript
axios向后台传递数组作为参数的方法
2018/08/11 Javascript
解决vue-cli webpack打包后加载资源的路径问题
2018/09/25 Javascript
微信小程序实现的绘制table表格功能示例
2019/04/26 Javascript
Vue开发环境中修改端口号的实现方法
2019/08/15 Javascript
layui实现把数据表格时间戳转换为时间格式的例子
2019/09/12 Javascript
Python操作MongoDB详解及实例
2017/05/18 Python
Python实现将Excel转换为json的方法示例
2017/08/05 Python
浅析Python数据处理
2018/05/02 Python
python Tkinter版学生管理系统
2019/02/20 Python
python3字符串操作总结
2019/07/24 Python
python pandas cumsum求累计次数的用法
2019/07/29 Python
在tensorflow中实现屏蔽输出的log信息
2020/02/04 Python
UNIONBAY官网:美国青少年服装品牌
2019/03/26 全球购物
波兰办公用品和学校用品在线商店:Dlabiura24.pl
2020/11/18 全球购物
请用用Java代码写一个堆栈
2012/01/26 面试题
自动化工程专业个人应聘自荐信
2013/09/26 职场文书
新年爱情寄语
2014/04/08 职场文书
国家机关领导干部民主生活会对照检查材料思想汇报
2014/09/17 职场文书
检察院对照“四风”认真查找问题落实整改措施
2014/09/26 职场文书
2016年全国爱牙日宣传活动总结
2016/04/05 职场文书
熟背这些句子,让您的英语口语突飞猛进(135句)
2019/09/06 职场文书
Java 深入探究讲解简单工厂模式
2022/04/07 Java/Android