OpenRA开源红色警戒游戏RPG源码PlayerDatabase.cs解读

python编程示例系列
python编程示例系列二
python的Web神器Streamlit
如何应聘高薪职位
C#视觉应用开发问题系列
c#串口应用开发问题系列
microPython Python最小内核源码解析
NI-motion运动控制c语言示例代码解析
OpenRA开源红色警戒游戏RPG源码解读
在这里插入图片描述# PlayerDatabase 代码详解

代码逻辑解读

这段代码实现了OpenRA游戏中的玩家徽章管理系统,主要功能是加载、缓存和渲染玩家的徽章图标。核心逻辑如下:

  1. 初始化:在首次加载徽章时,初始化纹理表构建器和图标缓存系统。
  2. 徽章加载:从YAML配置中加载徽章信息,包括标签和不同分辨率的图标URL。
  3. 图标加载:根据URL异步加载图标,支持不同密度(1x, 2x, 3x)的图标以适应不同的显示设备。
  4. 缓存机制:使用缓存系统避免重复加载相同的图标,提高性能。
  5. 响应式显示:根据当前窗口缩放比例自动选择最合适分辨率的图标。

整个系统设计考虑了性能优化、异步加载和高DPI显示支持,确保了游戏中徽章显示的高效和流畅。

代码注释版本

using System.Threading.Tasks; // 引入任务并行库
using OpenRA.FileFormats; // 引入OpenRA文件格式处理库
using OpenRA.Graphics; // 引入OpenRA图形处理库
using OpenRA.Primitives; // 引入OpenRA基本数据类型库
using OpenRA.Support; // 引入OpenRA支持库

namespace OpenRA
{
    // 玩家数据库类,实现IGlobalModData接口,用于管理玩家徽章和图标
    public class PlayerDatabase : IGlobalModData
    {
        // 玩家资料的基础URL
        public readonly string Profile = "https://forum.openra.net/openra/info/";
        // 基础图标尺寸,单位为像素
        public readonly int IconSize = 24;

        // 512x512的纹理表足够存储:
        // 49个独特的72x72徽章
        // 或100个独特的42x42徽章
        // 或441个独特的24x24徽章
        // 或者根据游戏内DPI变化的上述组合
        
        // FieldLoader.Ignore标记表示该字段不会被外部配置加载器处理
        [FieldLoader.Ignore]
        SheetBuilder sheetBuilder; // 纹理表构建器,用于将多个小图像合并到一个大纹理中

        // 图标缓存,键为(徽章,密度)元组,值为对应的Sprite
        [FieldLoader.Ignore]
        Cache<(PlayerBadge, int), Sprite> iconCache;

        // 从URL加载精灵图,根据指定密度调整大小
        Sprite LoadSprite(string url, int density)
        {
            // 计算实际精灵尺寸 = 基础尺寸 * 密度
            var spriteSize = IconSize * density;
            // 在纹理表中分配空间
            var sprite = sheetBuilder.Allocate(new Size(spriteSize, spriteSize), 1f / density);

            // 异步加载图像
            Task.Run(async () =>
            {
                try
                {
                    // 创建HTTP客户端
                    var client = HttpClientFactory.Create();
                    
                    // 异步获取图像数据
                    var httpResponseMessage = await client.GetAsync(url);
                    var result = await httpResponseMessage.Content.ReadAsStreamAsync();

                    // 将数据解析为PNG图像
                    var icon = new Png(result);
                    // 验证图像尺寸是否符合要求
                    if (icon.Width == spriteSize && icon.Height == spriteSize)
                    {
                        // 在游戏主线程执行图像数据拷贝操作
                        Game.RunAfterTick(() =>
                        {
                            // 将图像数据复制到精灵中
                            Util.FastCopyIntoSprite(sprite, icon);
                            // 提交缓冲数据到纹理表
                            sprite.Sheet.CommitBufferedData();
                        });
                    }
                }
                catch { } // 捕获但忽略所有异常
            });

            // 立即返回空白精灵,稍后异步填充数据
            return sprite;
        }

        // 创建新的纹理表
        Sheet CreateSheet()
        {
            // 创建512x512大小的BGRA格式纹理表
            var sheet = new Sheet(SheetType.BGRA, new Size(512, 512));

            // 手动强制创建缓冲区,避免渲染尚未写入数据的纹理表时崩溃
            sheet.CreateBuffer();
            // 设置纹理缩放过滤器为线性,提高缩放质量
            sheet.GetTexture().ScaleFilter = TextureScaleFilter.Linear;

            return sheet;
        }

