Creator填色游戲的一種實現方案


前言

先上一個辛苦弄出來的gif效果。寫公眾號時間不長,很多技巧還在慢慢跟小伙伴學習。可關注公眾號,回復“繪圖”或者“填色”都可獲得demo的git地址。請使用Creator2.4.0運行
fillcolor.gif

填色游戲種類也挺多的,我今天要說的是一種相對簡單的填色。
對於填色游戲的做法,我在論壇里搜到不少帖子,尤其是這個帖子的留言比較多:油漆桶填色效果怎么實現啊,找了兩天都找不到資源
其中有一條留言跟我的想法不謀而合,

尤其是做了之前的取色,繪圖等功能后,對webgl的readPixels()函數返回的數據處理起來越來越順手。所以就用了替換數據的方式。
還有一種填色游戲采用的純Graphics的方式,各種貝塞爾曲線,矩形,直線和moveTo,實現幾個區塊填指定顏色的填色游戲,我感覺那種應該是借助工具的,因為生成的文件相當大。如果有知道的同學可以在下方留言,一起交流。

制作方式

  1. 先上一張圖
    image.png
    這是一張我在《繪圖游戲調色盤取色方法》的文章中展示的一張圖,圖片左側的色盤是原始圖,右側是使用相機截屏獲得的數據更新后的圖。當時是為了驗證截屏的正確性而做的。這次正好用來做填色游戲。
  2. 制作原理
    實際上更改的就是右側這張圖使用的數據。左側的圖接收觸摸事件,通過觸摸點的位置,更新顏色數據。所以只要將兩張圖片重疊,用右邊的圖片蓋住左邊的圖片,然后使用處理過的顏色數據更新右邊的這張圖,效果也就出來了。這里需要說一嘴,為什么要用兩張圖,就是相機截屏獲得的數據初始化出來的紋理,正好是y反轉的,所以右側的圖的scaleY我給了-1.否則就是倒着的。
  3. 接收事件的處理
    接收事件,獲得點擊坐標位置,這個沒什么可多說的。
  4. 更新數據
    更新數據的時候我是從點擊的點向四周擴散,因為顏色的點太多,所以不能用遞歸操作,因此做了每幀更新多少個點的方式,目前我給的是5000,OPPO A9真機實測不卡。使用一個數組記錄更新過的點,避免重復更新消耗時間。
  5. 坑與新玩法
    我沒有做在更新數據時不可以更換顏色操作,所以在更新數據時如果點擊了左側的色盤,那么右側的顏色會跟着更新,這個也可以說是坑,也可以說是玩法。
    色盤也是通過相機截屏獲得的數據獲取的,但是這種獲取有缺陷,就是點擊的色盤上的點不能有陰影,但是我使用的色盤剛好有,所以有的時候獲取的顏色會是黑色或者灰色。

代碼

import TextureRenderUtils from "../TextureRenderUtils";

const { ccclass, property } = cc._decorator;

@ccclass
export default class FillColorV1 extends cc.Component {

    @property([cc.Component.EventHandler])
    callback: cc.Component.EventHandler[] = [];

    @property(cc.Camera)
    camera: cc.Camera = null;

    @property(cc.Sprite)
    target: cc.Sprite = null;

    @property(cc.Node)
    renderNode: cc.Node = null;

    private pointList: number[] = []
    private r: number;
    private g: number;
    private b: number;

    protected textureHelper: TextureRenderUtils = new TextureRenderUtils()

    private grid: number[] = []

    private imgData: ArrayBufferView = null;

    start() {
        this.node.on(cc.Node.EventType.TOUCH_START, this.touchStart, this)
        this.init();
    }

    getTextureInfo() {
        return this.textureHelper.getTextureInfo();
    }

    getDataUrl() {
        return this.textureHelper.getDataUrl()
    }

    changeColor(color: cc.Color) {
        this.r = color.r;
        this.g = color.g;
        this.b = color.b;

    }

