一个单机棋盘式半即时解谜RPG的开发与反思、3

无人机地面站链路全解析:数传、AP、4G/5G 与 RTK 差分接入原理及排查实践 本文系统梳理了无人机地面站与飞控的通讯链路架构,涵盖数传电台、WiFi AP及蜂窝(4G/5G)三种接入方式的工作原理与排查流程。重点强调物理层(波特率、供电、天线)、MAVLink层(心跳、SYSID、协议版本)和应用层(端口、心跳保活、网络配置)的逐层排查逻辑。对比分析了AP与蜂窝链路在延迟、覆盖、多机支持等方面的优劣,提出“专用链路控实时、AP传数据、蜂窝远监控”的组合使用策略,并指出共性风险如省电模式、NAT超时等需统一防范。 阅读详情

综述

游戏核心部分目前完成了Json数据载入、Lua调用、大地图的显示、玩家移动、墙壁阻断这些内容。结构为GBase(基础设施:数据类、实例类、宏定义)、Logic(主要逻辑实现)、UI(用户接口)。

GBase-helper: GGameLoader , GManager , GObject
GBase-data: GItem , GMap , GPackage
GBase-instance: GInstance , GItemInstance , GMapInstance , GRoleInstance , GWallInstance , GMapTile

Logic: Runtime , MapEventCallbacks , Logic

UI: LMap , LMapPlane , KeyMapping

软件结构

GBase

GBase主要实现了数据、实例、管理器、游戏加载器四个部分。一个数据对应多个实例,管理器管理数据集,加载器从Json加载游戏。
在游戏加载时GPackage、GMap、GItem是同一层级的,不具备树状关系,它们Json中的Name字段也是全局唯一的,即便在不同包之间也必须可以通过Name来进行精确的定位。游戏中有一些不同的GManager,例如GToolManager用来管理游戏中的道具,只要Tool被载入后(即便来自不同包),他们也会通过同一个GToolManager来管理,因此Name的唯一性十分重要。开发过程中Name具有命名规范,大约为包名-种类名-Item名等,不再详述。这样做的好处是逻辑上的松耦合,Item和Map以及Package没有关联,减少逻辑复杂性。
GGameLoader在需要的时候从Json加载数据,生成游戏数据,把它们交给GManager管理,GGameLoader不会生成数据的实例。
GInstance是个基类,被实现为GItemInstance、GMapInstance等,实际上目前大部分是typedef。关于数据和实例的关系在第一篇文章中介绍过了。
UI部分负责数据的显示和相应操作,数据的实例化是在UI中实现的,例如当玩家创建地图开始游戏时,UI层会创建一个GMapInstance,GMapInstance会创建它内部的GItemInstance。GMapInstance首先通过RJCBLib::Matrix管理GMapTile,直接地把地图块当做矩阵管理,每一个块有地形、道具、陷阱、墙等实例。LMap是一个继承自cocos2d::Layer的Map UI,LMap下面有一些LMapPlane同样继承自cocos2d::Layer,在GMapInstance中实例是通过GMapTile作为矩阵被管理的,到了UI层这些实例又被打散为一层一层的被LMapPlane管理。这样就可以按层调整显示顺序,如地形在最后面,然后是陷阱、道具、角色、墙等。但是这样不利于逻辑的控制,所以UI部分被实现得尽量透明,开发者只要通过GMapInstance中的Matrix来管理GMapTile就可以,对象的移动会自动的反应到UI上。
GItem和GInstance继承自GObject,GObject继承自RJCBLib::LuaObject和RJCBLib::KVObject,GInstance还继承了cocos2d::Sprite这样实力可以直接被显示在UI上。
实际上之前GInstance并没有直接继承自cocos2d::Sprite而是在UI层增加了一个叫NMapNode的类,这个类做为实例和UI的接口,这样有利于保持逻辑上的隔离。但是经过实践发现NMapNode本身没有新功能的实现,它仅仅是逻辑上的存在对实际使用没有帮助,而且增加了逻辑复杂性和操作的复杂性。在使用时要使用类似node->instance->getAttribute<int>("key")的代码,体验很不好于是就将其删除了。

GObject

