Balloon game with Corona SDK - ios

I am totally new to game development for iPhone/iPad.
I have got my code working and all the 10 balloons are floating in the air but I have a few questions:
The balloons should be in the sequence or random order. They move the tendon to the edge and then the player should move back the balloons to the right place with the mouse. How?
What are the right dimensional numbers (x, y) so my balloons are equally displayed and positioned on the screen?
My random function keeps popping out more balloons by simple click.
I would like the user to perform some math operations, for instance add two random balloons and display the right answer on the screen so the result can move back to the right edge of balloon placement. how to code this? How can I use 2 different level of difficulties? (L1, L2)
How to make my balloons to move to the different edges on the screen?
How can a user move back the balloons with mouse to the right places?
How can I tie my balloons to a rope (horizontally)? so the user can make a choice.
My background image is about 3MB original(1024 x 768) to match well with iPad resolution, can I change the size without affecting the display in iPad?
I feel like the local balloon1, 2, 3, is repeated too much, and same goes to moveBalloon and applyLinear. Is there a way of shortening them? or is it normal since there are 10 balloons?
I have added sound to the first balloon by simple click, should duplicate the same function for the rest of the 9 balloons (another mess)? I will use the same sound to all.
Your feedback is much appreciated.

If you want multiple balloons, it would be MUCH MUCH easier to use a table. You can have as many baloons as you want with very little effort.
Balloons = {} -- track all baloons
Function addBalloon(x,y,xVel,yVel)
Tab = {x = x, y = y, vel = {x = xVel, y = yVel}}
Table.insert(balloons,tab)
End
Function moveAllBalloons()
For_,i in pairs(balloons) do
i.x = i.x + i.vel.x
i.y = i.y + i.vel.y
End
End
Function isPlaying
For _,i in pairs(balloons)
If --[[mouse.x]] <= i.x - (balloon.width/2) and --[[other parameters here]] then
PlaySound
End
End
End
for different difficulties, you can do something like
if L1 then
Num1 = math.random(3,15)
Num2 = math.random(3,15
OpFind = math.random(3)
If opfind == 1 then
Operation = "+"
Elseif opfind == 2 then
Operation = "-"
Elseif opfind ==3 then
Operation = "*"
End
ElseIf L2 then
num1 = math.random(7,50)
Num2 = math.random(7,50)
OpFind = math.random(4)
If opfind == 1 then
Operation = "^"
Elseif opfind == 2 then
Operation = "%"
Elseif opfind ==3 then
Operation = "*"
Elseif opfind == 4 then
Operation == "/"
End
End

Related

Trying to write a recursive program that reveals all adjacent tiles that are blank

I'm trying to make a clone of minesweeper. In that game, there is a feature that, whenever you click an empty box, all adjacent empty tiles are revealed and empty tiles adjacent to those empty tiles are also revealed.
Right now when I tried to implement this, it only reveals the 8 adjacent tiles of the tile I clicked, not any other empty tiles which are next to the empty tiles revealed
Here is the code that I'm running right now (it has 2 parameters row and col):
local rowCords = {row-16, row, row+16}
local colCords = {col-16, col, col+16}
--Check surroundings
for r = 1, 3, 1 do
for c = 1, 3, 1 do
curRow = rowCords[r]
curCol = colCords[c]
if (curRow >= 16 and curRow <= 400 and curCol >= 16 and curCol <= 176) then
if boardCords[Board:getBox(curRow, curCol)].value == 1 then
boardCords[Board:getBox(curRow, curCol)].revealed = true
end
end
end
end
In your algorithm you are checking only 9 tiles, but you must do this recursively for checked tiles. So your algorithm must be like:
function revealTile(row, col)
if (row >= 16 and row <= 400 and col >= 16 and col <= 176) then
local tile = boardCords[Board:getBox(row, col)]
-- Try to reveal tile
if not tile.revealed and tile.value == 1 then
tile.revealed = true
-- Try to reveal surroundings
for r = row-16,row+16,16 do
for c = col-16,col+16,16 do
revealTile(r, c)
end
end
end
end
end

How to use bounding box in Love2d?

I've been using some extremely bulky code to detect collision between simple objects, and I've heard about bounding boxes. I can't find any tutorials on how to use it, so I'm asking about how to use it. Here is how I detect collision:
function platform.collision()
if player.x + player.width / 2 <= platform.x + platform.width and
player.x + player.width / 2 >= platform.x and
player.y + player.height <= platform.y + platform.height and
player.y + player.height >= platform.y then
The MDN has a rather concise article on 2D collision detection. Being the MDN, the examples are in javascript, but are easily translated to, and applicable in, any language - including Lua.
Let's take a look:
Axis-Aligned Bounding Box
One of the simpler forms of collision detection is between two rectangles that are axis aligned — meaning no rotation. The algorithm works by ensuring there is no gap between any of the 4 sides of the rectangles. Any gap means a collision does not exist.
Their example, translated to Lua:
local rect1 = { x = 5, y = 5, width = 50, height = 50 }
local rect2 = { x = 20, y = 10, width = 10, height = 10 }
if
rect1.x < rect2.x + rect2.width and
rect1.x + rect1.width > rect2.x and
rect1.y < rect2.y + rect2.height and
rect1.height + rect1.y > rect2.y
then
-- collision detected!
end
-- filling in the values =>
if
5 < 30 and
55 > 20 and
5 < 20 and
55 > 10
then
-- collision detected!
end
A live example, again in JavaScript, demonstrates this well.
Here's a quick (and imperfect) Love2D example you can throw into a main.lua and play around with.
local function rect (x, y, w, h, color)
return { x = x, y = y, width = w, height = h, color = color }
end
local function draw_rect (rect)
love.graphics.setColor(unpack(rect.color))
love.graphics.rectangle('fill', rect.x, rect.y,
rect.width, rect.height)
end
local function collides (one, two)
return (
one.x < two.x + two.width and
one.x + one.width > two.x and
one.y < two.y + two.height and
one.y + one.height > two.y
)
end
local kp = love.keyboard.isDown
local red = { 255, 0, 0, 255 }
local green = { 0, 255, 0, 255 }
local blue = { 0, 0, 255, 255 }
local dim1 = rect(5, 5, 50, 50, red)
local dim2 = rect(20, 10, 60, 40, green)
function love.update ()
if kp('up') then
dim2.y = dim2.y - 1
end
if kp('down') then
dim2.y = dim2.y + 1
end
if kp('left') then
dim2.x = dim2.x - 1
end
if kp('right') then
dim2.x = dim2.x + 1
end
dim2.color = collides(dim1, dim2) and green or blue
end
function love.draw ()
draw_rect(dim1)
draw_rect(dim2)
end
Oka explained it very well. This works for everything rectangular, not rotated and axis aligned. And you even already did it that way. This is great for buttons and the like!
But what I like doing is using (invisible) circles around objects and see if these collide. This works for everything where height is about the same as the width (which is the case for many sidescrolling platformers or top-down RPGs).
It's quite handy if you want to have the object centered at the current position. And it's especially helpful to simulate a finger on a touchscreen device, because a finger is quite a bit bigger than a mouse cursor. ;)
Here's an example on how to use this method. You can copy it as an actual game, it'll work.
--[[ Some initial default settings. ]]
function love.load()
settings = {
mouseHitbox = 5, -- A diameter around the mouse cursor.
-- For a finger (thouchscreen) this could be bigger!
}
objects = {
[1] = {
x = 250, -- Initial X position of object.
y = 200, -- Initial Y position of object.
hitbox = 100, -- A diameter around the CENTER of the object.
isHit = false -- A flag for when the object has been hit.
},
[2] = {
x = 400,
y = 250,
hitbox = 250,
isHit = false
}
}
end
--[[ This is the actual function to detect collision between two objects. ]]
function collisionDetected(x1,y1,x2,y2,d1,d2)
-- Uses the x and y coordinates of two different points along with a diameter around them.
-- As long as these two diameters collide/overlap, this function returns true!
-- If d1 and/or d2 is missing, use the a default diameter of 1 instead.
local d1 = d1 or 1
local d2 = d2 or 1
local delta_x = x2 - x1
local delta_y = y2 - y1
local delta_d = (d1 / 2) + (d2 / 2)
if ( delta_x^2 + delta_y^2 < delta_d^2 ) then
return true
end
end
--[[ Now, some LÖVE functions to give the collisionDetection() some context. ]]
function love.draw()
for i=1,#objects do -- Loop through all objects and draw them.
if ( objects[i].isHit ) then
love.graphics.setColor(255, 0, 0) -- If an object is hit, it will flash red for a frame.
objects[i].isHit = false
else
love.graphics.setColor(255, 255, 255)
end
love.graphics.circle("line", objects[i].x, objects[i].y, objects[i].hitbox/2)
end
end
-- You can use the following to check, if any object has been clicked on (or tapped on a touch screen device).
function love.mousepressed(x,y,button)
if ( button == 1 ) then
local i = objectIsHit(x,y) -- Check, if an object has been hit.
if ( i ) then
-- The object number 'i' has been hit. Do something with this information!
objects[i].isHit = true
end
end
end
function objectIsHit(x,y)
for i=1,#objects do -- Loop through all objects and see, if one of them has been hit.
if ( collisionDetected(x, y, objects[i].x, objects[i].y, settings.mouseHitbox, objects[i].hitbox) ) then
return i -- This object has been hit!
end
end
end
-- For the sake of completeness: You can use something like the following to check, if the objects themselves collide.
-- This would come in handy, if the objects would move around the screen and then bounce from each other, for example.
function love.update(dt)
if ( collisionDetected(objects[1].x, objects[1].y, objects[2].x, objects[2].y, objects[1].hitbox, objects[2].hitbox) ) then
-- The objects collided. Do something with this information!
end
end
As you can see, the collisionDetection() function is quite easy and intuitive to use.
Hopefully I could give you some more insight. And have fun with LÖVE 2D! :)

