pygame-KidsCanCode系列jumpy-part3-重力及碰撞检测
这个游戏叫jumpy,大致玩法就是模拟超级玛丽一样,可以不停在各个档板上跳动,同时受到重力的作用,会向下掉,如果落下时,没有站在档板上,就挂了。
这节,我们加入重力因素,继续改造sprites.py
- from part_03.settings import *
- import pygame as pg
- vec = pg.math.Vector2
- class Player(pg.sprite.Sprite):
- def __init__(self):
- pg.sprite.Sprite.__init__(self)
- self.image = pg.Surface((30, 30))
- self.image.fill(YELLOW)
- self.rect = self.image.get_rect()
- self.rect.center = WIDTH / 2, HEIGHT / 2
- self.pos = self.rect.center
- self.vel = vec(0, 0)
- self.acc = vec(0, 0)
- self.width = self.rect.width
- self.height = self.rect.height
- def update(self):
- # 初始化时,垂直方向加入重力加速度
- self.acc = vec(0, PLAYER_GRAVITY)
- keys = pg.key.get_pressed()
- if keys[pg.K_LEFT]:
- self.acc.x = -PLAYER_ACC
- if keys[pg.K_RIGHT]:
- self.acc.x = PLAYER_ACC
- self.acc.x += self.vel.x * PLAYER_FRICTION
- self.vel += self.acc
- self.pos += self.vel
- if self.rect.left > WIDTH:
- self.pos.x = 0 - self.width / 2
- if self.rect.right < 0:
- self.pos.x = WIDTH + self.width / 2
- # 碰撞后,方块底部要停在档板上,所以要改成rect.midbottom
- self.rect.midbottom = self.pos
- # 档板类
- class Platform(pg.sprite.Sprite):
- def __init__(self, x, y, w, h):
- pg.sprite.Sprite.__init__(self)
- self.image = pg.Surface((w, h))
- self.image.fill(GREEN)
- self.rect = self.image.get_rect()
- self.rect.x = x
- self.rect.y = y
新建了一个Platform类,用来模拟档板,其实就是一个绿色的长矩形条;其次Player在update中,acc加速度初始化时,引入了垂直方向的加速度,其值仍然在settings.py中定义:
- # game options
- SIZE = WIDTH, HEIGHT = 360, 480
- FPS = 60
- DEBUG = True
- TITLE = "Jumpy!"
- # Player properties
- PLAYER_ACC = 0.5
- PLAYER_GRAVITY = 0.5 # 重力加速度
- PLAYER_FRICTION = -0.06
- # define color
- BLACK = 0, 0, 0
- WHITE = 255, 255, 255
- RED = 255, 0, 0
- GREEN = 0, 255, 0
- BLUE = 0, 0, 255
- YELLOW = 255, 255, 0
然后在main.py中使用这个Platform类:
- from part_03.sprites import *
- from part_03.settings import *
- class Game:
- def __init__(self):
- pg.init()
- pg.mixer.init()
- self.screen = pg.display.set_mode(SIZE)
- pg.display.set_caption(TITLE)
- self.clock = pg.time.Clock()
- self.running = True
- self.playing = False
- self.p1 = object
- def new(self):
- self.all_sprites = pg.sprite.Group()
- # 创建一个档板Group
- self.platforms = pg.sprite.Group()
- self.player = Player()
- self.all_sprites.add(self.player)
- # 加入2个档板实例
- self.p1 = Platform(0, HEIGHT - 40, WIDTH, 40)
- p2 = Platform(WIDTH / 2 - 50, HEIGHT / 2 + 100, 100, 20)
- self.all_sprites.add(self.p1)
- self.all_sprites.add(p2)
- self.platforms.add(self.p1)
- self.platforms.add(p2)
- g.run()
- def run(self):
- self.playing = True
- while self.playing:
- self.clock.tick(FPS)
- self.events()
- self.update()
- self.draw()
- def update(self):
- self.all_sprites.update()
- # 碰撞检测
- hits = pg.sprite.spritecollide(self.player, self.platforms, False)
- if hits:
- self.player.pos.y = hits[0].rect.top
- # 碰撞后,将player 垂直方向的速度归0(否则物体还是会继续向下掉)
- self.player.vel.y = 0
- def events(self):
- for event in pg.event.get():
- if event.type == pg.QUIT:
- if self.playing:
- self.playing = False
- self.running = False
- def draw(self):
- self.screen.fill(BLACK)
- self.all_sprites.draw(self.screen)
- self.debug()
- pg.display.flip()
- def debug(self):
- if DEBUG:
- font = pg.font.SysFont('Menlo', 25, True)
- pos_txt = font.render(
- 'Pos:(' + str(round(self.player.pos.x, 2)) + "," + str(round(self.player.pos.y, 2)) + ")", 1, GREEN)
- vel_txt = font.render(
- 'Vel:(' + str(round(self.player.vel.x, 2)) + "," + str(round(self.player.vel.y, 2)) + ")", 1, GREEN)
- acc_txt = font.render(
- 'Acc:(' + str(round(self.player.acc.x, 2)) + "," + str(round(self.player.acc.y, 2)) + ")", 1, GREEN)
- self.screen.blit(pos_txt, (20, 10))
- self.screen.blit(vel_txt, (20, 40))
- self.screen.blit(acc_txt, (20, 70))
- pg.draw.line(self.screen, WHITE, (0, HEIGHT / 2), (WIDTH, HEIGHT / 2), 1)
- pg.draw.line(self.screen, WHITE, (WIDTH / 2, 0), (WIDTH / 2, HEIGHT), 1)
- def show_start_screen(self):
- pass
- def show_go_screen(self):
- pass
- g = Game()
- g.show_start_screen()
- while g.running:
- g.new()
- g.show_go_screen()
- pg.quit()
这里使用到了spritecollide这个超级好用的方法,可以很轻松的搞定碰撞检测。
如果仔细观察的话,会发现一个小问题,方块掉到档板上后,一直在上下轻微晃动,从Vel的调试输出值,也能看到y方向的速度,一直在0.5和0之间切换。原因在于:Player的update()方法,初始化时,给了acc在y方向0.5的加速度(具体值在settings.py中通过PLAYER_GRAVITY定义), 这个0.5,直到碰撞后,在main.py中,才通过self.player.pos.y = hits[0].rect.top纠正回来,即代码先物体向下落0.5px, 然后再强制重新调整位置,让它向上拉0.5px.
改进方法:将sprites.py中Player的update()方法改成下面这样
- def update(self):
- # 初始化时,垂直方向加入重力加速度
- self.acc = vec(0, PLAYER_GRAVITY)
- keys = pg.key.get_pressed()
- if keys[pg.K_LEFT]:
- self.acc.x = -PLAYER_ACC
- if keys[pg.K_RIGHT]:
- self.acc.x = PLAYER_ACC
- self.acc.x += self.vel.x * PLAYER_FRICTION
- self.vel += self.acc
- self.pos += self.vel
- if self.rect.left > WIDTH:
- self.pos.x = 0 - self.width / 2
- if self.rect.right < 0:
- self.pos.x = WIDTH + self.width / 2
- # self.rect.midbottom = self.pos
- # 校正0.5px上下抖动的问题
- if abs(self.rect.bottom - self.pos.y) >= 1:
- self.rect.bottom = self.pos.y
- self.rect.x = self.pos.x - self.width / 2
即:最后三行,先判断下y轴方向的位置变化量,只有>=1px的情况下才更新,再运行下
已经没有刚才的抖动问题。注:个人感觉这更像是pygame在渲染机制上的一个缺陷,只有0.5px这种不足1px的位移,才会有这个问题,同学们可以尝试把PLAYER_GRAVITY从0.5改成2(即:让每次的y轴位移>1px),也不会有抖动问题。
pygame-KidsCanCode系列jumpy-part3-重力及碰撞检测的更多相关文章
- UIDynamic(重力行为+碰撞检测)
一.重力行为 说明:给定重力方向.加速度,让物体朝着重力方向掉落 1.方法 (1)UIGravityBehavior的初始化 - (instancetype)initWithItems:(NSArra ...
- iOS开发拓展篇—UIDynamic(重力行为+碰撞检测)
iOS开发拓展篇—UIDynamic(重力行为+碰撞检测) 一.重力行为 说明:给定重力方向.加速度,让物体朝着重力方向掉落 1.方法 (1)UIGravityBehavior的初始化 - (inst ...
- 李洪强iOS开发拓展篇—UIDynamic(重力行为+碰撞检测)
iOS开发拓展篇—UIDynamic(重力行为+碰撞检测) 一.重力行为 说明:给定重力方向.加速度,让物体朝着重力方向掉落 1.方法 (1)UIGravityBehavior的初始化 - (inst ...
- Unity3D实践系列09, 物理引擎与碰撞检测
在Unity3D中,一个物体通常包含一个Collider和一个Rigidbody.Collider是碰撞体,一个物体是Collider,才可以进行碰撞检测.Collider组件中的"Is T ...
- 【Flask-RESTPlus系列】Part3:请求解析
0x00 内容概览 请求解析 基本参数 必需参数 多值和列表 其他目标 参数位置 参数多个位置 高级类型处理 解析器继承 文件上传 错误处理 错误消息 参考链接 0x01 请求解析 注意:Flask- ...
- 2015/11/7用Python写游戏,pygame入门(7):碰撞检测
我们已经完成了飞机大战的大部分东西,但是游戏还是没有办法正式开玩,因为子弹并不能打掉飞机.只有完成了这一个工作,游戏才算基本成型. 今天的内容就非常简单了,就是做到这个碰撞检测,以及控制好子弹和飞机的 ...
- Python游戏编程(Pygame)
安装Pygame pip install pygame C:\Users> pip install pygame Collecting pygame Downloading https://fi ...
- Android系统编程入门系列之硬件交互——传感器
到目前为止,关于应用程序与用户之间的相关内容便比较肤浅的大致介绍完毕.而在整个系统架构中,应用程序与用户之间的交互,犹如参天大树上的枝干和树叶,交互起来五彩缤纷,但使整个生态系统保持生命力的核心,在于 ...
- 文顶顶iOS开发博客链接整理及部分项目源代码下载
文顶顶iOS开发博客链接整理及部分项目源代码下载 网上的iOS开发的教程很多,但是像cnblogs博主文顶顶的博客这样内容图文并茂,代码齐全,示例经典,原理也有阐述,覆盖面宽广,自成系统的系列教程 ...
- UIDynamic--动力元素行为:UIDynamicItemBehavior
属性分析: @property (nonatomic, readonly, copy) NSArray* items; @property (readwrite, nonatomic) CGFloat ...
随机推荐
- 3. 深入研究 UCenter API 之 加密与解密(转载)
1. 深入研究 UCenter API 之 开篇 (转载) 2. 深入研究 UCenter API 之 通讯原理(转载) 3. 深入研究 UCenter API 之 加密与解密(转载) 4. ...
- OAuth2:隐式授权(Implicit Grant)类型的开放授权
适用范围 仅需临时访问的场景 用户会定期在API提供者那里进行登录 OAuth客户端运行在浏览器中(Javascript.Flash等) 浏览器绝对可信,因为该类型可能会将访问令牌泄露给恶意用户或应用 ...
- 【Android】Android 代码判断是否获取ROOT权限(一)
[Android]Android 代码判断是否获取ROOT权限 方法比较简单,直接粘贴代码 public synchronized boolean getRootAhth() { Process pr ...
- Python学习(二十八)—— Django模板系统
转载自http://www.cnblogs.com/liwenzhou/p/7931828.html Django模板系统 官方文档 一.常用语法 只需要记两种特殊符号: {{ }}和 {% %} ...
- AtCoder Grand Contest 002 (AGC002) F - Leftmost Ball 动态规划 排列组合
原文链接https://www.cnblogs.com/zhouzhendong/p/AGC002F.html 题目传送门 - AGC002F 题意 给定 $n,k$ ,表示有 $n\times k$ ...
- 关于用舞蹈链DLX算法求解数独的解析
欢迎访问——该文出处-博客园-zhouzhendong 去博客园看该文章--传送门 描述 在做DLX算法题中,经常会做到数独类型的题目,那么,如何求解数独类型的题目?其实,学了数独的构建方法,那么DL ...
- Vijos1982 NOIP2015Day2T2 子串 substring 动态规划
子串 (substring.cpp/c/pas) 题目链接 [问题描述]有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个 互不重叠 的非空子串,然后把这 k 个子串按照 ...
- JDK自带工具keytool生成ssl证书
前言: 因为公司项目客户要求使用HTTPS的方式来保证数据的安全,所以木有办法研究了下怎么生成ssl证书来使用https以保证数据安全. 百度了不少资料,看到JAVA的JDK自带生成SSL证书的工具: ...
- XXX系统项目目标文档课堂讨论
XXXX重大技术征集系统 1.讨论结果: 2.项目目标文档 A目标: 1. 实现普通用户在线需求填报,个人信息管理,需求结果查看. 2. 实现审核员用户的需求审核,需求查看浏览和生成图表结果. 3. ...
- PAT (Basic Level) Practise - 换个格式输出整数
题目链接:https://www.patest.cn/contests/pat-b-practise/1006 1006. 换个格式输出整数 (15) 时间限制 400 ms 内存限制 65536 k ...