这个游戏叫jumpy,大致玩法就是模拟超级玛丽一样,可以不停在各个档板上跳动,同时受到重力的作用,会向下掉,如果落下时,没有站在档板上,就挂了。

这节,我们加入重力因素,继续改造sprites.py

  1. from part_03.settings import *
  2. import pygame as pg
  3.  
  4. vec = pg.math.Vector2
  5.  
  6. class Player(pg.sprite.Sprite):
  7. def __init__(self):
  8. pg.sprite.Sprite.__init__(self)
  9. self.image = pg.Surface((30, 30))
  10. self.image.fill(YELLOW)
  11. self.rect = self.image.get_rect()
  12. self.rect.center = WIDTH / 2, HEIGHT / 2
  13. self.pos = self.rect.center
  14. self.vel = vec(0, 0)
  15. self.acc = vec(0, 0)
  16. self.width = self.rect.width
  17. self.height = self.rect.height
  18.  
  19. def update(self):
  20. # 初始化时,垂直方向加入重力加速度
  21. self.acc = vec(0, PLAYER_GRAVITY)
  22. keys = pg.key.get_pressed()
  23. if keys[pg.K_LEFT]:
  24. self.acc.x = -PLAYER_ACC
  25. if keys[pg.K_RIGHT]:
  26. self.acc.x = PLAYER_ACC
  27.  
  28. self.acc.x += self.vel.x * PLAYER_FRICTION
  29.  
  30. self.vel += self.acc
  31. self.pos += self.vel
  32.  
  33. if self.rect.left > WIDTH:
  34. self.pos.x = 0 - self.width / 2
  35. if self.rect.right < 0:
  36. self.pos.x = WIDTH + self.width / 2
  37. # 碰撞后,方块底部要停在档板上,所以要改成rect.midbottom
  38. self.rect.midbottom = self.pos
  39.  
  40. # 档板类
  41. class Platform(pg.sprite.Sprite):
  42. def __init__(self, x, y, w, h):
  43. pg.sprite.Sprite.__init__(self)
  44. self.image = pg.Surface((w, h))
  45. self.image.fill(GREEN)
  46. self.rect = self.image.get_rect()
  47. self.rect.x = x
  48. self.rect.y = y

