原生js实现2048小游戏(es5、es6、ts版本)欢迎star!

948 阅读5分钟

项目仓库欢迎star github.com/PH-C/2048-g…

这个项目两年前写的,用于练习原生js,现在新增了es6版本和typescript版本,发出来的目的是想让大家看看es5版本和es6版本以及ts版本的异同点、优缺点,了解js的发展趋势,欢迎大家各抒己见!

三个版本都是js面向对象编程的经典实例,支持主题颜色和色块颜色的配置

var options = {  cellColors: ['#EEE4DA', '#ede0c8', '#f2b179', '#f59563', '#f67c5f', '#f65e3b'],             themeColor:"rgba(238, 228, 218, 0.35)" }; new Game(options);

点击进入我的个人网站查看详细代码:www.front-end.xin/article/det…

es5版本

var Game = (function (options) {
    var constructor = function (options) {
        this.tdim = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
        options = options||{}
        this.cellColors = options['cellColors']
        this.themeColor = options['themeColor']
        this.init();
    }

    /**
     * init 初始化
     */
    var init = function() {
        var self = this;
        self.getRestItem();
        self.getRestItem();
        self.rendering();
        this.addEvent();
    }

    /**
     * addEvent 事件绑定
     */
    var addEvent = function() {
        var tdim = this.tdim;
        var self = this;
        var newGame = document.getElementsByClassName('btn')[0];
        newGame.onclick = this.onNewGame.bind(this);
        document.body.onkeydown = function (event) {
            if (event.keyCode == 39)   //向右code为39
            {
                self.onKeyRight();
            }

            if (event.keyCode == 37)   //向右code为39
            {
                self.onKeyLeft();
            }

            if (event.keyCode == 38)   //向右code为39
            {
                self.onKeyUp();
            }

            if (event.keyCode == 40)   //向右code为39
            {
                self.onKeyDown();
            }
        }

    }

    var onNewGame = function () {
        var tdim = this.tdim;
        var gameover = document.getElementsByClassName('gameover')[0];
        gameover.style.display = "none";
        for (var i = 0; i < 4; i++) {
            for (var j = 0; j < 4; j++) {
                tdim[i][j] = 0;
            }
        }
        this.countScore();
        this.getRestItem();
        this.getRestItem();
        this.rendering();
    }

    /**
     * onKeyRight 点击向右键响应事件
     */
    var onKeyRight = function() {
        var tdim = this.tdim;
        var self = this;
        var tdimf = self.clone(tdim);
        for (var i = 0; i < 4; i++) {
            var pos = 3;
            for (var j = 3; j >= 0; j--) {
                if (tdim[i][j] != 0) {
                    if (pos > j) {
                        tdim[i][pos--] = tdim[i][j];
                        tdim[i][j] = 0;
                    } else {
                        tdim[i][pos--] = tdim[i][j];
                    }
                }
            }

            for (var j = 3; j >= 1; j--) {
                if (tdim[i][j] == tdim[i][j - 1] && tdim[i][j] > 0 && tdim[i][j - 1] > 0) {
                    tdim[i][j] = tdim[i][j] + tdim[i][j - 1];
                    tdim[i][j - 1] = 0;
                }
            }

        }
        self.rendering();
        self.getRestItem(tdimf);
        self.countScore();
        setTimeout(function () {
            self.rendering();
        }, 500)

    }

    /**
     * onKeyLeft 按下向左键响应事件
     */
    var onKeyLeft = function() {
        var tdim = this.tdim;
        var self = this;
        var tdimf = self.clone(tdim);
        for (var i = 0; i < 4; i++) {
            var pos = 0;
            for (var j = 0; j < 4; j++) {
                if (tdim[i][j] != 0) {
                    if (pos < j) {
                        tdim[i][pos++] = tdim[i][j];
                        tdim[i][j] = 0;
                    } else {
                        tdim[i][pos++] = tdim[i][j];
                    }
                }
            }

            for (var j = 0; j < 3; j++) {
                if (tdim[i][j] == tdim[i][j + 1] && tdim[i][j] > 0 && tdim[i][j + 1] > 0) {
                    tdim[i][j] = tdim[i][j] + tdim[i][j + 1];
                    tdim[i][j + 1] = 0;
                }
            }

        }
        self.rendering();
        self.getRestItem(tdimf);
        self.countScore();
        setTimeout(function () {
            self.rendering();
        }, 500)

    }

    /**
     * onKeyUp 按下向下键响应事件
     */
    var onKeyUp = function() {
        var tdim = this.tdim;
        var self = this;
        var tdimf = self.clone(tdim);
        for (var j = 0; j < 4; j++) {
            var pos = 0;
            for (var i = 0; i < 4; i++) {
                if (tdim[i][j] != 0) {
                    if (pos < i) {
                        tdim[pos++][j] = tdim[i][j];
                        tdim[i][j] = 0;
                    } else {
                        tdim[pos++][j] = tdim[i][j];
                    }
                }
            }

            for (var i = 0; i < 3; i++) {
                if (tdim[i][j] == tdim[i + 1][j] && tdim[i][j] > 0 && tdim[i + 1][j] > 0) {
                    tdim[i][j] = tdim[i][j] + tdim[i + 1][j];
                    tdim[i + 1][j] = 0;
                }
            }

        }
        self.rendering();
        self.getRestItem(tdimf);
        self.countScore();
        setTimeout(function () {
            self.rendering();
        }, 500)

    }

    /**
     * onKeyDown 按下向下键响应事件
     */
    var onKeyDown = function() {
        var tdim = this.tdim;
        var self = this;
        var tdimf = self.clone(tdim);
        for (var j = 0; j < 4; j++) {
            var pos = 3;
            for (var i = 3; i >= 0; i--) {
                if (tdim[i][j] != 0) {
                    if (pos > i) {
                        tdim[pos--][j] = tdim[i][j];
                        tdim[i][j] = 0;
                    } else {
                        tdim[pos--][j] = tdim[i][j];
                    }
                }
            }
            for (var i = 3; i >= 1; i--) {
                if (tdim[i][j] == tdim[i - 1][j]) {
                    tdim[i][j] = tdim[i][j] + tdim[i - 1][j];
                    tdim[i - 1][j] = 0;
                }
            }

        }
        self.rendering();
        self.getRestItem(tdimf);
        self.countScore();
        setTimeout(function () {
            self.rendering();
        }, 500)

    }

    /**
     * getRestItem 从剩下的空白格子里选择一个并产生新数2或者4
     * @param tdimf
     */
    var getRestItem = function(tdimf) {
        var tdim = this.tdim;
        var self = this;
        var newAry = [];
        var countdif = 0;
        var cnt = 0;
        //获取所有值为0的位置用i,j表示
        for (var i = 0; i < 4; i++) {
            for (var j = 3; j >= 0; j--) {
                if (tdim[i][j] == 0) {
                    newAry.push({i: i, j: j});
                }
            }
        }
        //
        if (tdimf) {
            for (var p = 0; p < 4; p++) {
                for (var s = 3; s >= 0; s--) {
                    if (tdim[p][s] == tdimf[p][s]) {
                        cnt++;
                        if (cnt == 16 && newAry.length > 0) {
                            return
                        }
                    }
                }
            }
        }

        //一个数与前后左右都不相等结束
        if (newAry.length <= 0) {

            for (var m = 0; m < 4; m++) {
                for (var n = 3; n >= 0; n--) {
                    var compare = [];
                    var count = 0;
                    var cur = tdim[m][n];
                    var ary = [];
                    ary = [{s: m - 1, t: n}, {s: m, t: n - 1}, {s: m + 1, t: n}, {s: m, t: n + 1}];

                    ary.forEach(function (eml) {
                        if ((eml.s >= 0 && eml.s < 4) && (eml.t >= 0 && eml.t < 4)) {
                            compare.push(eml);
                        }
                    })
                    for (var k = 0; k < compare.length; k++) {
                        var curl = compare[k];
                        if (tdim[curl.s][curl.t] != cur) {
                            count++;
                            //如果当前值和前后左右都不相等
                            if (count >= compare.length) {
                                countdif++;
                                if (countdif >= 16) {
                                    var gameover = document.getElementsByClassName('gameover')[0];
                                    gameover.style.display = "block";
                                    self.tryAgain();
                                    return
                                }
                            }

                        } else {
                            return
                        }
                    }
                }
            }
        } else {
            var ranNum = Math.floor(Math.random() * newAry.length);
            var item = newAry[ranNum];
            var tmp = Math.floor(Math.random() * 100);
            if (tmp > 20) {
                tdim[item.i][item.j] = 2;
            }
            else {
                tdim[item.i][item.j] = 4;
            }
            console.log(tdim);
        }
    }

    /**
     * clone 克隆二维数组
     * @param tdim
     * @returns {*[]}
     */
    var clone = function(tdim) {
        var newAry = [[], [], [], []];
        for (var i = 0; i < 4; i++) {
            for (var j = 0; j < 4; j++) {
                newAry[i][j] = tdim[i][j]
            }
        }
        return newAry
    }

    /**
     * rendering 渲染页面
     */
    var rendering = function () {
        var tdim = this.tdim;
        var cellColors = this.cellColors;
        var themeColor = this.themeColor;
        var row = document.getElementsByClassName("grid-row");
        var cell = document.getElementsByClassName("grid-cell");
        for (var m = 0; m < 4; m++) {
            for (var n = 0; n < 4; n++) {
                var seqnum = m * 4 + n;
                if (tdim[m][n] != 0) {
                    var num = tdim[m][n];
                    switch (num) {
                        case 2:
                            cell[seqnum].style.background =cellColors[0];
                            break;
                        case 4:
                            cell[seqnum].style.background = cellColors[1];
                            break;
                        case 8:
                            cell[seqnum].style.background = cellColors[2];
                            break;
                        case 16:
                            cell[seqnum].style.background = cellColors[3];
                            break;
                        case 32:
                            cell[seqnum].style.background = cellColors[4];
                            break;
                        default:
                            cell[seqnum].style.background = cellColors[5];
                            break;
                    }
                    cell[seqnum].innerHTML = tdim[m][n];
                }
                else {
                    cell[seqnum].innerHTML = '';
                    cell[seqnum].style.background = themeColor;
                }
            }
        }
    }

    /**
     * tryAgain 点击tryAgain按钮响应事件重新开始
     */
    var tryAgain = function() {
        var tdim = this.tdim;
        var self = this;
        var againBtn = document.getElementById('again');
        againBtn.onclick = function () {
            var gameover = document.getElementsByClassName('gameover')[0];
            gameover.style.display = "none";
            for (var i = 0; i < 4; i++) {
                for (var j = 0; j < 4; j++) {
                    tdim[i][j] = 0;
                }
            }
            self.countScore();
            self.rendering();
        }
    }

    /**
     * countScore 计算得分
     */
    var countScore = function() {
        var tdim = this.tdim;
        var sum = 0;
        for (var i = 0; i < 4; i++) {
            for (var j = 0; j < 4; j++) {
                if (tdim[i][j] > 2) {
                    sum += tdim[i][j];
                }
            }
        }
        var score = document.getElementById('score');
        score.innerHTML = sum;
    }

    var prototype = constructor.prototype;
    prototype.init = init;
    prototype.addEvent = addEvent;
    prototype.onNewGame = onNewGame;
    prototype.onKeyRight = onKeyRight;
    prototype.onKeyLeft = onKeyLeft;
    prototype.onKeyUp = onKeyUp;
    prototype.onKeyDown = onKeyDown;
    prototype.getRestItem = getRestItem;
    prototype.clone = clone;
    prototype.rendering = rendering;
    prototype.tryAgain = tryAgain;
    prototype.countScore = countScore;
    return constructor;
})()
var options = {
    cellColors: ['#EEE4DA', '#ede0c8', '#f2b179', '#f59563', '#f67c5f', '#f65e3b'],
    themeColor:"rgba(238, 228, 218, 0.35)"
};
new Game(options);

