SOURCE

console 命令行工具 X clear

                    
>
console
let stage = new createjs.Stage('stage')

let stageWidth = 1080
let stageHeight = 1920
let stageColor = '#666666'

let gridXCount = 11
let gridYCount = 16
let cellSize = stageWidth / (gridXCount + 1)
let gridWidth = gridXCount * cellSize
let gridHeight = gridYCount * cellSize
let gridLeft = (stageWidth - gridWidth) * 0.5
let gridTop = (stageHeight - gridHeight) * 0.4

let beanSize = cellSize * 0.945
let beanCornerRadius = beanSize * 0.1
let beanProps = {
    A: {
        color: '#1f77b4'
    },
    B: {
        color: '#ff7f0e'
    },
    C: {
        color: '#2ca02c'
    },
    D: {
        color: '#d62728'
    },
    E: {
        color: '#9467bd'
    },
    F: {
        color: '#8c564b'
    },
    G: {
        color: '#e377c2'
    },
    H: {
        color: '#7f7f7f'
    },
    I: {
        color: '#bcbd22'
    },
    J: {
        color: '#17becf'
    }
}
let beanTypeCount = _.keys(beanProps).length
let beanEachTypeCount = 2
let beanCount = beanTypeCount * beanEachTypeCount
/*


function Beans() {
    this.map = {}
    let ijFullList = _.map(
        _.range(gridXCount * gridYCount),
        ixj => [parseInt(ixj / gridYCount), ixj % gridYCount])

    let ijInitList = _.sampleSize(ijFullList, beanCount)

    let ijtInitList = []
    for (let u = 0; u < beanTypeCount; u++) {
        let beansT = ijInitList.slice(u * beanEachTypeCount, (u + 1) * beanEachTypeCount)
        ijtInitList = ijtInitList.concat(_.map(beansT, e => [e[0], e[1], _.keys(beanProps)[u]]))
    }
    let k = 0
    for (let ijt of ijtInitList) {
        let i = ijt[0]
        let j = ijt[1]
        let t = ijt[2]
        let color = beanProps[t]['color']
        let x = i2x(i) - beanSize * 0.5
        let y = j2y(j) - beanSize * 0.5
        let doBean = new createjs.Shape()
        doBean.graphics.beginFill(color).drawRoundRectComplex(
            0, 0, beanSize, beanSize,
            beanCornerRadius, beanCornerRadius,
            beanCornerRadius, beanCornerRadius)
        doBean.x = x
        doBean.y = y
        this.map[k] = [i, j, t, doBean]
        k++
    }
    this.do = new createjs.Container()
    for (let ijtb of _.values(this.map)) {
        this.do.addChild(ijtb[3])
    }
}

function createStageDO() {
    let r = new createjs.Shape()
    r.graphics.beginFill(stageColor).drawRect(0, 0, stageWidth, stageHeight)
    return r
}

function createGridDO() {
    let r = new createjs.Shape()
    for (let i = 0; i < gridXCount; i++) {
        for (let j = 0; j < gridYCount; j++) {
            r.graphics.beginFill((i + j) % 2 ? '#efefef' : '#ffffff').drawRect(cellSize * i, cellSize * j, cellSize, cellSize)
        }
    }
    return r
}

function Score() {
    this.value = 0
    this.do = new createjs.Text('SCORE: 0', '60px sans-serif', 'white')
    this.do.x = gridLeft
    this.do.y = stageWidth * 0.05
    this.update = v => {
        this.value = v
        this.do.text = 'Score: ' + v
    }
    this.change = diff => {
        this.update(this.value + diff)
    }
}

function OverPage() {
    let _doBG = new createjs.Shape()
    _doBG.graphics.beginFill('black').drawRect(0, 0, stageWidth, stageHeight)
    _doBG.alpha = 0.5

    function _doBG_onMouseDown(event) {
        event.preventDefault()
    }
    _doBG.addEventListener('mousedown', _doBG_onMouseDown)

    let _doScoreLabel = new createjs.Text('= SCORE =', 'bold 100px sans-serif', 'white')
    _doScoreLabel.textAlign = 'center'
    _doScoreLabel.x = stageWidth * 0.5
    _doScoreLabel.y = stageHeight * 0.1

    let _doScore = new createjs.Text('200', 'bold 300px sans-serif', 'white')
    _doScore.textAlign = 'center'
    _doScore.x = stageWidth * 0.5
    _doScore.y = stageHeight * 0.15

    let _doAgainBG = new createjs.Shape()
    _doAgainBG.graphics.beginFill('#eeeeee').drawRoundRectComplex(
        0, 0, stageWidth * 0.8, 120 * 1.45, stageWidth * 0.03, stageWidth * 0.03, stageWidth * 0.03, stageWidth * 0.03)

    let _doAgainText = new createjs.Text('New Game', 'bold 120px sans-serif', '#343434')
    _doAgainText.textAlign = 'center'
    _doAgainText.x = stageWidth * 0.8 * 0.5
    _doAgainText.y = 0

    let _doAgain = new createjs.Container()
    _doAgain.addChild(_doAgainBG, _doAgainText)
    _doAgain.x = stageWidth * 0.1
    _doAgain.y = stageHeight * 0.6

    this.do = new createjs.Container()
    this.do.addChild(_doBG, _doScoreLabel, _doScore, _doAgain)
}

function playAgain() {

}

function over(win) {
    let overPage = new OverPage()
    stage.addChild(overPage.do)
    if (win) {
        alert('win: ' + win)
    }
}

let doStage = createStageDO()
stage.addChild(doStage)

let doGrid = createGridDO()
doGrid.x = gridLeft
doGrid.y = gridTop
stage.addChild(doGrid)

let score = new Score()
stage.addChild(score.do)

let beans = new Beans()
stage.addChild(beans.do)

let overPage = new OverPage()
stage.addChild(overPage.do)

// @return
//  [k1, k2, ...]: beans to eliminate
//  null: hit on a bean
function hitTest(i, j) {
    let r = []
    if (_.findKey(beans, b => b.i === i && b.j === j)) {
        return null
    }
    let kLeft = null, kRight = null, kTop = null, kBottom = null
    let u = i, v = j
    while (u > 0) {
        u--
        let f = _.findKey(beans, b => b.i === u && b.j === v)
        if (f) {
            kLeft = f
            break
        }
    }
    u = i, v = j
    while (u < gridXCount) {
        u++
        let f = _.findKey(beans, b => b.i === u && b.j === v)
        if (f) {
            kRight = f
            break
        }
    }
    u = i, v = j
    while (v > 0) {
        v--
        let f = _.findKey(beans, b => b.i === u && b.j === v)
        if (f) {
            kTop = f
            break
        }
    }
    u = i, v = j
    while (v < gridYCount) {
        v++
        let f = _.findKey(beans, b => b.i === u && b.j === v)
        if (f) {
            kBottom = f
            break
        }
    }
    let kLTRB = _.pull([kLeft, kTop, kRight, kBottom], null)
    let tLTRB = _.map(kLTRB, k => beans[k].t)
    let tc = _.countBy(tLTRB)
    for (let t in tc) {
        if (tc[t] > 1) {
            for (let k of kLTRB) {
                if (beans[k].t === t) {
                    r.push(k)
                }
            }
        }
    }
    return r
}

function hitTip() {
    for (let i of _.range(gridXCount)) {
        for (let j of _.range(gridYCount)) {
            let targets = hitTest(i, j)
            if (targets) {
                if (targets.length) {
                    return [i, j]
                }
            }
        }
    }
    return null
}

doGrid.addEventListener('mousedown', grid_onMouseDown);
function grid_onMouseDown(event) {
    event.preventDefault()
    let i = parseInt(event.localX / cellSize)
    let j = parseInt(event.localY / cellSize)
    let targets = hitTest(i, j)
    if (targets) {
        _.each(targets, k => {
            stage.removeChild(beans[k].do)
            delete beans[k]
        })
        let count = targets.length
        if (count > 0) {
            score.change(Math.pow(2, count - 1))
        }
    }
    let tip = hitTip()
    if (!tip) {
        over(true)
    }
}

*/
function stage_onTick(event) {
    stage.update()
}

createjs.Ticker.addEventListener('tick', stage_onTick)

function xMouseNotGoThrough(event) {
    event.preventDefault()
}

class CPlayPage {
    constructor() {
        this.beans = {}
        this.score = 0

        this.do = new createjs.Container()
        {
            this.doBG = new createjs.Shape()
            this.doBG.graphics.beginFill('#dedede').drawRect(0, 0, stageWidth, stageHeight)
            this.doBG.addEventListener('mousedown', xMouseNotGoThrough)
        }
        {
            this.doBoard = new createjs.Container()
            this.doBoard.x = gridLeft
            this.doBoard.y = gridTop
            {
                this.doGrid = new createjs.Shape()
                for (let i = 0; i < gridXCount; i++) {
                    for (let j = 0; j < gridYCount; j++) {
                        this.doGrid.graphics.beginFill((i + j) % 2 ? '#efefef' : '#ffffff').drawRect(
                            cellSize * i, cellSize * j, cellSize, cellSize)
                    }
                }

            }
            {
                this.doBeans = new createjs.Container()
            }
            this.doBoard.addChild(this.doGrid)
        }
        this.do.addChild(this.doBG)
        this.do.addChild(this.doBoard)
        this.do.visible = false
        stage.addChild(this.do)
    }
    show(visible) {
        this.do.visible = !!visible
    }
    _i2x(i) {
        return cellSize * (i + 0.5)
    }

