Join tiles in Corona SDK into one word for a Breakout game grid?

MatrixLuaCoronasdkBreakout

Matrix Problem Overview


I have a game project to re-implement Breakout. I want to display two words, each word on a line. They are joined by the bricks block. Inside, the top line is the first name, aligned left. The bottom line is the last name, aligned right. They are input from textboxes, and rendered as shown:

As described above

Each second that passes, the screen will add a configurable number of bricks to the grid (for example, five bricks per second) until the two words appear complete. I displayed a letter of the alphabet which is created from the matrix(0,1).

...But I don’t know how to join them into one word. How can I join these letters?

This is what I've gotten so far:

###Bricks.lua

local Bricks = display.newGroup() -- static object
local Events = require("Events")
local Levels = require("Levels")
local sound = require("Sound")
local physics = require("physics")
local Sprites = require("Sprites")
local Func = require("Func")


local brickSpriteData = 
{
	{
		name = "brick",
		frames = {Sprites.brick}
	},

	{
		name = "brick2",
		frames = {Sprites.brick2}
	},

	{
		name = "brick3",
		frames = {Sprites.brick3}
	},

}

-- animation table
local brickAnimations = {}

Sprites:CreateAnimationTable
{
	spriteData = brickSpriteData,
	animationTable = brickAnimations
}

-- get size from temp object for later use
local tempBrick = display.newImage('red_apple_20.png',300,500)
--local tempBrick = display.newImage('cheryGreen2.png',300,500)
local brickSize =
{
	width = tempBrick.width, 
	height = tempBrick.height
}
--tempBrick:removeSelf( )


----------------
-- Rubble -- needs to be moved to its own file
----------------

local rubbleSpriteData =
{
	{
		name = "rubble1",
		frames = {Sprites.rubble1}
	},

	{
		name = "rubble2",
		frames = {Sprites.rubble2}
	},

	{
		name = "rubble3",
		frames = {Sprites.rubble3}
	},

	{
		name = "rubble4",
		frames = {Sprites.rubble4}
	},

	{
		name = "rubble5",
		frames = {Sprites.rubble5}
	},

}

local rubbleAnimations = {}
Sprites:CreateAnimationTable
{
	spriteData = rubbleSpriteData,
	animationTable = rubbleAnimations
}

local totalBricksBroken = 0 -- used to track when level is complete
local totalBricksAtStart = 0

-- contains all brick objects
local bricks = {}


local function CreateBrick(data)

	-- random brick sprite
	local obj = display.newImage('red_apple_20.png')
	local objGreen = display.newImage('cheryGreen2.png')
	obj.name = "brick"
	obj.x = data.x --or display.contentCenterX
	obj.y = data.y --or 1000
	obj.brickType = data.brickType or 1
	obj.index = data.index

	function obj:Break()
	
		totalBricksBroken =  totalBricksBroken + 1
		bricks[self.index] = nil
		obj:removeSelf( )
		sound.play(sound.breakBrick)

	end

	function obj:Update()
		if(self == nil) then
			return
		end 

		if(self.y > display.contentHeight - 20) then
			obj:Break()
		end 
	end 
	if(obj.brickType ==1) then
		physics.addBody( obj, "static", {friction=0.5, bounce=0.5 } )
	elseif(obj.brickType == 2) then
	 	physics.addBody( objGreen,"static",{friction=0.2, bounce=0.5, density = 1 } )
	end 

	return obj
end

local currentLevel = testLevel
-- create level from bricks defined in an object
-- this allows for levels to be designed
local function CreateBricksFromTable(level)

	totalBricksAtStart = 0
	local activeBricksCount = 0
	for yi=1, #level.bricks do
		for xi=1, #level.bricks[yi] do
			-- create brick?
			if(level.bricks[yi][xi] > 0) then
				local xPos
				local yPos
				if(level.align == "center") then
					--1100-((99*16)*0.5)
					xPos = display.contentCenterX- ((level.columns * brickSize.width) * 0.5/3) + ((xi-1) * level.xSpace)--display.contentCenterX 
					--xPos = 300 +(xi * level.xSpace)
					yPos = 100 + (yi * level.ySpace)--100
				else
					xPos = level.xStart + (xi * level.xSpace)
					yPos = level.yStart + (yi * level.ySpace)
				end

				local brickData = 
		  		{
			 		x = xPos,
					y = yPos,
					brickType = level.bricks[yi][xi],
					index = activeBricksCount+1
				}
				bricks[activeBricksCount+1] = CreateBrick(brickData)
			
				activeBricksCount = activeBricksCount + 1

			end

		end 

	end
	
	totalBricks = activeBricksCount
	totalBricksAtStart = activeBricksCount


end

-- create bricks for level --> set from above functions, change function to change brick build type
local CreateAllBricks = CreateBricksFromTable
-- called by a timer so I can pass arguments to CreateAllBricks
local function CreateAllBricksTimerCall()
	CreateAllBricks(Levels.currentLevel)
end 
-- remove all brick objects from memory
local function ClearBricks()

	for i=1, #bricks do
		bricks[i] = nil
	end