GObject为游戏对象提供KV属性和Lua支持。

    class GObjectNoManaged : public RJCBLib::LuaObject, public RJCBLib::KVObject
    {
    public:
        //直接从KV定义中开启Lua支持,用于对Json文件的支持
        void openLuaSupportFromKVObject(std::string packageName);
        //通过文件路径开启Lua支持
        void openLuaSupport(std::string luaScriptFilePath);
    protected:
        //存储这个对象的Lua文件路径
        std::string luaScriptFilePath;

        GObjectNoManaged();

        virtual std::string getLuaScriptFilePath() override;
        virtual std::string getUpdateFunctionName() override;
        virtual std::string LuaObjectGetString(std::string key) override;
        virtual int LuaObjectGetInt(std::string key) override;
        virtual bool LuaObjectGetBool(std::string key) override;
        virtual double LuaObjectGetDouble(std::string key) override;
        virtual void LuaObjectSetString(std::string key, std::string value) override;
        virtual void LuaObjectSetInt(std::string key, int value) override;
        virtual void LuaObjectSetBool(std::string key, bool value) override;
        virtual void LuaObjectSetDouble(std::string key, double value) override;
    };

    class GObject : public GObjectNoManaged, public cocos2d::Ref
    {

    };

结合上一篇文章对RJCBLib的介绍,GObject继承了RJCBLib::LuaObject和RJCBLib::KVObject两个类,KVObject可以自动读取rapidjson的数据,将它们作为KV存储起来,结合getLuaScriptFilePath()和getUpdateFunctionName()可以实现自动从Json获取Lua相关数据。GObjectNoManaged是没有继承cocos2d::Ref的版本,这样做是为了消除继承的二义性,后面会提到。

GItem

GItem仅仅继承自GObject,没有其他功能。

class GItem : public GObject
{
private:
    GItem();
public:
    static GItem* create();
};

Instance

GInstance继承自GObject,其保留一个对数据(GItem)的指针。

class GInstance : public GBase::GObjectNoManaged , public cocos2d::Sprite
{


private:
    cocos2d::Vec2 toGamePosition;//MovingByUpdating中记录目标点
    bool isMovingByUpdate;//标记是否处于MovingByUpdate中
    bool shouldCallInstanceLuaUpdate;//这个实例要求调用Lua Update回调
    bool shouldCallDataLuaUpdate;//这个实例对应的数据要求调用Lua Update回调
    cocos2d::Vec2 gamePosition;//这个对象所在地图的格子坐标,应总是为整数
    cocos2d::Vec2 gamePositionOffset;//这个对象实际坐标对gamePosition的位移,XY位对格子尺寸WH的系数


public:
    GObject* data;//对应的数据
    GMapInstance* iMap;//所在Map实例
    bool isMoving;//移动中


private:
    //将gamePosition的变化更新到Lua中
    void updateLuaPosition();

    //通过update实现move的函数
    void updateMoveStep(float deltaTime);

protected:
    GInstance();

public:
    ~GInstance();

    bool init(GObject* data,GMapInstance* iMap = nullptr);

    //获取属性,优先从实例获取,若不存在则从数据获取
    template<typename T>
    RJCBLib::FUNC_RETURN_TYPE getAttribute(std::string key, RJCBLib::GenericValue & out)
    {
        RJCBLib::FUNC_RETURN_TYPE_W ret;
        ret = this->getValue<T>(key, out);
        if (ret == RJCBLib::FUNC_RETURN_VALUE_SUCCESS)
            return RJCBLib::FUNC_RETURN_VALUE_SUCCESS;

        ret = this->data->getValue<T>(key, out);
        return ret;
    }

    //设置属性,可选(toData)为实例或数据设置
    template<typename T>
    RJCBLib::FUNC_RETURN_TYPE setAttribute(std::string key, const RJCBLib::GenericValue& in,bool toData = false)
    {
        if (toData == true)
            return this->data->setValue<T>(key, in);
        return this->setValue<T>(key, in);
    }

    //GamePosition存取器
    inline void setGamePositionAtt(const cocos2d::Vec2& pos)
    {
        gamePosition = pos;
        updateLuaPosition();
    }

