鱼C论坛

 找回密码
 立即注册
楼主: 小甲鱼

[扩展阅读] 游戏中的角色移动:闭包(closure)在实际开发中的作用

    [复制链接]
发表于 2018-3-29 10:21:12 | 显示全部楼层
发现了一个问题,好像并没有初始化为0啊,都是在上一步的位置上移动的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-3-30 22:35:33 | 显示全部楼层
本帖最后由 jasonpy 于 2018-3-30 22:43 编辑

个人的一些学习心得,希望能帮助到看不懂的鱼友们

origin = (0, 0)         # 原点
legal_x = [-100, 100]   # x轴的移动范围
legal_y = [-100, 100]   # y轴的移动范围

def create(pos_x=0, pos_y=0):
# 初始化位于原点为主   
    def moving(direction, step):
    # direction参数设置方向,1为向右(向上),-1为向左(向下),0为不移动
    # step参数设置移动的距离
        nonlocal pos_x, pos_y #强制pos为非局部变量,可记录
        print('initial value pos_x: ',pos_x)
        print('initial valu pos_y: ',pos_y)

        new_x = pos_x + direction[0] * step
        new_y = pos_y + direction[1] * step
        # 检查移动后是否超出x轴边界
        if new_x < legal_x[0]:
            pos_x = legal_x[0] - (new_x - legal_x[0])
        elif new_x > legal_x[1]:
            pos_x = legal_x[1] - (new_x - legal_x[1])
        else:            
            pos_x = new_x
        # 检查移动后是否超出y轴边界
        if new_y < legal_y[0]:
            pos_y = legal_y[0] - (new_y - legal_y[0])
        elif new_y > legal_y[1]:
            pos_y = legal_y[1] - (new_y - legal_y[1])
        else:            
            pos_y = new_y
        print('final value pos_x: ',pos_x)
        print('final valu pos_y: ',pos_y)

        return pos_x, pos_y # return 这里是让moving这个function输出pos_x,pos_y
        #pos_x and pos_y are global virables, here specify nonlocal
    return moving
   
move = create() # move is a function type that returns the closure function//
# move(direction, step)
print('向右移动10步后,位置是:', move([1, 0], 10))
print('向上移动130步后,位置是:', move([0, 1], 130))
print('向左移动10步后,位置是:', move([-1, 0], 10))

# pos_x pos_y is not defined globally.....!!!

个人的一些研究,上面的代码加上几个注释后会输出以下,也就是说闭包很大的一个好处就是可以记住历史,这个用一般方程比较难做到。。
initial value pos_x:  0
initial valu pos_y:  0
final value pos_x:  10
final valu pos_y:  0
向右移动10步后,位置是: (10, 0)
initial value pos_x:  10
initial valu pos_y:  0
final value pos_x:  10
final valu pos_y:  70
向上移动130步后,位置是: (10, 70)
initial value pos_x:  10
initial valu pos_y:  70
final value pos_x:  0
final valu pos_y:  70
向左移动10步后,位置是: (0, 70)

我尝试了一下不用闭包写一段比较容易明白的代码:
origin = (0, 0)         # 原点
legal_x = [-100, 100]   # x轴的移动范围
legal_y = [-100, 100]   # y轴的移动范围

tempos_x = 0
tempos_y = 0

def moving(direction, step):
# direction参数设置方向,1为向右(向上),-1为向左(向下),0为不移动
# step参数设置移动的距离
    #nonlocal pos_x, pos_y #强制pos为非局部变量
    global tempos_x, tempos_y
    pos_x = tempos_x #设置起始值
    pos_y = tempos_y #设置起始值
   
    new_x = pos_x + direction[0] * step
    new_y = pos_y + direction[1] * step
    # 检查移动后是否超出x轴边界
    if new_x < legal_x[0]:
        pos_x = legal_x[0] - (new_x - legal_x[0])
    elif new_x > legal_x[1]:
        pos_x = legal_x[1] - (new_x - legal_x[1])
    else:            
        pos_x = new_x
    # 检查移动后是否超出y轴边界
    if new_y < legal_y[0]:
        pos_y = legal_y[0] - (new_y - legal_y[0])
    elif new_y > legal_y[1]:
        pos_y = legal_y[1] - (new_y - legal_y[1])
    else:            
        pos_y = new_y
    tempos_x = pos_x
    tempos_y = pos_y
    return pos_x, pos_y
    #pos_x and pos_y are global virables, here specify nonlocal
#return moving
   
#move = create() # move is a function type that returns the closure function//
# move(direction, step)
print('向右移动10步后,位置是:',moving([1, 0],10))
print('向上移动130步后,位置是:',moving([0, 1],130))
print('向左移动10步后,位置是:',moving([-1, 0],10))
# if use this function, then it can't remember pos_x and pos_y..
#..need to manually define the last positon to return the same results...

