#この記事は、
ヘックス・ターン制SLG好きが、最近スマホでその手の面白いゲームが無いので自分で作る、と頑張る記録です。
この記事のまとめ
- Hexを、座標計算してCocosで線で描画してみた
- 正六角形は、正三角形が6個集まったものと考えて座標計算した
実装してわかった、設計上のポイントは、こちらの記事。
Cocos Creatorを使ってJavaScriptでヘックスマップを描画してみた
まずはプリミティブなLine描画を使って、ヘックスマップを実装してみます。
まず動くものを作って実践して、雰囲気を掴みます。作ってみないとわからないことが沢山あると思うからです。ぶっちゃけ、マップは最終的にはスプライト表示になるので、このライン描画は使わないと思うのですが(その割には結構苦労した)、まずは動くものを作ります。
こんな感じのものを作りました。
CocosCreatorで作成して、Web viewで動作しています。
今後は動くものを貼っていきたいので、どこか無料で、良いHTML5ホスティングサービスがあったら教えて下さい。
どのように実装したか
正六角形は、正三角形が6個集まってできています。
正三角形は、角度30°・60°・90°からなる直角三角形が2つ合わさったものだと考えることができます。
この直角三角形:図では赤の三角形に注目します。
この赤の三角形の斜辺の長さ:UNITは、正六角形に外接する円の半径、と考えることができます。
ここから、底辺の長さと高さ、UNIT_BとUNIT_Hをsin,cosを使って計算することができます。
import CONST from '../../Defines/Constant'; // 定数
// JSはクラスメンバ参照が遅いので、高速化のためグローバル変数を宣言
// 高速化のため、CONSTの値をローカル変数に再代入
let UNIT = CONST.UNIT;
let UNIT_B = CONST.UNIT_B;
let UNIT_H = CONST.UNIT_H;
let HeightMod = CONST.HeightMod; // 視点の傾きの高さ補正
// 描画用変数群
let BaseNode; // 描画用の親ノード
let Grp; // cc.Graphics
let hexPoints = []; // 描画するHexの座標群
let Nodes = []; // マップ座標の文字表示用のノード
// *********************************
// Hexを描画する DrawHex
// ********************************
class DH {
// *********************************
// DrawHesクラスの初期化
// node: 描画の親ノード
// ********************************
static init(node) {
BaseNode = node;
// cc.Graphicsの初期化
Grp = node.addComponent(cc.Graphics);
Grp.lineWidth = 3;
Grp.strokeColor = cc.Color.RED;
// ヘックスの描画用の座標6つをvec2で確保
for (let loop = 0; loop < 6; loop++) {
hexPoints[loop] = new cc.Vec2();
};
// 高さの補正を計算
UNIT *= HeightMod;
UNIT_H *= HeightMod;
}
// **********************************************************
// 与えられたマップ座標からヘックスを1つ描画
// mapX, mapY: マップ座標
// **********************************************************
static DrawHex(mapX, mapY) {
// マップ座標からヘックス描画の中心座標を計算
let drawCenterPosX = (mapX * 2 + mapY % 2) * UNIT_B;
let drawCenterPosY = mapY * (UNIT + UNIT_H);
// ヘックスを構成する座標群を計算
// ヘックスの上の座標
hexPoints[0].x = drawCenterPosX;
hexPoints[0].y = drawCenterPosY + UNIT;
// ヘックスの右上の座標
hexPoints[1].x = drawCenterPosX + UNIT_B;
hexPoints[1].y = drawCenterPosY + UNIT_H;
// ヘックスの右上の座標
hexPoints[2].x = drawCenterPosX + UNIT_B;
hexPoints[2].y = drawCenterPosY - UNIT_H;
// ヘックスの下の座標
hexPoints[3].x = drawCenterPosX;
hexPoints[3].y = drawCenterPosY - UNIT;
// ヘックスの左下の座標
hexPoints[4].x = drawCenterPosX - UNIT_B;
hexPoints[4].y = drawCenterPosY - UNIT_H;
// ヘックスの左上の座標
hexPoints[5].x = drawCenterPosX - UNIT_B;
hexPoints[5].y = drawCenterPosY + UNIT_H;
// 座標群を渡してヘックスを描画
DH.DrawLine(hexPoints);
if (CC_DEBUG) { // 開発用座標表示
DH.DrawMapCord(mapX, mapY, drawCenterPosX, drawCenterPosY);
}
}
// **********************************************************
// 線を描画
// points: 線を描画するvex2の配列
// **********************************************************
static DrawLine(points) {
Grp.moveTo(points[0].x, points[0].y); // 開始座標をセット
let length = points.length;
for (let loop = 1; loop < length; loop++) {
Grp.lineTo(
points[loop].x, points[loop].y);
};
Grp.close(); // 最後に線を閉じる
Grp.stroke(); // 描画
}
// **********************************************************
// マップ座標を描画(開発用)
// 念の為、何度呼び出されても良いような作り
// x, y: マップ座標
// drawX, drawY: 描画座標
// **********************************************************
static DrawMapCord(x, y, drawX, drawY) {
// Nodeがない場合、新規に作成する
if (!Nodes[x]) {
Nodes[x] = [];
}
if (!Nodes[x][y]) {
let node = new cc.Node(); // ノードを作成
Nodes[x][y] = node;
node.label = node.addComponent(cc.Label); // ラベルコンポーネントをセット
node.label.fontSize = 32;
node.label.lineHeight = 32;
node.color = cc.Color.BLUE;
node.parent = BaseNode;
// cc.log('Node Created: ' + x + ', ' + y);
}
Nodes[x][y].setPosition(drawX, drawY); // ラベル表示位置をセット
Nodes[x][y].label.string = x + ', ' + y; // ラベル文字をセット
}
// **********************************************************
// Graphoc描画のクリア用関数
// **********************************************************
static Clear() {
Grp.clear();
}
}
export default DH;
外部で宣言している定数はこんな感じ。
const CONSTANT = {
UNIT: 80, // 六角形を構成する12の直角三角形の斜辺=六角形に概説する円の半径
UNIT_B: 80 * Math.cos(30 * Math.PI / 180), // 六角形を構成する12の直角三角形の底辺(長い方):Bottom
UNIT_H: 80 * Math.sin(30 * Math.PI / 180), // 六角形を構成する12の直角三角形の高さ(短い方):Height
HeightMod: 0.7, // マップ視点の傾きの高さ補正
};
export default CONSTANT;
Nodeツリー内のNodeに、以下のコンポーネントをつけて呼び出します。
const { ccclass, property } = cc._decorator;
import CONST from '../Defines/Constant'; // 定数宣言
import DH from './DrawHex'; // ヘックス描画クラス
// *********************************
// Map Manager
// ********************************
@ccclass
class MAPM extends cc.Component {
// **********************************************************
// オンロード
// **********************************************************
onLoad() {
DH.init(this.node); // 初期化
DH.Clear(); // 描画クリア
for (let loop1 = 0; loop1 < 11; loop1++) {
for (let loop2 = 0; loop2 < 12; loop2++) {
DH.DrawHex(loop2, loop1); // ヘックス描画
};
};
}
}
export default MAPM;
次は、タッチした座標を取得するインターフェイスを実装しようと思います。