    //GamePosition存取器
    inline cocos2d::Vec2 getGamePositionAtt()
    {
        return gamePosition;
    }

    //cocos2d update
    virtual void update(float deltaTime) override;

    //获取移动速度
    double getSpeed();

    //执行Lua回调,state - 回调名
    void doLua(GBase::LUA_INTERFACE_TYPE state);

    //设置这个对象的位置(游戏坐标)
    void setGamePosition(const cocos2d::Vec2 & position, const cocos2d::Vec2 & positionOffset = cocos2d::Vec2::ZERO);

    //使用cocos2d action移动
    void moveTo(const cocos2d::Vec2 & to);

    //使用update实现的移动,会触发Lua的Update回调(若注册了)
    void moveToByUpdate(const cocos2d::Vec2 & to);
};

GInstance还实现了移动、Lua事件的具体功能,getAttribut<>()和setAttribute<>()封装了RJCBLib::KVObject的相关方法,因为玩家肯能对实例操作也可能对他背后的数据操作。例如一个道具小刀,它可能有自己的数据材质为木头,但是实例化后某一个小刀可能为钢铁材质,这样只需要将实例的材质改为钢铁,这样对实例getAttribute<>()会优先返回实例属性,若不存在则返回数据属性,设置的时候可以选择是对实例还是数据操作。
移动没有使用cocos2d的MoveTo动作而是自己通过Update实现的移动,这样做是为了对代码提供更好的控制,例如在Update每一帧可能会调用Lua事件,这时修改了对象的速度,新的速度就可以直接的产生作用。
GItem继承自GObject,GInstance继承自GObjectNoManaged,这样做是因为GObject和cocos2d::Sprite都继承自cocos2d::Ref,如果GInstance继承自GObject,那么通过cocos2d::Ref对其管理将造成二义性。

GManager

GManager不能再简单了。

class GPackageManager : public RJCBLib::ObjectManager<GPackageManager, std::string, GPackage*>
{

};

class GMapManager : public RJCBLib::ObjectManager<GMapManager, std::string, GMap*>
{

};

class GItemManager :public RJCBLib::ObjectManager<GItemManager, std::string, GItem*>
{

};

GMapInstance

class GMapInstance : public GInstance
{
private:
    GMapInstance();
public :
    GMap* getDataMap();
    RJCBLib::Matrix<GMapTile>* dataTiles;
    virtual ~GMapInstance();
    static GMapInstance* create();
    bool init(std::string mapName, std::string packageName);

    bool isPositionValid(int x, int y);

    static void calcDirectionPosition(std::string direction, int inX, int inY, int &outX, int &outY);
};

GMapTile

class GMapTile : public RJCBLib::KVObject,public cocos2d::Ref
{
private:
    GMapTile();
public:
    static GMapTile* create();
    GItemInstance *trap;
    GItemInstance *tool;
    GItemInstance *terrainBack;
    GItemInstance *terrainFront;
    GWallInstance *wallLeft;
    GWallInstance *wallRight;
    GWallInstance *wallTop;
    GWallInstance *wallBottom;
    GRoleInstance *role;
    GMapInstance *iMap;
    int x;
    int y;
    bool init(int y,int x,std::string terrainBackName,std::string terrainFrontName, std::string toolName, std::string trapName,GMapInstance* iMap);

    //设置墙,会根据wallName创建新的墙,返回创建的墙
    GWallInstance* setWall(GBase::TYPE_DIRECTION direction, std::string wallName);

    //设置墙,使用传入的已有墙实例,返回这个实例
    GWallInstance* setWall(GBase::TYPE_DIRECTION direction, GWallInstance* wallInstance);

    //获取墙
    GWallInstance* getWall(GBase::TYPE_DIRECTION direction);

    void setRole(GRoleInstance *rolei);
    GRoleInstance *getRole();
    virtual ~GMapTile();
};

LMap

