实现LUA脚本同步处理事件:LUA的coroutine

(转)LUA脚本实现角色AI的新方法(一、二) 在用Lua写AI脚本这一块,这是我从网上找到的唯一一篇文章,而且写的非常好,读后受宜菲浅!让我少走很多弯路。但文章源出处找不到了,在这里对这篇文章的作者表示非常的感谢! LUA实现角色AI的新方法 怪物AI只需要提供3种条件集: 1. 无目标的条件集 2. 有目标的条件集 3. 无论是有目标还是无目标, 都必须检测的条件集. 或者叫做定时器条件集. ... 阅读详情

需求

    受WOW的影响,LUA越来越多地被应用于游戏中。脚本被用于游戏中主要用于策划编写游戏规则相关。实际运用中,
我们会将很多宿主语言函数绑定到LUA脚本中,使脚本可以更多地控制程序运行。例如我们可以绑定NPCDialog之类的函数
到LUA中,然后策划便可以在脚本里控制游戏中弹出的NPC对话框。
    我们现在面临这样的需求:对于宿主程序而言,某些功能是不能阻塞程序逻辑的(对于游戏程序尤其如此),但是为
了方便策划,我们又需要让脚本看起来被阻塞了。用NPCDialog举个例子,在脚本中有如下代码 :

    ret = NPCDialog( " Hello bitch " )
   
if ret == OK then print( " OK " ) end


    对于策划而言,NPCDialog应该是阻塞的,除非玩家操作此对话框,点击OK或者关闭,不然该函数不会返回。而对于
宿主程序C++而言,我们如何实现这个函数呢:

 

 

    static   int do_npc_dialog( lua_State * L )
   
{
       
const char *content = lua_tostring( L, -1 );
       
        lua_pushnumber( ret );
       
return 1;
    }


    显然,该函数不能阻塞,否则它会阻塞整个游戏线程,这对于服务器而言是不可行的。但是如果该函数立即返回,那
么它并没有收集到玩家对于那个对话框的操作。
    综上,我们要做的是,让脚本感觉某个操作阻塞,但事实上宿主程序并没有阻塞。

 

事件机制

    一个最简单的实现(对于C程序员而言也许也是优美的),就是使用事件机制。我们将对话框的操作结果作为一个事件。
脚本里事实上没有哪个函数是阻塞的。为了处理一些“阻塞”函数的处理结果,脚本向宿主程序注册事件处理器(同GUI事件
处理其实是一样的),例如脚本可以这样:

    function onEvent( ret )
       
if ret == OK then print( " OK " ) end
    end
   
-- register event handler
    SetEventHandler(
" onEvent " )
    NPCDialog(
" Hello bitch " )


    宿主程序保存事件处理器onEvent函数名,当玩家操作了对话框后,宿主程序回调脚本中的onEvent,完成操作。
    事实上我相信有很多人确实是这么做的。这样做其实就是把一个顺序执行的代码流,分成了很多块。但是对于sleep
这样的脚本调用呢?例如:

 

 

    -- do job A
    sleep(
10 )
   
-- do job B
    sleep(
10 )
   
-- do job C
   


    那么采用事件机制将可能会把代码分解为:

    function onJobA
       
-- do job A
        SetEventHandlerB(
" onJobB " )
        sleep(
10 )
    end
    function onJobB
       
-- do job B
        SetEventHandlerC(
" onJobC " )
    end
    function onJobC
       
-- do job C
    end
   
-- script starts here
    SetEventHandlerA(
" onJobA " )
    sleep(
10 )


    代码看起来似乎有点难看了,最重要的是它不易编写,策划估计会抓狂的。我想,对于非专业程序员而言,程序的
顺序执行可能理解起来更为容易。

 

SOLVE IT

    我们的解决方案,其实只有一句话:当脚本执行到阻塞操作时(如NPCDialog),挂起脚本,当宿主程序某个操作完
成时,让脚本从之前的挂起点继续执行。
    这不是一种假想的功能。我在刚开始实现这个功能之前,以为LUA不支持这个功能。我臆想着如下的操作:
    脚本:
    ret = NPCDialog("Hello bitch")
    if ret == 0 then print("OK") end
    宿主程序:

    static   int do_npc_dialog( lua_State * L )
   
{
       
        lua_suspend_script( L );
       
    }


    某个地方某个操作完成了:
    lua_resume_script( L );
    当我实现了这个功能后,我猛然发现,实际情况和我这里想的差不多(有点汗颜)。

 


认识Coroutine

    coroutine是LUA中类似线程的东西,但是它其实和fiber更相似。也就是说,它是一种非抢占式的线程,它的切换取决
于任务本身,也就是取决你,你决定它们什么时候发生切换。建议你阅读lua manual了解更多。
    coroutine支持的典型操作有:lua_yield, lua_resume,也就是我们需要的挂起和继续执行。
    lua_State似乎就是一个coroutine,或者按照LUA文档中的另一种说法,就是一个thread。我这里之所以用’似乎‘是
