Пробный адрес, в настоящее время подходит только для ПК.исходный код
Создателем игры в шестиугольник должен быть этотhex-frvr, оригинальный автор разработал с использованиемpixiИгровой движок, в соответствии с концепцией быстрой разработки, в этой игре используется создатель кокосов, а пользовательский интерфейс продолжает использоваться.hex-frvr. В процессе обучения есть различные реализации для справки. Этот исходный код предназначен только для обучения, спасибо.
предварительный просмотр
Функции
Игра с шестиугольниками — это, по сути, тетрис, и понимание этого очень поможет в следующей разработке.
Функции этой игры следующие:
- [x] рисунок шестиугольной шахматной доски, случайная генерация квадратов
- [x] определить, может ли блок падать на доску
- [X] поле и в конце игры решение об устранении
- [x] Различные эффекты анимации
- [x] Счет игры
cocos creator
Прежде чем говорить об идеях разработки игр, рекомендуется сначала понять создателя кокосов.
API, которые необходимо понимать:
- Game
- Canvas
- Scene
- Node
- Component
- Sprite
- Texture2D
- Director
- loader
- Event
- Touch
- Action
- Vec2
- Animation
- AnimationClip
- Prefab
- sys
Среди них Node, Event и Vec2 находятся в центре внимания разработки этой игры.
идеи развития
Ниже описаны идеи развития одна за другой из функции.
рисунок в шахматном порядке
На шахматной доске используется шестиугольная сетка. Использование шестиугольных сеток в видеоиграх не так распространено, как квадратные сетки. Во-первых, давайте кратко разберемся с шестиугольной сеткой.
Шестиугольная сетка
Шестиугольные сетки, обсуждаемые в этой статье, используют правильные шестиугольники. Существует две наиболее типичных ориентации шестиугольных сеток: горизонтальная (вершины обращены вверх) и вертикальная квадратная (ребра обращены вверх). В этой игре используется ориентация вершинами вверх.
Внимательные учащиеся обнаружат, что на рисунке есть нечто похожее на систему координат, которая называется координатной осью.
координаты оси
Система координат оси, иногда называемая «системой координат трапеции», представляет собой систему координат, созданную путем взятия двух из трех координат кубической системы координат. Поскольку у нас есть ограниченияx + y + z = 0
, так что третья координата на самом деле избыточна. Координаты осей подходят для хранения данных карты, а также для координат отображения лицом к игроку. Подобно кубическим координатам, вы также можете использовать основные операции, такие как сложение, вычитание, умножение и деление в декартовых координатах.
Существует множество видов кубических систем координат и, следовательно, естественно, множество видов осевых систем координат, производных от них. В этой игре выбранныйq = x
так же какr = z
Случай. Здесь q представляет столбцы, а r представляет строки.
Координаты смещения — это первая система координат, которая приходит на ум, потому что она может напрямую использовать декартовы координаты квадратной сетки. Но, к сожалению, смещение одной из осей в системе координат всегда будет выглядеть неуместно и в конечном итоге все усложнит. Кубические координаты и координаты осей дополняют друг друга, алгоритм становится проще и понятнее, но немного усложняется аспект хранения карты. Поэтому проще использовать кубическую/осевую систему координат.
От шестиугольной сетки к пикселям
Получите общее представление о том, что такое шестиугольная сетка, а затем узнайте, как преобразовать шестиугольную сетку в пиксели.
Если вы используете координаты оси, вы можете сначала наблюдать единичный вектор, показанный на рисунке ниже. На рисунке ниже стрелкаA→Q
представляет единичный вектор оси q иA→R
- единичный вектор для оси r. координаты пикселейq_basis _ q + r_basis _ r
. Например, точка B находится в(1, 1)
, равный сумме единичных векторов q и r.
Когда сетка горизонтально ориентирована, высота гексагональных高度 = size * 2
, Расстояние по вертикали между соседними шестиугольниками равно竖直 = 高度 * 3/4
.
Ширина шестиугольника宽度 = sqrt(3)/2 * 高度
. Расстояние по горизонтали между соседними шестиугольниками равно水平 = 宽度
.
Для этой игры возьмем центральную точку доски как (0,0). Из известных координат шестиугольной сетки (правильного шестиугольника) и высоты шестиугольника можно получить координаты каждого правильного шестиугольника. Можно получить следующий код преобразования пикселей:
hex2pixel(hex, h) {
let size = h / 2;
let x = size * Math.sqrt(3) * (hex.q + hex.r / 2);
let y = ((size * 3) / 2) * hex.r;
return cc.p(x, y);
}
генерация координатной сетки
Проблема перевода системы координат в пиксели решена, теперь нужно получить систему координат, соответствующую гексагональной сетке в этой игре.
Эта проблема, по сути, заключается в хранении карты осевой системы координат. 8)
Для шестиугольной компоновки радиуса N, когдаN = max(abs(x), abs(y), abs(z)
,имеютfirst_column[r] == -N - min(0, r)
. Последний визит будетarray[r][q + N + min(0, r)]
. Однако, поскольку мы можем положить некоторыеr < 0
в качестве отправной точки, поэтому мы также должны сместить строку с помощьюarray[r + N][q + N + min(0, r)]
.
Например, в этой игре шахматная доска представляет собой шестиугольную сетку с 5 граничными шестиугольниками, а сгенерированный код хранения системы координат выглядит следующим образом:
setHexagonGrid() {
this.hexSide = 5;
this.hexSide--;
for (let q = -this.hexSide; q <= this.hexSide; q++) {
let r1 = Math.max(-this.hexSide, -q - this.hexSide);
let r2 = Math.min(this.hexSide, -q + this.hexSide);
for (let r = r1; r <= r2; r++) {
let col = q + this.hexSide;
let row = r - r1;
if (!this.hexes[col]) {
this.hexes[col] = [];
}
this.hexes[col][row] = this.hex2pixel({ q, r }, this.tileH);
}
}
}
Шестиугольная сетка с 6 границами, всего 61 шестиугольник. Затем вам нужно только пройти и добавить фон, чтобы завершить рисунок шахматной доски.
setSpriteFrame(hexes) {
for (let index = 0; index < hexes.length; index++) {
let node = new cc.Node('frame');
let sprite = node.addComponent(cc.Sprite);
sprite.spriteFrame = this.tilePic;
node.x = hexes[index].x;
node.y = hexes[index].y;
node.parent = this.node;
hexes[index].spriteFrame = node;
this.setShadowNode(node);
this.setFillNode(node);
this.boardFrameList.push(node);
}
}
На этом рисунок шахматной доски закончен.
Случайно сгенерированные блоки
Форма блока может постоянно меняться.Давайте сначала посмотрим на 23 формы, оговоренные заранее в этой игре.
Реализовать эти 23 формы несложно, основываясь на предыдущих знаниях о гексагональной сетке. Вам нужно только согласовать координаты осей, соответствующие каждой форме.
Конфигурация кода выглядит следующим образом:
const Tiles = [
{
type: 1,
list: [[[0, 0]]]
},
{
type: 2,
list: [
[[1, -1], [0, 0], [1, 0], [0, 1]],
[[0, 0], [1, 0], [-1, 1], [0, 1]],
[[0, 0], [1, 0], [0, 1], [1, 1]]
]
},
{
type: 3,
list: [
[[0, -1], [0, 0], [0, 1], [0, 2]],
[[0, 0], [1, -1], [-1, 1], [-2, 2]],
[[-1, 0], [0, 0], [1, 0], [2, 0]]
]
},
{
type: 4,
list: [
[[0, 0], [0, 1], [0, -1], [-1, 0]],
[[0, 0], [0, -1], [1, -1], [-1, 1]],
[[0, 0], [0, 1], [0, -1], [1, 0]],
[[0, 0], [1, 0], [-1, 0], [1, -1]],
[[0, 0], [1, 0], [-1, 0], [-1, 1]]
]
},
{
type: 5,
list: [
[[0, 0], [0, 1], [0, -1], [1, -1]],
[[0, 0], [1, -1], [-1, 1], [-1, 0]],
[[0, 0], [1, -1], [-1, 1], [1, 0]],
[[0, 0], [1, 0], [-1, 0], [0, -1]],
[[0, 0], [1, 0], [-1, 0], [0, 1]]
]
},
{
type: 6,
list: [
[[0, -1], [-1, 0], [-1, 1], [0, 1]],
[[-1, 0], [0, -1], [1, -1], [1, 0]],
[[0, -1], [1, -1], [1, 0], [0, 1]],
[[-1, 1], [0, 1], [1, 0], [1, -1]],
[[-1, 0], [-1, 1], [0, -1], [1, -1]],
[[-1, 0], [-1, 1], [0, 1], [1, 0]]
]
}
];
Так как вероятность появления квадратов отсутствует, здесь мы просто и грубо используем рандом, чтобы добиться случайной генерации квадратов.
const getRandomInt = function(min, max) {
let ratio = cc.random0To1();
return min + Math.floor((max - min) * ratio);
};
Все сетки и блоки готовы.Мне очень нравится этот простой стиль пользовательского интерфейса, который очень подходит для начального изучения разработки игр. Далее обрабатывается логика игрового взаимодействия.
Кубики попадают в логику шахматной доски
Взаимодействие между квадратом и шахматной доской осуществляется методом перетаскивания.cocos creator
В настоящее время компонент, связанный с перетаскиванием, не найден, и в настоящее время он моделируется с помощью события касания. в квадратахtouchmove
В процессе перетаскивания и выпадения две вещи должны быть решены. Во-первых, обнаружить, пересекается ли блок с шахматной доской во время процесса перетаскивания, что называется в игре.碰撞检测
, cc предоставляет соответствующие компоненты коллизии, но он недостаточно гибкий, потому что мы хотим получить отношения перекрытия между квадратом и шахматной доской (ps: не обязательно, чтобы они полностью перекрывались), поэтому мы по-прежнему используем скрипты для имитации реализация, cc предоставляет для этого множество API, в основном связанных с vec2. Во-вторых, проверьте, может ли блок упасть на доску.
Обнаружение столкновений (определение совпадения)
Квадрат и шахматная доска на самом деле состоят из правильных шестиугольников.Вот относительно простой способ определить, есть ли какое-либо перекрытие между ними, то есть определить расстояние между центрами двух шестиугольников.Когда оно меньше, чем установленное значение, считается, что есть совпадение.
Здесь для простоты начало системы координат родительского узла шахматной доски и поля намеренно установлено одинаковым (центральная точка). Кокосовая система координат может относиться кэто
Поскольку квадрат расположен относительно центральной точки его родителя, а его родитель расположен относительно холста, вы можете передатьcc.pAdd(this.node.position, tile.position)
чтобы получить координаты квадрата относительно начала координат шахматной доски. Затем пройдитесь по координатам шестиугольников на шахматной доске, чтобы проверить, какие из перетаскиваемых шестиугольников и шахматная доска имеют перекрывающиеся отношения. Соответствующий код выглядит следующим образом:
checkCollision(event) {
const tiles = this.node.children; // this.node 为 方块的父级,拖拽改变的是这个节点的坐标
this.boardTiles = []; // 保存棋盘与方块重合部分。
this.fillTiles = []; // 保存方块当前重合的部分。
for (let i = 0; i < tiles.length; i++) {
const tile = tiles[i];
const pos = cc.pAdd(this.node.position, tile.position); // pAdd 是cc早期提供的 api,可用 vec2 中向量相加替换
const boardTile = this.checkDistance(pos);
if (boardTile) {
this.fillTiles.push(tile);
this.boardTiles.push(boardTile);
}
}
},
checkDistance(pos) {
const distance = 50;
const boardFrameList = this.board.boardFrameList;
for (let i = 0; i < boardFrameList.length; i++) {
const frameNode = boardFrameList[i];
const nodeDistance = cc.pDistance(frameNode.position, pos);
if (nodeDistance <= distance) {
return frameNode;
}
}
},
В процессе перетаскивания шестиугольники с перекрывающимися отношениями шахматной доски сохраняются в режиме реального времени, что используется для определения того, могут ли квадраты упасть на шахматную доску.
Переместить решение
Пока количество клеток равно количеству заполняемых частей поля, на котором расположена шахматная доска (на доске нет клеток), считается, что ход можно сделать.
checkCanDrop() {
const boardTiles = this.boardTiles; // 当前棋盘与方块重合部分。
const fillTiles = this.node.children; // 当前拖拽的方块总数
const boardTilesLength = boardTiles.length;
const fillTilesLength = fillTiles.length;
// 如果当前棋盘与方块重合部分为零以及与方块数目不一致,则判定为不能落子。
if (boardTilesLength === 0 || boardTilesLength != fillTilesLength) {
return false;
}
// 如果方块内以及存在方块,则判定为不能落子。
for (let i = 0; i < boardTilesLength; i++) {
if (this.boardTiles[i].isFulled) {
return false;
}
}
return true;
},
советы по ставкам
После получения значения решения падать или нет, необходимо дать пользователю подсказку, что он может двигаться. Один из подходов здесь состоит в том, чтобы создать новое имя для каждого узла сетки шахматной доски перед созданием шахматной доски.shadowNode
дочерний узел . Затем вам нужно только изменить узлы, которые соответствуют условиямspriteFrame
для текущего перетаскиваемого блокаspriteFrame
и уменьшите прозрачность. код показывает, как показано ниже:
dropPrompt(canDrop) {
const boardTiles = this.boardTiles;
const boardTilesLength = boardTiles.length;
const fillTiles = this.fillTiles;
this.resetBoardFrames();
if (canDrop) {
for (let i = 0; i < boardTilesLength; i++) {
const shadowNode = boardTiles[i].getChildByName('shadowNode');
shadowNode.opacity = 100;
const spriteFrame = fillTiles[i].getComponent(cc.Sprite).spriteFrame;
shadowNode.getComponent(cc.Sprite).spriteFrame = spriteFrame;
}
}
}
впадать в логику
До сих пор площадьtouchmove
Добавлено событие. Далее необходимо выполнить соответствующую логическую обработку после перетаскивания.
В двух случаях блок может упасть, а блок - нет. Решение о том, может ли он упасть, было получено ранее. Затем следующим шагом будет добавление соответствующей обработки.
Что вам нужно сделать, когда вы можете упасть, так это добавить соответствующие квадраты на шахматную доску и генерировать новые квадраты случайным образом после добавления квадратов. Если он не может упасть, перетаскиваемый блок вернется в исходное положение.
При добавлении квадрата использовался метод, аналогичный упоминавшейся ранее подсказке с падением, и под каждым узлом сетки на шахматной доске добавлялось новое имя.fillNode
Узел , падение блока связано с этим узлом.
tileDrop() {
this.resetBoardFrames();
if (this.checkCanDrop()) {
const boardTiles = this.boardTiles;
const fillTiles = this.fillTiles;
const fillTilesLength = fillTiles.length;
for (let i = 0; i < fillTilesLength; i++) {
const boardTile = boardTiles[i];
const fillTile = fillTiles[i];
const fillNode = boardTile.getChildByName('fillNode');
const spriteFrame = fillTile.getComponent(cc.Sprite).spriteFrame;
boardTile.isFulled = true;
fillNode.getComponent(cc.Sprite).spriteFrame = spriteFrame;
this.resetTile();
}
this.board.curTileLength = fillTiles.length;
this.board.node.emit('dropSuccess');
} else {
this.backSourcePos();
}
this.board.checkLose();
}
устранить логику
С шахматной доской вы также можете судить, может ли квадрат упасть на шахматную доску. Следующее, что нужно сделать, это разобраться с логикой исключения.Как я уже говорил, шестиугольная игра на выбывание является производной от Тетриса.На самом деле, есть еще несколько направлений устранения.Давайте посмотрим на картинку:
Если вы думаете об этой шахматной доске как о массиве, то есть сложите ее по порядку, начиная с левого наклонного направления[0,1,2.....]
, и, наконец, можно получить следующие правила исключения:
const DelRules = [
//左斜角
[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15, 16, 17],
[18, 19, 20, 21, 22, 23, 24, 25],
[26, 27, 28, 29, 30, 31, 32, 33, 34],
[35, 36, 37, 38, 39, 40, 41, 42],
[43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55],
[56, 57, 58, 59, 60],
//右斜角
[26, 35, 43, 50, 56],
[18, 27, 36, 44, 51, 57],
[11, 19, 28, 37, 45, 52, 58],
[5, 12, 20, 29, 38, 46, 53, 59],
[0, 6, 13, 21, 30, 39, 47, 54, 60],
[1, 7, 14, 22, 31, 40, 48, 55],
[2, 8, 15, 23, 32, 41, 49],
[3, 9, 16, 24, 33, 42],
[4, 10, 17, 25, 34],
//水平
[0, 5, 11, 18, 26],
[1, 6, 12, 19, 27, 35],
[2, 7, 13, 20, 28, 36, 43],
[3, 8, 14, 21, 29, 37, 44, 50],
[4, 9, 15, 22, 30, 38, 45, 51, 56],
[10, 16, 23, 31, 39, 46, 52, 57],
[17, 24, 32, 40, 47, 53, 58],
[25, 33, 41, 48, 54, 59],
[34, 42, 49, 55, 60]
];
С правилом, за которым следует устранение логики, прямой взгляд на код:
deleteTile() {
let fulledTilesIndex = []; // 存储棋盘内有方块的的索引
let readyDelTiles = []; // 存储待消除方块
const boardFrameList = this.boardFrameList;
this.isDeleting = true; // 方块正在消除的标识,用于后期添加动画时,充当异步状态锁
this.addScore(this.curTileLength, true);
// 首先获取棋盘内存在方块的格子信息
for (let i = 0; i < boardFrameList.length; i++) {
const boardFrame = boardFrameList[i];
if (boardFrame.isFulled) {
fulledTilesIndex.push(i);
}
}
for (let i = 0; i < DelRules.length; i++) {
const delRule = DelRules[i]; // 消除规则获取
// 逐一获取规则数组与存在方块格子数组的交集
let intersectArr = _.arrIntersect(fulledTilesIndex, delRule);
if (intersectArr.length > 0) {
// 判断两数组是否相同,相同则将方块添加到待消除数组里
const isReadyDel = _.checkArrIsEqual(delRule, intersectArr);
if (isReadyDel) {
readyDelTiles.push(delRule);
}
}
}
// 开始消除
let count = 0;
for (let i = 0; i < readyDelTiles.length; i++) {
const readyDelTile = readyDelTiles[i];
for (let j = 0; j < readyDelTile.length; j++) {
const delTileIndex = readyDelTile[j];
const boardFrame = this.boardFrameList[delTileIndex];
const delNode = boardFrame.getChildByName('fillNode');
boardFrame.isFulled = false;
// 这里可以添加相应消除动画
const finished = cc.callFunc(() => {
delNode.getComponent(cc.Sprite).spriteFrame = null;
delNode.opacity = 255;
count++;
}, this);
delNode.runAction(cc.sequence(cc.fadeOut(0.3), finished));
}
}
if (count !== 0) {
this.addScore(count);
this.checkLose();
}
this.isDeleting = false;
}
игра важнее логики
Если ни один из трех квадратов не помещается на доске, игра считается оконченной.
Сначала получите информацию о незаполненной сетке шахматной доски, а затем поместите три квадрата в незаполненную область один за другим, чтобы определить, можно ли их вставить. код показывает, как показано ниже:
checkLose() {
let canDropCount = 0;
const tiles = this.node.children;
const tilesLength = tiles.length;
const boardFrameList = this.board.boardFrameList;
const boardFrameListLength = boardFrameList.length;
// TODO: 存在无效检测的情况,可优化
for (let i = 0; i < boardFrameListLength; i++) {
const boardNode = boardFrameList[i];
let srcPos = cc.p(boardNode.x, boardNode.y);
let count = 0;
if (!boardNode.isFulled) {
// 过滤出未填充的棋盘格子
for (let j = 0; j < tilesLength; j++) {
let len = 27; // 设定重合判定最小间距
// 将方块移到未填充的棋盘格子原点,并获取当前各方块坐标值
let tilePos = cc.pAdd(srcPos, cc.p(tiles[j].x, tiles[j].y));
// 遍历棋盘格子,判断方块中各六边形是否可以放入
for (let k = 0; k < boardFrameListLength; k++) {
const boardNode = boardFrameList[k];
let dis = cc.pDistance(cc.p(boardNode.x, boardNode.y), tilePos);
if (dis <= len && !boardNode.isFulled) {
count++;
}
}
}
if (count === tilesLength) {
canDropCount++;
}
}
}
if (canDropCount === 0) {
return true;
} else {
return false;
}
}
система баллов
Правила подсчета очков постоянно меняются в зависимости от ваших потребностей. Как правило, добавление и удаление блоков может добавить очки.
scoreRule(count, isDropAdd) {
let x = count + 1;
let addScoreCount = isDropAdd ? x : 2 * x * x;
return addScoreCount;
}
Спасибо
Проект относится к начальному уровню, впервые в контакте с создателями игр cocos, большинство из них ссылаются на какие-то шестиугольные игры с открытым исходным кодом в Интернете. Спасибо за открытый исходный код, в проекте есть некоторые методы, интегрированные в его собственные, такие как работа с шестиугольной сеткой, но устранение правил требует больше знаний для улучшения. Сначала напишите такую статью начального уровня, а затем углубитесь в нее. Надеюсь, она поможет некоторым новичкам в разработке игр, таким как я. Последующие действия можно сочетать с соответствующими примерами, рассказами о некоторых, анимацией создателя кокосов, системой частиц, системой физики, webgl и так далее.