Get the full commented source code of

HTML5 Suika Watermelon Game

Talking about zNumbers game, Defold, Game development, HTML5 and Users contributions.

Defold engine, the free forever engine for 2D games powered by King with more than 40,000 registered users, is gaining more and more popularity and Björn Ritzl, who already ported my version of Mike Dangers game on Defold now released the Defold version of my Phaser zNumbers prototype. The game also looks very good thanks to Kenney‘s icons.
Defold uses LUA which is quite understandable if you are used to programming and you had a look at the commented source code of my Phaser prototype.
local WIDTH = 6
local HEIGHT = 6

local DIRECTIONS = {
	{ x = -1, y = -1 },
	{ x = -1, y =  0 },
	{ x = -1, y =  1 },
	
	{ x =  1, y = -1 },
	{ x =  1, y =  0 },
	{ x =  1, y =  1 },
	
	{ x =  0, y = -1 },
	{ x =  0, y =  0 },
	{ x =  0, y =  1 },
}

local LEVELS = {
	{ -- level 1
		{0, 0, 0, 0, 0, 0},
		{3, 2, 3, 2, 2, 2},
		{0, 0, 2, 3, 2, 2},
		{2, 0, 2, 2, 0, 0},
		{0, 2, 3, 0, 2, 2},
		{2, 3, 0, 2, 0, 4}
	},
	{ -- level 2
		{0, 2, 3, 3, 2, 1},
		{2, 0, 3, 3, 0, 2},
		{1, 4, 3, 3, 0, 1},
		{1, 4, 3, 3, 0, 1},
		{2, 0, 3, 3, 0, 2},
		{0, 2, 3, 3, 2, 1}
	},
	{ -- level 3
		{0, 2, 2, 2, 0, 2},
		{1, 1, 1, 1, 1, 1},
		{1, 3, 0, 3, 3, 1},
		{1, 3, 3, 3, 3, 1},
		{1, 1, 1, 1, 1, 1},
		{4, 4, 0, 4, 0, 1}
	},
	{ -- level 4
		{3, 4, 2, 2, 0, 2},
		{1, 1, 1, 1, 1, 1},
		{0, 1, 3, 0, 3, 1},
		{1, 3, 1, 3, 1, 1},
		{1, 1, 1, 1, 1, 1},
		{3, 0, 0, 4, 0, 1}
	},
	{ -- level 5
		{4, 2, 1, 2, 1, 4},
		{1, 2, 1, 1, 2, 1},
		{1, 3, 2, 3, 3, 1},
		{1, 1, 2, 2, 3, 1},
		{1, 0, 1, 1, 2, 1},
		{4, 0, 0, 4, 1, 4}
	},
	{ -- level 6
		{3, 2, 1, 1, 2, 1},
		{1, 2, 1, 0, 2, 2},
		{2, 1, 1, 1, 2, 1},
		{1, 2, 1, 1, 2, 1},
		{0, 2, 1, 1, 2, 4},
		{3, 0, 0, 4, 0, 4}
	},
	{ -- level 7
		{2, 0, 2, 3, 0, 2},
		{0, 2, 1, 3, 2, 1},
		{2, 0, 1, 3, 0, 2},
		{0, 2, 3, 3, 2, 1},
		{2, 0, 1, 3, 0, 2},
		{0, 2, 0, 3, 2, 1}
	},
	{ -- level 8
		{1, 3, 0, 1, 1, 2},
		{0, 4, 0, 0, 2, 3},
		{3, 1, 0, 0, 3, 1},
		{1, 2, 0, 0, 1, 2},
		{4, 3, 1, 0, 4, 3},
		{2, 4, 1, 1, 2, 4}
	},
	{ -- level 9
		{4, 1, 0, 0, 2, 4},
		{2, 4, 2, 4, 1, 0},
		{0, 0, 2, 0, 4, 2},
		{1, 1, 0, 0, 4, 2},
		{2, 4, 1, 4, 0, 1},
		{3, 0, 4, 1, 0, 4}
	},
	{ -- level 10
		{3, 2, 2, 0, 2, 0},
		{2, 3, 2, 3, 2, 0},
		{0, 1, 3, 1, 2, 2},
		{1, 1, 0, 0, 0, 1},
		{2, 2, 1, 3, 3, 1},
		{3, 2, 1, 1, 2, 2}
	}
}

local function play_animation(id, animation)
	msg.post(msg.url(nil, id, "sprite"), "play_animation", { id = animation })
end

-- update the visual representation of the cell based on its state
local function update_cell(cell, pressed)
	if cell.number and cell.number > 0 then
		label.set_text(msg.url(nil, cell.square_id, "label"), cell.number)
		if pressed then
			play_animation(cell.square_id, hash("buttonSquare_lightblue"))
		elseif cell.locked then
			play_animation(cell.square_id, hash("buttonSquare_darkblue_pressed"))
		else
			play_animation(cell.square_id, hash("buttonSquare_blue"))
		end
	else
		label.set_text(msg.url(nil, cell.square_id, "label"), "")
		play_animation(cell.square_id, hash("buttonSquare_darkblue_pressed"))
	end
end

-- find a cell on the map based on the game object id of the square
local function find_cell(board, square_id)
	for x=1,WIDTH do
		for y=1,HEIGHT do
			local cell = board[x][y]
			if cell.square_id == square_id then
				return cell
			end
		end
	end
