2016-08-04 174 views
1

我想選擇給定範圍內的所有十六進制數。然而,我得到奇怪的結果,而實現這個代碼發現在阿米特帕特爾的page選擇一個十六進制附近的十六進制數

var results = [] 
for each -N ≤ dx ≤ N: 
    for each max(-N, -dx-N) ≤ dy ≤ min(N, -dx+N): 
     var dz = -dx-dy 
     results.append(cube_add(center, Cube(dx, dy, dz))) 

這是我到目前爲止有:

var center = this._cel.copy(hex.coords); 
    var dx = range - center.q; 
    var dy = range - center.r; 

    var results = []; 

    for (var q = -range; q <= dx; q++) { 
     var r1 = Math.max(-range, -q - range); 
     var r2 = Math.min(range, -q + range); 
     for (var r = r1; r <= r2; r++) { 
      //console.log(q, r, -q-r) 
      var c = new Cell(q, r, -q-r) 
      results.push(c.add(center)); 
     } 
    } 

我想環路限制需要我修改一點點,利用DX,DY值。

<body> 
 
\t <canvas width="420px" height="420px" id="myCanvas" style="margin:0; padding:0; border:1px solid #d3d3d3;"></canvas> 
 
</body> 
 

 
<script id="hexagon"> 
 
function Point(pos) { 
 
    this.x = 0; 
 
\t this.y = 0; 
 
\t if(typeof(pos) !== "undefined"){ 
 
\t \t this.x = pos[0]; 
 
\t \t this.y = pos[1]; 
 
\t } 
 
}; 
 

 
function Cell(_q, _r, _s){ //// direction /// 
 
\t this.q = _q; 
 
\t this.r = _r; 
 
\t this.s = _s; 
 
\t this._hashID = null; 
 
\t this.generateHashID(); 
 
} 
 

 
Cell.prototype = { 
 
\t constructor: Cell, 
 
\t add: function(d){ 
 
\t \t this.q += d.q; 
 
\t \t this.r += d.r; 
 
\t \t this.s += d.s; 
 
\t \t this.generateHashID(); 
 
\t \t return this; 
 
\t }, 
 
\t copy: function(c){ 
 
\t \t this.set(c.q, c.r, c.s); 
 
\t \t return this; 
 
\t }, 
 
\t set: function(_q, _r, _s){ 
 
\t \t this.q = _q; 
 
\t \t this.r = _r; 
 
\t \t this.s = _s; 
 
\t \t this.generateHashID(); 
 
\t \t return this; 
 
\t }, 
 
\t generateHashID: function(){ 
 
\t \t this._hashID = this.q+"."+this.r+"."+this.s; 
 
\t }, 
 
\t getHashID: function(){ 
 
\t \t return this._hashID; 
 
\t }, 
 
\t round: function(){ 
 
\t \t var q = Math.trunc(Math.round(this.q)); 
 
\t \t var r = Math.trunc(Math.round(this.r)); 
 
\t \t var s = Math.trunc(Math.round(this.s)); 
 
\t \t var q_diff = Math.abs(q - this.q); 
 
\t \t var r_diff = Math.abs(r - this.r); 
 
\t \t var s_diff = Math.abs(s - this.s); 
 
\t \t if (q_diff > r_diff && q_diff > s_diff){ 
 
\t \t \t q = -r - s; 
 
\t \t }else if (r_diff > s_diff){ 
 
\t \t \t r = -q - s; 
 
\t \t }else{ 
 
\t \t \t s = -q - r; 
 
\t \t } 
 
\t \t 
 
\t \t return this.set(q, r, s); 
 
\t } 
 
} 
 

 
var Hex = function(coords, l_){ //// [axial], [cartesian] , layout 
 
\t this.coords = new Cell(coords[0], coords[1], coords[2]); 
 
\t 
 
\t this.content = -2; 
 
\t 
 
\t this.pos = this.coords; //// set primary coorinate type /// 
 
\t 
 
\t this.neighbors = []; 
 
\t 
 
\t this.layout = l_; 
 
\t this.corners = []; 
 
\t 
 
\t this.center = this.get_center_p(); 
 
\t 
 
\t //this.id = this.generate_id(cart_coord); 
 

 
\t this.colors = { 
 
\t \t "base" : { 
 
\t \t \t filling : "#008844", 
 
\t \t \t border : "#FFDD88", 
 
\t \t }, 
 
\t \t "selected": { 
 
\t \t \t filling: "#00cc00" 
 
\t \t }, 
 
\t \t "hovered": { 
 
\t \t \t filling: "#006600" 
 
\t \t }, 
 
\t \t "path" : { 
 
\t \t \t filling: "#80ff00" 
 
\t \t }, 
 
\t \t "obstacle" : { 
 
\t \t \t filling: "#86592d" 
 
\t \t }, 
 
\t \t "neighbor": { 
 
\t \t \t filling: "#ffbf00" 
 
\t \t } 
 
\t } 
 
\t 
 
\t this.states = { 
 
\t \t "selected" : false, 
 
\t \t "hovered" : false, 
 
\t \t "isPath": false, 
 
\t \t "isObstacle": false, 
 
\t \t "isNeighbor": false 
 
\t } 
 

 
\t this.generate_corners(); 
 
}; 
 

 
Hex.prototype = { 
 
\t constructor: Hex, 
 

 
\t get_corner_offset: function(corner){ 
 
\t \t var angle = 2.0 * Math.PI * (corner + this.layout.orientation.start_angle)/6; 
 
\t \t return new Point([ size.x * Math.cos(angle), size.y * Math.sin(angle) ]); 
 
\t }, 
 
\t 
 
\t generate_corners: function(h){ 
 
\t \t var offset = null, angle = 0; 
 
\t \t var size = this.layout.size; 
 
\t \t for (var i = 0; i < 6; i++) { 
 
\t \t \t angle = 2.0 * Math.PI * (i + this.layout.orientation.start_angle)/6; 
 
\t \t \t offset = new Point([ size.x * Math.cos(angle), size.y * Math.sin(angle)]); 
 
\t \t \t 
 
\t \t \t this.corners.push( 
 
\t \t \t \t new Point([ this.center.x + offset.x, this.center.y + offset.y ]) 
 
\t \t \t); 
 
\t \t } 
 
\t }, 
 
\t 
 
\t draw: function(ctx){ 
 
\t \t var points = this.corners; 
 
\t \t ctx.beginPath(); 
 
\t \t ctx.moveTo(points[0].x, points[0].y); 
 
\t \t for(var i = 1; i < points.length; i++){ 
 
\t \t \t var p = points[i]; 
 
\t \t \t ctx.lineTo(p.x, p.y); 
 
\t \t } 
 
\t \t ctx.closePath(); 
 
\t \t //// fill Hex /// 
 
\t \t if(this.checkState("selected")){ 
 
\t \t \t ctx.fillStyle = this.colors.selected.filling; 
 
\t \t }else if( this.checkState("hovered")){ 
 
\t \t \t ctx.fillStyle = this.colors.hovered.filling; 
 
\t \t }else if( this.checkState("isPath")){ 
 
\t \t \t ctx.fillStyle = this.colors.path.filling; 
 
\t \t }else if( this.checkState("isNeighbor")){ 
 
\t \t \t ctx.fillStyle = this.colors.neighbor.filling; 
 
\t \t }else if( this.checkState("isObstacle")){ 
 
\t \t \t ctx.fillStyle = this.colors.obstacle.filling; 
 
\t \t }else{ 
 
\t \t \t ctx.fillStyle = this.colors.base.filling; 
 
\t \t } 
 
\t \t ctx.fill(); 
 
\t \t //// draw border /// 
 
\t \t ctx.lineWidth = 1; 
 
\t \t ctx.strokeStyle = "#19334d"; 
 
\t \t ctx.stroke(); 
 
\t \t 
 
\t \t this.draw_coords(ctx); 
 
\t \t 
 
\t \t this.draw_center_point(ctx); 
 
\t }, 
 
\t 
 
\t add_neighbor: function(neighbor){ 
 
\t \t this.neighbors.push(neighbor); 
 
\t }, 
 
\t 
 
\t show_neighbors: function(){ 
 
\t \t for(var nb = 0, nb_l = this.neighbors.length; nb < nb_l; nb++){ 
 
\t \t \t this.neighbors[nb].changeState("isNeighbor", true); 
 
\t \t } 
 
\t }, 
 
\t 
 
\t hide_neighbors: function(){ 
 
\t \t for(var nb = 0, nb_l = this.neighbors.length; nb < nb_l; nb++){ 
 
\t \t \t this.neighbors[nb].changeState("isNeighbor", false); 
 
\t \t } 
 
\t }, 
 
\t 
 
\t draw_coords: function(ctx){ 
 
\t \t var text = this.coords.q+" : "+ this.coords.s; 
 
\t \t var text_z = this.coords.r; 
 
\t \t var metrics1 = ctx.measureText(text); 
 
\t \t var metrics2 = ctx.measureText(text_z); 
 
\t \t var w1 = metrics1.width; 
 
\t \t var w2 = metrics2.width; 
 
\t \t var h = 8; 
 
\t \t ctx.font = h+'pt Calibri bold'; 
 
\t \t ctx.textAlign = 'center'; 
 
\t \t ctx.fillStyle = '#FFFFFF'; 
 
\t \t ctx.fillText(text, this.center.x, this.center.y + (h/2) - 5); 
 
\t \t ctx.fillText(text_z, this.center.x, this.center.y + (h/2) + 7); 
 
\t }, 
 
\t 
 
\t get_center_p: function(){ 
 
\t \t var M = this.layout.orientation; 
 
\t \t var x = (M.f0 * this.pos.q + M.f1 * this.pos.r) * this.layout.size.x; 
 
\t \t var y = (M.f2 * this.pos.q + M.f3 * this.pos.r) * this.layout.size.y; 
 
\t \t return new Point([ 
 
\t \t \t x + this.layout.origin.x, 
 
\t \t \t y + this.layout.origin.y 
 
\t \t ]); 
 
\t }, 
 
\t 
 
\t draw_center_point: function(ctx){ 
 
\t \t ctx.beginPath(); 
 
\t \t ctx.lineWidth="1"; 
 
\t \t ctx.fillStyle="red"; 
 
\t \t ctx.arc(this.center.x , this.center.y , 2, 0 ,2*Math.PI); 
 
\t \t ctx.closePath(); 
 
\t \t ctx.stroke(); 
 
\t \t ctx.fill(); 
 
\t }, 
 
\t 
 
\t generate_id: function(coords){ 
 
\t \t return parseInt(coords[0]+''+coords[1]); 
 
\t }, 
 
\t 
 
\t checkState: function(state){ 
 
\t \t return this.states[ state ]; 
 
\t }, 
 
\t 
 
\t changeState: function(state , value){ 
 
\t \t this.states[ state ] = value; 
 
\t }, 
 
\t 
 
\t trigger: function(ev_name){ 
 
\t \t if(this.events[ ev_name ]){ 
 
\t \t \t this.events[ ev_name ].call(this); 
 
\t \t } 
 
\t }, 
 
\t 
 
\t setContent: function(type){ 
 
\t \t this.content = type; 
 
\t \t this.changeState("isObstacle" , true); 
 
\t }, 
 
\t 
 
\t hover: function(){ 
 
\t \t if(! this.checkState("isPath")){ 
 
\t \t \t this.trigger("hover"); 
 
\t \t } 
 
\t }, 
 
\t 
 
\t clear_hover: function(){ 
 
\t \t if(! this.checkState("isPath")){ 
 
\t \t \t this.trigger("clear_hover"); 
 
\t \t } 
 
\t }, 
 
\t 
 
\t select: function(){ 
 
\t \t this.trigger("select"); 
 
\t \t //this.show_neighbors(); 
 
\t }, 
 
\t 
 
\t unselect: function(){ 
 
\t \t this.trigger("unselect"); 
 
\t }, 
 
\t 
 
\t events: { 
 
\t \t select: function(){ 
 
\t \t \t this.changeState("selected", true); 
 
\t \t \t this.changeState("hovered", false); 
 
\t \t }, 
 
\t \t unselect: function(){ 
 
\t \t \t this.changeState("selected", false); 
 
\t \t }, 
 
\t \t hover: function(){ 
 
\t \t \t this.changeState("hovered", true); 
 
\t \t }, 
 
\t \t clear_hover: function(){ 
 
\t \t \t this.changeState("hovered", false); 
 
\t \t } 
 
\t } 
 
}; 
 

 

 
</script> 
 

 
<script id="grid"> 
 

 
var Grid = function(size, hex_size, origin, ctx_pos, layout_type){ 
 
\t this.size = size; 
 
\t this.grid_r = size/2; 
 
\t 
 
\t this.layout_type = layout_type; 
 
\t this.layout = this.set_layout(this.layout_types[this.layout_type], hex_size, origin); 
 
\t 
 
\t this.hexes = []; 
 
\t 
 
\t this.hovered = [null, null]; //// [cur, prev] /// 
 
\t this.selected = [null, null]; ///// [cur , prev] /// 
 
\t 
 
\t this.dots = []; 
 
\t 
 
\t this._list = []; 
 
\t this._cel = new Cell(); 
 
\t 
 
\t this._directions = [new Cell(+1, 0, -1), new Cell(+1, -1, 0), new Cell(0, -1, +1), 
 
\t \t \t \t \t \t new Cell(-1, 0, +1), new Cell(-1, +1, 0), new Cell(0, +1, -1)]; 
 
\t 
 
\t this.generate(); 
 
\t this.add_neighbors(); 
 
\t 
 
\t this.mouse = new Point(); 
 
\t this.mouse_events(new Point(ctx_pos)); 
 
} 
 

 
Grid.prototype = { 
 
\t constructor: Grid, 
 
\t layout_types: { 
 
\t \t "pointy": [ 
 
\t \t \t [ Math.sqrt(3.0), Math.sqrt(3.0)/2.0, 0.0, 3.0/2.0], //// 2x2 forward matrix 
 
\t \t \t [ Math.sqrt(3.0)/3.0, -1.0/3.0, 0.0, 2.0/3.0], ///// 2x2 inverse matrix 
 
\t \t \t 0.5 
 
\t \t ], //// starting angle in multiples of 60° ///// 
 
\t \t "flat": [ 
 
\t \t \t [3.0/2.0, 0.0, Math.sqrt(3.0)/2.0, Math.sqrt(3.0)], //// 2x2 forward matrix 
 
\t \t \t [2.0/3.0, 0.0, -1.0/3.0, Math.sqrt(3.0)/3.0], ///// 2x2 inverse matrix 
 
\t \t \t 1.0 
 
\t \t ] 
 
\t }, 
 
\t set_layout: function(orn_type , hex_s_, ogn_ ){ 
 
\t \t return { 
 
\t \t \t orientation: this.set_orientation(orn_type), ///// orientation type /// 
 
\t \t \t size: new Point([ hex_s_ , hex_s_ ]), ///// hex size /// 
 
\t \t \t origin: new Point(ogn_) //// Grid center ///// 
 
\t \t } 
 
\t }, 
 

 
\t set_orientation: function(opts){ /// [0] : forward_matrix, [1] : inverse_matrix, [2] : starting_angle 
 
\t \t return { 
 
\t \t \t f0: opts[0][0], f1: opts[0][1], f2: opts[0][2], f3: opts[0][3], b0: opts[1][0], b1: opts[1][1], b2: opts[1][2], b3: opts[1][3], start_angle: opts[2] 
 
\t \t } 
 
\t }, 
 
\t 
 
\t get_hex_at_p: function(p){ //// point /// 
 
\t \t var M = this.layout.orientation; 
 
\t \t var pt = new Point([ (p.x - this.layout.origin.x)/this.layout.size.x, (p.y - this.layout.origin.y)/this.layout.size.y ]); 
 
\t \t var q = M.b0 * pt.x + M.b1 * pt.y; 
 
\t \t var r = M.b2 * pt.x + M.b3 * pt.y; 
 
\t \t var c = this._cel.set(q, r, -q-r); 
 
\t \t return c.round(); 
 
\t }, 
 
\t 
 
\t generate: function(){ 
 
\t \t var n_hex = null; 
 
\t \t for (var q = -this.grid_r; q <= this.grid_r; q++) { 
 
\t \t \t var r1 = Math.max(-this.grid_r, -q - this.grid_r); 
 
\t \t \t var r2 = Math.min(this.grid_r, -q + this.grid_r); 
 
\t \t \t for (var r = r1; r <= r2; r++) { 
 
\t \t \t \t n_hex = new Hex([ q, r, -q-r ], this.layout); 
 
\t \t \t \t this.hexes[ n_hex.coords.getHashID() ] = n_hex; 
 
\t \t \t } 
 
\t \t } 
 
\t }, 
 
\t 
 
\t _selectHexesInRange: function(hex, range){ 
 
\t \t var center = this._cel.copy(hex.coords); 
 
\t \t var dx = range - center.q; 
 
\t \t var dy = range - center.r; 
 
\t \t 
 
\t \t var results = []; 
 
\t \t for (var q = -range; q <= dx; q++) { 
 
\t \t \t var r1 = Math.max(-range, -q - range); 
 
\t \t \t var r2 = Math.min(range, -q + range); 
 
\t \t \t for (var r = r1; r <= r2; r++) { 
 
\t \t \t \t var c = new Cell(q, r, -q-r) 
 
\t \t \t \t results.push(c.add(center)); 
 
\t \t \t } 
 
\t \t } 
 
\t \t 
 
\t \t for(var h in results){ 
 
\t \t \t if(typeof(this.hexes[results[h].getHashID()]) !== "undefined"){ 
 
\t \t \t \t this.hexes[results[h].getHashID()].select() 
 
\t \t \t } 
 
\t \t } 
 
\t \t //console.log(results) 
 
\t }, 
 
\t 
 
\t hex_corner_offset : function (corner) { 
 
\t \t var size = this.layout.size; 
 
\t \t var angle = 2.0 * Math.PI * (this.layout.orientation.start_angle - corner)/6; 
 
\t \t return new Point([size.x * Math.cos(angle), size.y * Math.sin(angle)]); 
 
\t }, 
 
\t 
 
\t point_add : function(p, q) { 
 
\t \t return new Point([p.x + q.x, p.y + q.y]); 
 
\t }, 
 

 
\t add_neighbors: function(){ 
 
\t \t var nbor = null, hex = null; 
 
\t \t for(var h in this.hexes){ 
 
\t \t \t hex = this.hexes[h]; 
 
\t \t \t var i, n, l = this._directions.length; 
 
\t \t \t this._list.length = 0;//// reset array /// 
 
\t \t \t for (i = 0; i < l; i++) { 
 
\t \t \t \t this._cel.copy(hex.coords); 
 
\t \t \t \t this._cel.add(this._directions[i]); 
 
\t \t \t \t n = this.hexes[ this._cel.getHashID() ]; 
 
\t \t \t \t if (typeof(n) == "undefined") { ///// if doesn't exists //// 
 
\t \t \t \t \t this._list.push(null); 
 
\t \t \t \t \t continue; 
 
\t \t \t \t } 
 
\t \t \t \t this._list.push(n); 
 
\t \t \t } 
 
\t \t \t 
 
\t \t \t hex.neighbors = this._list.slice(); //// take copy of the array //// 
 
\t \t } 
 
\t }, 
 
\t 
 
\t draw: function(ctx){ 
 
\t \t for(var h in this.hexes){ 
 
\t \t \t this.hexes[h].draw(ctx); 
 
\t \t } 
 
\t }, 
 
\t 
 
\t checkCollisions: function(){ 
 
\t \t var h_pos = this.get_hex_at_p(this.mouse); 
 
\t \t var hex = this.hexes[ h_pos.getHashID() ]; 
 
\t \t if(typeof(hex) !== "undefined"){ 
 
\t \t \t if(this.hovered[0] == null){ //// cur 
 
\t \t \t \t this.hovered[0] = hex; 
 
\t \t \t \t this.hovered[0].hover(); 
 
\t \t \t }else{ 
 
\t \t \t \t this.hovered[1] = this.hovered[0]; 
 
\t \t \t \t this.hovered[0] = hex; 
 
\t \t \t \t if(this.hovered[0].coords._hashID != this.hovered[1].coords._hashID){ 
 
\t \t \t \t \t this.hovered[1].clear_hover(); 
 
\t \t \t \t \t this.hovered[1] = null; 
 
\t \t \t \t } 
 
\t \t \t } 
 
\t \t \t this.hovered[0].hover(); 
 
\t \t } 
 
\t }, 
 
\t 
 
\t mouse_events: function(ctx_pos){ 
 
\t \t var self = this; 
 
\t \t 
 
\t \t window.addEventListener('mousemove', function(e){ 
 
\t \t \t self.mouse.x = (e.clientX - ctx_pos.x); 
 
\t \t \t self.mouse.y = (e.clientY - ctx_pos.y); 
 
\t \t }); 
 
\t \t 
 
\t \t window.addEventListener('mousedown', function(e){ 
 
\t \t \t //console.log("neighbors : ",self.hovered[0].neighbors) 
 
\t \t \t self._selectHexesInRange(self.hovered[0], 2); 
 
\t \t }); 
 
\t } 
 
} 
 
</script> 
 

 
<script id="main"> 
 
var c_el = document.getElementById("myCanvas"); 
 
var ctx = c_el.getContext("2d"); 
 

 
var nGrid = new Grid(6, 25, [ c_el.width/2, c_el.height/2 ], [c_el.getBoundingClientRect().left, c_el.getBoundingClientRect().top], "pointy"); 
 

 
function animate(){ 
 
\t window.requestAnimationFrame(animate); 
 
\t ctx.clearRect(0, 0, c_el.width, c_el.height); 
 
\t nGrid.checkCollisions(); 
 
\t nGrid.draw(ctx); 
 
} 
 

 
animate(); 
 
</script>

回答

0

就拿座標x,y,z和再搜索所有字段此計算的一個:

  1. z是常數,x是加/減1, y是負/加1
  2. x是常數,z是正負1,y是負/正1
  3. y是常數,z是正負1,x是負/正1

這應該是所有鄰居

實施例:提起0,1,-1(X,Y,Z)

  1. z是常數,x是加/減1 => [ -1,2,-1],[1,0,1]
  2. x是常數,z是正/負1 => [0,2,-2],[0,0,0]
  3. y是常數,z是正/負1 => [1,1,-2],[-1,1,0]

對於更快的搜索,你可以你的細胞存儲這樣的對象中:

var cells = new Object(); 
for(x=-2; x<3; x++){ 
    cells[x] = new Object(); 
    for(y=-2; y<3; y++){ 
     cells[x][y] = new Object(); 
     for(z=-2; z<3; z++){ 
      cells[x][y][z] = cell; 
     } 
    } 
} 

然後你就可以有座標進入細胞:

var x = 0; 
var y = 1; 
var z = -1; 
var neighbors = new Array(); 
neighbors.push(cells[x-1][y+1][z]); 
neighbors.push(cells[x+1][y-1][z]); 
neighbors.push(cells[x][y+1][z-1]); 
neighbors.push(cells[x][y-1][z+1]); 
neighbors.push(cells[x+1][y][z-1]); 
neighbors.push(cells[x-1][y][z+1]); 
+0

什麼?我似乎不明白..爲什麼我需要使用另一個數組填充對象?每個十六進制都存儲在一個數組中,並且具有一個「neighbors」屬性,它包含所有周圍的hexes,並且它們都包含一個單元座標。我的例子是部分工作,它只是需要對循環約束稍作修改。 – Alexus

+0

哦,現在我看到你的問題了。我的計算結果與距離爲1的循環相同。 – Marcus