end
-- stuff run on enterFrame event
function Bricks:Update()

-- update individual bricks
	if(totalBricksAtStart > 0) then
		for i=1, totalBricksAtStart do
			-- brick exists?
			if(bricks[i]) then
				bricks[i]:Update()
			end 
		end 
	end
	-- is level over?
	if(totalBricksBroken == totalBricks) then
		Events.allBricksBroken:Dispatch()
	end

end
----------------
-- Events
----------------
function Bricks:allBricksBroken(event)
	-- cleanup bricks
	ClearBricks()
	local t = timer.performWithDelay( 1000, CreateAllBricksTimerCall)
	--CreateAllBricks()
	totalBricksBroken = 0		
	
	-- play happy sound for player to enjoy
	sound.play(sound.win)

	print("You Win!")
end
Events.allBricksBroken:AddObject(Bricks)
CreateAllBricks(Levels.currentLevel)
return Bricks

###Levels.lua

local Events = require("Events")
local Levels = {}
local function MakeLevel(data)
	local level = {}
	level.xStart = data.xStart or 100
	level.yStart = data.yStart or 100
	level.xSpace = data.xSpace or 23
	level.ySpace = data.ySpace or 23
	level.align = data.align or "center"
	level.columns = data.columns or #data.bricks[1]
	level.bricks = data.bricks --> required
	return level
end
Levels.test4 = MakeLevel
{
	bricks =
	{
		{0,2,0,0,2,0,0,2,0},
		{0,0,2,0,2,0,2,0,0},
		{0,0,0,0,2,0,0,0,0},
		{1,1,2,1,1,1,2,1,1},
		{0,0,0,0,1,0,0,0,0},
		{0,0,0,0,1,0,0,0,0},
		{0,0,0,0,1,0,0,0,0},
	}
}