end

-- find empty target cells at the correct distance from a specific cell
-- containing a number
local function find_targets(board, cell)
	local targets = {}
	for _,dir in pairs(DIRECTIONS) do
		local tx = cell.x + cell.number * dir.x
		local ty = cell.y + cell.number * dir.y
		if tx > 0 and tx <= WIDTH and ty > 0 and ty <= HEIGHT then
			local target = board[tx][ty]
			if not target.number then
				table.insert(targets, target)
			end
		end
	end
	return targets
end

-- highlight target cells
local function highlight_targets(board, cell)
	local targets = find_targets(board, cell)
	for _,target in ipairs(targets) do
		play_animation(target.square_id, hash("buttonSquare_grey_pressed"))
	end
end

-- reset target cells
local function reset_targets(board, cell)
	local targets = find_targets(board, cell)
	for _,target in ipairs(targets) do
		play_animation(target.square_id, hash("buttonSquare_darkblue_pressed"))
	end
end

local function random(max, fillrate)
	if math.random() > fillrate then return 0 end
	local n = 1
	for i=1,max-1 do
		n = n + math.random(0, 1)
	end
	return n
end

local function new_level(self, level, additional_delay)
	self.level = level
	self.board = {}
	self.numbers_left = 0
	for x=1,WIDTH do
		self.board[x] = {}
		for y=1,HEIGHT do
			local cell = { x = x, y = y, locked = false }
			self.board[x][y] = cell

			-- create the square and let it fall down to it's position
			local duration = 1
			local delay = math.random(1,10) * 0.05 + x * 0.05 + y * 0.1 + (additional_delay or 0)
			local to = vmath.vector3(140 + x * 48, 360 + y * 48, 1 - y / 10)
			cell.square_id = factory.create("#squarefactory", to + vmath.vector3(0, 1000, 0))
			go.animate(cell.square_id, "position", go.PLAYBACK_ONCE_FORWARD, to, go.EASING_OUTBOUNCE, duration, delay)

			-- possibly assign a number
			local number = random(4, 0.5)
			if level <= #LEVELS then
				number = LEVELS[level][x][y]
			end
			if number > 0 then
				cell.number = number
				self.numbers_left = self.numbers_left + 1
			end

			update_cell(cell, false)
		end
	end
end

local function end_level(board)
	local down = vmath.vector3(0, 1000, 0)
	for x=1,WIDTH do
		for y=1,HEIGHT do
			local cell = board[x][y]
			local duration = 0.5
			local delay = math.random(1,10) * 0.05 + x * 0.05 + y * 0.1
			local to = go.get_position(cell.square_id) - down
			go.animate(cell.square_id, "position", go.PLAYBACK_ONCE_FORWARD, to, go.EASING_INQUAD, duration, delay, function()
				go.delete(cell.square_id)
			end)
		end
	end
end

function init(self)
	msg.post(".", "acquire_input_focus")
	msg.post("@render:", "clear_color", { color = vmath.vector4(0.15, 0.15, 0.15, 1.0) })
	math.randomseed(os.time())
	new_level(self, 1)
end

function on_message(self, message_id, message, sender)
	-- keep track of which cell we're currently pointing at
	if message_id == hash("trigger_response") then
		if message.enter then
			self.over_id = message.other_id
		elseif self.over_id == message.other_id then
			self.over_id = nil
		end
	elseif message_id == hash("restart") then
		end_level(self.board)
		new_level(self, self.level, 2)
	end
end

function on_input(self, action_id, action)
	-- move the cursor
	go.set_position(vmath.vector3(action.x, action.y, 0))

	-- handle clicks
	if action_id == hash("touch") and action.released then
		-- get which cell we clicked on
		local current = find_cell(self.board, self.over_id)
		if self.selected_id then
			-- get the cell that the user has selected to move
			local selected = find_cell(self.board, self.selected_id)
			
			-- deselect if clicking on the same as the selected cell
			if selected == current then
				reset_targets(self.board, selected)
				update_cell(selected, false)
				self.selected_id = nil
			-- deselect and select a new one
			elseif not current.locked and current.number then
				reset_targets(self.board, selected)
				update_cell(selected, false)
				self.selected_id = self.over_id
				update_cell(current, true)
				highlight_targets(self.board, current)
			-- try to move the selected cell to the one we clicked on
			else
				local targets = find_targets(self.board, selected)
				for _,target in ipairs(targets) do
					if target == current then
						reset_targets(self.board, selected)
						self.selected_id = nil
						target.number = selected.number
						target.locked = true
						selected.number = nil
						go.set_position(go.get_position(target.square_id), target.number_id)
						update_cell(selected, false)
						update_cell(target, false)
						self.numbers_left = self.numbers_left - 1
						if self.numbers_left == 0 then
							end_level(self.board)
							new_level(self, self.level + 1, 2)
						end
						break
					end
				end
			end
		-- clicked on a non-locked cell with a number
		elseif self.over_id and not current.locked and current.number then
			self.selected_id = self.over_id
			update_cell(current, true)
			highlight_targets(self.board, current)
		end
	end
end
The whole project code is on Björn GitHub page and if you want to give it a try, I would suggest to grab the Defold Editor 2, it’s still in beta but it features a dark interface and the capability of importing projects right from the disk.

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