18 April 2015

Hey there,
Today, I'd like to show you how to create a match3 style game.






We will start of by setting up our scene as following:



  • Set new Main Camera position to Vector3(5, 4.5f, -10f)
  • Create two c# scripts (Board and block)
  • Create new empty Game Object and assign Board script



Once you have that you can go ahead and create gems or blocks for this match3 game: 



  • Create new 3d object - Cube Set cube scale to Vector3(0.8f,0.8f,0.8f)
  • Make a prefab and change material(this way you can have more different blocks)
  • Do this for at least 4 blocks.


Board script:






  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
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Board : MonoBehaviour {

 //Blocks used in game
 public GameObject[] Blocks;

 //Size of the board
 public int Width = 10;
 public int Height = 10;

 //2D grid
 public Block[,] Grid;

 //Blocks falling
 public bool Falling;

 void Start(){
  //Initialize grid
  Grid = new Block[Width,Height*2];
 }


 void Update(){

  Falling = BlocksFalling();

  //If blocks are not falling then we can spawn :]
  if(!Falling)
   Spawn();

  //Make them fall down each frame
  Fall();
 }


 void Spawn(){
  //For each collumn
  for(int x=0; x<Width; x++){

   int count = 0;// Count how many blocks we spawned

   //Go from bottom up
   for(int y=0; y<Height; y++){

    //If we found empty block and there is empty position above playable board
    if(!Grid[x,y] && !Grid[x,Height+count]){

     //Spawn it above the board
     CreateBlock(x,Height+count);

     //We spawned one more block
     count++;
    }
   }
  }
 }


 void Fall(){
  //For each collumn
  for(int x=0; x<Width; x++){

   int count = 0; //counter

   //Start from bottom and go up
   for(int y=0; y<Height*2; y++){

    Block block = Grid[x,y];//Get block at this position

    //If the block exist 
    if(block){
   
     //If this block ID equals 1, that means that this block is currently getting destroyed
     if(block.ID == -1)
      y = Height*2;//Skip this collumn
     else if(block.NY != count){//If the new block position is not equal to current position....Then move it down
      Grid[x,y] = null;//Old position is now empty
      block.NY = count;//Set new block height
      block.CheckForMatch = true;//This block moved, so we check for match
      Grid[x,count] = block;//New position now equals this block
     }
     else if(block.CheckForMatch && !Falling){//If no blocks are falling then we can check for match if we need to
      Solve(Match (block)); //We call Solve method passing List that we found in match method
      block.CheckForMatch = false;//Do not check anymore
     }

     //We found one more block
     count++;
    }
   }
  }
 }


 void CreateBlock(int x, int y){
  //Random ID
  int id = Random.Range(0,Blocks.Length);
  //Create block
  GameObject obj = Instantiate(Blocks[id], new Vector3(x,y), Quaternion.identity) as GameObject;
  //Block component
  Block block = obj.AddComponent<Block>();

  //Set values
  Grid[x,y] = block; //We spawned block here
  block.ID = id; //Block have this ID
  block.X = x; 
  block.Y = y;
  block.NY = y;
  block.board = this;

  //Just to make things clean
  obj.transform.parent = transform;
 }

 //This will return true if the blocks are falling and false if not
 bool BlocksFalling(){
  for(int x=0; x<Width; x++){
   for(int y=0; y<Height; y++){
    if(Grid[x,y] && !Grid[x,y].IsReady()){
      return true;
    }
   }
  }

  return false;

 }

 //Match3 will return List of Blocks that has been found against check block
 List<Block> Match(Block check){

  List<Block> ToReturn = new List<Block>(); //Blocks to return

  List<Block> Matches = new List<Block>();//List of blocks 
  bool linked = false; //If we found our check block

  //HORIZONTAL CHECK

  for(int x=0; x<Width; x++){//Left to right
   if(x==(int)check.X)//If we found our check block on this position then link matches
    linked = true;
   if(Grid[x,(int)check.Y] && Grid[x,(int)check.Y].IsReady() && Grid[x,(int)check.Y].ID == check.ID)//If this block is same as check block(id)
    Matches.Add(Grid[x,(int)check.Y]);//Add this block in the list
   else if(linked)//The block doesn't exist or ID is not equal or Its Falling....Then if linked we will stop there and we will check whatever we have in list
    break;
   else //Nothing of this is true, then just clear list and keep checking
    Matches.Clear();
  }

  //We have list and blocks in it but we will return it only if we found 3 or more blocks
  if(Matches.Count>=3)
   ToReturn.AddRange(Matches);

  //Rese
  Matches.Clear();
  linked = false;


  //VERTICAL CHECK
 
  //Same as before
  for(int y=0; y<Height; y++){
   if(y==(int)check.Y)
    linked = true;
   if(Grid[(int)check.X, y] && Grid[(int)check.X, y].IsReady() && Grid[(int)check.X, y].ID == check.ID)
    Matches.Add(Grid[(int)check.X, y]);
   else if(linked)
    break;
   else 
    Matches.Clear();
  }

  if(Matches.Count>=3)
   ToReturn.AddRange(Matches);


  return ToReturn;

 }

 //Solve List of blocks
 void Solve(List<Block> Matches){

  int count = Matches.Count; //How many blocks we have

  
  

  //We will destroy every block in this list, no matter how many we found...You can do stuff based on count
  foreach(Block block in Matches){
   block.StartCoroutine("Destroy");//Start destroy 
  }

 }


}