新建了一个Platform类,用来模拟档板,其实就是一个绿色的长矩形条;其次Player在update中,acc加速度初始化时,引入了垂直方向的加速度,其值仍然在settings.py中定义:

  1. # game options
  2.  
  3. SIZE = WIDTH, HEIGHT = 360, 480
  4. FPS = 60
  5. DEBUG = True
  6.  
  7. TITLE = "Jumpy!"
  8.  
  9. # Player properties
  10. PLAYER_ACC = 0.5
  11. PLAYER_GRAVITY = 0.5 # 重力加速度
  12. PLAYER_FRICTION = -0.06
  13.  
  14. # define color
  15. BLACK = 0, 0, 0
  16. WHITE = 255, 255, 255
  17. RED = 255, 0, 0
  18. GREEN = 0, 255, 0
  19. BLUE = 0, 0, 255
  20. YELLOW = 255, 255, 0

 然后在main.py中使用这个Platform类:

  1. from part_03.sprites import *
  2. from part_03.settings import *
  3.  
  4. class Game:
  5.  
  6. def __init__(self):
  7. pg.init()
  8. pg.mixer.init()
  9. self.screen = pg.display.set_mode(SIZE)
  10. pg.display.set_caption(TITLE)
  11. self.clock = pg.time.Clock()
  12. self.running = True
  13. self.playing = False
  14. self.p1 = object
  15.  
  16. def new(self):
  17. self.all_sprites = pg.sprite.Group()
  18. # 创建一个档板Group
  19. self.platforms = pg.sprite.Group()
  20. self.player = Player()
  21. self.all_sprites.add(self.player)
  22. # 加入2个档板实例
  23. self.p1 = Platform(0, HEIGHT - 40, WIDTH, 40)
  24. p2 = Platform(WIDTH / 2 - 50, HEIGHT / 2 + 100, 100, 20)
  25. self.all_sprites.add(self.p1)
  26. self.all_sprites.add(p2)
  27. self.platforms.add(self.p1)
  28. self.platforms.add(p2)
  29. g.run()
  30.  
  31. def run(self):
  32. self.playing = True
  33. while self.playing:
  34. self.clock.tick(FPS)
  35. self.events()
  36. self.update()
  37. self.draw()
  38.  
  39. def update(self):
  40. self.all_sprites.update()
  41. # 碰撞检测
  42. hits = pg.sprite.spritecollide(self.player, self.platforms, False)
  43. if hits:
  44. self.player.pos.y = hits[0].rect.top
  45. # 碰撞后,将player 垂直方向的速度归0(否则物体还是会继续向下掉)
  46. self.player.vel.y = 0
  47.  
  48. def events(self):
  49. for event in pg.event.get():
  50. if event.type == pg.QUIT:
  51. if self.playing:
  52. self.playing = False
  53. self.running = False
  54.  
  55. def draw(self):
  56. self.screen.fill(BLACK)
  57. self.all_sprites.draw(self.screen)
  58. self.debug()
  59. pg.display.flip()
  60.  
  61. def debug(self):
  62. if DEBUG:
  63. font = pg.font.SysFont('Menlo', 25, True)
  64. pos_txt = font.render(
  65. 'Pos:(' + str(round(self.player.pos.x, 2)) + "," + str(round(self.player.pos.y, 2)) + ")", 1, GREEN)
  66. vel_txt = font.render(
  67. 'Vel:(' + str(round(self.player.vel.x, 2)) + "," + str(round(self.player.vel.y, 2)) + ")", 1, GREEN)
  68. acc_txt = font.render(
  69. 'Acc:(' + str(round(self.player.acc.x, 2)) + "," + str(round(self.player.acc.y, 2)) + ")", 1, GREEN)
  70. self.screen.blit(pos_txt, (20, 10))
  71. self.screen.blit(vel_txt, (20, 40))
  72. self.screen.blit(acc_txt, (20, 70))
  73. pg.draw.line(self.screen, WHITE, (0, HEIGHT / 2), (WIDTH, HEIGHT / 2), 1)
  74. pg.draw.line(self.screen, WHITE, (WIDTH / 2, 0), (WIDTH / 2, HEIGHT), 1)
  75.  
  76. def show_start_screen(self):
  77. pass
  78.  
  79. def show_go_screen(self):
  80. pass
  81.  
  82. g = Game()
  83. g.show_start_screen()
  84. while g.running:
  85. g.new()
  86. g.show_go_screen()
  87.  
  88. 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()方法改成下面这样

  1. def update(self):
  2. # 初始化时,垂直方向加入重力加速度
  3. self.acc = vec(0, PLAYER_GRAVITY)
  4. keys = pg.key.get_pressed()
  5. if keys[pg.K_LEFT]:
  6. self.acc.x = -PLAYER_ACC
  7. if keys[pg.K_RIGHT]:
  8. self.acc.x = PLAYER_ACC
  9.  
  10. self.acc.x += self.vel.x * PLAYER_FRICTION
  11.  
  12. self.vel += self.acc
  13. self.pos += self.vel
  14.  
  15. if self.rect.left > WIDTH:
  16. self.pos.x = 0 - self.width / 2
  17. if self.rect.right < 0:
  18. self.pos.x = WIDTH + self.width / 2
  19.  
  20. # self.rect.midbottom = self.pos
  21. # 校正0.5px上下抖动的问题
  22. if abs(self.rect.bottom - self.pos.y) >= 1:
  23. self.rect.bottom = self.pos.y
  24. 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-重力及碰撞检测的更多相关文章

  1. UIDynamic(重力行为+碰撞检测)

    一.重力行为 说明:给定重力方向.加速度,让物体朝着重力方向掉落 1.方法 (1)UIGravityBehavior的初始化 - (instancetype)initWithItems:(NSArra ...

  2. iOS开发拓展篇—UIDynamic(重力行为+碰撞检测)

    iOS开发拓展篇—UIDynamic(重力行为+碰撞检测) 一.重力行为 说明:给定重力方向.加速度,让物体朝着重力方向掉落 1.方法 (1)UIGravityBehavior的初始化 - (inst ...

  3. 李洪强iOS开发拓展篇—UIDynamic(重力行为+碰撞检测)

    iOS开发拓展篇—UIDynamic(重力行为+碰撞检测) 一.重力行为 说明:给定重力方向.加速度,让物体朝着重力方向掉落 1.方法 (1)UIGravityBehavior的初始化 - (inst ...

  4. Unity3D实践系列09, 物理引擎与碰撞检测

    在Unity3D中,一个物体通常包含一个Collider和一个Rigidbody.Collider是碰撞体,一个物体是Collider,才可以进行碰撞检测.Collider组件中的"Is T ...

  5. 【Flask-RESTPlus系列】Part3:请求解析

    0x00 内容概览 请求解析 基本参数 必需参数 多值和列表 其他目标 参数位置 参数多个位置 高级类型处理 解析器继承 文件上传 错误处理 错误消息 参考链接 0x01 请求解析 注意:Flask- ...

  6. 2015/11/7用Python写游戏,pygame入门(7):碰撞检测

    我们已经完成了飞机大战的大部分东西,但是游戏还是没有办法正式开玩,因为子弹并不能打掉飞机.只有完成了这一个工作,游戏才算基本成型. 今天的内容就非常简单了,就是做到这个碰撞检测,以及控制好子弹和飞机的 ...

  7. Python游戏编程(Pygame)

    安装Pygame pip install pygame C:\Users> pip install pygame Collecting pygame Downloading https://fi ...

  8. Android系统编程入门系列之硬件交互——传感器

    到目前为止,关于应用程序与用户之间的相关内容便比较肤浅的大致介绍完毕.而在整个系统架构中,应用程序与用户之间的交互,犹如参天大树上的枝干和树叶,交互起来五彩缤纷,但使整个生态系统保持生命力的核心,在于 ...

  9. 文顶顶iOS开发博客链接整理及部分项目源代码下载

    文顶顶iOS开发博客链接整理及部分项目源代码下载   网上的iOS开发的教程很多,但是像cnblogs博主文顶顶的博客这样内容图文并茂,代码齐全,示例经典,原理也有阐述,覆盖面宽广,自成系统的系列教程 ...

  10. UIDynamic--动力元素行为:UIDynamicItemBehavior

    属性分析: @property (nonatomic, readonly, copy) NSArray* items; @property (readwrite, nonatomic) CGFloat ...

随机推荐

  1. 3. 深入研究 UCenter API 之 加密与解密(转载)

    1.  深入研究 UCenter API 之 开篇 (转载) 2.  深入研究 UCenter API 之 通讯原理(转载) 3.  深入研究 UCenter API 之 加密与解密(转载) 4.  ...

  2. OAuth2:隐式授权(Implicit Grant)类型的开放授权

    适用范围 仅需临时访问的场景 用户会定期在API提供者那里进行登录 OAuth客户端运行在浏览器中(Javascript.Flash等) 浏览器绝对可信,因为该类型可能会将访问令牌泄露给恶意用户或应用 ...

  3. 【Android】Android 代码判断是否获取ROOT权限(一)

    [Android]Android 代码判断是否获取ROOT权限 方法比较简单,直接粘贴代码 public synchronized boolean getRootAhth() { Process pr ...

  4. Python学习(二十八)—— Django模板系统

    转载自http://www.cnblogs.com/liwenzhou/p/7931828.html Django模板系统 官方文档 一.常用语法 只需要记两种特殊符号: {{  }}和 {% %} ...

  5. AtCoder Grand Contest 002 (AGC002) F - Leftmost Ball 动态规划 排列组合

    原文链接https://www.cnblogs.com/zhouzhendong/p/AGC002F.html 题目传送门 - AGC002F 题意 给定 $n,k$ ,表示有 $n\times k$ ...

  6. 关于用舞蹈链DLX算法求解数独的解析

    欢迎访问——该文出处-博客园-zhouzhendong 去博客园看该文章--传送门 描述 在做DLX算法题中,经常会做到数独类型的题目,那么,如何求解数独类型的题目?其实,学了数独的构建方法,那么DL ...

  7. Vijos1982 NOIP2015Day2T2 子串 substring 动态规划

    子串 (substring.cpp/c/pas) 题目链接 [问题描述]有两个仅包含小写英文字母的字符串 A 和 B.现在要从字符串 A 中取出 k 个 互不重叠 的非空子串,然后把这 k 个子串按照 ...

  8. JDK自带工具keytool生成ssl证书

    前言: 因为公司项目客户要求使用HTTPS的方式来保证数据的安全,所以木有办法研究了下怎么生成ssl证书来使用https以保证数据安全. 百度了不少资料,看到JAVA的JDK自带生成SSL证书的工具: ...

  9. XXX系统项目目标文档课堂讨论

    XXXX重大技术征集系统 1.讨论结果: 2.项目目标文档 A目标: 1. 实现普通用户在线需求填报,个人信息管理,需求结果查看. 2. 实现审核员用户的需求审核,需求查看浏览和生成图表结果. 3. ...

  10. PAT (Basic Level) Practise - 换个格式输出整数

    题目链接:https://www.patest.cn/contests/pat-b-practise/1006 1006. 换个格式输出整数 (15) 时间限制 400 ms 内存限制 65536 k ...