我正在尝试选择给定范围内的所有六角形。但是,当我在Amit Patel的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>
<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;
this.y = 0;
if( typeof( pos ) !== "undefined" ){
this.x = pos[0];
this.y = pos[1];
}
};
function Cell( _q, _r, _s ){ //// direction ///
this.q = _q;
this.r = _r;
this.s = _s;
this._hashID = null;
this.generateHashID();
}
Cell.prototype = {
constructor: Cell,
add: function( d ){
this.q += d.q;
this.r += d.r;
this.s += d.s;
this.generateHashID();
return this;
},
copy: function( c ){
this.set( c.q, c.r, c.s );
return this;
},
set: function( _q, _r, _s ){
this.q = _q;
this.r = _r;
this.s = _s;
this.generateHashID();
return this;
},
generateHashID: function(){
this._hashID = this.q+"."+this.r+"."+this.s;
},
getHashID: function(){
return this._hashID;
},
round: function(){
var q = Math.trunc(Math.round(this.q));
var r = Math.trunc(Math.round(this.r));
var s = Math.trunc(Math.round(this.s));
var q_diff = Math.abs(q - this.q);
var r_diff = Math.abs(r - this.r);
var s_diff = Math.abs(s - this.s);
if (q_diff > r_diff && q_diff > s_diff){
q = -r - s;
}else if (r_diff > s_diff){
r = -q - s;
}else{
s = -q - r;
}
return this.set( q, r, s );
}
}
var Hex = function( coords, l_ ){ //// [axial], [cartesian] , layout
this.coords = new Cell( coords[0], coords[1], coords[2] );
this.content = -2;
this.pos = this.coords; //// set primary coorinate type ///
this.neighbors = [];
this.layout = l_;
this.corners = [];
this.center = this.get_center_p();
//this.id = this.generate_id( cart_coord );
this.colors = {
"base" : {
filling : "#008844",
border : "#FFDD88",
},
"selected": {
filling: "#00cc00"
},
"hovered": {
filling: "#006600"
},
"path" : {
filling: "#80ff00"
},
"obstacle" : {
filling: "#86592d"
},
"neighbor": {
filling: "#ffbf00"
}
}
this.states = {
"selected" : false,
"hovered" : false,
"isPath": false,
"isObstacle": false,
"isNeighbor": false
}
this.generate_corners();
};
Hex.prototype = {
constructor: Hex,
get_corner_offset: function( corner ){
var angle = 2.0 * Math.PI * (corner + this.layout.orientation.start_angle) / 6;
return new Point( [ size.x * Math.cos(angle), size.y * Math.sin(angle) ] );
},
generate_corners: function( h ){
var offset = null, angle = 0;
var size = this.layout.size;
for (var i = 0; i < 6; i++) {
angle = 2.0 * Math.PI * (i + this.layout.orientation.start_angle) / 6;
offset = new Point( [ size.x * Math.cos(angle), size.y * Math.sin(angle )] );
this.corners.push(
new Point( [ this.center.x + offset.x, this.center.y + offset.y ] )
);
}
},
draw: function( ctx ){
var points = this.corners;
ctx.beginPath();
ctx.moveTo( points[0].x, points[0].y );
for(var i = 1; i < points.length; i++){
var p = points[i];
ctx.lineTo(p.x, p.y);
}
ctx.closePath();
//// fill Hex ///
if( this.checkState("selected") ){
ctx.fillStyle = this.colors.selected.filling;
}else if( this.checkState("hovered") ){
ctx.fillStyle = this.colors.hovered.filling;
}else if( this.checkState("isPath") ){
ctx.fillStyle = this.colors.path.filling;
}else if( this.checkState("isNeighbor") ){
ctx.fillStyle = this.colors.neighbor.filling;
}else if( this.checkState("isObstacle") ){
ctx.fillStyle = this.colors.obstacle.filling;
}else{
ctx.fillStyle = this.colors.base.filling;
}
ctx.fill();
//// draw border ///
ctx.lineWidth = 1;
ctx.strokeStyle = "#19334d";
ctx.stroke();
this.draw_coords( ctx );
this.draw_center_point( ctx );
},
add_neighbor: function( neighbor ){
this.neighbors.push( neighbor );
},
show_neighbors: function(){
for( var nb = 0, nb_l = this.neighbors.length; nb < nb_l; nb++ ){
this.neighbors[nb].changeState("isNeighbor", true);
}
},
hide_neighbors: function(){
for( var nb = 0, nb_l = this.neighbors.length; nb < nb_l; nb++ ){
this.neighbors[nb].changeState("isNeighbor", false);
}
},
draw_coords: function( ctx ){
var text = this.coords.q+" : "+ this.coords.s;
var text_z = this.coords.r;
var metrics1 = ctx.measureText(text);
var metrics2 = ctx.measureText(text_z);
var w1 = metrics1.width;
var w2 = metrics2.width;
var h = 8;
ctx.font = h+'pt Calibri bold';
ctx.textAlign = 'center';
ctx.fillStyle = '#FFFFFF';
ctx.fillText(text, this.center.x, this.center.y + (h/2) - 5 );
ctx.fillText(text_z, this.center.x, this.center.y + (h/2) + 7 );
},
get_center_p: function(){
var M = this.layout.orientation;
var x = ( M.f0 * this.pos.q + M.f1 * this.pos.r ) * this.layout.size.x;
var y = ( M.f2 * this.pos.q + M.f3 * this.pos.r ) * this.layout.size.y;
return new Point([
x + this.layout.origin.x,
y + this.layout.origin.y
]);
},
draw_center_point: function( ctx ){
ctx.beginPath();
ctx.lineWidth="1";
ctx.fillStyle="red";
ctx.arc( this.center.x , this.center.y , 2, 0 ,2*Math.PI);
ctx.closePath();
ctx.stroke();
ctx.fill();
},
generate_id: function( coords ){
return parseInt( coords[0]+''+coords[1] );
},
checkState: function( state ){
return this.states[ state ];
},
changeState: function( state , value){
this.states[ state ] = value;
},
trigger: function( ev_name ){
if( this.events[ ev_name ] ){
this.events[ ev_name ].call( this );
}
},
setContent: function( type ){
this.content = type;
this.changeState( "isObstacle" , true );
},
hover: function(){
if( ! this.checkState("isPath") ){
this.trigger("hover");
}
},
clear_hover: function(){
if( ! this.checkState("isPath") ){
this.trigger("clear_hover");
}
},
select: function(){
this.trigger("select");
//this.show_neighbors();
},
unselect: function(){
this.trigger("unselect");
},
events: {
select: function(){
this.changeState("selected", true);
this.changeState("hovered", false);
},
unselect: function(){
this.changeState("selected", false);
},
hover: function(){
this.changeState("hovered", true);
},
clear_hover: function(){
this.changeState("hovered", false);
}
}
};
</script>
<script id="grid">
var Grid = function( size, hex_size, origin, ctx_pos, layout_type ){
this.size = size;
this.grid_r = size/2;
this.layout_type = layout_type;
this.layout = this.set_layout( this.layout_types[this.layout_type], hex_size, origin );
this.hexes = [];
this.hovered = [null, null]; //// [cur, prev] ///
this.selected = [null, null]; ///// [cur , prev] ///
this.dots = [];
this._list = [];
this._cel = new Cell();
this._directions = [new Cell(+1, 0, -1), new Cell(+1, -1, 0), new Cell(0, -1, +1),
new Cell(-1, 0, +1), new Cell(-1, +1, 0), new Cell(0, +1, -1)];
this.generate();
this.add_neighbors();
this.mouse = new Point();
this.mouse_events( new Point( ctx_pos ) );
}
Grid.prototype = {
constructor: Grid,
layout_types: {
"pointy": [
[ Math.sqrt(3.0), Math.sqrt(3.0) / 2.0, 0.0, 3.0 / 2.0], //// 2x2 forward matrix
[ Math.sqrt(3.0) / 3.0, -1.0 / 3.0, 0.0, 2.0 / 3.0], ///// 2x2 inverse matrix
0.5
], //// starting angle in multiples of 60° /////
"flat": [
[3.0 / 2.0, 0.0, Math.sqrt(3.0) / 2.0, Math.sqrt(3.0)], //// 2x2 forward matrix
[2.0 / 3.0, 0.0, -1.0 / 3.0, Math.sqrt(3.0) / 3.0], ///// 2x2 inverse matrix
1.0
]
},
set_layout: function( orn_type , hex_s_, ogn_ ){
return {
orientation: this.set_orientation( orn_type ), ///// orientation type ///
size: new Point( [ hex_s_ , hex_s_ ] ), ///// hex size ///
origin: new Point( ogn_ ) //// Grid center /////
}
},
set_orientation: function( opts ){ /// [0] : forward_matrix, [1] : inverse_matrix, [2] : starting_angle
return {
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]
}
},
get_hex_at_p: function( p ){ //// point ///
var M = this.layout.orientation;
var pt = new Point( [ (p.x - this.layout.origin.x) / this.layout.size.x, (p.y - this.layout.origin.y) / this.layout.size.y ] );
var q = M.b0 * pt.x + M.b1 * pt.y;
var r = M.b2 * pt.x + M.b3 * pt.y;
var c = this._cel.set( q, r, -q-r );
return c.round();
},
generate: function(){
var n_hex = null;
for (var q = -this.grid_r; q <= this.grid_r; q++) {
var r1 = Math.max(-this.grid_r, -q - this.grid_r);
var r2 = Math.min(this.grid_r, -q + this.grid_r);
for (var r = r1; r <= r2; r++) {
n_hex = new Hex( [ q, r, -q-r ], this.layout );
this.hexes[ n_hex.coords.getHashID() ] = n_hex;
}
}
},
_selectHexesInRange: function( hex, range ){
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++ ) {
var c = new Cell(q, r, -q-r)
results.push( c.add( center ) );
}
}
for( var h in results){
if( typeof( this.hexes[results[h].getHashID()]) !== "undefined" ){
this.hexes[results[h].getHashID()].select()
}
}
//console.log( results )
},
hex_corner_offset : function ( corner ) {
var size = this.layout.size;
var angle = 2.0 * Math.PI * (this.layout.orientation.start_angle - corner) / 6;
return new Point([size.x * Math.cos(angle), size.y * Math.sin(angle)]);
},
point_add : function(p, q) {
return new Point([p.x + q.x, p.y + q.y]);
},
add_neighbors: function(){
var nbor = null, hex = null;
for( var h in this.hexes ){
hex = this.hexes[h];
var i, n, l = this._directions.length;
this._list.length = 0;//// reset array ///
for ( i = 0; i < l; i++ ) {
this._cel.copy( hex.coords );
this._cel.add( this._directions[i] );
n = this.hexes[ this._cel.getHashID() ];
if (typeof(n) == "undefined") { ///// if doesn't exists ////
this._list.push( null );
continue;
}
this._list.push(n);
}
hex.neighbors = this._list.slice(); //// take copy of the array ////
}
},
draw: function( ctx ){
for( var h in this.hexes ){
this.hexes[h].draw( ctx );
}
},
checkCollisions: function(){
var h_pos = this.get_hex_at_p( this.mouse );
var hex = this.hexes[ h_pos.getHashID() ];
if( typeof(hex) !== "undefined" ){
if( this.hovered[0] == null ){ //// cur
this.hovered[0] = hex;
this.hovered[0].hover();
}else{
this.hovered[1] = this.hovered[0];
this.hovered[0] = hex;
if( this.hovered[0].coords._hashID != this.hovered[1].coords._hashID ){
this.hovered[1].clear_hover();
this.hovered[1] = null;
}
}
this.hovered[0].hover();
}
},
mouse_events: function( ctx_pos ){
var self = this;
window.addEventListener( 'mousemove', function(e){
self.mouse.x = ( e.clientX - ctx_pos.x );
self.mouse.y = ( e.clientY - ctx_pos.y );
});
window.addEventListener( 'mousedown', function(e){
//console.log( "neighbors : ",self.hovered[0].neighbors )
self._selectHexesInRange( self.hovered[0], 2);
});
}
}
</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(){
window.requestAnimationFrame( animate );
ctx.clearRect(0, 0, c_el.width, c_el.height);
nGrid.checkCollisions();
nGrid.draw( ctx);
}
animate();
</script>
答案 0 :(得分:0)
只需取坐标x,y,z,然后将所有字段搜索到以下计算之一:
这应该是所有邻居
示例:归档0,1,-1(x,y,z)
为了加快搜索速度,您可以将单元格存储在Object中,如下所示:
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]);