同样,这个会输出一样的结果:
向右移动10步后,位置是: (10, 0)
向上移动130步后,位置是: (10, 70)
向左移动10步后,位置是: (0, 70)

显而,第二段代码是比较“低级”的也更容易明白的,明白了后,就知道闭包的好处啦,就是可以非常简单的“记忆”,只需要定义一个“nonlocal”,就可以有记忆功能了,也不需要定义全局变量。希望这个可以帮助到看不懂的人
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-4-1 12:39:24 | 显示全部楼层
66666666,赞一个
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-4-11 15:50:43 | 显示全部楼层
关于每次都会初始化的理解:
有两个关键知识点:
1.函数中的默认参数值:
当某些函数需要有默认输入(即提前设定好缺省值)可用以下格式:
def myfun(x=缺省值):
        print(x)
2.闭包函数(函数中的函数)的调用:
example:
def test1():
    def test2():
        print('sucessful')
    return test2()
def test1_1():
    def test2_2():
        print('bingo')
    return test2_2
如果需要访问test2以及test2_2,则分别输入test1()以及test1_1()()。
而此程序中,move=create(),相当于move已经调用了create(位置1)(位置2)的位置一,而且位置一使用了默认值(pos_x=0,pos_y=0),这样相当于通过move()这种操作把一个闭包函数脱掉了一层衣服。在需要调用的时候,只需要输入里面那层衣服需要的值就好。
如果要是type(move)的话可以发现其返回值是function类型。
当然也可以试试 test=create(2,2)([1,0],1),这样也是有输出结果的。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 1 反对 0

使用道具 举报

发表于 2018-4-13 22:00:27 | 显示全部楼层
666
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-4-24 11:33:33 | 显示全部楼层
看不懂 ,长路漫漫呀
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-4-27 19:40:40 | 显示全部楼层
yu_wind 发表于 2014-1-11 16:22
请问
if new_x < legal_x[0]:
            pos_x = legal_x[0] - (new_x - legal_x[0])

等于的不算超出边界,在else里 就行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-4-29 11:19:29 | 显示全部楼层
新手,,,,,看不懂。。。。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-9 13:24:53 | 显示全部楼层
能复制否
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-19 14:45:05 | 显示全部楼层
IDLE返回:SyntaxError: multiple statements found while compiling a single statement
查了下是说我在一行里写了多行的代码,是版本的问题么,我装的是3.4.1
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-22 21:35:14 | 显示全部楼层
guokai83524 发表于 2014-3-17 13:05
看不懂最后的调用30-33行,为什么move里面可以这样带参数,不理解

因为move = create()之后,move 就相当于将内部函数moving了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-22 21:37:23 | 显示全部楼层
为什么每次动作完之后需要强制将pos_x和pos_y强制归零呢,为什么不能在上次位置的基础上进行移动呢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-23 09:41:43 | 显示全部楼层
ddddddddd
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-28 14:46:59 | 显示全部楼层
yu_wind 发表于 2014-1-11 16:22
请问
if new_x < legal_x[0]:
            pos_x = legal_x[0] - (new_x - legal_x[0])

假设 pos_x等于legal_x[0] 那么 if 里面 改写一下 变成  pos_x+new_x = legal_x【0】+legal_x[0]
因为pos_x等于legal_x[0] 所以消掉  那么久变成  new_x = legal_x[0]了  如果 new_x= legal_x[0]就不会进if了 应该进 else 毕竟你的if条件是 new_x < legal_x[0]
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-31 11:18:21 | 显示全部楼层
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-6-8 15:57:10 | 显示全部楼层
yu_wind 发表于 2014-1-11 16:55
我估计是我没看明白咋么移动的,
我的理解是, x轴上  原来-80 往左挪30  变成-110  然后 if  的结果是-90 ...

我觉得也是,撞完墙会退回来
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-6-10 23:30:34 | 显示全部楼层
想问一下:28行return moving没有看懂,moving不是一个变量,那返回的是什么呢,是将这个函数运行一遍吗。还有move到底是一个函数还是变量呢。move运行之后的返回结果moving到底是什么形式呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-6-20 12:00:02 | 显示全部楼层
还没明白,学完20课再来学
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-6-21 01:10:54 | 显示全部楼层
小甲鱼哥哥能赠送一点鱼币吗,好想做课后习题却没有鱼币,内心十分纠结呢,下个月我就可以开会员了,这个月实在囊中羞涩
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-6-27 10:11:31 | 显示全部楼层
小甲鱼 发表于 2014-1-11 16:24
等于的话走else:分支,临界并不算超界

可是else:分支不是pos_x = new_x吗?为什么if new_x < legal_x[0]时,不直接pox_x=legal_x[0]呢?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-3 20:26

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表