FROM URL:http://blog.csdn.net/nizhenyang/article/details/26339383

感谢原作者nizhenyang分享这样好的实战案例!


概述

这是一篇通过一个简单的 treasure 捡宝的例子讲述如何使用 Bearcat 来快速, 高效的进行 pomelo game 开发

起步

添加 bearcat

npm install bearcat --save

添加context.json, 并指定 scan 扫描路径, 来自动扫描 POJOs

context.json

{    "name": "bearcat-treasures",    "scan": "app",    "beans": []}

修改app.js, 添加 bearcat 启动代码

app.js

var contextPath = require.resolve('./context.json');bearcat.createApp([contextPath]);bearcat.start(function() {  Configure(); // pomelo configure in app.js  app.set('bearcat', bearcat);  // start app  app.start();});

就是这么简单, bearcat 开发环境就已经搭建完毕, 之后就可以利用 bearcat 所提供的 IoC, AOP, 一致性配置等特性来编写简单, 可维护的 pomelo 应用

途中

handler, remote 交由 bearcat 管理

handler, remote 都以 POJO 的形式编写

由于之前handler, remote在pomelo里面是通过 pomelo-loader 来管理的, 因此需要做一下适配转化

m

通过适配, gateHandler 就交给了 bearcat 来进行管理, 之后 gateHandler 需要什么依赖, 仅仅在 getBean 的 metadata 配置中描述好依赖关系就行了

上面的gateHandler例子中, 就向 bearcat 容器描述了, gateHandler 需要在构造函数中传入一个 app 对象, 在对象属性中需要一个 dispatcher 依赖

domain 对象编写

domain 代表着数据和模型, 包括玩家player, 宝物treasure, 移动move等等

domain 里的数据要被序列化, 需要定义序列化方法, 比如toJSON

entity.js

var EventEmitter = require('events').EventEmitter;var util = require('util');var id = 1;function Entity(opts) {    EventEmitter.call(this);    this.opts = opts || {};    this.entityId = id++;    this.kindId = opts.kindId;    this.kindName = opts.kindName;    this.areaId = opts.areaId || 1;    this.x = 0;    this.y = 0;}util.inherits(Entity, EventEmitter);Entity.prototype._init = function() {    var opts = this.opts;    if (opts.x === undefined || opts.y === undefined) {        this.randPos();    } else {        this.x = opts.x;        this.y = opts.y;    }}Entity.prototype._toJSON = function() {    return {        x: this.x,        y: this.y,        entityId: this.entityId,        kindId: this.kindId,        kindName: this.kindName,        areaId: this.areaId    }}// random positionEntity.prototype.randPos = function() {};module.exports = {    id: "entity",    func: Entity,    abstract: true,    props: [{        name: "dataApiUtil",        ref: "dataApiUtil"    }, {        name: "utils",        ref: "utils"    }]}

entity 是一个抽象的bean, 意味着它只是作为子bean的模版, 并不会被实例化, 它通过对象属性依赖注入了 dataApiUtil 和 util

player.js

var logger = require('pomelo-logger').getLogger('bearcat-treasures', 'Player');var bearcat = require('bearcat');var util = require('util');function Player(opts) {  this.opts = opts;  this.id = opts.id;  this.type = null;  this.name = opts.name;  this.walkSpeed = 240;  this.score = opts.score || 0;  this.target = null;}Player.prototype.init = function() {  this.type = this.consts.EntityType.PLAYER;  var Entity = bearcat.getFunction('entity');  Entity.call(this, this.opts);  this._init();}Player.prototype.addScore = function(score) {  this.score += score;};Player.prototype.toJSON = function() {  var r = this._toJSON();  r['id'] = this.id;  r['type'] = this.type;  r['name'] = this.name;  r['walkSpeed'] = this.walkSpeed;  r['score'] = this.score;  return r;};module.exports = {  id: "player",  func: Player,  scope: "prototype",  parent: "entity",  init: "init",  args: [{    name: "opts",    type: "Object"  }],  props: [{    name: "consts",    ref: "consts"  }]}

player 是 entity 的一个子类, 它通过在metadata配置中的 parent 继承了 entity prototype 里的方法

player 的scope是 prototype 的, 并且需要定义一个 init 方法, 来调用 entity 的构造函数以及 entity 的 init 方法 _init

var Entity = bearcat.getFunction('entity'); Entity.call(this, this.opts); this._init();

这里通过 bearcat.getFunction 来拿到 entity 的构造函数来进行调用

使用 domain

在没有bearcat的情况下, 使用domain需要自己先require进来, 然后再 new domain(), 现在你可以直接通过 getBean 来得到相应 domain 的实例

playerHandler enterScene

PlayerHandler.prototype.enterScene = function(msg, session, next) {  var role = this.dataApiUtil.role().random();  var player = bearcat.getBean('player', {    id: msg.playerId,    name: msg.name,    kindId: role.id  });  player.serverId = session.frontendId;  if (!this.areaService.addEntity(player)) {    logger.error("Add player to area faild! areaId : " + player.areaId);    next(new Error('fail to add user into area'), {      route: msg.route,      code: this.consts.MESSAGE.ERR    });    return;  }  var r = {    code: this.consts.MESSAGE.RES,    data: {      area: this.areaService.getAreaInfo(),      playerId: player.id    }  };  next(null, r);};
var player = bearcat.getBean('player', {    id: msg.playerId,    name: msg.name,    kindId: role.id  });

player 通过 bearcat.getBean 拿到

domain 事件的处理

移动和捡宝是通过 event 事件来处理的, 在一个 tick 时间内, 当移动到宝物的捡宝范围之内, 就会出发 pickItem 事件

Move.prototype.update = function() {  var time = Date.now() - this.time;  var speed = this.entity.walkSpeed;  var moveLength = speed * time / 1000;  var dis = getDis(this.entity.getPos(), this.endPos);  if (dis <= moveLength / 2) {    this.finished = true;    this.entity.setPos(this.endPos.x, this.endPos.y);    return;  } else if (dis < 55 && this.entity.target) {    this.entity.emit('pickItem', {      entityId: this.entity.entityId,      target: this.entity.target    });  }  var curPos = getPos(this.entity.getPos(), this.endPos, moveLength, dis);  this.entity.setPos(curPos.x, curPos.y);  this.time = Date.now();};

触发时间后, 就向channel广播捡宝这个事件

player.on('pickItem', function(args) {    var player = self.getEntity(args.entityId);    var treasure = self.getEntity(args.target);    player.target = null;    if (treasure) {      player.addScore(treasure.score);      self.removeEntity(args.target);      self.getChannel().pushMessage({        route: 'onPickItem',        entityId: args.entityId,        target: args.target,        score: treasure.score      });    }  });

areaService 编写

areaService 里面维护着当前area里面的玩家, 排名, 宝物等数据

它在tick时间内, 向channel广播更新着area里面的最新数据

AreaService.prototype.tick = function() {  //run all the action  this.actionManagerService.update();  this.entityUpdate();  this.rankUpdate();}

entityUpdate 更新着area里面的entity情况

AreaService.prototype.entityUpdate = function() {  if (this.reduced.length > 0) {    this.getChannel().pushMessage({      route: 'removeEntities',      entities: this.reduced    });    this.reduced = [];  }  if (this.added.length > 0) {    var added = this.added;    var r = [];    for (var i = 0; i < added.length; i++) {      r.push(added[i].toJSON());    }    this.getChannel().pushMessage({      route: 'addEntities',      entities: r    });    this.added = [];  }};

总结

在bearcat的统一管理协调下, 去除了烦人的require直接依赖关系, 可以放心大胆的进行编码甚至重构, bearcat 里面的任一组件都被有序的管理维护着, 使用时不再是一个个单一的个体, 而是一个集体

项目代码在 bearcat-treasures

Bearcat pomelo game 实战 -- treasures相关推荐

  1. (十四)nodejs循序渐进-高性能游戏服务器框架pomelo之开发Treasures游戏

    #Tutorial 2 -- Treasures ##描述 Treasures 游戏是从 LordOfPomelo 中抽取出来,去掉了大量的游戏逻辑,用以更好的展示 Pomelo 框架的用法以及运作机 ...

  2. Pomelo Treasures

    需求分析 玩家进入遍布宝物的地图中,通过拾取宝物获取积分. 玩家积分排行 每个玩家的行动对其它玩家都是实时的 拾取宝物获得积分时会实时更新积分排行榜,更新对所有玩家实时可见. 宝物定时刷新 应用目录结 ...

  3. 跟我一起学.NetCore之EF Core 实战入门,一看就会

    前言 还记得当初学习数据库操作时,用ADO.NET一步一步地进行数据操作及查询,对于查询到的数据还得对其进行解析,然后封装返回给应用层:遇到这种重复而繁琐的工作,总有一些大神或团队对其进行封装,从而出 ...

  4. ASP.NET Core 实战:Linux 小白的 .NET Core 部署之路

    一.前言  最近一段时间自己主要的学习计划还是按照毕业后设定的计划,自己一步步的搭建一个前后端分离的 ASP.NET Core 项目,目前也还在继续学习 Vue 中,虽然中间断了很长时间,好歹还是坚持 ...

  5. pomelo服务器 性能,Pomelo游戏服务器端开发系列(1)-介绍

    Pomelo框架总结 A fast,scalable,distributed game server framework for Node.js 联系我 Pomelo交流群 @老顽童-NextZeus ...

  6. Pomelo框架总结

    Pomelo框架总结 A fast,scalable,distributed game server framework for Node.js 联系我 Pomelo交流群 @老顽童-NextZeus ...

  7. [egret+pomelo]实时游戏杂记(2)

    [egret+pomelo]学习笔记(1) [egret+pomelo]学习笔记(2) [egret+pomelo]学习笔记(3) pomelo pomelo服务端介绍(game-server/con ...

  8. IDEA的Docker插件实战(Dockerfile篇)

    IDEA的Docker插件实战(Dockerfile篇) IntelliJ IDEA的Docker插件能帮助我们将当前工程制作成Docker镜像.运行在指定的远程机器上,是学习和开发阶段的好帮手,本文 ...

  9. 数据结构(04)— 线性顺序表实战

    1. 设计思路 本实战的实质是完成对学生成绩信息的建立.查找.插入.修改.删除等功能,可以首先定义项目的数据结构,然后将每个功能写成一个函数来完成对数据的操作,最后完成主函数以验证各个函数功能并得出运 ...

  10. 【置顶】利用 NLP 技术做简单数据可视化分析教程(实战)

    置顶 本人决定将过去一段时间在公司以及日常生活中关于自然语言处理的相关技术积累,将在gitbook做一个简单分享,内容应该会很丰富,希望对你有所帮助,欢迎大家支持. 内容介绍如下 你是否曾经在租房时因 ...

最新文章

  1. 【学术前沿】26 亿参数训练量,水平接近人类,Google 开发的“史上最强”聊天机器人意义何在?...
  2. C语言中printf是不是关键字,C语言中printf是什么意思
  3. signature=6a8815f5009aacac86e725bea54f840f,A wave packet signature for complex networks
  4. mysql数据库入门教程(14):函数
  5. 如何使用subversion管理iOS源代码
  6. ACNet论文阅读笔记
  7. java socket编程聊天室_Java Socket通信之聊天室功能
  8. Hive的基本操作总结
  9. 淮阴工学院计算机学院机房,实验室开放
  10. 梯度消失和梯度爆炸_梯度消失和梯度爆炸详解
  11. 【Axure9.0原型实战(一)】Axure9.0的元件库的使用、导入、制作、路径等操作方法与技巧(附Axure元件库大全)
  12. 视频教程-2021软考软件设计师--基础知识培训视频-软考
  13. 建设银行安徽分行副行长王文兵:金融科技赋能银行数字化转型
  14. 【VB】中CInt()、Fix()、Int()的区别
  15. MongoDB(四)——GridFS
  16. MySQL中的auto_increment
  17. python发邮件附件_python 发送带附件的邮件
  18. IDea 工具debug模式详细说明
  19. 数据库设计-逻辑设计
  20. python小项目超级大脑抱香_“超级大脑”来了!丰泽区建成全市首个区县级大数据中心...

热门文章

  1. Directx11教程(54) 简单的基于GS的billboard实现
  2. 计量经济学计算机实验报告,综合实训报告范文
  3. java sqlserver数据库连接_JAVA连接SQLserver数据库
  4. Android 7.1关机充电流程
  5. oracle varchar默认长度_Mysql Online DDL之VARCHAR字段扩容探索
  6. 砸金蛋vue插件_小程序商城系统插件代码该如何写?
  7. 2021-10-28 ACWING826 单链表
  8. kmeans算法详解与spark实战
  9. 阿里云Linux服务器配置Java环境
  10. php调取 zabbix实时数据_Zabbix监控系统部署详细步骤