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>
什麼?我似乎不明白..爲什麼我需要使用另一個數組填充對象?每個十六進制都存儲在一個數組中,並且具有一個「neighbors」屬性,它包含所有周圍的hexes,並且它們都包含一個單元座標。我的例子是部分工作,它只是需要對循環約束稍作修改。 – Alexus
哦,現在我看到你的問題了。我的計算結果與距離爲1的循環相同。 – Marcus