博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Bearcat pomelo game 实战 -- treasures
阅读量:6228 次
发布时间:2019-06-21

本文共 6591 字,大约阅读时间需要 21 分钟。

FROM URL:

 

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


概述

这是一篇通过一个简单的 treasure 捡宝的例子讲述如何使用  来快速, 高效的进行  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 里面的任一组件都被有序的管理维护着, 使用时不再是一个个单一的个体, 而是一个集体

项目代码在 

 

转载地址:http://bjjna.baihongyu.com/

你可能感兴趣的文章
mysql+keepalived 双主热备高可用
查看>>
Hive之 hive的三种使用方式(CLI、HWI、Thrift)
查看>>
DOM基础总结
查看>>
微信公众平台源码
查看>>
Struts2--HelloWord
查看>>
linux C学习笔记05--信号量与共享内存(进程同步)
查看>>
go-mysql,一个易用的mysql接口框架实现
查看>>
POJ3320 Jessica's Reading Problem【尺取法】
查看>>
201671010117 2016-2017-2《Java程序设计》第八周学习Java心得
查看>>
画廊视图(Gallery)的功能和用法
查看>>
自己动手编写一个VS插件(七)
查看>>
Android里面的Toast
查看>>
mysql双机热备的实现
查看>>
前加绩中国、信雅达高级全栈工程师:吴劲松
查看>>
-bash: pod: command not found 解决办法
查看>>
GCD hdu1695容斥原理
查看>>
Node.js:回调函数
查看>>
python 发送邮件 <QQ+腾讯企业邮箱>
查看>>
细数JDK里的设计模式
查看>>
Linux~上部署.net MVC出现的问题与解决
查看>>