class LMap : public cocos2d::Layer
{
private:
    LMap();
    cocos2d::EventListenerKeyboard* eventListenerKeyboard;
public:
    GBase::GMapInstance* iMap;
    LMapTerrainPlane* terrainBackPlane;
    LMapTerrainPlane* terrainFrontPlane;
    LMapTrapPlane* trapPlane;
    LMapToolPlane* toolPlane;
    LMapWallPlane* wallPlane;
    LMapRolePlane* rolePlane;
    static LMap* create();
    bool init(std::string mapName, std::string packageName);
    void onKeyPressed(cocos2d::EventKeyboard::KeyCode keycode, cocos2d::Event *event);//implemented in Logic/MapEventCallbacks.cpp
    virtual ~LMap();
};

LMapPlane

class LMapPlane :public cocos2d::Layer
{
protected:
    LMapPlane();

public:
    RJCBLib::Matrix<GBase::GInstance>* data;
    cocos2d::Vector<GBase::GInstance*>* dataList;
    GBase::GMapInstance* iMap;
    LMap* lMap;
    static LMapPlane* create();

    bool init(LMap* lMap);


    virtual void afterDataSeted();

    virtual ~LMapPlane();
};

LMapPlane有两个数据集:data和dataList,对于地形等使用矩阵data管理,对于稀疏数据如角色、墙使用dataList管理。
afterDataSeted()在数据设置完毕时被执行,对数据进行定位等操作,将数据显示到UI上(UI透明性)。

小结

工程进展目前(2016-3-7)如此,日后在适当的时候我会继续这个系列的写作。

【图数据库与知识图谱入门】2.2 图数据库 vs. 关系型数据库 vs. NoSQL数据库 本文对比了关系型数据库、NoSQL数据库和图数据库的核心差异与应用场景。关系型数据库以二维表结构为核心,适合结构化数据的事务处理(如MySQL),但多表关联查询性能随层级增加而下降。NoSQL数据库(如MongoDB)具有灵活schema,适合海量非结构化数据存储,但关联查询能力较弱。图数据库专注于节点-边关系建模,擅长处理复杂关联分析(如社交网络)。通过学生-课程案例展示了MySQL的多表JOIN操作和MongoDB的两种关联实现方式(内嵌文档和文档引用),揭示了不同数据库在数据关联处理上的本质区别。 阅读详情

相关推荐

从零到一:KUKA机械臂与ROS的工业级通讯协议深度解析

本文深度解析KUKA机械臂与ROS的工业级通讯协议,重点对比EKI与RSI两种核心接口的技术特点与应用场景。详细介绍了网络架构设计、数据包解析机制及ROS-I集成方法,并提供实时性能优化与故障排除策略,为工程师实现高可靠性工业自动化集成提供完整解决方案。

2a4s6d8f0g的博客 296

一个单机棋盘式半即时解谜RPG的开发与反思、1

前言过年这几天写了几篇Angular2的开发笔记,算是有点“不务正业”,这次为大家带来我正在参与开发的一款游戏。这个小的系列大概有三、四篇组成,随着项目进展我会把这个坑填上。系列的内容是从程序的角度观察和反思这个游戏,包括它构建的基本思想和设计、编码过程中遇到的困难、重构来降低复杂度等。这个项目目前仅依赖于cocos2d,实际上他就是使用cocos2d来作为引擎的。需要说明的是,这个系列记述的是软件的开

ruojianll的博客 928

【汽车ECU标定技术解析】DCM文件与A2L、HEX的协同工作机制

本文深入解析了汽车ECU标定中DCM、A2L与HEX三大核心文件的协同工作机制。A2L文件作为定义标定变量地址与规则的“图纸”,DCM文件承载工程师调试后的具体标定数据,最终通过A2L的地址映射,将DCM数据固化生成可刷入ECU的HEX文件,形成完整的标定数据流转闭环。

weixin_29214559的博客 437

RPG类游戏主角移动的代码

本来RPG类游戏主角移动的代码没什么特别, 这里要指出的是在使用character.simpleMove(moveSpeed * transform.TransformDirection(new Vector3(0, 0, 1))) 来移动,但是当角色在斜坡上由于角色角度的变化而会出现方向改变不能直接到达目的地的问题。这个问题 我尝试了好多方法,但是由于自己判断不准确,好久都没有解决。所以找

脚踏实地,给自己一个更好的生活 4512

告别‘报错马拉松’:一份保姆级的Ubuntu 20.04编译OpenWrt 15.05环境配置与问题修复清单

