美文网首页Screeps 游戏指南
Screeps 浅谈游戏中的原型拓展

Screeps 浅谈游戏中的原型拓展

作者: HoPGoldy | 来源:发表于2019-09-23 23:06 被阅读0次
screeps 系列教程

简介

在游戏的教程中,我们了解到可以通过游戏给定的基本 api 如Game.creeps Game.spawns等获取游戏对象,然后设计一层层的封装,并将这些游戏对象作为参数传递给封装好的函数,进而完成我们的逻辑。

但是这么做有一点缺陷,假如我们代码封装做的比较多的话,就会出现游戏对象被一层层的传递下去,如下:

// 获取游戏对象
const creep = Game.creeps['creep1']

// 传递给任务分发函数
work(creep)

// work 函数里传递给指定的角色函数
upgrader(creep) 

// upgrader 函数里再传递给状态更新函数
updateState(creep)

…

可以看到 creep 对象被一步步的传递给不同的函数,这样的设计会增加参数的个数,不方便理解,进而增加代码的维护成本。

那么有没有一种更简洁的方式来避免这种设计呢,答案就是本文要讲的 游戏原型拓展

什么是原型?

js 中的继承是通过原型链实现的,每一个对象都有一个链接指向了另一个对象,被指向的对象就称为前者的原型

比如 screeps 中的每一个creep的原型都是Creep注意区分这两者的大小写,我们常用的.moveTo().harvest()就是在Creep原型上定义的。

而如果我们尝试调用某个对象上不存在的属性时,它就会去它的原型上去查找,如果原型对象上有的话,就会执行原型上的方法。这也就是我们可以进行原型拓展的根本。

简单的例子

刚才讲了一大堆概念,可能对没有系统学过 js 的同学有点难以理解。接下来就举一个简单的例子。我们在游戏代码入口处进行如下定义:

module.exports.loop = function () {
    Creep.prototype.sayHello = function () {
        console.log('hello world!')
    }
}

然后随便抓个正在干活的creep执行下面代码:

Game.creeps['creep name'].sayHello()

然后你就会发现控制台输出了hello world!。完美!我们成功的修改了Creep,让每一个creep都获得了sayHello方法。接下来我们讲解一下上面的例子:

我们在Creep.prototype上定义了sayHello,并把一个函数赋值给它。这里的Creep.prototype就是Creep原型对象,当creep上找不到sayHello方法的时候就会去prototype上寻找,正好就找到了我们刚才定义的方法。

很好,我们来更近一步,把上面的代码替换如下:

Creep.prototype.sayHello = function () {
    this.say(`我的名字是${this.name}`)
}

然后再找一个creep执行sayHello方法,就会出现如下情况:

image.png

creep他自己说话了!没错,在原型对象上定义的方法中,你可以使用this访问到其他所有的属性!这么一来,我们就可以将常用的方法挂载到creep来简化我们的代码结构,比如下面这样:

// 建设房间内的建筑工地
Creep.prototype.buildStructure = function () {
    const targets = this.room.find(FIND_CONSTRUCTION_SITES)
    // 找到就去建造
    if (targets.length > 0) {
        if(this.build(targets[0]) == ERR_NOT_IN_RANGE) {
            this.moveTo(targets[0])
        }
    }   
}

这样我们只需要执行creep.buildStructure()就可以让creep自己跑到建筑工地然后干活了。至于原型拓展的用处还有很多,这里不再深入,有兴趣的可以参考官方的这篇文档 《screeps modifying-prototypes》 来了解更多用法。

接下来,我们讲一下如何优雅清晰的规模化拓展原型。

更好的代码结构

和其他的逻辑代码一样,我们总不能把所有的原型拓展代码都写到主入口module.exports.loop里吧,接下来就分享一种比较清晰的代码结构。当然,如果你有自己的想法的话大可不必按照我的来做。

首先假设我们想拓展Creep原型,那么可以新建一个名为mount.creep.js的文件,其内容如下:

// 将拓展签入 Creep 原型
module.exports = function () {
    _.assign(Creep.prototype, creepExtension)
}

// 自定义的 Creep 的拓展
const creepExtension = {
    // 自定义敌人检测
    checkEnemy() { 
        // 代码实现...
    },
    // 填充所有 spawn 和 extension
    fillSpawnEngry() { 
        // 代码实现...
    },
    // 填充所有 tower
    fillTower() {
        // 代码实现...
    },
    // 其他更多自定义拓展
}

我们将所有的自定义属性都存放到creepExtension对象中,然后使用lodashassign方法将其一次性全部签入到Creep原型中。

然后我们再新建mount.js文件,这个文件引入mount.creep.js并将封装成一个单独的入口函数。这样,如果有新的拓展,也可以统一挂载到这层封装中:

const mountCreep = require('./mount.creep')
// const mountFlag = require('./mount.flag')
// const mountRoom = require('./mount.room')

// 挂载所有的额外属性和方法
module.exports = function () {
    console.log('[mount] 重新挂载拓展')

    mountCreep()
    // mountFlag()
    // mountRoom()
    // 其他更多拓展...
}

最后,我们在 main.js 中引入 mount.js 并执行就好了。注意,这里的方法调用应该写在 loop 之外,这样只会在全局重置(我们的拓展就是这时被清空的 )时重新挂载,这样就不用每个 tick 都执行从而带来不必要的消耗:

require('./mount')()

module.exports.loop = function () {
    // 其他逻辑代码
}

这里放一张拓展挂载的流程图来方便理解。

拓展挂载流程图

总结

本文简单介绍了 screeps 中如何拓展原型,只需要在对应原型的prototype属性上添加新的属性即可,添加完成后所有由该原型派生出的对象都可以调用该属性,并且在 screeps - api 中提到的原型都可以通过这种方式进行拓展。

最后我们介绍了一种封装拓展的代码结构,做到了拓展的统一挂载,并且方便了日后的维护。想要了解更多内容欢迎访问 《Screeps 文集》

相关文章

  • Screeps 浅谈游戏中的原型拓展

    简介 在游戏的教程中,我们了解到可以通过游戏给定的基本 api 如Game.creeps Game.spawns等...

  • screeps 游戏中的 tips

    screeps 里会时不时的给你一个提示,平时也没怎么看过,今天特地点了一遍,把常见的 tip 都记录一下供大家参...

  • Creep移动原理和对穿的应用 - Screep技术

    在Screeps游戏中,寻路是最基本、最重要也最需要细致优化的事情。 在前期游戏中你可能会遇到两个Creep在对向...

  • 廖雪峰JS小记

    (function(){})() 原型,原型链 浅谈Js原型的理解JS 原型与原型链终极详解 对象 对象:一种无序...

  • Screeps 浅谈代码优化

    代码优化可以说是每一个在 shard3 生活的玩家都要经历的。这篇文章我们就来分析一下 cpu 消耗的来源和如何进...

  • 2019-08-05 拓展现有函数

    定义、声明的函数 拓展原型链上的方法

  • 浅谈原型

    1、[[Prototype]]JavaScript中的对象有一个特殊的[[Prototype]]内置属性,其实就是...

  • Screeps 游戏中的两大设计模式

    简介 作为一款代码主导的游戏,有代码的地方就有设计模式。本文就作为一篇拓展阅读性质的文章,来简单介绍一下 Scre...

  • 7.第二篇:第7章 原型模式

    本文摘自 《JavaScript 设计模式》张容铭 著 版权归原作者所有 原型的拓展 原型继承

  • 原型链模式-拓展

    批量设置原型上的原型和方法方法一 方法二重构原型对象的方式 -> 自己新开辟一个堆内存,存储公有属性和方法,把浏览...

网友评论

    本文标题:Screeps 浅谈游戏中的原型拓展

    本文链接:https://www.haomeiwen.com/subject/kdkmuctx.html