        // 从YAML配置加载玩家徽章
        public PlayerBadge LoadBadge(MiniYaml yaml)
        {
            // 如果纹理表构建器未初始化,则初始化
            if (sheetBuilder == null)
            {
                // 创建纹理表构建器,使用CreateSheet方法作为工厂函数
                sheetBuilder = new SheetBuilder(SheetType.BGRA, CreateSheet);

                // 初始化图标缓存,使用lambda表达式定义图标加载逻辑
                iconCache = new Cache<(PlayerBadge Badge, int Density), Sprite>(p =>
                {
                    // 根据密度选择最合适的图标版本
                    // 优先使用高分辨率图标
                    if (p.Density > 2 && !string.IsNullOrEmpty(p.Badge.Icon3x))
                        return LoadSprite(p.Badge.Icon3x, 3);

                    if (p.Density > 1 && !string.IsNullOrEmpty(p.Badge.Icon2x))
                        return LoadSprite(p.Badge.Icon2x, 2);

                    // 默认使用1x密度的图标
                    return LoadSprite(p.Badge.Icon, 1);
                });
            }

            // 从YAML中提取徽章信息
            var labelNode = yaml.NodeWithKeyOrDefault("Label");
            var icon24Node = yaml.NodeWithKeyOrDefault("Icon24");
            var icon48Node = yaml.NodeWithKeyOrDefault("Icon48");
            var icon72Node = yaml.NodeWithKeyOrDefault("Icon72");
            
            // 如果没有标签节点,则返回null
            if (labelNode == null)
                return null;

            // 创建并返回新的PlayerBadge对象
            return new PlayerBadge(
                labelNode.Value.Value,
                icon24Node?.Value.Value,  // 1x密度图标URL
                icon48Node?.Value.Value,  // 2x密度图标URL
                icon72Node?.Value.Value); // 3x密度图标URL
        }

        // 获取徽章对应的图标精灵
        public Sprite GetIcon(PlayerBadge badge)
        {
            // 获取当前窗口缩放比例
            var ws = Game.Renderer.WindowScale;
            // 根据窗口缩放比例确定使用的密度
            var density = ws > 2 ? 3 : ws > 1 ? 2 : 1;
            // 从缓存中获取对应的精灵
            return iconCache[(badge, density)];
        }
    }
}

流程图

开始
是否初始化?
初始化SheetBuilder
从YAML加载徽章数据
初始化图标缓存
是否有标签?
返回null
创建PlayerBadge对象
获取图标
确定当前密度
缓存中是否存在?
返回缓存的Sprite
加载新Sprite
分配纹理空间
异步HTTP请求
解析PNG数据
尺寸是否正确?
游戏主线程拷贝数据
忽略
提交到纹理表

特殊语法与技巧解读

  1. 只读字段

    public readonly string Profile = "https://forum.openra.net/openra/info/";
    

    使用readonly关键字确保字段在初始化后不会被修改,增加代码安全性。

  2. 特性标记

    [FieldLoader.Ignore]
    SheetBuilder sheetBuilder;
    

    使用自定义特性FieldLoader.Ignore标记字段,告诉外部加载器忽略这些字段。

  3. 元组类型

    Cache<(PlayerBadge, int), Sprite> iconCache;
    

    使用C#7.0引入的值元组作为缓存键,简洁地组合多个值。

  4. 异步编程

    Task.Run(async () => { ... });
    

    使用Task.Runasync/await模式实现非阻塞的异步图像加载。

  5. 空异常处理

    catch { }
    

    捕获但不处理异常,适用于非关键操作的错误可以被安全忽略的场景。

  6. 委托工厂模式

    sheetBuilder = new SheetBuilder(SheetType.BGRA, CreateSheet);
    

    将方法作为委托传递给构造函数,实现工厂模式。

  7. Lambda表达式

    iconCache = new Cache<(PlayerBadge Badge, int Density), Sprite>(p => { ... });
    

    使用Lambda表达式定义缓存的值获取逻辑,简化代码。

  8. 空条件运算符

    icon24Node?.Value.Value
    

    使用?.运算符安全访问可能为null的对象,避免空引用异常。

  9. 三元条件运算符链

    var density = ws > 2 ? 3 : ws > 1 ? 2 : 1;
    

    嵌套使用三元运算符实现简洁的多条件判断。

  10. 游戏线程同步

    Game.RunAfterTick(() => { ... });
    

    确保图形操作在游戏主线程执行,避免多线程访问图形资源导致的问题。

  11. 懒加载模式

    if (sheetBuilder == null) { ... }
    

    资源仅在首次需要时才初始化,提高程序启动性能。

  12. 值类型参数解构

    Cache<(PlayerBadge Badge, int Density), Sprite>(p => { ... });
    

    在Lambda表达式中使用命名的元组字段,提高代码可读性。

  13. 资源预分配

    var sprite = sheetBuilder.Allocate(new Size(spriteSize, spriteSize), 1f / density);
    

    先分配资源再异步填充数据,避免UI线程阻塞。

这段代码展示了现代C#编程的多种高级特性和游戏开发中的性能优化技巧,特别在异步处理、缓存管理和高DPI适配方面有很好的实践。

