Сначала создадим блоки. Для этого используем простой куб с разными цветами (я взял 4 цвета) и установим скейл кубов в (0.8, 0.8, 0.8). Затем создадим C# скрипт, назовем его Match3
Что нам нужно сделать: 1) Генерация игрового поля (доски). 2) Выбор двух блоков. 3) Проверка рядом ли они. 4) Обмен позициями и данными. 5) Сравнение блоков. 6) Разрушение и спаун объектов.
Генерация поля(доски).
Код
//Доска public int[, ] board;
//блоки public Transform[] block;
void Start(){ blocks = new int[10,10]; //генерация доски GenBoard(); }
void GenBoard(){ //10x10 = 100blocks for(int x=0; x<board.GetLength(0); x++){ for(int y=0; y<board.GetLength(1); y++){ int randomNumber = Random.Range(0,block.Length); //ID //спаун блоков Transform obj = (Transform)Instantiate(block[randomNumber].transform, new Vector3(x,y,0), Quaternion.identity) as Transform; //назначаем parent obj.parent = transform; //назначаем имя obj.name = "Block[X:"+x+"Y:"+y+"]ID:"+randomNumber; // установим ID на доске в этой позиции board[x,y] = randomNumber; } } }
Проходим по каждому блоку на доске и получаем для него рандомный номер (это будет цвет). Спауним блок. Не забудьте каждому блоку назначить префабы в массив block. Теперь создадим новый скрипт. Назовем его Block. Назначим этот скрипт каждому новому созданному блоку. Добавим в него несколько переменных для позиции и ID, они понадобятся нам в дальнейшем.
Код
//позиции блока public int ID; public int x; public int y;
private Vector3 myScale; private float startTime;
public static Transform select; public static Transform moveTo;
void Update(){ //эффект роста if(Time.time-startTime<3){//после спауна блока, расти он будет не более 3 секунд transform.localScale = Vector3.Lerp(new Vector3(0,0,0),myScale, (Time.time-startTime)/2); } }
Теперь нужно добавить этот скрипт к каждому блоку, назначить позицию и ID. В скрипте Match3 в функцию GenBoard добавим
Код
//Прикрепим скрипт к каждому блоку Block b = obj.gameObject.AddComponent<Block>(); //назначим переменные b.x = x; b.y = y; b.ID = randomNumber;
Выбор двух блоков.
Для выбора двух блоков, нам нужна проверка, нажал ли игрок левую кнопку мышки. Потом нужно проверить, над каким именно блоком находится курсор. В скрипте блока мы можем использовать функцию OnMouseOver, которая вызывается когда курсор оказывается над блоком. Затем, если ничего не выделено, и игрок нажимает левую кнопку, выделяем данный блок. И, если данный блок уже выделен - выделяем его снова. Для этого нам нужно определить две статичные переменные.
Код
public static Transform select; public static Transform moveTo;
void OnMouseOver(){ // курсор мыши над блоком transform.localScale = new Vector3(myScale.x+0.2f,myScale.y+0.2f,myScale.z+0.2f); //выделение объектов if(Input.GetMouseButtonDown(0)){ if(!select){//если ни один не выделен, выделяем данный блок select = transform; } else if(select != transform && !moveTo ){ //если один блок уже выделен, проверим не выделен ли он снова. Выделяем второй объект moveTo = transform; } } }
Проверка рядом ли блоки Для проверки, находятся ли блоки рядом друг с другом, нужно узнать их позиции. Используем block.select для доступа к статичной переменной. Мы получим transform выделенного блока. В скрипте Match3, в функции Update нам нужно проверить, выбраны ли два блока. Если это так, нужно вызвать функцию CheckIfNear, которая вернет true или false.
Код
void Update(){ if(Block.select && Block.moveTo){//два выбранных блока есть //Проверка рядом ли они if(CheckIfNear()==true){
//Изменение ID на доске board[sel.x, sel.y] = sel.ID; board[mov.x, mov.y] = mov.ID;
}
Сравнение
Проверка на сравнение заключается в следующем. Мы знаем выделенный блок. Который, например, черный. Мы знаем позицию блока (имеем доступ к статичной переменной). Но мы не знаем, так это - есть ли 3 таких же блока рядом с выделенным. Чтобы узнать это, мы: 1) От позиции выделенного блока пойдем вправо. 2) Если этот блок того же цвета, что и выделенный, снова пойдем вправо и отметим что мы нашли +1 блок. 3) Если цвет блока отличается от выделено, останавливаемся, вправо больше не идем. Почти то же самое с другими направлениями, за исключение того что в этом случае мы начинаем проверку не с позиции выделенного блока. Отсчет мы начнем с позиции, стоящей перед выделенным блоком. Мы же не хотим проверять один и тот же блок дважды.
Тот же принцип для верхнего и нижнего направлений.
После этого нужно проверить, получился ли у нас ряд одинаковых блоков. Если countL + countR => 3, блоки разрушим и отметим их как пустые.
Код
bool CheckMatch(){ //получаем все доступ ко всем блокам в сцене Block[] allb = FindObjectsOfType(typeof(Block)) as Block[]; Block sel = Block.select.gameObject.GetComponent<Block>();
int countU = 0; //счетчик вверх int countD = 0; //счетчик вниз int countL = 0; //счетчик влево int countR = 0; //счетчик вправо
//Влево for(int l = sel.x-1; l>=0; l--){ if(board[l,sel.y]==sel.ID){//если у блока такое же ID countL++; } if(board[l,sel.y]!=sel.ID){//если у блока другое ID //останавливаемся break; } } //Вправо for(int r = sel.x; r<board.GetLength(0); r++){ if(board[r,sel.y]==sel.ID){ countR++; } if(board[r,sel.y]!=sel.ID){ break; } } //Вниз for(int d = sel.y-1; d>=0; d--){ if(board[sel.x,d]==sel.ID){ countD++; } if(board[sel.x,d]!=sel.ID){ break; } }
//Вверх for(int u = sel.y; u<board.GetLength(1); u++){ if(board[sel.x,u]==sel.ID){ countU++; }
if(board[sel.x,u]!=sel.ID){ break; } }
//Проверяем, есть ли ряд из трех блоков if(countL+countR>=3 || countD+countU>=3){ if(countL+countR>=3){ //разрушаем и отмечаем пустые блоки for(int cl = 0; cl<=countL; cl++){ foreach(Block b in allb){ if(b.x == sel.x-cl && b.y == sel.y){ Destroy(b.gameObject); board[b.x,b.y] = 500; //отмечаем пустой блок } } } for(int cr = 0; cr<countR; cr++){ foreach(Block b in allb){ if(b.x == sel.x+cr && b.y == sel.y){ Destroy(b.gameObject); board[b.x,b.y] = 500; } } } } if(countD+countU>=3){ for(int cd = 0; cd<=countD; cd++){ foreach(Block blc in allb){ if(blc.x == sel.x && blc.y == sel.y - cd){ board[blc.x, blc.y] = 500; Destroy(blc.gameObject); } } } for(int cu = 0; cu<countU; cu++){ foreach(Block blc in allb){ if(blc.x == sel.x && blc.y == sel.y+cu){ board[blc.x, blc.y] = 500; Destroy(blc.gameObject); } } } } Respawn(); return true;
}
return false; }
Теперь мы можем создать новые блоки на отмеченных позициях поля. Почти тоже самое мы делали в функции GenBoard
Код
void Respawn(){ for(int x=0; x<board.GetLength(0); x++){ for(int y=0; y<board.GetLength(1); y++){ if(board[x,y]==500){ //спауним только на разрушенной клетке int randomNumber = Random.Range(0,blocks.Length); //ID Transform obj = (Transform)Instantiate(blocks[randomNumber].transform, new Vector3(x,y,0), Quaternion.identity); obj.parent = transform; Block b = obj.gameObject.AddComponent<Block>(); //назначим переменные b.ID = randomNumber; b.x = x; b.y = y; //назначим ID на доске новое значение board[x,y] = randomNumber; } } } }
И, уже в функции Update
Код
void Update(){ if(Block.select && Block.moveTo){ //If 2 blocks are selected, what we need more? //Check if they are near if(CheckIfNear()==true){ //Near Swap();//Swap their position and data
//Check for match3 if(CheckMatch()==true){ //There is match Block.select = null; Block.moveTo = null; } else{ //There is no match, return them in their default position Swap(); Block.select = null; Block.moveTo = null; } } else{ //Not near Block.select = null; Block.moveTo = null; //We can again select new blocks } } }
Также если вы считаете, что данный материал мог быть интересен и полезен кому-то из ваших друзей, то вы бы могли посоветовать его, отправив сообщение на e-mail друга:
Игровые объявления и предложения:
Если вас заинтересовал материал «Программирование match3 игры на Unity», и вы бы хотели прочесть что-то на эту же тему, то вы можете воспользоваться списком схожих материалов ниже. Данный список сформирован автоматически по тематическим меткам раздела.
Предлагаются такие схожие материалы:
Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями.
Не правильно работает демонстрация: если в результате смены кубиков образуется не одна линия, а сразу две или больше, то исчезает всё-равно одна. Например: К З К З З К меняем нижние буквы местами, должно исчезнуть 6 букв (все К и все З), а исчезают только одни.
Спасибо, интересненько Кстати, есть продолжение этого урока Тыц Там изменен вид появления квадратиков до типичных на сегодня match3 игр Очень интересные глюки притом начинают появляться
Привет) Да, разные. Например, вместо заполнения пустого места с только что удаленным квадратом ничего не приходит, или приходит, но цвет, выглядя, например, красным, на самом деле является зеленым и т.п. Минут пять достаточно поиграть, чтоб эти глюки вылезли