本文提供了一份详细的Ubuntu 20.04编译OpenWrt 15.05的环境配置与问题修复指南,帮助开发者告别‘报错马拉松’。从基础环境搭建到典型报错分类与修复方案,再到高阶问题的深度修复,全面覆盖编译过程中可能遇到的各类问题,并提供自动化补丁脚本和Docker环境固化方案,确保编译过程高效顺畅。

weixin_33230433的博客 295

多核系统核间通信(IPC)设计:从硬件机制到软件实现

在多核处理器与嵌入式系统设计中,核间通信(IPC)是实现计算资源协同工作的核心技术。其原理基于共享内存、硬件邮箱与中断等底层硬件机制,通过构建结构化的消息传递通道,实现核间高效、可靠的数据交换。该技术的核心价值在于打破多核间的壁垒,将分散的计算单元整合为有机整体,从而显著提升系统整体性能与响应能力。在工程实践中,IPC广泛应用于智能座舱、边缘AI网关、实时控制系统等场景,用于处理如仪表显示、AI推理、实时控制等复杂任务。本文聚焦于基于共享内存与VRING的消息队列实现,深入剖析缓存一致性、内存屏障等关键问题

weixin_27006759的博客 597

一个单机棋盘式半即时解谜RPG的开发与反思、2

接上篇在本系列第一篇文章中,我介绍了这个项目的Json、Lua相关设计,这篇文章中将会对基础库RJCBLib进行详细介绍。我将相关的头文件给出以供参考。RJCBLib库包含功能(2016-3-6):GenericValue : 通用类型。Singleton<> : 提供单例支持。ObjectManager<> : 提供对象管理功能,继承自Sigleton<>。JsonBuffer : 提供对Json

ruojianll的博客 559

【Simulink教程案例7】基于Simulink的滑模控制器设计与实现

欢迎订阅滑膜控制是一种变结构控制策略,其和常规控制方法的主要区别在于控制的不连续性,即一种使系统结构随时间变化的开关特性。所以,滑膜控制器也叫做变结构控制器,其本质是一类特殊的非线性控制器,并且这种非线性为不连续性。滑膜控制器和其他控制方式最大的区别在于其结构的不固定性,在其工作过程中,系统当前的状态会发生变化,使得系统按照预先设置的“滑动模态”的状态轨迹运动。正是由于这个特点,滑膜控制器具有快速响应的优点。滑模控制的基本定义如下所示:1).穿越切换面上的某个点;2).从切换面上的某个点离开;

FPGA/MATLAB学习教程/源码/项目合作开发 3241

【Lua 进阶系列】从调用栈查询到 Hook(钩子):一文理解 Lua 虚拟机的事件回调机制

本文深入解析 Lua 的 Hook 机制,揭示其如何在不修改业务代码的前提下,实现函数调用追踪、行级监控与执行控制。通过对比 debug.getinfo() 和 traceback() 的主动查询局限,引出 Hook 的自动触发优势——基于虚拟机执行事件(call/return/line/count),结合 debug.sethook() 实现解耦式调试。文章以 Reactor 模型类比,阐明 Hook 的事件驱动本质,并梳理注册对象(线程)、监听内容与回调分发逻辑,为工程化调试提供高效方案。

努力努力再努力wz的博客 742

【华为OD技术面试手撕真题】3、小行星碰撞 | 手撕真题+思路参考+代码解析(C & C++ & Java & Python & JS)

小行星碰撞,本专栏更新每年华为OD机试的高频手撕代码题,每个题目都会使用五种语言进行解答(C & C++& Java & Python & JS),思路分析都非常详细, 实现最低的时间复杂度和高通过率,每个解题思路超过百字,内含各个编程语言的八股文面试题,欢迎大家订阅学习, 代码可以直接运行使用,全网限时最低价,持续更新

KJ.JK 8170

【openGauss实战1】openGauss基于CentOS8的部署

基于openGauss数据库在CentOS8上的安装实践。

IT邦德 3050

Lua 热更新不生效:改完文件线上仍是旧逻辑,package.loaded 与 upvalue 重绑定详解