class GameTS {    private tdim: number[][];    private cellColors: string[];    private themeColor: string;    constructor(cellColors:string[],themeColor:string) {      this.cellColors = cellColors      this.themeColor = themeColor      this.tdim = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]      this.init();    }    /**     * init 初始化     */    init() {      let self = this;      self.getRestItem(null);      self.getRestItem(null);      self.rendering();      this.addEvent();    }    /**     * addEvent 事件绑定     */    addEvent () {      let tdim = this.tdim;      let self = this;      let newGame =  <HTMLElement>document.getElementsByClassName('btn')[0];      newGame.onclick = this.onNewGame.bind(this);      document.body.onkeydown = function (event) {        if (event.keyCode == 39)   //向右code为39        {          self.onKeyRight();        }        if (event.keyCode == 37)   //向右code为39        {          self.onKeyLeft();        }        if (event.keyCode == 38)   //向右code为39        {          self.onKeyUp();        }        if (event.keyCode == 40)   //向右code为39        {          self.onKeyDown();        }      }    }    onNewGame() {      let tdim = this.tdim;      let gameover =  <HTMLElement>document.getElementsByClassName('gameover')[0];      gameover.style.display = "none";      for (let i = 0; i < 4; i++) {        for (let j = 0; j < 4; j++) {          tdim[i][j] = 0;        }      }      this.countScore();      this.getRestItem(null);      this.getRestItem(null);      this.rendering();    }    /**     * onKeyRight 点击向右键响应事件     */    onKeyRight () {      let tdim = this.tdim;      let self = this;      let tdimf = self.clone(tdim);      for (let i = 0; i < 4; i++) {        let pos = 3;        for (let j = 3; j >= 0; j--) {          if (tdim[i][j] != 0) {            if (pos > j) {              tdim[i][pos--] = tdim[i][j];              tdim[i][j] = 0;            } else {              tdim[i][pos--] = tdim[i][j];            }          }        }        for (let j = 3; j >= 1; j--) {          if (tdim[i][j] == tdim[i][j - 1] && tdim[i][j] > 0 && tdim[i][j - 1] > 0) {            tdim[i][j] = tdim[i][j] + tdim[i][j - 1];            tdim[i][j - 1] = 0;          }        }      }      self.rendering();      self.getRestItem(tdimf);      self.countScore();      setTimeout(function () {        self.rendering();      }, 500)    }    /**     * onKeyLeft 按下向左键响应事件     */    onKeyLeft () {      let tdim = this.tdim;      let self = this;      let tdimf = self.clone(tdim);      for (let i = 0; i < 4; i++) {        let pos = 0;        for (let j = 0; j < 4; j++) {          if (tdim[i][j] != 0) {            if (pos < j) {              tdim[i][pos++] = tdim[i][j];              tdim[i][j] = 0;            } else {              tdim[i][pos++] = tdim[i][j];            }          }        }        for (let j = 0; j < 3; j++) {          if (tdim[i][j] == tdim[i][j + 1] && tdim[i][j] > 0 && tdim[i][j + 1] > 0) {            tdim[i][j] = tdim[i][j] + tdim[i][j + 1];            tdim[i][j + 1] = 0;          }        }      }      self.rendering();      self.getRestItem(tdimf);      self.countScore();      setTimeout(function () {        self.rendering();      }, 500)    }    /**     * onKeyUp 按下向下键响应事件     */    onKeyUp () {      let tdim = this.tdim;      let self = this;      let tdimf = self.clone(tdim);      for (let j = 0; j < 4; j++) {        let pos = 0;        for (let i = 0; i < 4; i++) {          if (tdim[i][j] != 0) {            if (pos < i) {              tdim[pos++][j] = tdim[i][j];              tdim[i][j] = 0;            } else {              tdim[pos++][j] = tdim[i][j];            }          }        }        for (let i = 0; i < 3; i++) {          if (tdim[i][j] == tdim[i + 1][j] && tdim[i][j] > 0 && tdim[i + 1][j] > 0) {            tdim[i][j] = tdim[i][j] + tdim[i + 1][j];            tdim[i + 1][j] = 0;          }        }      }      self.rendering();      self.getRestItem(tdimf);      self.countScore();      setTimeout(function () {        self.rendering();      }, 500)    }    /**     * onKeyDown 按下向下键响应事件     */    onKeyDown () {      let tdim = this.tdim;      let self = this;      let tdimf = self.clone(tdim);      for (let j = 0; j < 4; j++) {        let pos = 3;        for (let i = 3; i >= 0; i--) {          if (tdim[i][j] != 0) {            if (pos > i) {              tdim[pos--][j] = tdim[i][j];              tdim[i][j] = 0;            } else {              tdim[pos--][j] = tdim[i][j];            }          }        }        for (let i = 3; i >= 1; i--) {          if (tdim[i][j] == tdim[i - 1][j]) {            tdim[i][j] = tdim[i][j] + tdim[i - 1][j];            tdim[i - 1][j] = 0;          }        }      }      self.rendering();      self.getRestItem(tdimf);      self.countScore();      setTimeout(function () {        self.rendering();      }, 500)    }    /**     * getRestItem 从剩下的空白格子里选择一个并产生新数2或者4     * @param tdimf     */    getRestItem (tdimf:any) {      let tdim = this.tdim;      let self = this;      let newAry = [];      let countdif = 0;      let cnt = 0;      //获取所有值为0的位置用i,j表示      for (let i = 0; i < 4; i++) {        for (let j = 3; j >= 0; j--) {          if (tdim[i][j] == 0) {            newAry.push({ i: i, j: j });          }        }      }            if (tdimf) {        for (let p = 0; p < 4; p++) {          for (let s = 3; s >= 0; s--) {            if (tdim[p][s] == tdimf[p][s]) {              cnt++;              if (cnt == 16 && newAry.length > 0) {                return              }            }          }        }      }      //一个数与前后左右都不相等结束      if (newAry.length <= 0) {        for (let m = 0; m < 4; m++) {          for (let n = 3; n >= 0; n--) {            let compare = [];            let count = 0;            let cur = tdim[m][n];            let ary = [];            ary = [{ s: m - 1, t: n }, { s: m, t: n - 1 }, { s: m + 1, t: n }, { s: m, t: n + 1 }];            ary.forEach(function (eml) {              if ((eml.s >= 0 && eml.s < 4) && (eml.t >= 0 && eml.t < 4)) {                compare.push(eml);              }            })            for (let k = 0; k < compare.length; k++) {              let curl = compare[k];              if (tdim[curl.s][curl.t] != cur) {                count++;                //如果当前值和前后左右都不相等                if (count >= compare.length) {                  countdif++;                  if (countdif >= 16) {                    let gameover =  <HTMLElement>document.getElementsByClassName('gameover')[0];                    gameover.style.display = "block";                    self.tryAgain();                    return                  }                }              } else {                return              }            }          }        }      } else {        let ranNum = Math.floor(Math.random() * newAry.length);        let item = newAry[ranNum];        let tmp = Math.floor(Math.random() * 100);        if (tmp > 20) {          tdim[item.i][item.j] = 2;        }        else {          tdim[item.i][item.j] = 4;        }        console.log(tdim);      }    }    /**     * clone 克隆二维数组     * @param tdim     * @returns {*[]}     */    clone (tdim: number[][]): number[][] {      let newAry = [[], [], [], []];      for (let i = 0; i < 4; i++) {        for (let j = 0; j < 4; j++) {          newAry[i][j] = tdim[i][j]        }      }      return newAry    }    /**     * rendering 渲染页面     */    rendering () {      let tdim = this.tdim;      let cellColors = this.cellColors;      let themeColor = this.themeColor;      let row =  <HTMLCollectionOf<HTMLElement>>document.getElementsByClassName("grid-row");      let cell =  <HTMLCollectionOf<HTMLElement>>document.getElementsByClassName("grid-cell");      for (let m = 0; m < 4; m++) {        for (let n = 0; n < 4; n++) {          let seqnum = m * 4 + n;          if (tdim[m][n] != 0) {            let num = tdim[m][n];            switch (num) {              case 2:                cell[seqnum].style.background = cellColors[0];                break;              case 4:                cell[seqnum].style.background = cellColors[1];                break;              case 8:                cell[seqnum].style.background = cellColors[2];                break;              case 16:                cell[seqnum].style.background = cellColors[3];                break;              case 32:                cell[seqnum].style.background = cellColors[4];                break;              default:                cell[seqnum].style.background = cellColors[5];                break;            }            cell[seqnum].innerHTML = tdim[m][n].toString();          }          else {            cell[seqnum].innerHTML = '';            cell[seqnum].style.background = themeColor;          }        }      }    }    /**     * tryAgain 点击tryAgain按钮响应事件重新开始     */    tryAgain () {      let tdim = this.tdim;      let self = this;      let againBtn = <HTMLElement>document.getElementById('again');      againBtn.onclick = function () {        let gameover = <HTMLElement>document.getElementsByClassName('gameover')[0];        gameover.style.display = "none";        for (let i = 0; i < 4; i++) {          for (let j = 0; j < 4; j++) {            tdim[i][j] = 0;          }        }        self.countScore();        self.rendering();      }    }    /**     * countScore 计算得分     */    countScore () {      let tdim = this.tdim;      let sum = 0;      for (let i = 0; i < 4; i++) {        for (let j = 0; j < 4; j++) {          if (tdim[i][j] > 2) {            sum += tdim[i][j];          }        }      }      let score = document.getElementById('score');      score.innerHTML = sum.toString();    }}const cellColors = ['#EEE4DA', '#ede0c8', '#f2b179', '#f59563', '#f67c5f', '#f65e3b']const themeColor ="rgba(238, 228, 218, 0.35)"new GameTS(cellColors, themeColor);

项目仓库:欢迎star哦! github.com/PH-C/2048-g…