    _j2y(j) {
        return cellSize * (j + 0.5)
    }
    reset() {
        for (let k in this.beans) {
            this.doBoard.removeChild(this.beans[k][3])
        }
        this.beans = {}
        this.score = 0
        let ijFullList = _.map(
            _.range(gridXCount * gridYCount),
            ixj => [parseInt(ixj / gridYCount), ixj % gridYCount])

        let ijInitList = _.sampleSize(ijFullList, beanCount)

        let ijtInitList = []
        for (let u = 0; u < beanTypeCount; u++) {
            let beansT = ijInitList.slice(u * beanEachTypeCount, (u + 1) * beanEachTypeCount)
            ijtInitList = ijtInitList.concat(_.map(beansT, e => [e[0], e[1], _.keys(beanProps)[u]]))
        }
        let k = 0
        for (let ijt of ijtInitList) {
            let i = ijt[0]
            let j = ijt[1]
            let t = ijt[2]
            let color = beanProps[t]['color']
            let x = this._i2x(i) - beanSize * 0.5
            let y = this._j2y(j) - beanSize * 0.5
            let doBean = new createjs.Shape()
            doBean.graphics.beginFill(color).drawRoundRectComplex(
                0, 0, beanSize, beanSize,
                beanCornerRadius, beanCornerRadius,
                beanCornerRadius, beanCornerRadius)
            doBean.x = x
            doBean.y = y
            this.beans[k] = [i, j, t, doBean]
            k++
        }
        this.do = new createjs.Container()
        for (let ijtb of _.values(this.beans)) {
            this.doBoard.addChild(ijtb[3])
        }
    }
}

class CHomePage {
    constructor() {
        this.do = new createjs.Container()
        {
            this.doBG = new createjs.Shape()
            this.doBG.graphics.beginFill('black').drawRect(0, 0, stageWidth, stageHeight)
            this.doBG.alpha = 0.6
            this.doBG.addEventListener('mousedown', xMouseNotGoThrough)
        }
        {
            this.doTitleText = new createjs.Text('BEAT it!', 'bold 200px sans-serif', 'white')
            this.doTitleText.textAlign = 'center'
            this.doTitleText.x = stageWidth * 0.5
            this.doTitleText.y = stageHeight * 0.1
        }
        {
            this.doPHText = new createjs.Text('Love SONG', '100px sans-serif', '#ababab')
            this.doPHText.textAlign = 'center'
            this.doPHText.x = stageWidth * 0.5
            this.doPHText.y = stageHeight * 0.35
        }
        {
            this.doStart = new createjs.Container()
            {
                this.doStartBG = new createjs.Shape()
                this.doStartBG.graphics.beginFill('#eeeeee').drawRoundRectComplex(
                    0, 0, stageWidth * 0.6, 120 * 1.45, stageWidth * 0.03, stageWidth * 0.03, stageWidth * 0.03, stageWidth * 0.03)

                this.doStartText = new createjs.Text('Start', 'bold 120px sans-serif', '#343434')
                this.doStartText.textAlign = 'center'
                this.doStartText.x = stageWidth * 0.6 * 0.5
                this.doStartText.y = 0
            }
            this.doStart.addChild(this.doStartBG, this.doStartText)
            this.doStart.x = stageWidth * 0.2
            this.doStart.y = stageHeight * 0.6
            this.doStart.addEventListener('mousedown', function (event) {
                this.show(false)
                PlayPage.reset()
            })
        }
        this.do.addChild(this.doBG, this.doTitleText, this.doPHText, this.doStart)
        this.do.visible = false
        stage.addChild(this.do)
    }
    show(visible) {
        this.do.visible = !!visible
    }
    update() {

    }
    show(visible) {
        this.do.visible = !!visible
    }

}

function COverPage() {

}

function CRankPage() {

}

let PlayPage = new CPlayPage()
PlayPage.show(true)

let HomePage = new CHomePage()
HomePage.show(true)







<canvas id="stage" width="1080" height="1920"/>
canvas {
    max-width: 100%;
}

本项目引用的自定义外部资源