Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about Perfectionism game, Flash and Game development.

4th step of the quickest game creation tutorial… in the last step we added elements to the game field… now we have to introduce real clicks

Real clicks

What is a real click? In Perfectionism game you can have only two buttons clicked at once: since it’s basically a “swap some elements” game, you can only click the “from” button and the “to” button.

Moreover, if you click a button on the horizontal row and then roll over a button on the vertical row, the button you clicked must become unclicked, and the same must happen when you click a button on the vertical row and then roll over a button on the horizontal one.

_root.attachMovie("grid","grid",1,{_x:90, _y:90});
_root.createEmptyMovieClip("rays",2);
swapping = false;
horizontal_hover = new Array(0, 0, 0, 0, 0, 0, 0, 0);
vertical_hover = new Array(0, 0, 0, 0, 0, 0, 0, 0);
horizontal_click = new Array(0, 0, 0, 0, 0, 0, 0, 0);
vertical_click = new Array(0, 0, 0, 0, 0, 0, 0, 0);
level = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
for (x=0; x<64; x++) {
	if (level[x] == 1) {
		grid.attachMovie("cell","cell_"+x,grid.getNextHighestDepth(),{_x:(x%8)*40, _y:Math.floor(x/8)*40});
	}
	if (level[x] == 2) {
		grid.attachMovie("atom","atom"+x,grid.getNextHighestDepth(),{_x:(x%8)*40, _y:Math.floor(x/8)*40});
	}
}
for (x=1; x<=8; x++) {
	hs = grid.attachMovie("hswapper", "hswapper_"+x, grid.getNextHighestDepth(), {_x:-20, _y:40*x-20});
	hs.pos = x;
	hs.onEnterFrame = function() {
		if (!swapping) {
			if (this.hitTest(_root._xmouse, _root._ymouse, true)) {
				this.gotoAndStop(2);
				horizontal_hover[this.pos-1] = 1;
				for (x=0; x<8; x++) {
					vertical_click[x] = 0;
				}
			}
			else {
				this.gotoAndStop(1);
				horizontal_hover[this.pos-1] = 0;
			}
			if (horizontal_click[this.pos-1] == 1) {
				(this.gotoAndStop(3));
			}
		}
	};
	vs = grid.attachMovie("vswapper", "vswapper_"+x, grid.getNextHighestDepth(), {_x:40*x-20, _y:-20});
	vs.pos = x;
	vs.onEnterFrame = function() {
		if (!swapping) {
			if (this.hitTest(_root._xmouse, _root._ymouse, true)) {
				this.gotoAndStop(2);
				vertical_hover[this.pos-1] = 1;
				for (x=0; x<8; x++) {
					horizontal_click[x] = 0;
				}
			}
			else {
				this.gotoAndStop(1);
				vertical_hover[this.pos-1] = 0;
			}
			if (vertical_click[this.pos-1] == 1) {
				(this.gotoAndStop(3));
			}
		}
	};
}
rays.onEnterFrame = function() {
	if (!swapping) {
		this.clear();
		clicks = 0;
		this.lineStyle(2,0x00ff00);
		for (x=0; x<8; x++) {
			if ((horizontal_hover[x] == 1) or (horizontal_click[x] == 1)) {
				this.moveTo(90,x*40+110);
				this.lineTo(410,x*40+110);
				if (horizontal_click[x] == 1) {
					clicks++;
				}
			}
			if ((vertical_hover[x] == 1) or (vertical_click[x] == 1)) {
				this.moveTo(x*40+110,90);
				this.lineTo(x*40+110,410);
				if (vertical_click[x] == 1) {
					clicks++;
				}
			}
		}
		if (clicks == 2) {
			swapping = true;
		}
	}
};
_root.onMouseDown = function() {
	for (x=0; x<8; x++) {
		if (horizontal_hover[x] == 1) {
			horizontal_click[x] = 1-horizontal_click[x];
		}
		if (vertical_hover[x] == 1) {
			vertical_click[x] = 1-vertical_click[x];
		}
	}
};

Line 3: Creating a boolean variable called swapping that will be true if we are ready to swap elements (two buttons on the same row or column have been clicked) or false otherwise

Line 21: Now all operations on the horizontal buttons are performed only if we aren't swapping elements

Lines 25-27: If we are rolling over an horizontal button, then set all vertical buttons to unclicked

Line 41: Now all operations on the vertical buttons are performed only if we aren't swapping elements

Lines 45-47: If we are rolling over an vertical button, then set all horizontal buttons to unclicked

Line 60: Now all operations on rays are performed only if we aren't swapping elements

Line 62: Setting a variable called clicks, that will store the number of buttons clicked, to zero

Lines 68-70: If the x-th element of the horizontal_click array is set to 1 (the button is clicked), then increment clicks value

Lines 75-77: Same thing with the vertical_click array