写法 1 只让"自己手里那份"变新,其他持有者停在旧版本,因为它们的槽没有被改过。运行期累积在表上的字段在写法 1 下会一起消失,因为新表是重新执行模块体造出来的,模块体里没有这些字段。写法 2 改的是同一张表,所有持有者同时看到新代码,新表里没有的字段不会覆盖老表上的。写法 2 解决的是一个 VM 内部多处引用的问题,不解决跨服务一次性生效的问题。函数对象没换,但它每次调用都去读槽,所以槽一改,行为就变。写法 1 换掉的是槽里装的东西,老表还在,只是没人指向它。写法 2 不碰槽,改的是表里面的字段。

m0_74234485的博客 272

蓝牙功耗优化实战:连接蓝牙耳机时高耗电问题的深度排查与解决

连接任意一款蓝牙耳机, 进行插入实网SIM卡, 同时连接蓝牙耳机后, 进入IDLE模式, 测试时间为10分钟的测试结果, 平均电流毫安在8左右. 测试结果1: 平均电流 8.84mA 测试结果2: 平均电流 7.39mA 厘清问题: 由于出现上两幅图中 绿色线圈中的 20mA 左右高耗电时段, 从而将整体的平均电流抬高. 于是在记录IDLE下电流出现绿色线圈中的 20mA 左右高耗电时段, 同时录制UART1 Catcher log. Filter: MOD_BT/MOD_ATC.

专业开发者的博客,一个从事Android WiFi和蓝牙的工程师 1001

【Lua进阶系列】Lua 面向对象编程:从 Table 到类:构造函数、继承、多态、多继承与封装

Lua虽无原生class语法,但通过Table、函数、元表(__index)与闭包等机制,可实现封装、继承与多态。核心思想是:用Table表示对象,将状态与方法分离;利用__index实现公共方法共享;通过元表链支持继承与重写;结合闭包隐藏私有状态。最终,以灵活组合原生特性,构建出完整的面向对象模型。

努力努力再努力wz的博客 604

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Skynet 热更新三条通道:clearcache、inject、injectcode 的粒度与代价

从日志里找出报错时的服务地址和文件行号,确认要改的是哪个服务里的哪个模块。还有一个容易忽略的限制:它收集的是「函数的 upvalue 里的 table」。在 A 里执行一次模块 reload,A 变,B 不变——B 是另一个 VM,它那份表从头到尾没被碰过。局部变量在栈帧上,不挂在任何函数的 upvalue 里,收集不到。在 skynet 里做热更,先要分清"没生效"是哪一层断的:文件没被读到、模块没重新 require、还是补丁没送到目标服务。要一次覆盖全部服务,只有重启进程,或者把每个服务都执行一遍。

m0_74234485的博客 245

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

【政安晨】嵌入式AI开发实践 —— ESP-Claw 深度拆解:把 AI Agent 塞进 $5 芯片,它是怎么“看见“并“握住“硬件的

最近一个月,我几乎把 Espressif 新推的 ESP-Mosaico 开发板(2026-10-20 发布,基于全新 RISC-V 双核 ESP32-S31)和它背后的 ESP-Claw 智能体框架翻了三遍——官网、GitHub 全部 6 个仓库、ESP-Claw 官方文档,外加 arXiv 上端侧 Agent 的几篇论文。ESP-Claw 不是"在 ESP32 上跑大模型",而是把大模型当成一个会下棋但棋力不稳的对手——能算的地方绝不让它算,不能算的地方只许它走一个格。

政安晨——致力于AI人工智能数字互动领域 336

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Redis Lua 原子限流:Lua 脚本、竞态条件与并发控制

Lua是轻量级可嵌入脚本语言,Redis内置Lua5.1解释器,支持通过EVAL或SCRIPTLOAD执行脚本,实现多命令原子操作。利用redis.call()调用Redis命令,结合KEYS和ARGV传参,可将读取、判断、更新等操作封装为原子逻辑,有效避免限流中的竞态条件。固定窗口限流通过Lua脚本实现计数与过期控制,保证操作连续性。但脚本不可回滚,需避免复杂逻辑;执行时间过长会阻塞Redis,且需满足Cluster哈希槽约束。实际应用中还需考虑故障降级策略。

Joy T的博客 131

