I'm trying to create a break breaker game that contains brinks that can be hit twice before the disappear.
I have tried:
--FOR STRONGER DEFENDERS
for i = 1, len do
for j = 1, level_W do
if(level[i][j] == 2) then
local strong = display.newImage('images/strongdefender.png')
strong.name = 'strong'
strong.x = def_W * j - offset
strong.y = def_H * i
physics.addBody(strong, {density = 1, friction = 0, bounce = 0})
strong.bodyType = 'static'
strongs.insert(strongs, strong)
end
end
end
for i = 1, len do
for j = 1, level_W do
if(level[i][j] == 2) then
local defender = display.newImage('images/defender.png')
defender.name = 'defender'
defender.x = def_W * j - offset
defender.y = def_H * i
physics.addBody(defender, {density = 1, friction = 0, bounce = 0})
defender.bodyType = 'static'
end
end
end
level is a table which is filled with 0 and 2. 2 is where the defender image will be in the game.
My collision event is like so:
function onCollision(e)
if(e.other.name == 'defender' or e.other.name == 'strong' and (ball.x + ball.width * 0.5) < (e.other.x + e.other.width * 0.5)) then
xSpeed = -5
elseif(e.other.name == 'defender' or e.other.name == 'strong' and (ball.x + ball.width * 0.5) >= (e.other.x + e.other.width * 0.5)) then
xSpeed = 5
end
if(e.other.name == 'defender') then
audio.play(defencePop)
ySpeed = ySpeed * -1
e.other:removeSelf()
e.other = nil
defenders.numChildren = defenders.numChildren - 1
--SORT SCORE
score = score + 1
scoreNum.text = score * points
scoreNum:setReferencePoint(display.CenterLeftReferencePoint)
scoreNum.x = 54
elseif(e.other.name == 'strong') then
audio.play(defencePop)
ySpeed = ySpeed * -1
e.other:removeSelf()
e.other = nil
defenders.numChildren = defenders.numChildren - 1
--SORT SCORE
score = score + 1
scoreNum.text = score * points
scoreNum:setReferencePoint(display.CenterLeftReferencePoint)
scoreNum.x = 54
end
--defenders.numChildren < 0
if(strongs.numChildren < 0) then
bgAlert('win')
gameStatus = 'win'
end
end -- removeDefender
When the ball collides with the element, both of them disappear. How can I make one disappear at a time?
I would suggest you just put the strong on the screen and add an event listener to them the weaker brick is created when the collision occurs with the stronger brick. The idea is to remove the object and add a new one when the collision occurs.
First you would display the strong object and add them to physics. You would also add a local collision event listener to the object
for i = 1, len do
for j = 1, level_W do
if(level[i][j] == 2) then
local strong = display.newImage('images/strongdefender.png')
strong.name = 'strong'
strong.x = def_W * j - offset
strong.y = def_H * i
physics.addBody(strong, {density = 1, friction = 0, bounce = 0})
strong.bodyType = 'static'
strong.collision = onBrickCollision --onStrongCollision is the name of the collision handler function
strong:addEventListener("collision" , strong) --add collision listener
strongs.insert(strongs, strong)
end
end
end
The event listener would be like
function onBrickCollision(self , event)
if event.phase == "began" and event.other.name == "ball" then
if (ball.x + ball.width * 0.5) < (self.x + self.width * 0.5) then
xSpeed = -5
else
xSpeed = 5
end
if self.name == "strong" then
audio.play(defencePop)
ySpeed = ySpeed * -1
--Create defender on the position of strong and add it to physics
local defender = display.newImage('images/defender.png')
defender.name = 'defender'
set the position same as the object which is hit by ball
defender.x = self.x
defender.y = self.y
physics.addBody(defender, {density = 1, friction = 0, bounce = 0})
defender.bodyType = 'static'
defender.collision = onBrickCollision
defender:addEventListener("collision", defender)
--remove the strong brick
self:removeSelf()
self = nil
--SORT SCORE
score = score + 1
scoreNum.text = score * points
scoreNum:setReferencePoint(display.CenterLeftReferencePoint)
scoreNum.x = 54
elseif self.name == "defender" then
audio.play(defencePop)
ySpeed = ySpeed * -1
self:removeSelf()
self = nil
defenders.numChildren = defenders.numChildren - 1
--SORT SCORE
score = score + 1
scoreNum.text = score * points
scoreNum:setReferencePoint(display.CenterLeftReferencePoint)
scoreNum.x = 54
end
end
Hope the code is self explanatory :) Feel free to ask me if you have any further questions.
Related
I am creating a simple platformer with love2d in lua.
I want the player to stand on the ground so that it won't fall.
However I got some proablem that I cannot change the string of a table return from player.lua
(It is a table because the player.lua return m and the last sentance, and m is a table)
I tested that the isOnFloor function is work, but I just can't change the boolean in the player table.
Main.lua
local love = require("love")
local tileMapper = require("tile/tileMapper")
local player = require "player"
local isOnFloor = require("isOnFloor")
function love.load()
love.window.setMode(1080, 640)
love.window.setTitle("Simple Platformer")
tileMapper:spawn()
tiles = tileMapper.tiles
player:setValue()
love.keyboard.keyPressed = {}
end
function love.update(dt)
for i = 1, #tiles do
if isOnFloor(player.x, player.y, tiles[i].x, tiles[i].y, 32, 32 * 3, 72, 72) then
player.currentState = "ground" -- I wanna change it here but when I go back to
--player.lua and try to let it out put the self.currentState, nothing changed --
else
player.currentState = "air"
end
end
player:update(dt)
love.keyboard.keyPressed = {}
end
I try to print out the player.currentState the the line after I set the player.currentState = "ground". It printed out "ground"
But if I print it in player.lua, it is always "air"
player.lua(I didn't paste some of the code here)
m = {}
function m:setValue()
self.x = 400
self.y = 50
self.vtx = 0
self.y_input = 0
self.speed = 300
self.jumpForce = -800
self.gravity = 100
self.anim = {idle = {img = love.graphics.newImage("assets/Idle.png"), maxFrame = 10},
run = {img = love.graphics.newImage("assets/Run.png"), maxFrame = 11},
jump = {img = love.graphics.newImage("assets/Jump.png"), maxFrame = 0},
fall = {img = love.graphics.newImage("assets/Fall.png"), maxFrame = 0}}
self.currentAnim = nil
for i = 1, #self.anim do
self.anim[i]:setFilter("nearest", "nearest")
end
self.frame = 0
self.timer = 0
self.currentState = nil
end
function m:update(dt)
print(self.currentState)
---------------------- Player States Update ------------------------
self:getXInput()
if self.currentState == "ground" then
if self.vtx == 0 then
self.currentAnim = self.anim.idle
elseif not(self.vtx == 0) then
self.currentAnim = self.anim.run
end
elseif self.currentState == "air" then
self.y_input = self.y_input + self.gravity
if self.y_input > 0 then
self.currentAnim = self.anim.fall
elseif self.y_input < 0 then
self.currentAnim = self.anim.jump
end
end
------------------------ Anim --------------------
self:animUpdate(dt)
if love.keyboard.keyPressed["space"] == true then
self.y_input = self.jumpForce
end
self.x = self.x + self.speed * dt * self.vtx
self.y = self.y + self.y_input * dt
end
return m
If you have an idea of this porblem, please tell, thank you.
Since I have a collision check function in Lua:
function onCollision(obj1,obj2)
obj1x = obj1.left
obj1y = obj1.top
obj1w = obj1.width
obj1h = obj1.height
obj2x = obj2.left
obj2y = obj2.top
obj2w = obj2.width
obj2h = obj2.height
if obj2x + obj2w >= obj1x and obj2y + obj2h >= obj1y and obj2y <= obj1y + obj1h and obj2x <= obj1x + obj1w then
return true
end
end
And I did make some panels as bricks using array table on my form, with this function, I did collision check between ball with each form sides without problems.
function createBricks()
for row = 1, brickRows do
bricks[row] = {}
for col = 1, brickColumns do
local x = (col - 1) * (width + gap) -- x offset
local y = (row - 1) * (height + gap) -- y offset
local newBrick = createPanel(gamePanel)
newBrick.width = brickWidth
newBrick.height = brickHeight
newBrick.top = y + 15
newBrick.left = x + 15
newBrick.BorderStyle = 'bsNone'
if level == 1 then newBrick.color = '65407' -- green
elseif level == 2 then newBrick.color = '858083' -- red
elseif level == 3 then newBrick.color = '9125192' -- brown
elseif level == 4 then newBrick.color = math.random(8,65255) end
bricks[row][col] = newBrick
end
end
end
Next how to detect if the ball collided with the bricks?. So far I did:
for row = 1, brickRows do
bricks[row] = {}
for col = 1, brickColumns do
dBrick = bricks[row][col]
if onCollision(gameBall,dBrick) then
dBrick.destroy() -- destroy the collided brick
end
end
end
I want to learn how to implement this collision logic in VB Net script which VB script easier for me, I did the whole game project using VB Net, now I try to re-write the project using CE Lua.
Private brickArray(brickRows, brickColumns) As Rectangle
Private isBrickEnabled(brickRows, brickColumns) As Boolean
For rows As Integer = 0 To brickRows
For columns As Integer = 0 To brickColumns
If Not isBrickEnabled(rows, columns) Then Continue For
If gameBall.IntersectsWith(brickArray(rows, columns)) Then
isBrickEnabled(rows, columns) = False
If gameBall.X + 10 < brickArray(rows, columns).X Or _
gameBall.X > brickArray(rows, columns).X + brickArray(rows, columns).Width _
Then
xVel = -xVel
Else
yVel = -yVel
End If
End If
Next
Next
And also this private sub, how to write it CE Lua?
Sub loadBricks()
Dim xOffset As Integer = 75, yOffset As Integer = 100
For row As Integer = 0 To brickRows
For column As Integer = 0 To brickColumns
brickArray(row, column) = New Rectangle(xOffset, yOffset, brickWidth, brickHeight)
xOffset += brickWidth + 10
isBrickEnabled(row, column) = True
Next
yOffset += brickHeight + 10
xOffset = 75
Next
End Sub
Function getBrickCount() As Integer
Dim Count As Integer = 0
For Each brick As Boolean In isBrickEnabled
If brick = True Then Count += 1
Next
Return Count
End Function
function onCollision(obj1,obj2)
obj1x = obj1.left
obj1y = obj1.top
obj1w = obj1.width
obj1h = obj1.height
obj2x = obj2.left
obj2y = obj2.top
obj2w = obj2.width
obj2h = obj2.height
if obj2x + obj2w >= obj1x and obj2y + obj2h >= obj1y and obj2y <= obj1y + obj1h and obj2x <= obj1x + obj1w then
return true
end
end
Then to detect collision the collision and remove from the table:
-- Drawback table
local function tcount( t )
local c = 0
for k,v in pairs(t) do
c = c + 1
end
return c
end
local count = #brickArray
for x = 1, count do
if onCollision(gameBall, brickArray[x]) then
if gameBall.Left + 10 < brickArray[x].Left or gameBall.Left > brickArray[x].Left + brickArray[x].Width then
xVel = -xVel else yVel = -yVel
end
playSound(findTableFile('strikeball.wav'))
brickArray[x] = brickArray[count]
brickArray[x] = x
brickArray[count] = nil
brickArray[x].Visible = false
tcount(brickArray)
end
end
The code above detected the collision and remove the object from the table, but that is not removed from display. How to remove the bricks from the table and display, using Cheat Engine Lua script?.
So I have this module, where all of its activity during the game is in. In t.physics I add a collision event listener (differentiating if target is a group or a single object). When the concerning objects detect a collision though, the property col of the other object (event.other) seems to be nil, although I initially set it to a string representing a color in t.create. I just can't find the cause for that, can anyone?
Thanks for your help.
Greetings, Nils
local fence = require("lib.fence")
local physics = require("physics")
local t = {}
local stages = {yellow = 1, lila = 1, red = 1}
local sizes = {1, 3.625, 7.25}
t.colors = {"yellow", "lila", "red"}
t.growing = false
t.setSize = function(fill)
local tHeight = fill.contentHeight * sizes[stages[fill.col]]
local tScale = tHeight / fill.contentHeight
fill.yScale = tScale
end
t.grow = function(group, color, hero)
local counter = 0
stages[color] = stages[color] + 1
for i = 1, group.numChildren, 1 do
if group[i].col == color then
counter = counter + 1
local function newPhysics() t.physics(group) end
if counter == 1 then
local function reset() t.growing = false if stages[color] == 3 then stages[color] = 1; newPhysics(); end end
local function start() t.growing = true end
transition.to(group[i], {time = 260, yScale = sizes[stages[color]], onStart = start, onComplete = reset})
else
transition.to(group[i], {time = 250, yScale = sizes[stages[color]], onStart = start})
end
end
end
end
t.physics = function(target)
if target.numChildren == nil then
physics.removeBody(target)
local function add()
physics.addBody( target, "static", {isSensor = true} )
target.collision = function(self, event)
if event.phase == "began" then
target.count = target.count + 1
if target.count == 1 then
t.grow(target.parent, self.col, event.other)
end
elseif event.phase == "ended" then
target.count = 0
end
end
end
timer.performWithDelay(1, add, 1)
else
for i = 1, target.numChildren, 1 do
physics.removeBody( target[i] )
physics.addBody( target[i], "static", {isSensor = true} )
target[i].name = "fill"
local fill = target[i]
fill.count = 0
fill.collision = function(self, event)
if event.phase == "began" then
self.count = self.count + 1
if self.count == 1 and event.other.x ~= nil then
t.grow(target, self.col, event.other)
end
else
fill.count = 0
end
end
fill:addEventListener("collision")
end
end
end
t.setColor = function(fill)
local colors = {
{238 / 255, 228 / 255, 28 / 255},
{38 / 255, 33 / 255, 77 / 255},
{175 / 255, 24 / 255, 52 / 255},
}
local names = {"yellow", "lila", "red"}
local r = math.random(3)
fill.fill = colors[r]
fill.col = names[r]
end
t.create = function(fences, group, colors)
local fills = {}
for i = 1, #fences, 1 do
local rCol = math.random(3)
local col
if rCol == 1 then
col = colors.yellow
elseif rCol == 2 then
col = colors.lila
else
col = colors.red
end
fills[i] = display.newRect(
group, fences[i].x + fences[i].contentWidth * 0.125, fences[i].y,
fences[i].contentWidth * 0.9, (fences[i].contentHeight * 0.5 / 3)
)
fills[i].dPosX = fills[i].x
fills[i].y = display.contentHeight- fills[i].contentHeight / 2
fills[i].fill = col
fills[i].col = t.colors[rCol]
fills[i].increased = false
end
return fills
end
t.move = function(fills, fences, group)
for i = 1, #fills, 1 do
local fill = fills[i]
function fill:enterFrame()
self:translate(fence.speed, 0)
if t.growing == false then
t.setSize(self)
end
if self.x > display.contentWidth + 0.55 * fences[i].contentWidth then
local xT = {}
for i = 1, group.numChildren, 1 do
xT[i] = group[i].x
end
local function compare(a, b) return a < b end
table.sort(xT, compare)
self.x = xT[1] - fences[i].contentWidth * 0.98
t.setColor(self)
local function newPhysics() t.physics(self) end
timer.performWithDelay( 25, newPhysics, 1 )
self:toBack()
end
end
Runtime:addEventListener("enterFrame", fill)
end
end
return t
Solved. Ugh, sorry, I forgot to define the property on the other object involved (hero), that has its own module. What a stupid slip.
Thanks for your answers anyways!
You don't seem to have any dynamic bodies here. What is colliding with what? Could it be that the other object involved in the collision (the value of event.other) is not something initialized in t.create() and so doesn't have the col property?
From the Corona documentation on Collision Detection:
Some body types will — or will not — collide with other body types. In a collision between two physical objects, at least one of the objects must be dynamic, since this is the only body type which collides with any other type.
Also, in your fill.collision(), I think you want to pass event.target as the first argument to t.grow() rather than target. If you try things, please update the question with more information.
The code is for a simple snake clone and I don't want to let the snake me able to go left if it's going right already.
It works if I just press LEFT when going RIGHT but if I for example presses UP then LEFT within the time frame it starts to move left.
function self.update(dt)
if love.keyboard.isDown(self.left) and self.prevvelocity.x ~= 1 then
self.velocity.x = -1
self.velocity.y = 0
end
if love.keyboard.isDown(self.right) and self.prevvelocity.x ~= -1 then
self.velocity.x = 1
self.velocity.y = 0
end
if love.keyboard.isDown(self.up) and self.prevvelocity.y ~= 1 then
self.velocity.x = 0
self.velocity.y = -1
end
if love.keyboard.isDown(self.down) and self.prevvelocity.y ~= -1 then
self.velocity.x = 0
self.velocity.y = 1
end
if self.timeSinceLastMove < self.speedinverted then
self.timeSinceLastMove = self.timeSinceLastMove + dt
else
table.remove(self.tail, 1)
tail = { x = self.position.x, y = self.position.y }
table.insert(self.tail, tail)
self.position.x = self.position.x + self.velocity.x * tileSize
self.position.y = self.position.y + self.velocity.y * tileSize
self.prevvelocity = self.velocity
self.timeSinceLastMove = 0;
end
end
function self.update(dt)
if love.keyboard.isDown(self.left) and self.prevvelocity.x ~= 1 then
self.velocity.x = -1
self.velocity.y = 0
end
if love.keyboard.isDown(self.right) and self.prevvelocity.x ~= -1 then
self.velocity.x = 1
self.velocity.y = 0
end
if love.keyboard.isDown(self.up) and self.prevvelocity.y ~= 1 then
self.velocity.x = 0
self.velocity.y = -1
end
if love.keyboard.isDown(self.down) and self.prevvelocity.y ~= -1 then
self.velocity.x = 0
self.velocity.y = 1
end
self.timeSinceLastMove = self.timeSinceLastMove + dt
if self.timeSinceLastMove >= self.speedinverted then
self.timeSinceLastMove = self.timeSinceLastMove - self.speedinverted
self.position.x = self.position.x + self.velocity.x * tileSize
self.position.y = self.position.y + self.velocity.y * tileSize
table.remove(self.tail, 1)
local head = { x = self.position.x, y = self.position.y }
table.insert(self.tail, head)
self.prevvelocity = { x = self.velocity.x, y = self.velocity.y }
end
end
Basically what happens is objects spawn off screen at random positions and then flow in and out of the screen view.
as they flow of screen they reset at a random position off screen again, however I cannot get that to happen if the player collides with it.
So to summarise, how would I make the object position respawn off screen again on collision with player?
Heres the object code.
UFO = display.newImage("ufo.png")
UFO.name = "UFO"
UFO.x = 640
UFO.y = 100
UFO.speed = math.random(2,6)
UFO.initY = UFO.y
UFO.amp = math.random(20,100)
UFO.angle = math.random(1,360)
physics.addBody(UFO, "static")
function moveUFO(self,event)
if self.x < -50 then
self.x = math.random(500,1500)
self.y = math.random(90,220)
self.speed = math.random(2,6)
self.amp = math.random(20,100)
self.angle = math.random(1,360)
else
self.x = self.x - self.speed
self.angle = self.angle + .1
self.y = self.amp*math.sin(self.angle)+self.initY
end
Here is the code for collision detection
function ship:collision(event)
if (event.other.name == 'UFO') then
event.other:removeSelf(self)
scoreAnim = display.newText('+10', ship.x, ship.y-10, native.systemFontBold, 16)
transition.to(scoreAnim, {time = 1000, y = scoreAnim.y - 30, alpha = 0, onComplete = function() display.remove(scoreAnim) scoreAnim = nil end})
scoreAnim:setTextColor(0,255,12)
--increases score
collectedN.text = tostring(tonumber(collectedN.text) + 1)
ship:addEventListener("collision", onCollision, ship, addTime)
If I didn't misunderstand you don't know about collision detection. You should study this page:http://developer.coronalabs.com/content/game-edition-collision-detection
edit part:
function ship:collision(event)
if (event.other.name == 'UFO') then
timer.performWithDelay( 50, function() event.other.x = math.random( 0, 320 ); event.other.y = math.random( 0.480 ); end, 1 )
scoreAnim = display.newText('+10', ship.x, ship.y-10, native.systemFontBold, 16)
transition.to(scoreAnim, {time = 1000, y = scoreAnim.y - 30, alpha = 0, onComplete = function() display.remove(scoreAnim) scoreAnim = nil end})
scoreAnim:setTextColor(0,255,12)
--increases score
collectedN.text = tostring(tonumber(collectedN.text) + 1)
This will do it.. You can modify random values over there. And you couldn't move your object right in collision time, because Corona physics, lock all physics objects in collision time. So you should move your objects right after collision.