Line 80: If we have two buttons clicked (and we know they will be two horizontal buttons or two vertical buttons), then set swapping to true. We are now ready to swap elements

And here it is:

Now if you click an horizontal button and then roll over a vertical one, you will lose the clicked status on the horizontal button, and the same thing will happen if you click on the vertical one and then roll over an horizontal button

If you click two horizontal buttons, you're ready to swap elements! The game freezes at this point, because there is no swapping code, but it's exactly what we are going to make

Swapping elements

This is the hardest part of the game... once you click two horizontal or vertical buttons, we have to swap elements. Remember that only the squares can be moved, while the rings have to remain in the same position even if I try to swap them

_root.attachMovie("grid", "grid", 1, {_x:90, _y:90});
_root.createEmptyMovieClip("rays", 2);
swapping = false;
from = -1;
to = -1;
horizontal_swap = false;
vertical_swap = false;
horizontal_hover = new Array(0, 0, 0, 0, 0, 0, 0, 0);
vertical_hover = new Array(0, 0, 0, 0, 0, 0, 0, 0);
horizontal_click = new Array(0, 0, 0, 0, 0, 0, 0, 0);
vertical_click = new Array(0, 0, 0, 0, 0, 0, 0, 0);
level = new Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
for (x=0; x<64; x++) {
	if (level[x] == 1) {
		grid.attachMovie("cell", "cell_"+x, grid.getNextHighestDepth(), {_x:(x%8)*40, _y:Math.floor(x/8)*40});
	}
	if (level[x] == 2) {
		at = grid.attachMovie("atom", "atom_"+x, grid.getNextHighestDepth(), {_x:(x%8)*40, _y:Math.floor(x/8)*40});
		at.pos = x;
		at.moving = 0;
		at.onEnterFrame = function() {
			if (this.moving == 0) {
				if (swapping) {
					if (horizontal_swap) {
						if ((this.pos>=from*8) and (this.pos<=from*8+7)) {
							this.moving = (to-from)*40;
						}
						if ((this.pos>=to*8) and (this.pos<=to*8+7)) {
							this.moving = (from-to)*40;
						}
					}
					if (vertical_swap) {
						for (x=0; x<8; x++) {
							if (this.pos == x*8+from) {
								this.moving = (to-from)*40;
							}
						}
						for (x=0; x<8; x++) {
							if (this.pos == x*8+to) {
								this.moving = (from-to)*40;
							}
						}
					}
				}
			} else {
				if (this.moving>0) {
					if (horizontal_swap) {
						this._y += 10;
					}
					if (vertical_swap) {
						this._x += 10;
					}
					this.moving -= 10;
				}
				if (this.moving<0) {
					if (horizontal_swap) {
						this._y -= 10;
					}
					if (vertical_swap) {
						this._x -= 10;
					}
					this.moving += 10;
				}
				if (this.moving == 0) {
					this.pos = Math.round(this._x/40)+Math.round(this._y/40)*8;
					for (x=0; x<8; x++) {
						horizontal_click[x] = 0;
						vertical_click[x] = 0;
						swapping = false;
					}
				}
			}
		};
	}
}
for (x=1; x<=8; x++) {
	hs = grid.attachMovie("hswapper", "hswapper_"+x, grid.getNextHighestDepth(), {_x:-20, _y:40*x-20});
	hs.pos = x;
	hs.onEnterFrame = function() {
		if (!swapping) {
			if (this.hitTest(_root._xmouse, _root._ymouse, true)) {
				this.gotoAndStop(2);
				horizontal_hover[this.pos-1] = 1;
				for (x=0; x<8; x++) {
					vertical_click[x] = 0;
				}
			} else {
				this.gotoAndStop(1);
				horizontal_hover[this.pos-1] = 0;
			}
			if (horizontal_click[this.pos-1] == 1) {
				(this.gotoAndStop(3));
			}
		}
	};
	vs = grid.attachMovie("vswapper", "vswapper_"+x, grid.getNextHighestDepth(), {_x:40*x-20, _y:-20});
	vs.pos = x;
	vs.onEnterFrame = function() {
		if (!swapping) {
			if (this.hitTest(_root._xmouse, _root._ymouse, true)) {
				this.gotoAndStop(2);
				vertical_hover[this.pos-1] = 1;
				for (x=0; x<8; x++) {
					horizontal_click[x] = 0;
				}
			} else {
				this.gotoAndStop(1);
				vertical_hover[this.pos-1] = 0;
			}
			if (vertical_click[this.pos-1] == 1) {
				(this.gotoAndStop(3));
			}
		}
	};
}
rays.onEnterFrame = function() {
	if (!swapping) {
		horizontal_swap = false;
		vertical_swap = false;
		this.clear();
		clicks = 0;
		this.lineStyle(2, 0x00ff00);
		for (x=0; x<8; x++) {
			if ((horizontal_hover[x] == 1) or (horizontal_click[x] == 1)) {
				this.moveTo(90, x*40+110);
				this.lineTo(410, x*40+110);
				if (horizontal_click[x] == 1) {
					clicks++;
					horizontal_swap = true;
				}
			}
			if ((vertical_hover[x] == 1) or (vertical_click[x] == 1)) {
				this.moveTo(x*40+110, 90);
				this.lineTo(x*40+110, 410);
				if (vertical_click[x] == 1) {
					clicks++;
					vertical_swap = true;
				}
			}
		}
		if (clicks == 2) {
			from = -1;
			to = -1;
			swapping = true;
			if (horizontal_swap) {
				for (x=0; x<8; x++) {
					if (horizontal_click[x] == 1) {
						if (from == -1) {
							from = x;
						} else {
							to = x;
						}
					}
				}
			}
			if (vertical_swap) {
				for (x=0; x<8; x++) {
					if (vertical_click[x] == 1) {
						if (from == -1) {
							from = x;
						} else {
							to = x;
						}
					}
				}
			}
		}
	}
};
_root.onMouseDown = function() {
	for (x=0; x<8; x++) {
		if (horizontal_hover[x] == 1) {
			horizontal_click[x] = 1-horizontal_click[x];
		}
		if (vertical_hover[x] == 1) {
			vertical_click[x] = 1-vertical_click[x];
		}
	}
};