Levels.test5 = MakeLevel
{
	bricks =
	{		
        			{0,0,0,1,0,0,0,0},
				 	 {0,0,1,0,1,0,0,0},
				 	 {0,0,1,0,1,0,0,0},
				 	 {0,1,0,0,0,1,0,0},
				 	 {0,1,1,1,1,1,0,0},
				 	 {1,0,0,0,0,0,1,0},
				 	 {1,0,0,0,0,0,1,0},
				 	 {1,0,0,0,0,0,1,0},
				 	 {1,0,0,0,0,0,1,0}
	}
}
-- Levels.test6 = MakeLevel2
-- {
-- 	bricks =
-- 	{
----A 		  "a" = {{0,0,0,1,0,0,0,0},
-- 				 	 {0,0,1,0,1,0,0,0},
-- 				 	 {0,0,1,0,1,0,0,0},
-- 				 	 {0,1,0,0,0,1,0,0},
-- 				 	 {0,1,1,1,1,1,0,0},
-- 				 	 {1,0,0,0,0,0,1,0},
-- 				 	 {1,0,0,0,0,0,1,0},
-- 				 	 {1,0,0,0,0,0,1,0},
-- 				 	 {1,0,0,0,0,0,1,0}},
----B
-- 		      "b" = {{1,1,1,1,0,0,0},
-- 				 	 {1,0,0,0,1,0,0},
-- 				 	 {1,0,0,0,1,0,0},
-- 				 	 {1,0,0,0,1,0,0},
-- 				 	 {1,1,1,1,0,0,0},
-- 				 	 {1,0,0,0,1,0,0},
-- 				 	 {1,0,0,0,0,1,0},
-- 				 	 {1,0,0,0,0,1,0},
-- 				 	 {1,1,1,1,1,0,0}},
--...........
--.......
--...
-- --Z
-- 		 	   "z"= {{1,1,1,1,1,1,1,0},
-- 				 	 {0,0,0,0,0,1,0,0},
-- 				 	 {0,0,0,0,1,0,0,0},
-- 				 	 {0,0,0,0,1,0,0,0},
-- 				 	 {0,0,0,1,0,0,0,0},
-- 				 	 {0,0,1,0,0,0,0,0},
-- 				 	 {0,0,1,0,0,0,0,0},
-- 				 	 {0,1,0,0,0,0,0,0},
-- 				 	 {1,1,1,1,1,1,1,0}}	
-- 	}
-- }
-- stores all levels in ordered table so that one can be selected randomly by index
Levels.levels = 
{
	--Levels.test4,
	 Levels.test5
	-- Levels.test6,
}
function Levels:GetRandomLevel()
	return self.levels[math.random(#Levels.levels)]
end
Levels.notPlayedYet = {}
Levels.currentLevel = Levels:GetRandomLevel()
-- Events
function Levels:allBricksBroken(event)
	self.currentLevel = Levels:GetRandomLevel()
end
Events.allBricksBroken:AddObject(Levels)
return Levels

The work I've done thus far (same as above) as an external download: http://www.mediafire.com/download/1t89ftkbznkn184/Breakout2.rar

Matrix Solutions


Solution 1 - Matrix

In the interest of actually answering the question:

I'm not 100% sure what you mean by "How can I join these letters", but from poking through the code I have a guess, so please clarify on whether it is accurate, or if I am wrong about what you wanted.

Scenario 1

You haven't successfully achieved the image illustrated in the screenshot - you've been able to draw one letter, but not multiple ones.

In this case, you'll need to have a better understanding of what your code is doing. The CreateBricksFromTable function takes in a Level object, which is created by the MakeLevel function from a table with a bricks property, which is a table of tables that represent rows with columns in them, showing what type of brick should be at each position. In your commented-out level, you have created an table where the bricks field contains a field for each letter, but the MakeLevel function still expects a bricks field that directly contains the grid of blocks. You will have to - as it seems you attempted - create a MakeWordLevel function (or the like) that takes this letter list, and a word for each line, and constructs a larger grid by copying the appropriate letters into it.

StackOverflow is not your programming tutor, and an SO question is not the right forum for having people write code for you or getting into step-by-step details of how to do this, but I'll leave you a basic outline. Your function would look something like this:

local function MakeWordLevel(data, line1, line2)
    local level = {}
    ...
    return level
end

And then would have to:

  • Populate all of the same properties that MakeLevel does
  • Calculate how wide (level.columns) the level should be with all the letters
  • Create a table in the same format as the bricks properties, but big enough to hold all of the letters
  • Go through the input strings (line1 and line2), find the correct letter data from what is now the test6 array, and copy that data into the large table
  • Assign that table as level.bricks

This question already is a bit outside of what StackOverflow is intended for in that it asks about how to implement a feature rather than achieve a small, specific programming task, so any further followup should take place in a chatroom - perhaps the Hello World room would be helpful.

Scenario 2:

This was my original guess, but after considering and reading past edits, I doubt this is answering the right question

You may want a solid "background" of, say, red blocks, surrounding your letters and making the field into a solid "wall", with the name in a different color. And you may want these bricks to slowly show up a few at a time.

In that case, the main thing you need to do is keep track of what spaces are "taken" by the name bricks. There are many ways to do this, but I would start with a matrix to keep track of that - as big as the final playing field - full of 0's. Then, as you add the bricks for the name, set a 1 at the x,y location in that matrix according to that block's coordinate.

When you want to fill in the background, each time you go to add a block at a coordinate, check that "taken" matrix before trying to add a block - if it's taken (1), then just skip it and move onto the next coordinate.

This works if you're filling in the background blocks sequentially (say, left to right, top to bottom), or if you want to add them randomly. With random, you'd also want to keep updating the "taken" matrix so you don't try to add a block twice.

The random fill-in, however, presents its own problem - it will keep taking longer to fill in as it goes, because it'll find more and more "taken" blocks and have to pick a new one. There are solutions to this, of course, but I won't go too far down that road when I don't know if that's even what you want.

Solution 2 - Matrix

I don't really understand (or read, for that matter) your code but from what I see joining them into complete words is easy. You have two possibilities.

You can "render" them directly into your level/display data, simply copy them to the appropriate places, like this:

-- The level data.
local level = {}

-- Create the level data.
for row = 1, 25, 1 do
	local rowData = {}

	for column = 1, 80, 1 do
		rowData[column] = "."
	end

	level[row] = rowData
end

-- Now let us setup the letters.
local letters = {
	A = {
		{".",".",".","#",".",".",".","."},
		{".",".","#",".","#",".",".","."},
		{".",".","#",".","#",".",".","."},
		{".","#",".",".",".","#",".","."},
		{".","#","#","#","#","#",".","."},
		{"#",".",".",".",".",".","#","."},
		{"#",".",".",".",".",".","#","."},
		{"#",".",".",".",".",".","#","."},
		{"#",".",".",".",".",".","#","."}
	},
	B = {
		{"#","#","#","#",".",".","."},
		{"#",".",".",".","#",".","."},
		{"#",".",".",".","#",".","."},
		{"#",".",".",".","#",".","."},
		{"#","#","#","#",".",".","."},
		{"#",".",".",".","#",".","."},
		{"#",".",".",".",".","#","."},
		{"#",".",".",".",".","#","."},
		{"#","#","#","#","#",".","."}
	}
}

-- The string to print.
local text = "ABBA"

-- Let us insert the data into the level data.
for index = 1, #text, 1 do
	local char = string.sub(text, index, index)
	local charData = letters[char]

	local offset = index * 7

	for row = 1, 9, 1 do
		local rowData = charData[row]
	
		for column = 1, 7, 1 do
			level[row][offset + column] = rowData[column]
		end
	end
end

-- Print everything
for row = 1, 25, 1 do
	local rowData = level[row]

	for column = 1, 80, 1 do
		io.write(rowData[column])
	end
	print()

end

You save you letters in a lookup table and then copy them, piece by piece, to the level data. Here I replaced the numbers with dots and number signs to make it prettier on the command line.

Alternately to that you can also "render" the words into a prepared buffer and then insert that into the level data by using the same logic.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionnguyentrungkienView Question on Stackoverflow
Solution 1 - MatrixcincodenadaView Answer on Stackoverflow
Solution 2 - MatrixBobbyView Answer on Stackoverflow