Lua: Making a collision system in a simple shooter and im having issues with removing the enemy object

I'm making a simple shooter in lua using love2d. For some reason when i launch the game the program thinks the enemy has been shot and doesn't spawn it. I think theres an issue on line 80. It seems to think enemy is nil at all times no matter what. I'm not getting any errors. Ill link to a pastebin with the code.
Edit: I've updated my code quite a bit and have solved the issue above. I think im checking for collision using the bounding box incorrectly. No matter where the bullet passes the enemy is never set to nil. I think it's because it checks with bullets.x instead of o.x but i cant check with o.x because its a local variable in the for loop earlier in the code.
http://pastebin.com/iwL0QHsc
Currently, your code does
if (CheckCollision) then
If you don't provide any parameters, it will check if the variable 'CheckCollision' exists. In this case, it does because you have declared it as a function on line 53, so every update 'enemy' will be set to nil.
if CheckCollision(x3,y3,x2,y2,w2,h2) then
Use this line but replace the variables with the variables of the respective entity/s.
Using this, you can use
if enemy then
In your draw call, which will check if 'enemy' exists.
Just by the way, in lua an if statement doesnt need to be within brackets.
if (x > 3) then
Functions exactly the same as
if x > 3 then
Edit:
In the new code you have provided, when you declare the function you are naming its arguments as variables that already exist. Usually, you put in some arbitrary variables you haven't used as arguments. Eg.
function test(a, b)
print(a + b)
end
Then to use it.
test(1, 2)
Or if you want to use variables.
var1 = 1
var2 = 2
test(var1, var2)
Using variables that already exist isn't too bad, it just means you can't use them. Using variables in a table, lua probably isn't too happy about.
So where you have
function CheckCollision(o.x,o.y,o.w,o.h, enemy.x,enemy.y,enemy.w,enemy.h)
return o.x < enemy.x+enemy.w and
enemy.x < o.x+o.w and
o.y < enemy.y+enemy.h and
enemy.y < o.y+o.h
end
Use something like this instead.
function CheckCollision(x1,y1,w1,h1, x2,y2,w2,h2)
return x1 < x2+w2 and
x2 < x1+w1 and
y1 < y2+h2 and
y2 < y1+h1
end
Alternatively, you could skip out on the parameters and have it hard coded.
function CheckCollision()
return o.x < enemy.x+enemy.w and
enemy.x < o.x+o.w and
o.y < enemy.y+enemy.h and
enemy.y < o.y+o.h
end
I'm not sure if this is the source of your error as I don't have access to a proper computer to try it but it is useful information anyway.
When you load/run a file in Lua, Lua looks through the whole file in a sequential manner once, so your line to check collisions only occurs upon main.lua's loading, never to be looked at again.
As your code stands now, it only checks the collision of the enemy and bullet once
if CheckCollision(enemy.x,enemy.y,enemy.w,enemy.h,bullets.x,bullets.y,bullets.w,bullets.h) then enemy = nil
end
If you put this into the love.update(dt) method, it will achieve your desired effect.
I'd like to note that once the enemy is set to nil (collision occurs), you will throw an error about attempting to index a nil value since your enemy variable is no longer a table.
Also noteworthy, these lines
bullets.x = o.x
bullets.y = o.y
in the for loop
for i, o in ipairs(bullets) do
cause your bullets to behave improperly (at least, I assume you don't wish for the behavior they have) Each time a new bullet is fired, it is added to the bullets table with the code
table.insert(bullets, {
x = player.x,
y = player.y,
dir = direction,
speed = 400
})
This puts each new table into the #bullets + 1 (the table's last index + 1) index of bullets. Since your for loop iterates over each bullet object in the bullets table, the last assignment that occurs is always on the last bullet in the table.
Let me try to explain this simpler.
Say a player fires two bullets. The first bullet firing will invoke the table.insert(...) call I mentioned before. So, our bullets table will look like this
bullets = {
x = 100,
y = 100, -- This is what you set player.x and player.y to in the start.
w = 15,
h = 15,
-- This is that new table we added - the 1st bullet fired.
{
-- This will all be inside it according to the table.insert(...) call.
x = 100, -- What player.x is equal to
y = 100, -- What player.y is equal to
dir = ... -- Who knows what it is, just some radians that you calculated.
speed = 400
}
}
Now, you used an ipairs(...) call which means that our for loop will only look at the tables inside bullets - smart thinking. But there is a problem with its implementation.
-- With our new table inside bullets, we will only have that table to look at for the entire loop. So, lets jump right into the loop implementation.
local i, o
for i, o in ipairs(bullets) do
-- This is fine. These lines look at the new table's x and y values and move them correctly.
o.x = o.x + math.cos(o.dir) * o.speed * dt
o.y = o.y + math.sin(o.dir) * o.speed * dt
-- This is the problem.
bullets.x = o.x -- Now, those x and y values in the bullets table are set to the new table's x and y values.
bullets.y = o.y
-- The rest of the loop works fine.
...
end
Now, for one new bullet, it works fine. Each update will update bullets.x and bullets.y correctly as the new bullet travels. But now lets considered the second bullet our player fired.
The new look of bullets is like this
bullets = {
x = 150, -- These are equal to the first bullet's values - for now, at least.
y = 150,
w = 15,
h = 15,
-- This 1st bullet is still here.
{
x = 150, -- Lets say the bullet has moved 50 pixels in both directions.
y = 150,
dir = ...
speed = 400
},
-- This is the new second bullet.
{
x = 100, -- Remember player.x and player.y are both 100
y = 100,
dir = ...
speed = 400
}
}
See where this is going yet? Lets jump to the for loop on the first iteration.
-- First iteration occurs. We're looking at the first bullet.
for i, o in ipairs(bullets) do
o.x = o.x + math.cos(o.dir) * o.speed * dt -- Lets say o.x = 160 now
o.y = o.y + math.sin(o.dir) * o.speed * dt -- and o.y = 160
bullets.x = o.x -- bullets.x = o.x, so bullets.x = 160
bullets.y = o.y -- bullets.y = o.y, so bullets.y = 160
...
end
But then we get to the second bullet...
-- Second iteration, second bullet.
for i, o in ipairs(bullets) do
-- Since it's the new table, o.x and o.y start at 100
o.x = o.x + math.cos(o.dir) * o.speed * dt -- Lets say o.x = 110
o.y = o.y + math.sin(o.dir) * o.speed * dt -- Lets say o.y = 110 as well
bullets.x = o.x
bullets.y = o.y
-- But now our bullets.x and bullets.y have moved to the new bullet!
-- The position of the 1st bullet is completely forgotten about!
...
end
And this is the problem. The way the loop is written currently, the program only cares about the most recently fired bullet because it is going to be placed last in the bullets table - it is checked and assigned to bullets.x and bullets.y last. This causes the collision check to only care if the most recently fired bullet is touching the enemy, none of the other ones.
There are two ways to fix this. Either evaluate the position of each bullet separately on collisions and add widths and heights to their tables, like this
-- When you add a bullet
table.insert(bullets, {
x = player.x,
y = player.y,
w = bullets.w,
h = bullets.h,
dir = direction,
speed = 400
})
-- When looking for collisions
local i, o
for i, o in ipairs(bullets) do
o.x = o.x + math.cos(o.dir) * o.speed * dt
o.y = o.y + math.sin(o.dir) * o.speed * dt
-- This will destroy an enemy correctly
if CheckCollision(enemy.x,enemy.y,enemy.w,enemy.h, o.x, o.y, o.w, o.h) then enemy = nil end
if (o.x < -10) or (o.x > love.graphics.getWidth() + 10)
or (o.y < -10) or (o.y > love.graphics.getHeight() + 10) then
table.remove(bullets, i)
end
end
This way you just move the collision checker's position to inside the loop and change its parameters.
The other way is to make class-like tables that can be "instantiated," whose objects' metatables point to the class-like table. Harder, but better practice and much easier to write methods and what not for. Makes generic inspections and evaluations of multiple players, enemies, bullets, etc. much easier as well.

Lua Love2d Write Code Instance Once, Use Multiple Times With Each One Being Unique

I have asked a question similar to this, but i was asking it for Processing.JS. Now i am making something out of LOVE2D Lua, what I'm trying to do is that i have a button where when clicked it adds a circle on-screen. I already have code that when i click and hold on the circle, i can move it around. But when i add a second circle, they both are using he same variables. I want it so i write once instance of the code to move and add the circle, but i can call it multiple times and each one be unique without writing code to anticipate an infinite amount of circles. Here is my code:
obn = 0
ellipsex = 50
ellipsey = 50
ellipsew = 50
ellipseh = 50
ellipser = 255
ellipseg = 0
ellipseb = 0
function love.draw()
mousex, mousey = love.mouse.getPosition()
for i=0,obn,1 do
ellipse()
end
end
function love.mousereleased(x, y, button)
if button == 2 then
obn = obn + 1
end
end
function love.update(dt)
if love.mouse.isDown(1) then
if mousex > ellipsex and mousex < ellipsex + ellipsew and mousey > ellipsey and mousey < ellipsey + ellipseh then
ellipsex = mousex
ellipsey = mousey
end
end
end
function ellipse()
love.graphics.setColor(ellipser, ellipseg, ellipseb)
love.graphics.ellipse("fill", ellipsex, ellipsey, ellipsew, ellipseh)
end
But when i right-click to add a circle(increment how many times the for-loop runs) it doesnt add a second circle for me to move independent from the first one. Help?
The way I would go about handling multiple instances of ellipses is creating a table for every ellipse that would hold it's properties and a draw function.
local ellipses = {} -- store all ellipses into a table
function create_ellipse(x,y,w,h,r,g,b)
local ellipse = {
x = x,
y = y,
w = w,
h = h,
r = r,
g = g,
b = b
}
function ellipse.draw()
love.graphics.setColor(ellipse.r,ellipse.g,ellipse.b)
love.graphics.ellipse("fill",ellipse.x,ellipse.y,ellipse.w,ellipse.h)
end
ellipses[#ellipses+1] = ellipse -- insert new ellipse into ellipses table
return ellipse
end
function love.draw()
for i = 1,#ellipses do
ellipses[i].draw(); -- call each ellipse's separate draw function
end
end
function love.mousereleased(x,y,button)
if button == 2 then
create_ellipse(x,y,50,50,255,0,0) -- bonus: every ellipse is created where the user clicked
end
end
function love.update(dt)
if love.mouse.isDown(1) then
local mousex,mousey = love.mouse.getPosition() -- there is no need to request the mouse position every frame, but only when a user clicks anywhere on the screen
for i = 1,#ellipses do
local current_ellipse = ellipses[i]
if mousex >= current_ellipse.x and mousex <= current_ellipse.x+current_ellipse.w and mousey >= current_ellipse.y and mousey <= current_ellipse.y+current_ellipse.h then
current_ellipse.x = mousex
current_ellipse.y = mousey
end
end
end
end
You could even make your own Ellipse class if you're into OOP.

Tile Collision Detection

So, I have been working on this game for a bit. However, over the past day I have not been able to figure out how to work my collision detection.
The scale at default is equal to 2.
The player is 41*scale by 64*scale.
My player is centered in the middle of the screen in both the x and y axis.
Since the player is centered the world is what moves, those variables are worldx and worldy. The player always stays at the center of the screen.
My tile map is stored in an array and is based on the image pixel color. If the pixel is white at map[x][y] the value is set to 0 else it's set to the block. Meaning the block does not get rendered.
for x = 0, w-1 do --scans the image and builds the map array
amap[x] = {}
for y = 0, h-1 do
local r, g, b, a = source:getPixel(x, y)
if r == 255 and g == 255 and b == 255 then
block = 0
end
if r == 255 and g == 100 and b == 0 then
block = 1
end
if r == 130 and g == 125 and b == 0 then
block = 2
end
if r == 76 and g == 76 and b == 76 then
block = 3
end
if r == 255 and g == 0 and b == 255 then
--this is the spawn pixel yet to build
end
amap[x][y] = block
end
end --end function
function that draws the map
for x = 0, w-1 do --draws the map
for y = 0, h-1 do
if amap[x][y] ~= 0 then
love.graphics.drawq(ImgBlocks, Blocks[amap[x][y]], 32*x*(3/bscale) + worldx, 32*y*(3/bscale) + worldy + jy, 0 , 3/bscale, 3/bscale)
end
if amap[x][y] == 4 then
end
end
end --end function
The function needs to return true or false base on if there is collision between player and block.
Your tiles are 32x32, correct? (from the drawq call) I would recommend you make a function that checks if a point is in a solid tile:
function pointCollisionTest(x, y)
-- find which tile the point is in
local tx, ty = math.floor(x / 32), math.floor(y / 32)
-- check the tile
if map[tx][ty] == solid then
return true
else
return false
end
end
You'll have to change the if map[x][y] == solid logic based on how you determine solid tiles, but this code should otherwise work.
Once you have point collision, the way you make the player collide is by checking each corner of its hitbox (which you should easily be able to determine) against this function whenever the player moves. There are a few ways to do this; I use the relatively simple method of calculating the player's new position, testing it, then canceling the move entirely if the collision test returns true. You have to check/cancel the x and y components of the move separately, though, so the player can move along walls instead of sticking to them.
Are you asking for a basic 2d collision detection?
A simplified formula:
if (playerx > blockminx) and (playery < blockmaxx) and (playery > blockminy) and (playery < blockmaxy) then collission

Resources