Line 4: Declaring a from variable that will store the row (or column) to be swapped. -1 means no columns (or rows) to swap

Line 5: Same thing with the destination row (or column)

Line 6: Boolean flag that tells me if I should make an horizontal swap

Line 7: Boolean flag that tells me if I should make a vertical swap

Line 20: When I create the square movieclip, I assign it a moving variable that will tell me how many pixel the square has to move.

Line 22: If the square is not moving...

Line 23: If we must swap rows (or columns)...

Line 24: If we must perform an horizontal swap (we'll see later in this code how to determine if it's an horizontal or verticals swap)...

Line 25: If the square is in the starting row (we'll see later in this code how to determine which row is the starting one)...

Line 26: Calculating the number of pixels the square has to move. This number is determined multiplying 40 (the side of one cell of the game field) by the difference between the ending and the starting rows

Lines 28-30: Same thing as lines 25-27, but I am checking if the square is on the destination row

Lines 32-43: Same thing as lines 24-31, just applied to vertical swapping

In a brief summary, if the square is not already moving and I know I have to swap two rows (or columns), first I check if I am going to swap rows or columns, then I check if the square lies on one of the rows (or columns) to be swapped and in this case I determine how many pixels the square has to move up/down/left/right according to its position in the swapping row/column

Line 45: If the square is moving...

Line 46: If the amount of pixels the square has to move is greater than zero (the square moves from left to right or from up to down)

Line 47: If it's an horizontal swap...

Line 48: Move the square down by 10 pixels (an arbitrary speed I set)

Lines 50-52: Same thing for the vertical swap, just moving the square to the right by 10 pixels

Line 53: Since the square has moved by 10 pixels (no matter in which direction), I subtract 10 to moving variable

Lines 55-63: Same thing as lines 46-64, just managing movements when moving is less than zero

In a brief summary, if the square is moving, I determine the direction I will move the square, and move it by 10 pixels per frame, until I moved it for the same amount of pixels calculated at lines 26 or 29 or 35 or 40

Line 64: If moving is equal to zero (I just moved the square for the last 10 pixels step)

Line 65: Update pos value according to the physical position of the square in the stage

Lines 66-70: Now that columns/rows have been swapped, it's time to clear the click status of all buttons. I don't really know why I included line 69 inside the cycle... oh well...

Line 129: Setting horizontal_swap to true if an horizontal button has been clicked

Line 137: Same thing for the vertical_swap variable

Line 142: Now we have to manage the game when the player clicks on two buttons... first resetting from to -1...

Line 143: Then doing the same thing with to

Line 144: Set swapping to true, now we only need to know the couple of rows/columns to swap

Line 145: If it's an horizontal swap...

Line 146: Cycle scanning all horizontal_click array elements

Line 147: If the x-th element is equal to 1 (the button has been clicked)...

Lines 148-152: I have to assign the from and the to variables. I want the from variable to store the upper (or leftmost) position on the field where the player clicked the button and the the to variable to store the lower (or rightmost) one. So, if from is at -1, it means this is the first clicked button I found, so I assign x value to from. If from is not -1, it means I already found a clicked button so this must be the second button, so I store x value to to variable

Lines 156-166: Same thing as lines 145-155, but for vertical swapping

And that's it!! Now you can swap rows and columns, but the game still crashes if you try to swap empty rows/columns

Don't be afraid of the complexity of this code because this was the hardest part.

You'll see in next tutorial how things will get easier and easier now that the game is ready to be published

Download source codes and prepare yourself for next step

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.