    init() {

        this.textureHelper.init(this.camera, this.renderNode)

        this.textureHelper.render()

        let data = this.textureHelper.getData()

        if (data.length > 0) {
            this.imgData = data;
            cc.log('FillColorV1  width ', this.renderNode.width, ' height ', this.renderNode.height)
            cc.log(' 實際上有多少個點  == ', data.length / 4)
            let count = this.renderNode.width * this.renderNode.height;
            cc.log(" 應該有多少個點的顏色 ", count)
            if (this.target) {
                let tTexture = this.target.spriteFrame.getTexture()
                tTexture.setFlipY(false)
                this.target.node.scaleY = -1

                tTexture.initWithData(data, tTexture.getPixelFormat(), this.renderNode.width, this.renderNode.height)

            }
        }

    }


    update(dt: number) {
        let flag = false;
        let count = 0;
        let width = this.textureHelper.width;
        let r = this.r;
        let g = this.g;
        let b = this.b;
        //當發現有點擊坐標的時候開始執行。這個5000
        while (this.pointList.length >= 2 && count++ <= 5000) {
            flag = true;
            let x = this.pointList.shift();
            let y = this.pointList.shift();
            this.paintPoint(x, y, width, r, g, b)
        }

        if (flag) {
            let texture = this.target.spriteFrame.getTexture();
            texture.initWithData(this.imgData, texture.getPixelFormat(), texture.width, texture.height)
        }

    }

    paintPoint(x: number, y: number, width: number, r: number, g: number, b: number) {
        let data = this.imgData;
        let rowW = Math.floor(width) * 4//一行的長度
        x = Math.floor(x)
        let srow = Math.floor(y);//行開始位置
        let startX = srow * rowW + x * 4;//列開始位置
        if (!this.grid[startX]) {
            this.grid[startX] = 1
            // cc.log('r g b%{} ', data[startX + 0], data[startX + 1], data[startX + 2])
            if (data[startX + 0] > 100 || data[startX + 1] > 100 || data[startX + 2] > 50) {
                data[startX + 0] = r;
                data[startX + 1] = g;
                data[startX + 2] = b;

                this.pointList.push(x - 1)
                this.pointList.push(y);
                this.pointList.push(x + 1)
                this.pointList.push(y);
                this.pointList.push(x)
                this.pointList.push(y - 1)
                this.pointList.push(x)
                this.pointList.push(y + 1)
            }
        }
    }
    //用於打印點擊的位置,無關緊要
    showPointColor(x: number, y: number, width: number) {
        let data = this.imgData;
        let rowW = Math.floor(width) * 4//一行的長度
        x = Math.floor(x)
        let srow = Math.floor(y);//行開始位置
        let startX = srow * rowW + x * 4;//列開始位置
        cc.log('r g b', data[startX + 0], data[startX + 1], data[startX + 2])


    }

    touchStart(e: cc.Touch) {
        let pos = e.getLocation();
        pos = this.node.convertToNodeSpaceAR(pos)
        cc.log('touchStart  x ', pos.x, ' y = ', pos.y)
        this.pointList.length = 0;
        this.grid.length = 0;
        this.pointList.push(pos.x)
        this.pointList.push(pos.y)
        this.showPointColor(pos.x, pos.y, this.textureHelper.width)
    }

}

結語

以上是我做的一種填色方案,並沒有涉及到很大的圖案,也沒有涉及到放大縮小。我沒有說我的方案是最好的,我相信方案有很多種,很多方案都有它的局限性,有它的適用范圍;只要沒有bug,就有參考價值;但是不要拿來主義,要根據你自己的情況,酌情考慮。

前幾天公眾號好不容易湊夠了500人,開了廣告。但是感覺僅憑廣告的收入,不說了,都是眼淚。

image.png

以后更新的速度可能會慢很多,一周兩篇,或者一篇或者沒有,還請大家見諒。畢竟不能靠這個養活自己,而且還相當耗費時間。

歡迎掃碼關注公眾號《微笑游戲》,瀏覽更多內容。如果您覺得文章還可以,點贊、在看、分享、贊助、點下廣告都是對我最大的鼓勵,在下將感激不盡。

微信圖片_20190904220029.jpg
歡迎掃碼關注公眾號《微笑游戲》,瀏覽更多內容。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM