之前定义过 P21 项目作为示例, 这里是从 P21 项目当中扩展出来的项目工程化补充说明
工程化项目当时创建过以下目录作为项目分层:
P21Game: 游戏引擎相关
P21Tests: 游戏内部测试单元
P21Utility: 内部扩展通用功能
这个篇章就是基于 P21Utility 这方面展开的, 简单说下为什么有 Utility 层
有时候项目需要用到底层工具库, 比如 Protobuf 序列化、网络、寻路算法 等仅需要纯 C# 的通用功能
这种通用功能只需要 C# 来处理成单独功能库, 那么就不适合放在对外的 P21Game 游戏引擎相关工程之中
并且基于 C# 保证脱离游戏引擎存在, 如果后面迁移到 Unity3d 之类使用 C# 平台还能复用相关代码库
把封装代码塞到 Game 层之中会让游戏工程变得臃肿, 核心游戏逻辑(UI、玩法、节点交互)被这些代码淹没导致后期找 Bug、改功能都会极其繁琐
所以 P21Utility 只做纯 C# 通用功能封装, 对外提供清晰、简洁的 API 从而让 P21Game 只需要 调用 而不用关心底层实现
对于 Ut ...
在 GodotC# 的好处就是就是依靠引入 dotnet 大量支持, 相比 GDScript 更加现代化, 而目前主流单元测试框架以下方案:
xUnit: 比较简洁小型的测试单元框架
文档: https://learn.microsoft.com/zh-cn/dotnet/core/testing/unit-testing-csharp-with-xunit
MSTest: 微软官方的测试单元框架
文档: https://learn.microsoft.com/zh-cn/dotnet/core/testing/unit-testing-mstest-intro
NUnit: 大型且文档齐全的的测试单元
文档: https://learn.microsoft.com/zh-cn/dotnet/core/testing/unit-testing-csharp-with-nunit
这里采用比较简洁小巧的 xUnit, 避免引入过重测试单元
注意: GodotC# 和 GDScript 要求是不一样, GodotC# 更加需要严格工程化, 也就是 UI 层和功能层 ...
因为目前主要系统迁移到 Ubuntu/Debian 上, 基于这种情况就全面转移到 Linux 平台做相关游戏业务开发
这里主要是针对 Ubuntu 的 Godot C# 版本, 需要配置 dotnet 环境相关和 JetBrains Rider 的开发环境, 首先需要安装对应组件依赖:
这里官方文档都有脚本安装和 apt 安装配置; 注意不要安装 snap 版本, 这个版本会让 Rider 无法自动扫描到环境变量配置
dotnet 安装: https://learn.microsoft.com/zh-cn/dotnet/core/install
新版本 Rider 现在对于个人已经是免费提供, 所以直接去官网下载安装配置就行了; 只要你提前安装好 dotnet, Rider 就会自动扫描工具链
工具链配置在 Settings → Build,Execution,Deployment → Toolset And Build 内部, 确认 CLI 和 MSBuild 已经自动扫描到
之后就是 Godot 版本, 目前 Godot 官网默认下载不带 C#, 需要去对应页面选择下载
...
之前大部分操作都是针对单体 Actor, 但是实际生产之后免不了要操作数据库, 而 Pekko 内部已经集成这部分功能
JDBC 数据库操作: https://pekko.apache.org/docs/pekko-projection/current/jdbc.html
Slink 数据库操作: https://pekko.apache.org/docs/pekko-projection/current/slick.html
大部分情况都会看到内部所有模块都标注 用于对象持久化处理, 这些都是用于保存 Actor 状态, 如果想简单使用的话太过复杂
Slink 集成另外说明, 因为数据库相关篇幅很复杂没办法直接讲清楚; 绝大部分情况 Slink 是在 Scala 上用, Java 用 JDBC 熟悉
这里采用 pekko-projection-jdbc 官方模块和文档说明, 最后说下这个过程踩过的坑, 这里通过 Maven 引入第三方库:
123456789101112131415161718192021222324252627282930313233343536373839 ...
对于 A* 其实就是需要将整体游戏地图网格化(Grids), 很多人都戏称这种方式为 “刷格子”
网格化之后地图寻路操作其实就像是五子棋连线即可, 其中棋盘上不可获取就是障碍物列表和网格最大值.
一般寻路系统只需要做二维处理即可
对于网格化默认都是以地图左下最初地方设置为 (0,0) 起始点, 后续需要确定整个地图的最大定点值, 这部分代码如下:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314 ...
参考文档: https://docs.godotengine.org/zh-cn/latest/getting_started/first_2d_game/03.coding_the_player.html
对于新手入门来说, 没必要一上来就接触 3D 游戏开发, 如果游戏注重玩法直接采用 2D/2.5D 美术来构建即可.
一般 itch.io 都有不少很不错的游戏资源包, 自带人物角色动作和场景地图, 支付购买资源版权即可
如果想快速搭建自己的游戏底层架构, 采用 2D-Animation + TileMap 是很好的方向.
上面的 Godot 官方参考文档里面只说了基础的人物动画创建, 虽然直接用确实没问题, 但还是要处理上级封装成统一模块
这里采用 Godot 的脚本系统封装 Area2DCharacter.gd, 用于做统一角色抽象类
12345678##################################### 扩展 Area2D 人物类###################################extends Area2Dclass_ ...
相比于帧同步的复杂度和资源耗费, 状态同步的开发要求相对容易(主要实现起来很简单)
这里数据结构是采用 Protobuf 定义, 客户端和服务端数据交互的时候比较统一
假设目前想要设计个 2DRPG 游戏, 那么通用简单的玩家状态 proto 如下:
123456789101112131415161718192021222324252627282930313233343536syntax = "proto3";option java_package = "me.meteorcat.game.protobuf";option java_multiple_files = true;// 二维坐标系message Vector2{ float x = 1; float y = 2;}// 简略版本的玩家状态数据结构message PlayerState{ // 基础信息 int64 id = 1; // 玩家 ID Vector2 position = 2;// 玩家位置 int64 uptime = 3; ...
Pekko 是支持将数据对象作为 ProtobufV2/V3 序列化转发, 而且官方集群数据传输方案实现了这部分功能.
序列化说明: https://pekko.apache.org/docs/pekko/current/serialization.html#serialization-of-pekkos-messages
目前官方有两套 Protobuf 序列化方案支持, 比较推荐采用 pekko-protobuf-v3:
(建议采用)pekko-protobuf-v3_{scala.version}: https://mvnrepository.com/artifact/org.apache.pekko/pekko-protobuf-v3
(不建议采用)pekko-protobuf_{scala.version}: https://mvnrepository.com/artifact/org.apache.pekko/pekko-protobuf
如果没有客户端需求, 一般只有集群转发会引用, 而集群处理默认已经自动引入 protobuf 支持.
而如果客户端需要依 ...
早期 Java 的并没有统一的异步运行时, 所以很多都需要去自行实现处理, 而 Pekko 则是自行设计通用的异步运行时.
Pekko 异步运行时是由 Actor 模型 + 调度器 + 流处理 + 未来式(Future) 构成的完整异步运行体系, 包含有以下组件:
Scheduler/Dispatcher: 任务定时器/调度器, 底层执行核心, 负责线程分配和任务调度, 隔离不同类型的任务
Future/CompletionStage: 异步任务结果包装, 处理异步任务的返回值,避免同步阻塞等待
Stream: 支持运行时的数据流处理, 解决批量数据的异步生产 - 消费问题, 内置背压避免流量失控
Actor: 最上层的任务载体, 用 “消息队列 + 单线程执行” 的模式将并发问题收敛到"消息顺序"而非"锁"
这些组件都是能够独立使用
在 Java8 之后可以依靠 Runnable/Callable/ThreadPool 实现简单的异步运行时, 但是对比 Pekko 纯正 Actor 设计差距很大:
特性
Pekko ...
Pekko 消息交互
其他文章已经揭示过 Pekko 目前主流支持的网络流消息交互:
TCP
UDP
WebSocket
基本上需要的网络流处理, Pekko 都封装完成了, 所以也就不需要依赖第三方来处理这些.
TCP/UDP 文档我看目前没有跟进到最新强类型版本处理, 这里主要还是以 TCP 流处理为主
TCP/UDP 之类依赖只需要基础的 actor 即可, 无需其他多余依赖, 目前官网 TCP 样例如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081import java.net.InetSocketAddress;import org.apache.pekko.actor.ActorRef;import org.apache.pekko.actor.ActorSystem;import org.ap ...







