Python 超级玛丽代码实现:人物行走和碰撞检测
功能介绍
- 水平方向:设定X轴向右走的速度为大于0,向左走的速度为小于0
- 竖直方向:设定Y轴向下的速度为大于0,向上的速度为小于0
- 站立不动:水平方向速度为0,且竖直方向站在某个物体上。
- 向左或向右走:水平方向速度的绝对值大于0,且竖直方向站在某个物体上。
- 向上跳:竖直方向方向速度小于0,且上方没有碰到某个物体,同时需要玩家按住jump键。
- 向下降落:竖直方向方向速度大于0或者玩家没有按住jump键,且下方没有碰到某个物体。
碰撞检测
- 下方红色的长方形物体就是地面(ground)
- 右边的几个红色小方块是阶梯(step)
- 左边空中的像墙一样的是砖块(brick)
- 带问号的是箱子(box)
游戏代码
游戏实现代码的github链接 超级玛丽
这边是csdn的下载链接 超级玛丽
代码介绍
人物行走代码
有一个单独的人物类,在source\components\player.py 中,其中有个handle_state 函数,根据人物当前的状态执行不同的函数。
为了简洁下面所有函数中将不相关的代码都省略掉了。
代码已打包,学习python可加交流群:887934385 分享视频教程
学习python可加交流群:887934385 分享视频教程
def handle_state(self, keys, fire_group):
if self.state == c.STAND:
self.standing(keys, fire_group)
elif self.state == c.WALK:
self.walking(keys, fire_group)
elif self.state == c.JUMP:
self.jumping(keys, fire_group)
elif self.state == c.FALL:
self.falling(keys, fire_group)
人物的状态就是上面说的4个状态:
- 站立不动:c.STAND
- 向左或向右走:c.WALK
- 向上跳:c.JUMP
- 向下降落:c.FALL
人物类关于行走速度的成员变量先了解下:
水平方向相关的
- x_accel:水平方向的加速度,值大于0,不区别方向。
- max_x_vel:水平方向的最大速度,值大于0,不区别方向。
- x_vel:水平方向的速度,值大于0表示向右走,值小于0表示向左走。
- 初始值:max_run_vel和max_walk_vel 表示最大速度,run_accel和walk_accel表示加速度。
- facing_right:值为True表示当前是向右走,值为False表示当前是向左走,这个是用来设置人物的图像。
竖直方向相关的
- gravity:重力加速度,值大于0,表示方向向下。
- jump_vel:起跳时竖直方向的初始速度,值小于0,表示方向向上。
- y_vel:竖直方向的速度。
看下最复杂的 walking 函数,keys数组是当前按下的键盘输入,tools.keybinding中值的含义如下:
keybinding = {
'action':pg.K_s,
'jump':pg.K_a,
'left':pg.K_LEFT,
'right':pg.K_RIGHT,
'down':pg.K_DOWN
}
- 先根据当前是否有按下 keybinding[‘action’] 键来设置不同的最大水平方向速度和水平方向加速度。
- 如果有按下 keybinding[‘jump’] 键,则设置人物状态为c.JUMP,初始化竖直方向的速度
- 如果有按下keybinding[‘left’]键,表示要向左走,如果 x_vel 大于0,表示之前是向右走的,所以设置一个转身的加速度为SMALL_TURNAROUND,然后调用cal_vel 函数根据之前的速度和加速度,计算出当前的速度。
- 如果有按下keybinding[‘right’]键,表示要向右走,和上面类似
- 如果没有按下keybinding[‘left’]键和keybinding[‘right’]键,就像有摩擦力的存在,则水平方向的速度会慢慢变成0,如果 x_vel 值为0,则设置人物状态为c.STAND。
def walking(self, keys, fire_group):
if keys[tools.keybinding['action']]:
self.max_x_vel = self.max_run_vel
self.x_accel = self.run_accel
else:
self.max_x_vel = self.max_walk_vel
self.x_accel = self.walk_accel if keys[tools.keybinding['jump']]:
if self.allow_jump:
self.state = c.JUMP
if abs(self.x_vel) > 4:
self.y_vel = self.jump_vel - .5
else:
self.y_vel = self.jump_vel if keys[tools.keybinding['left']]:
self.facing_right = False
if self.x_vel > 0:
self.frame_index = 5
self.x_accel = c.SMALL_TURNAROUND self.x_vel = self.cal_vel(self.x_vel, self.max_x_vel, self.x_accel, True)
elif keys[tools.keybinding['right']]:
self.facing_right = True
if self.x_vel < 0:
self.frame_index = 5
self.x_accel = c.SMALL_TURNAROUND self.x_vel = self.cal_vel(self.x_vel, self.max_x_vel, self.x_accel)
else:
if self.facing_right:
if self.x_vel > 0:
self.x_vel -= self.x_accel
else:
self.x_vel = 0
self.state = c.STAND
else:
if self.x_vel < 0:
self.x_vel += self.x_accel
else:
self.x_vel = 0
self.state = c.STAND def cal_vel(self, vel, max_vel, accel, isNegative=False):
""" max_vel and accel must > 0 """
if isNegative:
new_vel = vel * -1
else:
new_vel = vel
if (new_vel + accel) < max_vel:
new_vel += accel
else:
new_vel = max_vel
if isNegative:
return new_vel * -1
else:
return new_vel
再看下jumping 函数,
- 开始gravity 设为 c.JUMP_GRAVITY,可以看到JUMP_GRAVITY 比GRAVITY值小很多,如果玩家长按jump键时,可以让人物跳的更高。
- 如果竖直方向速度y_vel 大于0,表示方向向下,则设置人物状态为c.FALL
- 如果按下 keybinding[‘left’]键或 keybinding[‘right’]键,则计算水平方向的速度。
- 如果没有按 keybinding[‘jump’]键,则设置人物状态为c.FALL
JUMP_GRAVITY = .31
GRAVITY = 1.01 def jumping(self, keys, fire_group):
""" y_vel value: positive is down, negative is up """
self.allow_jump = False
self.frame_index = 4
self.gravity = c.JUMP_GRAVITY
self.y_vel += self.gravity if self.y_vel >= 0 and self.y_vel < self.max_y_vel:
self.gravity = c.GRAVITY
self.state = c.FALL if keys[tools.keybinding['right']]:
self.x_vel = self.cal_vel(self.x_vel, self.max_x_vel, self.x_accel)
elif keys[tools.keybinding['left']]:
self.x_vel = self.cal_vel(self.x_vel, self.max_x_vel, self.x_accel, True) if not keys[tools.keybinding['jump']]:
self.gravity = c.GRAVITY
self.state = c.FALL
standing函数和 falling 函数比较简单,就省略了。
碰撞检测代码
- 人物的碰撞检测代码在 source\states\level.py 中的入口是
update_player_position函数 ,可以看到这边分成水平方向和竖直方向:
- 根据人物的水平方向速度x_vel 更新人物的X轴位置,同时人物的X轴位置不能超出游戏地图的X轴范围,然后调用check_player_x_collisions函数进行水平方向的碰撞检测。
- 根据人物的水平方向速度x_vel 更新人物的X轴位置,同时人物的X轴位置不能超出游戏地图的X轴范围,然后调用check_player_x_collisions函数进行水平方向的碰撞检测。
- 根据人物的竖直方向速度y_vel 更新人物的Y轴位置,然后调用check_player_y_collisions函数进行竖直方向的碰撞检测
def update_player_position(self):
self.player.rect.x += round(self.player.x_vel)
if self.player.rect.x < self.start_x:
self.player.rect.x = self.start_x
elif self.player.rect.right > self.end_x:
self.player.rect.right = self.end_x
self.check_player_x_collisions() if not self.player.dead:
self.player.rect.y += round(self.player.y_vel)
self.check_player_y_collisions()
具体实现时将同一类物体放在一个pygame.sprite.Group类中
pygame.sprite.Group
A container class to hold and manage multiple Sprite objects.
Group(*sprites) -> Group
这样每次调用pg.sprite.spritecollideany 函数就能判断人物和这一类物体是否有碰撞。
pygame.sprite.spritecollideany()
Simple test if a sprite intersects anything in a group.
spritecollideany(sprite, group, collided = None) -> Sprite Collision with the returned sprite.
spritecollideany(sprite, group, collided = None) -> None No collision
不同物体的group如下,另外敌人,金币和蘑菇等物体的碰撞检测先忽略。
- ground_step_pipe_group:地面,阶梯和水管的group。
- brick_group:砖块的group, 如果是金币砖块,从下面碰撞会获取金币。
- box_group:箱子的group,从下面碰撞箱子可以出现金币,蘑菇,花等的奖励。
因为不同种类group撞击时,后续产生的结果会有区别,所有需要对每一类group分别进行碰撞检测。
X轴方向上面3类group如果检测到有碰撞时,会调用adjust_player_for_x_collisions 函数,来调整人物的X轴位置。
def check_player_x_collisions(self):
ground_step_pipe = pg.sprite.spritecollideany(self.player, self.ground_step_pipe_group)
brick = pg.sprite.spritecollideany(self.player, self.brick_group)
box = pg.sprite.spritecollideany(self.player, self.box_group)
...
if box:
self.adjust_player_for_x_collisions(box)
elif brick:
self.adjust_player_for_x_collisions(brick)
elif ground_step_pipe:
if (ground_step_pipe.name == c.MAP_PIPE and
ground_step_pipe.type == c.PIPE_TYPE_HORIZONTAL):
return
self.adjust_player_for_x_collisions(ground_step_pipe)
elif powerup:
...
elif enemy:
...
elif coin:
...
adjust_player_for_x_collisions 函数先根据人物和碰撞物体的X轴相对位置,判断人物在碰撞物体的左边还是右边,来调整人物的X轴位置,然后设置人物水平方向的速度为0。
def adjust_player_for_x_collisions(self, collider):
if collider.name == c.MAP_SLIDER:
return if self.player.rect.x < collider.rect.x:
self.player.rect.right = collider.rect.left
else:
self.player.rect.left = collider.rect.right
self.player.x_vel = 0
学习python可加交流群:887934385 分享视频教程
check_player_y_collisions 函数也是对不同group分别进行碰撞检测,Y轴方向这3类group如果检测到有碰撞时,会调用adjust_player_for_y_collisions 函数,来调整人物的Y轴位置。 最后调用check_is_falling函数判断人物是否要设成 向下降落 的状态。
def walking(self, keys, fire_group):
if keys[tools.keybinding['action']]:
self.max_x_vel = self.max_run_vel
self.x_accel = self.run_accel
else:
self.max_x_vel = self.max_walk_vel
self.x_accel = self.walk_accel if keys[tools.keybinding['jump']]:
if self.allow_jump:
self.state = c.JUMP
if abs(self.x_vel) > 4:
self.y_vel = self.jump_vel - .5
else:
self.y_vel = self.jump_vel if keys[tools.keybinding['left']]:
self.facing_right = False
if self.x_vel > 0:
self.frame_index = 5
self.x_accel = c.SMALL_TURNAROUND self.x_vel = self.cal_vel(self.x_vel, self.max_x_vel, self.x_accel, True)
elif keys[tools.keybinding['right']]:
self.facing_right = True
if self.x_vel < 0:
self.frame_index = 5
self.x_accel = c.SMALL_TURNAROUND self.x_vel = self.cal_vel(self.x_vel, self.max_x_vel, self.x_accel)
else:
if self.facing_right:
if self.x_vel > 0:
self.x_vel -= self.x_accel
else:
self.x_vel = 0
self.state = c.STAND
else:
if self.x_vel < 0:
self.x_vel += self.x_accel
else:
self.x_vel = 0
self.state = c.STAND def cal_vel(self, vel, max_vel, accel, isNegative=False):
""" max_vel and accel must > 0 """
if isNegative:
new_vel = vel * -1
else:
new_vel = vel
if (new_vel + accel) < max_vel:
new_vel += accel
else:
new_vel = max_vel
if isNegative:
return new_vel * -1
else:
return new_vel
Python 超级玛丽代码实现:人物行走和碰撞检测的更多相关文章
- 如何用 Python 实现超级玛丽的人物行走和碰撞检测?
功能介绍 人物行走 人物的行走速度这边分成水平方向(X轴)和竖直方向(Y轴),水平方向的速度要考虑加速度和摩擦力,竖直方向的速度要考虑重力加速度. 水平方向:设定X轴向右走的速度为大于0,向左走的 ...
- Python一行代码
1:Python一行代码画出爱心 print]+(y*-)**-(x**(y*<= ,)]),-,-)]) 2:终端路径切换到某文件夹下,键入: python -m SimpleHTTPServ ...
- python爬虫代码
原创python爬虫代码 主要用到urllib2.BeautifulSoup模块 #encoding=utf-8 import re import requests import urllib2 im ...
- Python小代码_2_格式化输出
Python小代码_2_格式化输出 name = input("name:") age = input("age:") job = input("jo ...
- Python小代码_1_九九乘法表
Python小代码_1_九九乘法表 max_num = 9 row = 1 while row <= max_num: col = 1 while col <= row: print(st ...
- Python IDLE 代码高亮主题
Python IDLE 代码高亮主题 使用方法: 打开C盘我的 C:\Documents and Settings\你的用户名.idlerc文件夹 里面会有一个 config-highlight.cf ...
- 代码块: 以冒号作为开始,用缩进来划分作用域,这个整体叫做代码块,python的代码块可以提升整体的整齐度,提高开发效率
# ### 代码块: 以冒号作为开始,用缩进来划分作用域,这个整体叫做代码块 if 5 == 5: print(1) print(2) if True: print(3) print(4) if Fa ...
- uiautomatorviewer 优化定位符生成,支持生成Java,Python自动化代码
项目介绍 二次开发 uiautomatorviewer 优化定位符生成,支持生成Java,Python自动化代码,修复自带工具画面有动态加载时截图失败问题,优化自带工具截图速度 ,实现类似录制脚本功能 ...
- Python实现代码统计工具——终极加速篇
Python实现代码统计工具--终极加速篇 声明 本文对于先前系列文章中实现的C/Python代码统计工具(CPLineCounter),通过C扩展接口重写核心算法加以优化,并与网上常见的统计工具做对 ...
随机推荐
- Python基础10 回顾
从最初的"Hello World",走到面向对象,该回过头来看看,教程中是否遗漏了什么. 我们之前提到一句话,"Everything is Object".那么 ...
- Tyvj 1864 [Poetize I]守卫者的挑战
P1864 [Poetize I]守卫者的挑战时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 打开了黑魔法师Vani的大门,队员们在迷宫般的路上漫无目的地搜寻 ...
- python不得不知的几个开源项目
1.Trac Trac拥有强大的bug管理 功能,并集成了Wiki 用于文档管理.它还支持代码管理工具Subversion ,这样可以在 bug管理和Wiki中方便地参考程序源代码. Trac有着比较 ...
- URL的转义和解析
在开始python编程之前我们先来看看一个关与url的知识 在url中会有一些特殊字符,如果你写过cgi程序,并且提交一个表单去调用你的cgi,你会很清楚的 像?name=aiqier&age ...
- 【DCN】路由操作
offset */interface in/out access-list/prefix-list <1-16> // 修改路由偏移量 RIP偏移列表 ...
- Codeforces Round #178 (Div. 2)
A. Shaass and Oskols 模拟. B. Shaass and Bookshelf 二分厚度. 对于厚度相同的书本,宽度竖着放显然更优. 宽度只有两种,所以枚举其中一种的个数,另一种的个 ...
- fatal: Not a git repository (or any of the parent directories)
当从github.com上面下载下了Firmware后,无意中删除了Firmware目录下的.git文件夹,再去编译就会出现: fatal: Not a git repository (or an ...
- $_GET $_POST $_REQUEST
<form action="__APP__/View/editArticle?id=5" method="GET"> <form>表单提 ...
- Python--day32--复习:https和http的区别;黏包;黏包问题的解决方式;
1,https和http的区别: https比较安全,传输的时候先对内容进行加密,收到后再进行解密:它的传输内容不容易拦截,就算拦截下来了,也是加密的,看不懂.但是要买证书,一年要好几万,小公司承担不 ...
- 2019-8-31-C#-获取-PC-序列号
title author date CreateTime categories C# 获取 PC 序列号 lindexi 2019-08-31 16:55:58 +0800 2018-7-30 10: ...