因为我自己也无法确定,我只能说,lua_State看起来就是一个coroutine。
    LUA提供lua_newthread用于手工创建一个coroutine,然后将新创建的coroutine放置于堆栈顶,如同其他new出来的
对象一样。网上有帖子说lua_newthread创建的东西与脚本里调用coroutine.create创建出来的东西不一样,但是根据我
的观察来看,他们是一样的。lua_newthread返回一个lua_State对象,所以从这里可以看出,“lua_State看起来就是一个
coroutine”。另外,网上也有人说创建新的coroutine代价很大,但是,一个lua_State的代价能有多大?当然,我没做过
测试,不敢多言。
    lua_yield用于挂起一个coroutine,不过该函数只能用于coroutine内部,看看它的参数就知道了。
    lua_resume用于启动一个coroutine,它可以用于coroutine没有运行时启动之,也可以用于coroutine挂起时重新启动
之。lua_resume在两种情况下返回:coroutine挂起或者执行完毕,否则lua_resume不返回。
    lua_yield和lua_resume对应于脚本函数:coroutine.yield和coroutine.resume,建议你写写脚本程序感受下coroutine,
例如:

    function main()
        print(
" main start " )
        coroutine.yield()
        print(
" main end " )
    end
    co
= coroutine.create( main );
    coroutine.resume(co)


REALLY SOLVE IT

 

    你可能会想到,我们为脚本定义一个main,然后在宿主程序里lua_newthread创建一个coroutine,然后将main放进去,
当脚本调用宿主程序的某个’阻塞‘操作时,宿主程序获取到之前创建的coroutine,然后yield之。当操作完成时,再resume
之。
    事实上方法是对的,但是没有必要再创建一个coroutine。如之前所说,一个lua_State看上去就是一个coroutine,
而恰好,我们始终都会有一个lua_State。感觉上,这个lua_State就像是main coroutine。(就像你的主线程)
    思路就是这样,因为具体实现时,还是有些问题,所以我罗列每个步骤的代码。
    初始lua_State时如你平时所做:

    lua_State * L = lua_open();
    luaopen_base( L );


    注册脚本需要的宿主程序函数到L里:

    lua_pushcfunction( L, sleep );
    lua_setglobal( L,
" my_sleep " );


    载入脚本文件并执行时稍微有点不同:

    luaL_loadfile( L, " test.lua " );
lua_resume( L,
0 ); /* 调用resume */


    在你的’阻塞‘函数里需要挂起coroutine:

    return lua_yield( L, 0 );


    注意,lua_yield函数非常特别,它必须作为return语句被调用,否则会调用失败,具体原因我也不清楚。而在这里,
它作为lua_CFunction的返回值,会不会引发错误?因为lua_CFunction约定返回值为该函数对于脚本而言的返回值个数。
实际情况是,我看到的一些例子里都这样安排lua_yield,所以i do what they do。

 

    在这个操作完成后(如玩家操作了那个对话框),宿主程序需要唤醒coroutine:

    lua_resume( L, 0 );

 

 

    大致步骤就这些。如果你要单独创建新的lua_State,反而会搞得很麻烦,我开始就是那样的做的,总是实现不了自己
预想中的效果。

 

8.13补充

   可能有时候,我们提供给脚本的函数需要返回一些值给脚本,例如NPCDialog返回操作结果,我们只需要在宿主程序里lua_resume

之前push返回值即可,当然,需要设置lua_resume第二个参数为返回值个数。

2.9.2010
    lua_yield( L, nResults )第二个参数指定返回给lua_resume的值个数。如下:

   lua_pushnumber( L,  3  );
   
return  lua_yield( L,  1  );
 ..
   
int  ret  =  lua_resume( L,  0  );
   
if ( ret  ==  LUA_YIELD )
   
{
         lua_Number r 
= luaL_checknumber( L, -1 );
   }

lua 在unity 中的协程使用 最近尝试在unity中用上lua。 而其中必然会遇到的一个问题就是 阅读详情

相关推荐

mlua:具有asyncawait支持的高级Lua 5.45.35.25.1(包括LuaJIT)到Rust的绑定

mlua:具有asyncawait支持的高级Lua 5.45.35.25.1(包括LuaJIT)到Rust的绑定

lua coroutine 异步转同步

Global = { taskList = {} } Global.loadAsync = function(param, callback) Global.taskList[#Global.taskList + 1] = {param, callback} end Global.update = function() if #Global.taskList > 0 then

lqefn的专栏 2315

adams案例分析_案例1(麦弗逊悬架子系统创建)

本文字数3292字83图,建议阅读时间26分钟首先看下案例1的麦弗逊悬架数模结构就不细讲了,从数模上主要是获取硬点坐标(铰接点、安装点、参考点)及大部件结构(副车架、摆臂、转向节等实际运动过程中会产生变形的部件,在ADAMS Car中我们就可以用柔性体来搭建)再来回顾下上一篇讲到的模型元素1、Hardpoint——硬点(只有位置没有方向)2、Parameter Variable——参数...

weixin_39609407的博客 6476

Lua游戏脚本语言入门

Lua游戏脚本语言入门 2009年01月22日 14:34:52   【发表评论/查看评论】  作者: 沐枫 (第二人生成员)  在这篇文章中,我想向大家介绍如何进行Lua程序设计。我假设大家都学过至少一门编程语言,比如Basic或C,特别是C。因为Lua的最大用途是在宿主程序中作为脚本使用的。  Lu

xinxun的地盘 2157

Spring Cloud 整合(一) CRUD

Springcloud 整合之 CRUDSpringcloud介绍功能概述为什么要选用Springcloud Springcloud介绍 功能概述 实现微服务 Spring Cloud为开发人员提供了工具,以快速构建分布式系统中的某些常见模式(例如,配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁,领导选举,分布式会话,群集状态)。分布式系统的协调导致样板式样,并且使用Spring Cloud开发人员可以快速站起来实现这些样板的服务和应用程序。 为什么要选用Springcloud

Kerwin-Lin的博客 1501

强化学习经典算法笔记(九):LSTM加持的PolicyGradient算法

强化学习经典算法笔记(九):LSTM加持的PolicyGradient算法 在上文《强化学习经典算法笔记(八):LSTM加持的A2C算法解决POMDP问题》的基础上,实现了LSTM+MLP的Policy Gradient算法。 实现过程如下: import argparse, math, os, sys import numpy as np import gym from gym import wrappers import matplotlib.pyplot as plt import torch fr

hhy_csdn的博客 5636

Lua语言的并发编程

在现代软件开发中,特别是在需要处理大量任务或用户请求的应用程序中,并发编程已成为一个重要的主题。Lua作为一种轻量级的、高效的脚本语言,其灵活性和可嵌入性让它在游戏开发、网络应用以及其他多种场景中得到了广泛应用。本文将探讨Lua语言中的并发编程,包括其基本概念、实现方式、常用库以及示例代码。

2501_90181488的博客 500

别再只用GPS了!用Android手机传感器实现室内步行轨迹记录(避坑指南)

本文详细介绍了如何利用Android手机传感器(如加速度计、陀螺仪和磁力计)实现室内步行轨迹记录,克服GPS在室内的局限性。通过传感器数据采集、步态检测、航向估计和轨迹绘制等步骤,结合避坑指南和优化技巧,帮助开发者高效构建室内定位应用。

weixin_26821003的博客 274

Lua协程(同步的多线程)

创建一个协程,返回co(coroutine),参数是一个函数,当调用resume时就唤醒co并调用函数。返回正在跑的协程co,如果没有协程正在running就返回nil (协程处于running状态才行)创建一个协程,返回一个函数,调用函数就进入协程 => cfunc(函数参数)查看协程的状态,有 dead, suspend, running 3种状态。启动协程co并传入协程调用函数的参数,可以带回协程yield挂起返回的值。挂起协程co,可以带出参数作为resume的返回值。

qinghehe198508的博客 604

oracle p6 破解版下载,Primavera P6项目管理软件 16~17 图文详细安装教程(附下载)

Primavera P6 Professional项目管理软件结合了Oracle和Microsoft SQL Server关系数据库,是一款非常好用且功能强大的综合的项目管理软件(PPM) 解决方案,主要用于土建等方面的施工计划分析,具有进度时间安排与资源控制功能的多用户、多项目系统,支持多层项目分层结构、角色与技能导向的资源安排、记录实际数据、自定义视图以及自定义数据,本文主要为大家图文详细介绍...

weixin_33978451的博客 4912

AI人工智能领域多模态数据融合在智能诊断系统的应用案例

在医疗诊断领域,单一模态数据(如CT影像或电子病历)的局限性日益凸显——就像老中医只"望"不"闻"会漏掉关键线索。本文将深入解析多模态数据融合技术如何突破这一瓶颈:从生活化的"中医四诊"类比切入,拆解数据层/特征层/决策层融合的技术原理;结合肺癌智能诊断的真实案例,展示CT影像、病理文本、基因数据、生命体征的多模态融合全流程;最后探讨技术落地的核心挑战与未来方向。无论你是医疗从业者、AI开发者,还是对智能诊断感兴趣的爱好者,都能从中获得技术启发与应用思路。

AGI×大数据,开启智能时代的认知跃迁;解码AGI,赋能数据驱动的智能革命。 833

Lua的多任务机制——协程(coroutine)

并发是现实世界的本质特征,而聪明的计算机科学家用来模拟并发的技术手段便是多任务机制。大致上有这么两种多任务技术,一种是抢占式多任务(preemptive multitasking),它让操作系统来决定何时执行哪个任务。另外一种就是协作式多任务(cooperative multitasking),它把决定权交给任务,让它们在自己认为合适的时候自愿放弃执行。这两种多任务方式各有优缺点,前者固有的同步问

分享建筑软件的乐趣 1001

手把手教你学Simulink--单相逆变器模糊逻辑控制策略仿真

本文介绍了在Simulink中设计单相逆变器模糊逻辑控制策略的完整流程。主要包括:1)构建单相逆变器模型;2)使用FuzzyLogicToolbox设计模糊控制器,定义输入输出变量和模糊规则;3)将控制器集成到Simulink模型;4)添加干扰源和示波器;5)配置仿真参数并分析结果。该方法利用模糊控制处理非线性系统的优势,可实现输出电压的精确跟踪,具有良好的鲁棒性。文中提供了详细的步骤说明和示例代码,强调准确设计隶属函数和规则库对控制性能的关键作用。该仿真设计为电力电子控制系统的开发提供了有效支持。

MHD0815的博客 200

Coroutine,你究竟干了什么?

一 引子   使用Unity已经有一段时间了,对于Component、GameObject之类的概念也算是有所了解,而脚本方面从一开始就选定了C#,目前来看还是挺明智的:Boo太小众,而且支持有限;JS(或着说UnityScript)的话稍稍自由散漫了些,不太符合我们这些略显严谨的程序猿;相比之下,C#各方面都十分沁人心腑,使用起来还是相当舒畅的 :)   就游戏开发而言,Unit

tkokof1的专栏 2万+

深度解析长鑫G5 DRAM工艺的技术逻辑与微缩边界

长鑫存储G5 DRAM平台通过多重图形化、45:1高深宽比电容与外围HKMG技术,突破先进光刻受限瓶颈,在11.95 nm有源区半间距下实现阵列微缩与电容结构优化。其核心意义不在于对标国际节点,而在于系统性解决“尺寸缩小—电荷保持—外围跟进而”三大矛盾,展现国产DRAM在无EUV条件下推进先进制程的工艺整合能力。

硬核科技 36

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Lua 协同程序(coroutine)

Lua 协同程序(coroutine)摘要 Lua 协同程序(coroutine)是一种轻量级协作式多任务机制,允许多个函数在不使用线程的情况下交替执行。每个协同程序拥有独立的堆栈和局部变量,但共享全局资源。 核心功能 创建:coroutine.create(f) 返回新协同程序 执行/恢复:coroutine.resume(co,...) 启动或继续执行 挂起:coroutine.yield(...) 暂停当前协同程序 状态查询:coroutine.status(co) 查看运行状态 典型应用 实现迭代器

likuoelie的博客 999

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

RemDebug小巧的Lua远端调试器 告诉你coroutine很强大

 008-06-30 RemDebug小巧的Lua远端调试器 告诉你coroutine很强大 关键字: remdebug coroutine RemDebug is a remote debugger for Lua 5.0 and 5.1. It lets you controlthe execution of another Lua p

skyremember的专栏 2884

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

5 分钟跑通 ThinkRail:AI 智能体 IDE 本地运行、源码拆解与 PR 提交指南

同时让三个 AI 智能体改同一个仓库,谁先动的手谁说了算?ThinkRail 是围绕 `pi` coding agent 构建的 AI 智能体 IDE:每个智能体在独立的 git worktree 隔离工作区里干活,IDE 外壳、编辑器、终端和 diff 审查都围绕智能体任务展开。读完本文你可以克隆仓库,用三条命令在本地跑起完整可运行的版本,再顺着源码从浏览器界面追到进程内引擎,顺手提交自己的第一

gitblog_00863的博客 267

c语言yield用法,Lua中协同程序coroutine与yield用法详解

Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。而现在很多地方都会用到Lua语言,例如魔兽插件、剑网三插件、各种其他程序扩展、热更新等,所以这几天正在学习一下Lua语言,做技术储备。而在Lua的学习过程中,大部分都很容易理解,唯独协同程序Coroutine一直理解不了。于是上网查了很多人的解释,加上测试...

weixin_34300871的博客 1259

lua coroutine

Lua将它的协程函数都放进了coroutine这个表里,其中主要的函数如下

yangzhenzhen的专栏 362

Unity3D中的Coroutine详解

Unity中的Coroutine原理猜测:虚拟机分段执行机制, 同类型嵌套用栈存放实现串行执行. Unity中使用yield Coroutine需要注意的问题

自由理想的足迹 5万+
上一篇: Lua记事
下一篇: 材质继承 模板材质
Redefine
博客等级 码龄19年 4粉丝 13原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值