微信小游戏开发之三:实现小游戏的简易引擎

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Register_man/article/details/78931562

一、建立引擎目录

在主目录下创建名为'lib'的文件夹,存放引擎代码

二、创建所有游戏元素的基类:Node

在'lib'文件夹下创建'node.js'文件;

一个元素,需要坐标去定义位置,长宽来定义范围,还需要能够切换显示状态,添加子元素和获取父元素等等

代码如下:

export default class Node {
    constructor(x = 0, y = 0, width = 0, height = 0) {
        // 在父元素中的坐标
        this.x = x
        this.y = y
        // 父元素在世界坐标系中的坐标
        this.absX = 0
        this.absY = 0
        // 锚点
        this.anchorPointX = 0.5
        this.anchorPointY = 0.5
        // 宽和高
        this.width = width
        this.height = height
        // 子元素
        this.children = []
        // 是否显示
        this.visible = true
    }
    /**
     *  将当前元素绘制到屏幕中
     *  @ctx    canvas_context
     */
    draw(ctx) {
        if (this.visible) {
            this.children.forEach((child) => {
                child.draw(ctx)
            })
        }
        // node本身不进行绘制,需要让子类自行绘制
    }

    /**
     *  增加一个子元素
     *  @child  子元素
     */
    addChild(child) {
        child.parent = this
        child.absX += this.x
        child.y += this.y
        this.children.push(child)
        console.log("node.addChild")
    }

    /**
     *  获得计算锚点后的全局坐标
     */
    getFixedPosition() {
        let absPos = this.getAbsPosition()
        return {
            x: absPos.x - this.anchorPointX * this.width,
            y: absPos.y - this.anchorPointY * this.height
        }
    }
    /**
     *  设置锚点,值范围在(0, 1)
     */
    setAnchorPoint(x, y) {
        if (x < 0) x = 0
        if (y < 0) y = 0
        if (x > 1) x = 1
        if (y > 1) y = 1
        this.anchorPointX = x
        this.anchorPointY = y
    }




    /**
     *  快速设置宽和高
     */
    setContentSize(width, height) {
        this.width = width
        this.height = height
    }

    /**
     *  快速设置坐标,并修改子元素的绝对坐标
     */
    setPosition(x, y) {
        this.x = x
        this.y = y
        this.setChildrenAbsPosition(this.getAbsPosition())
    }
    setPositionX(x) {
        this.x = x
        this.setChildrenAbsPosition(this.getAbsPosition())
    }
    setPositionY(y) {
        this.y = y
        this.setChildrenAbsPosition(this.getAbsPosition())
    }

    /**
     *  获得未计算锚点的全局坐标
     */
    getAbsPosition() {
        return {
            x: this.x + this.absX,
            y: this.y + this.absY
        }
    }

    /**
     *  修改所有子元素的坐标
     */
    setChildrenAbsPosition(absPos) {
        this.children.forEach((child) => {
            child.setAbsPosition(absPos)
        })
    }

    setAbsPosition(absPos) {
        this.absX = absPos.x
        this.absY = absPos.y
        this.setChildrenAbsPosition(absPos)
    }
}



三、实现Label类

在'lib'文件夹下新建'label.js'文件
由于计算文字宽度,必须要获得canvas的context,
所以在'lib'文件夹下新建'warehouse'类作为数据仓库,存储游戏中需要用到的常量

let ctx

function WareHouse() {
    this.getCtx = function () {
        if (!ctx) {
            ctx = canvas.getContext('2d')
        }
        return ctx
    }
}

export default (new WareHouse())

‘lib/label.js’
import Node from './node.js'
import WareHouse from './warehouse.js'

export default class Lable extends Node {
    constructor(text = '', x = 0, y = 0, fontSize = "20px", fontFamily = "Courier New") {
        super(x, y)
        this.fontSize = fontSize
        this.fontFamily = fontFamily
        this.text = text
    }

    draw(ctx) {
        super.draw(ctx)
        if (this.visible) {
            ctx.font = this.fontSize + " " + this.fontFamily
            let fixedPos = this.getFixedPosition()
            ctx.fillText(this.text, fixedPos.x, fixedPos.y)
        }
    }

    /**
     *  Label的宽度需要通过canvas进行测量,所以要特殊处理
     */
    getFixedPosition() {
        let ctx = WareHouse.getCtx()
        this.width = ctx.measureText(this.text).width
        return super.getFixedPosition()
    }

    setFontSize(fontsize) {
        this.fontSize = fontSize
    }
    setFontFamily(fontFamily) {
        this.fontFamily = fontFamily
    }
}




四、实现Sprite类

在'lib'文件夹下新建'sprite.js'文件
import Node from './node'

export default class Sprite extends Node {
    constructor(imgSrc = '', width = 0, height = 0, x = 0, y = 0) {
        super(x, y, width, height)
        this.img = new Image()
        this.img.src = imgSrc
    }

    draw(ctx) {
        let absPos = this.getFixedPosition()
        if (this.visible) {
            ctx.drawImage(
                this.img,
                absPos.x,
                absPos.y,
                this.width,
                this.height
            )
        }
        super.draw(ctx)
    }

    setImage(imgSrc){
        this.img.src = imgSrc
    }
}



五、查看效果

在'main.js'中编辑如下代码:
import './js/libs/weapp-adapter'
import './js/libs/symbol'

import Sprite from './lib/sprite.js'
import Label from './lib/label.js'
import WareHouse from './lib/warehouse.js'

// 获取canvas上下文
let ctx = WareHouse.getCtx()

//新建一个Sprite和一个Label
let helloSprite = new Sprite("hello.png")
let helloLable = new Label("hello world")
let worldLable = new Label("world", 0, 50)

helloSprite.addChild(helloLable)
helloLable.addChild(worldLable)


helloSprite.setPosition(150, 50)
helloSprite.setContentSize(50, 50)
helloSprite.setAnchorPoint(0.5,0.5)
helloLable.setAnchorPoint(0.5, 0.5)

// 模拟游戏循环
window.requestAnimationFrame(loop, canvas)

// update中渲染元素
function update() {
    //helloSprite.setPositionY(helloSprite.y + 0.1)
    helloSprite.draw(ctx)
}

function loop() {
    // 清空显示区域
    ctx.clearRect(0, 0, canvas.width, canvas.height)
    // 渲染元素
    update()
    // 持续循环调用自身
    window.requestAnimationFrame(loop, canvas)
}



可以看到如下效果:



未完待续...


猜你喜欢

转载自blog.csdn.net/Register_man/article/details/78931562