• ng2048源码阅读


    ng2048源码阅读

    Tutorial: http://www.ng-newsletter.com/posts/building-2048-in-angularjs.html
    Github: https://github.com/fullstackio/ng2048.git

    本地不部署项目一直卡在node-sass不成功的问题上,需要的css文件没办法生成,我的目的是弄清设计原理,学习ng的用法,所以直接用sass编译sass文件为css文件,丢到项目文件夹下跑起来。

    sass编译css文件

    npm install node-sass -g
    sass D:GitHub
    g2048appstylesmain.scss D:GitHub
    g2048appstylesmain.css
    

    启动项目

    这个项目是grunt构建的, 使用--force忽略sass编译的错误继续执行

    grunt serve --force
    

    这个列子有些小复杂,看看能学到啥

    1. 数据传递,指令的使用,ng-if的使用

    grid的使用,通过ng-model传递到指令内部的独立scope

    <!-- 显示格子 -->
    <div grid ng-model='ctrl.game' class="row"></div>
    

    Grid中包含tile,tile指令也是通过ng-model传递到指令内部的独立scope,注意这里的ng-repeat迭代的对象的传递

    <div id="game-{{ ngModel.gameSize }}">
      <div class="grid-container">
        <div class="grid-cell" ng-repeat="cell in ngModel.grid track by $index"></div>
      </div>
    
      <div class="tile-container">
        <div tile 
              ng-model='tile'
              ng-repeat='tile in ngModel.tiles track by $id(tile.id || $index)'></div>
      </div>
    </div>
    
    

    tile的模板

    <div ng-if='ngModel' class="tile position-{{ ngModel.x }}-{{ ngModel.y }} tile-{{ ngModel.value }}" 
      ng-class="{ 'tile-merged': ngModel.merged}">
      <div class="tile-inner">
        {{ ngModel.value }}
      </div>
    </div>
    

    2. 通用的游戏键盘控制服务

    服务init的时候这个keydown什么也不做,通过on订阅事件,将自己的处理程序加到服务的keyEventHandlers列表中完成事件的定制。这个服务就通用的了,你只需要写好自己的控制程序,然后通过on订阅就可以了。这也算是一种设计技巧了。

    'use strict';
    
    angular.module('Keyboard', [])
    .service('KeyboardService', function($document) {
    
      var UP    = 'up',
          RIGHT = 'right',
          DOWN  = 'down',
          LEFT  = 'left';
    
      var keyboardMap = {
        37: LEFT,
        38: UP,
        39: RIGHT,
        40: DOWN
      };
    
      this.init = function() {
        var self = this;
        this.keyEventHandlers = [];
        $document.bind('keydown', function(evt) {
          var key = keyboardMap[evt.which];
    
          if (key) {
            // An interesting key was pressed
            evt.preventDefault();
            self._handleKeyEvent(key, evt);
          }
        });
      };
    
      this.on = function(cb) {
        this.keyEventHandlers.push(cb);
      };
    
      this._handleKeyEvent = function(key, evt) {
        var callbacks = this.keyEventHandlers;
        if (!callbacks) {
          return;
        }
    
        evt.preventDefault();
    
        if (callbacks) {
          for (var x = 0; x < callbacks.length; x++) {
            var cb = callbacks[x];
            cb(key, evt);
          }
        }
      };
    
    });
    
    //初始化
    KeyboardService.init();
    //订阅事件
    KeyboardService.on(function(key) {
        self.game.move(key);
    });
    

    3. 设计思路和实现思路

    代码看完了,游戏的思路和我设想的差不多,但是在实现上跟我想的有些不一样,大致也就是两层循环挨个的处理格子,但是实现上感觉还是有些技巧的。

    3.1 根据方向确定坐标的偏移量
        var vectors = {
          'left': { x: -1, y: 0 },
          'right': { x: 1, y: 0 },
          'up': { x: 0, y: -1 },
          'down': { x: 0, y: 1 }
        };
    
    3.2 根据方向确定两层循环的索引序列,[0,1,2,3]还是[3,2,1,0]
        this.traversalDirections = function(key) {
          var vector = vectors[key];
          var positions = {x: [], y: []};
          for (var x = 0; x < this.size; x++) {
            positions.x.push(x);
            positions.y.push(x);
          }
    
          if (vector.x > 0) {
            positions.x = positions.x.reverse();
          }
          if (vector.y > 0) {
            positions.y = positions.y.reverse();
          }
    
          return positions;
        };
    
    3.3 一次性拿到可以直接移动到的位置和紧跟的进行碰撞的位置
        this.calculateNextPosition = function(cell, key) {
          var vector = vectors[key];
          var previous;
    
          do {
            previous = cell;
            cell = {
              x: previous.x + vector.x,
              y: previous.y + vector.y
            };
          } while (this.withinGrid(cell) && this.cellAvailable(cell));
          //没有越界,并且cell是空的
    
          return {
            newPosition: previous,
            next: this.getCellAt(cell)
          };
        };
    
  • 相关阅读:
    【大数据】Hadoop的伪分布式安装
    【运维】什么是EPEL?
    【架构】RESTful的架构思想
    【python】有关python的异或操作的分析
    【Python】有关os.path.dirname(__file__)的注意事项
    Python中字符串前添加r ,b, u, f前缀的含义
    【Confluence】在CentOS7上的安装小记(下)
    Redis应用场景
    spring的context:exclude-filter 与 context:include-filter
    Spring的<context:annotation-config>和<annotation-driven>
  • 原文地址:https://www.cnblogs.com/wancy86/p/ng2048.html
Copyright © 2020-2023  润新知