【Lua 进阶系列】从 C++ 对象到 Lua 变量:一文理解 userdata、Lua 栈与元表绑定机制

本文从游戏服务端分层架构出发,解析 Lua 中 userdata 的设计意义。尽管 Lua 有 Table 可模拟对象,但 userdata 专为承载 C/C++ 自定义数据而生,实现 Lua 与原生代码间高效、安全的数据交互。通过 TValue 与 Udata 机制,区分 Full 与 Light userdata,结合元表实现面向对象调用,既保留性能优势,又提升封装性。最终揭示:userdata 是连接脚本层与宿主层的关键桥梁。

努力努力再努力wz的博客 188

【Lua进阶系列】Lua 调试机制详解:从虚拟机调用栈、错误传播到 debug 库

本文深入解析 Lua 调试机制的底层原理,强调调试并非重新执行程序,而是利用虚拟机已维护的运行时状态与编译阶段保留的调试信息。通过分析函数调用栈、字节码与源码行号映射关系,揭示 debug 库函数(如 getinfo、getlocal、traceback)如何读取调用链与局部变量。同时说明错误传播机制及 pcall/xpcall 的保护作用,并指出剥离调试信息虽可减小文件体积,但会削弱调试能力。核心在于理解:调试是基于虚拟机运行时状态与编译辅助信息的协同结果。

努力努力再努力wz的博客 269

【Lua进阶系列】从全局环境到 _ENV:理解全局变量解析、环境隔离与闭包生命周期

本文深入解析Lua为何无需定义即可直接调用print、table.insert等函数。核心在于:Lua运行时维护默认全局环境表,标准库通过C API注册为函数值,供所有Chunk共享。多个脚本共用同一环境,实现全局变量互通;而局部变量受词法作用域保护。通过_ENV机制,可灵活切换执行环境,提升模块化与安全性。最终,全局访问本质是环境表的键值查找,遵循表的读写规则。

努力努力再努力wz的博客 456

在多线程与多协程环境下驯服 Lua 虚拟机

在C++多协程环境下安全运行Lua,需遵循“线程绑定、栈隔离、重入保护”三铁律。通过lua_newthread创建协程专属栈,配合luaL_ref管理生命周期,确保主虚拟机不受干扰。禁止复用lua_State,避免闭包污染;沙盒环境应通过lua_setupvalue隔离_ENV;优化GC参数并主动触发垃圾回收,缓解高并发下的内存压力。最终实现万级并发下微秒级延迟的稳定脚本执行,打造高性能、可扩展的Lua底座。

draracle的巢穴 305

快速上手:如何调用大模型

本文介绍了如何通过HTTP请求或OpenAI SDK调用阿里云百炼平台的大模型。重点讲解了使用Postman和Python代码调用qwen3-max模型的方法,强调需配置API Key与base_url(https://dashscope.aliyuncs.com/compatible-mode/v1),并推荐将API Key设为环境变量以保障安全。同时说明OpenAI库可通过兼容模式调用第三方模型,最后演示了大模型无记忆特性及通过维护对话历史实现“记忆”的实践方法。

2301_80002260的博客 178

Python22-MCP-PostMan调试-Streamable

Python22-MCP-PostMan调试-Streamable

感谢所有乐于奉献的人,在此不一一具名 141

Python21-MCP代码修正

Python21-MCP代码修正

感谢所有乐于奉献的人,在此不一一具名 207

使用redis实现分布式锁(面试千题)

redis实现分布式锁

qq_40358025的博客 221

Postman 自动给 Claude Code、Codex、Cursor 装插件怎么查和卸载:本机实测 5 处痕迹(Postman 12.34)

Postman 桌面版升级时会自动给 Claude Code、Codex、Cursor 装插件。本文在 macOS 上实测 Postman 12.34 留下的 5 处痕迹:日志记录、Claude Code 插件和 SessionStart 指令、Codex 配置、Cursor 插件目录、Postman CLI,给出只读自查脚本和逐个卸载命令。

u011831527的博客 532
上一篇: 一个单机棋盘式半即时解谜RPG的开发与反思、2
下一篇: CSS第三级选择器 Selectors Level 3 文档翻译
若简LL
博客等级 码龄11年 8粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值