python如何用seleinum 搜索下载百度知道的回答内容
构建我们的Python代码库依赖图
python的Graphviz库生成思维导图
从ruby不适开发游戏说起
量子计算HHL算法
量子计算Bernstein-Vazirani算法
Python如何进行时间同步
Python如何编写一个钢琴弹奏软件,操作MIDI设备的详细流程
量化交易系统中+如何处理算法交易中的竞价和撮合机制?
智能农业设备软件工程师如何实现农业设备的用户权限管理
量化交易策略 标准差突破
工业运动控制涉及到哪些设备和技术
智能农业设备软件工程师如何实现农业设备的能量回收系统
python如何开发一个计算中国象棋下子优势的算法
c#视觉应用开发中如何在C#中进行图像边缘增强?
python如何进行内存监控
车载系统软件工程师如何处理车载系统的冷启动和热启动优化
量化交易系统中+如何处理多设备和多平台的兼容性?
量化交易系统中+如何设计高效的数据库架构?
microPython的源码解析之 objstr.c
量化交易系统中如何处理API的版本控制和兼容性?
python如何开发解压及压缩软件工具
Python如何创造可变形的地形的完整示例.
量化交易系统如何处理数据的清洗和预处理?
C#进行串口应用开发如何通过串口实现模拟串口的虚拟化
如何将一个Sqlite数据库Db中的所有表快速拆分到多个db文件中
量化交易策略 做多做空策略
microPython的源码解析之 objslice.c
智能农业设备软件工程师如何实现农田气象站的数据收集和分析
openai的plaNet 如何使用,请给出示例代码,并解读
C#进行串口应用开发如何实现基于串口的虚拟串口映射和串口共享
c#视觉应用开发中如何在C#中进行图像分块处理?
jupyter深度理解五 之 traitlets
Python如何遍历查看所有系统可用字体
量化交易系统中+如何实现算法的低延迟交易?
python如何知道一个第三方库依赖哪些其它的库
支持transformer模型的开源AI框架
如何应聘初级软件工程师,年薪10万到15万元之间
C#进行串口应用开发如何避免串口通信因缓冲区溢出丢失数据
microPython的源码解析之 objbool.c
openai的API实现代码函数检索
c#委托和事件
python的任务调度库 Advanced Python Scheduler (APScheduler)
python的xmlrpc库如何使用
python的unittest框架如何使用
C#进行串口应用开发如何实现串口通信的全双工与半双工工作模式
车载系统软件工程师如何管理车载系统的固件更新(OTA)
c#视觉应用开发中如何在C#中进行视频处理和实时流媒体处理?
python web应用开发神器 入门二十一
C#进行串口应用开发如何实现串口通信的异步发送与接收
智能农业设备软件工程师如何实现农场管理软件平台
NI-Motion如何在一个运动控制器上创建并运行一个简单的板载程序的C语言示例代码
车载系统软件工程师如何处理车载系统的动态配置和更新
python如何处理大规模的数据pyarrow
车载系统软件工程师如何确保车载系统的网络安全(防止黑客攻击)
智能农业设备软件工程师如何实现农业设备的智能灌溉控制
c#视觉应用开发中什么是图像滤波器,如何在C#中实现常见的图像滤波器?
量化交易系统中如何处理监管机构的检查和审核?
指数和对数
详细解读一下B树,及如何进行搜索
Python的高性能web框架库Tornado
智能农业设备软件工程师如何集成和管理农业设备的传感器数据融合
智能农业设备软件工程师如何集成和管理农业设备的能源管理系统
microPython的源码解析之 modmicropython.c
python如何操作pdf文档
microPython的源码解析之 modio.c
NI-Motion如何使用模拟电压反馈来控制运动控制器的速度的C语言示例代码
python生成和解决迷宫的库maze
python 开发EZRO内容管理系统的案例介绍
Python如何把sqlite完全加载到内存中操作
智能农业设备软件工程师如何实现农业设备的OTA安全性和完整性验证
C#进行串口应用开发如何处理串口通信因线路干扰导致的数据误码
microPython的源码解析之 objgenerator.c
python用于构建和运行自动化交易策略的框架的库trading-backend
python如何分析 图的最短路径
OpenAI表示,通过GPT-4更新,AI变得更加智能,更安全,更直观
Python的pkg_resources库介绍
车载系统软件工程师如何实现车载系统的用户反馈和数据收集
量子计算Grover搜索算法
车载系统软件工程师如何实现车载系统的蓝牙和无线连接
openai的Habitat 如何使用,请给出示例
量化交易系统中+如何进行策略的版本控制和管理?
计算机算法的树结构有哪些种请分别列举
3D人物的动作是如何制作出来的
能输出自身源代码的程序
python如何绘制思维导图
车载系统软件工程师如何处理车载系统的用户数据和偏好管理
智能农业设备软件工程师如何实现农业数据的云存储和备份
智能农业设备软件工程师如何实现农业设备的智能农业应用
量化交易系统如何进行版本控制和代码管理
github的检索功能
microPython的源码解析之 builtinimport.c
python如何实现事件发射器
量化交易系统中+如何进行多因子模型的构建和测试?
智能农业设备软件工程师如何实现和管理农田监测系统
GPT-4将使ChatGPT更智能
Pandas如何处理excel列中数据?
microPython的源码解析之 builtinhelp.c
c#视觉应用开发中如何在C#中进行图像变换(如旋转、缩放、平移)?
python的debugpy库

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

openwin_top

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值