Block script:





 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
61
62
63
using UnityEngine;
using System.Collections;

public class Block : MonoBehaviour {


 [HideInInspector]public int ID; //ID of this block

 //Position of this block in the board
 [HideInInspector]public float X;
 [HideInInspector]public float Y;

 [HideInInspector]public float NY; // New block height
 [HideInInspector]public Board board; 
 [HideInInspector]public bool CheckForMatch = false; //If we need to check for match

 void Update(){
  //If the new height is set then it will be lower than curent height
  if(NY<Y){//It should fall down

   //Move it down
   Y-=0.1f;

   //Update block position
   transform.position = new Vector3(X,Y);
  }
  else{//Its not falling, and it should not
  
   Y=NY; //Round Y

   transform.position = new Vector3(X,Y); //Round position

  }
 }

 //This will destroy block when called
 public IEnumerator Destroy(){
  ID = -1; //We update block ID so it doesn't get matched or moved
  float time = 0; 

  //Change block scale by time
  while(time<=1){

   transform.localScale = Vector3.Lerp(new Vector3(0.8f,0.8f,0.8f), Vector3.zero, time);
   time += Time.deltaTime/2;

   yield return null;
  }

  //Update grid, set empty
  board.Grid[(int)X, (int)Y] = null;

  //At the end destroy that block gameobject
  Destroy(gameObject);

 }

 // Determines whether this Block is ready - falling down
 public bool IsReady(){
  return Y==NY;
 }

}





board.Fall(): we go from bottom up to top. Once we found solid block we update that block height to equal current number of solid blocks found. Now we increase that value by one. You can go ahead and draw this method and see how it works. Here is my drawing :)

If you need anything else explained feel free to ask.



Thank's for reading , also I'd love to hear some feedback from you :]



SOURCE CODE


Source code
Donate Button

{ 4 коментара... read them below or Comment }

  1. do you have full c# sprite of this game?

    ReplyDelete
  2. The project is very interesting and useful.
    I like it.

    I wonder if the Horizontal + Vertical can be add to a same match list
    So I insert 3 lines code to verify:

    void CreateBlock (int x, int y)
    {
    //Random ID
    int id = Random.Range (0, Blocks.Length);
    //Create block
    //Manual set ID
    if(Time.timeSinceLevelLoad < 4)
    if(x== 2 ||y%10 == 1)
    id = 1;
    //print ("<<>>" + id);
    it will create a cross of id 1, and only horizontal matches found.

    ReplyDelete
  3. This really wasn't that useful, especially as a tutorial for new programmers
    Alongside the code you should add in step by step guides on how to create the game, not just write the scripts.

    ReplyDelete
    Replies
    1. You are right. I'll change it in the future. Thank's!

      Delete

- Copyright © Unity plus - Skyblue - Powered by Blogger - Designed by Johanes Djogan -