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?.
Related
I am trying to create a player in love2D, and I have a lerp function that brings the players speed to 0 , but I know I am not using the lerp function correctly because it never reaches the end value and starts acting funky and crazy, how do I use the lerp function correctly.
function love.load()
moon = require "Library/moon_light"
position = {x = 0, y = 0}
H = 0
V = 0
new_H = 0
new_V = 0
position["x"] = moon.Mid_point(0,0,1280,720)[1]
position["y"] = moon.Mid_point(0,0,1280,720)[2]
accel = 8
max_speed = 80
fps = 60
friction = 6
end
function love.update(dt)
if love.keyboard.isDown('escape') then
love.event.push('quit')
end
if love.keyboard.isDown("d") then
H = 1
elseif love.keyboard.isDown("a") then
H = -1
else
H = 0
end
if love.keyboard.isDown("w") then
V = -1
elseif love.keyboard.isDown("s") then
V = 1
else
V = 0
end
if H ~= 0 then -- use a new value and give it acceleration
new_H = H * accel * dt * fps
end
if H == 0 then -- Check if the player isnt moving lerp it to 0 so stopping the movement
new_H = moon.Lerp(new_H,0,friction * dt)
end
if V ~= 0 then
new_V = V * accel * dt * fps
end
if V == 0 then
new_V = moon.Lerp(new_V,0,friction * dt)
end
position["x"] = position["x"] + new_H -- Set the motion to the position
position["y"] = position["y"] + new_V
end
function love.draw()
love.graphics.rectangle("fill",position["x"] - 25,position["y"] - 25,50,50)
love.graphics.print("Horiztonal value : " .. H .. "\nVertical value : " .. V,100,400)
love.graphics.print("new_H value : " .. new_H .. "\nnew_V value : " .. new_V,100,440)
end
The lerp function, I think nothing is wrong with it, but just in case.
function moon_light.Lerp(start_v,end_v,percent)
return start_v + (end_v - start_v) * percent
end
EDIT I changed the lerp to be time based, from the suggestion and I also made a new variable called motion it seems setting the lerp to its self caused a weird issue, making it never reach 0:
if H ~= 0 then -- use a new value and give it acceleration
H_counter = 0
new_H = H * accel * dt * fps
motion_H = new_H
end
if H == 0 then -- Check if the player isnt moving lerp it to 0 so stopping the movement
if H_counter < slow_down_duration then
motion_H = moon.Lerp(new_H,0,H_counter/slow_down_duration)
H_counter = H_counter + dt
else
new_H = 0
motion_H = 0
end
end
if V ~= 0 then
V_counter = 0
new_V = V * accel * dt * fps
motion_V = new_V
end
if V == 0 then
if V_counter < slow_down_duration then
motion_V = moon.Lerp(new_V,0,V_counter/slow_down_duration)
V_counter = V_counter + dt
else
new_V = 0
motion_V = 0
end
end
position["x"] = position["x"] + motion_H -- Set the motion to the position
position["y"] = position["y"] + motion_V
i really hope im right here, as on a discord server no one wants to help me for some reason.
We run a Project for a game called Garry's Mod and currently try to get a "Toxic Gas" Script Working.
But we face the following issue
[ERROR] gamemodes/zombierp/plugins/toxicgas/sh_plugin.lua:44: attempt to index local 'item' (a boolean value)
1. IsEquippingGasmask - gamemodes/zombierp/plugins/toxicgas/sh_plugin.lua:44
2. v - gamemodes/zombierp/plugins/toxicgas/sh_plugin.lua:121
3. unknown - gamemodes/helix/gamemode/core/libs/sh_plugin.lua:477
And me being fairly new to Lua, im just completly confused and dont know how to fix it.
Here is the Full Script
local config = {
smokeColor = Color(63, 127, 0),
smokeAlpha = 110,
maskItem = "gasmask",
smokeSpawnerDistance = 100 -- distance between the smoke emitters on the box line
}
local PLUGIN = PLUGIN
PLUGIN.name = "Toxic Gas"
PLUGIN.author = ""
PLUGIN.description = ""
PLUGIN.positions = PLUGIN.positions or {}
PLUGIN.smokeStacks = PLUGIN.smokeStacks or {}
function PLUGIN:LoadData()
PLUGIN.positions = self:GetData()
self:UpdateWorldData()
end
function PLUGIN:SaveData()
self:SetData(PLUGIN.positions)
self:UpdateWorldData()
end
function PLUGIN:UpdateWorldData()
SetNetVar("toxicGasPositions", PLUGIN.positions)
-- global netvar doesn't seem to sync without this
for _, ply in pairs(player.GetAll()) do
ply:SyncVars()
end
end
function PLUGIN:IsEquippingGasmask(ply)
local character = ply:GetCharacter()
if not character then return false end
local inventoryID = character:GetInventory():GetID()
local inventory = ix.item.inventories[inventoryID]
for x, items in pairs(inventory.slots) do
for y, item in pairs(items) do
if item.uniqueID == config.maskItem
and item:GetData("equip") == true then
return true
end
end
end
return false
end
local function GetBoxLine(min, max)
local deltaX = math.abs(min.x - max.x)
local deltaY = math.abs(min.y - max.y)
local lineStart, lineEnd
if deltaX < deltaY then
lineStart = Vector(min.x + (max.x - min.x) / 2, min.y, min.z)
lineEnd = Vector(min.x + (max.x - min.x) / 2, min.y + (max.y - min.y), min.z)
else
lineStart = Vector(min.x, min.y + (max.y - min.y) / 2, min.z)
lineEnd = Vector(min.x + (max.x - min.x), min.y + (max.y - min.y) / 2, min.z)
end
return lineStart, lineEnd
end
if SERVER then
function PLUGIN:Think()
for idx, gasBox in pairs(PLUGIN.positions) do
if PLUGIN.smokeStacks[idx] == nil then
local min, max = gasBox.min, gasBox.max
local startSmoke, endSmoke = GetBoxLine(min, max)
PLUGIN.smokeStacks[idx] = {
count = math.floor(startSmoke:Distance(endSmoke) / config.smokeSpawnerDistance),
stacks = {}
}
for i = 1, PLUGIN.smokeStacks[idx].count do
local smoke = ents.Create("env_smokestack")
smoke:SetPos(startSmoke + (endSmoke - startSmoke):GetNormalized() * (i) * config.smokeSpawnerDistance)
smoke:SetKeyValue("InitialState", "1")
smoke:SetKeyValue("WindAngle", "0 0 0")
smoke:SetKeyValue("WindSpeed", "0")
smoke:SetKeyValue("rendercolor", tostring(config.smokeColor))
smoke:SetKeyValue("renderamt", tostring(config.smokeAlpha))
smoke:SetKeyValue("SmokeMaterial", "particle/particle_smokegrenade.vmt")
smoke:SetKeyValue("BaseSpread", tostring(config.smokeSpawnerDistance))
smoke:SetKeyValue("SpreadSpeed", "10")
smoke:SetKeyValue("Speed", "32")
smoke:SetKeyValue("StartSize", "32")
smoke:SetKeyValue("EndSize", "32")
smoke:SetKeyValue("roll", "8")
smoke:SetKeyValue("Rate", "64")
smoke:SetKeyValue("JetLength", tostring(max.z - min.z))
smoke:SetKeyValue("twist", "6")
smoke:Spawn()
smoke:Activate()
smoke.Think = function()
if PLUGIN.positions[idx] == nil then
smoke:Remove()
end
end
PLUGIN.smokeStacks[idx].stacks[i] = smoke
end
end
end
for _, ply in pairs(player.GetAll()) do
local pos = ply:EyePos()
if not ply:Alive() then continue end
local canBreathe = false
if not canBreathe then
canBreathe = self:IsEquippingGasmask(ply)
end
if not canBreathe then
for _, gasBox in pairs(PLUGIN.positions) do
if pos:WithinAABox(gasBox.min, gasBox.max) then
ply.nextGasDamage = ply.nextGasDamage or CurTime()
if CurTime() >= ply.nextGasDamage then
ply.nextGasDamage = CurTime() + .75
ply:TakeDamage(6)
ix.util.Notify("You are choking. You need a gas mask.", ply)
end
break
end
end
end
end
end
end
if CLIENT then
-- toggles showing toxic gas boxes when in noclip/observer
CreateConVar("ix_toxicgas_observer", "0", FCVAR_ARCHIVE)
local function IsInRange(min, max, scale)
local localPos = LocalPlayer():GetPos()
local distance = min:Distance(max)
if localPos:Distance(min + ((max - min) / 2)) <= distance * scale then
return true
end
return false
end
function PLUGIN:PostDrawTranslucentRenderables()
local toxicGasPositions = GetNetVar("toxicGasPositions")
if toxicGasPositions == nil then return end
for _, gasBox in pairs(toxicGasPositions) do
local min, max = gasBox.min, gasBox.max
if not IsInRange(min, max, 3) then continue end
local observerCvar = GetConVar("ix_toxicgas_observer")
if LocalPlayer():IsAdmin()
and LocalPlayer():GetMoveType() == MOVETYPE_NOCLIP
and observerCvar and observerCvar:GetBool() then
render.DrawWireframeBox(min, Angle(), Vector(0, 0, 0), max - min, Color(142, 222, 131, 255), false)
local startSmoke, endSmoke = GetBoxLine(min, max)
render.DrawLine(startSmoke, endSmoke, Color(0, 255, 0), false)
end
end
end
function PLUGIN:HUDPaint()
-- this is an FPS killer tbh
--[[
local toxicGasPositions = game.GetWorld():GetNetVar("toxicGasPositions")
if toxicGasPositions == nil then return end
local inToxicGas = false
local center
local cornerDist
for _, gasBox in pairs(toxicGasPositions) do
local min, max = gasBox.min, gasBox.max
center = min + ((max - min) / 2)
cornerDist = min:Distance(max)
if LocalPlayer():EyePos():WithinAABox(min, max) then
inToxicGas = true
continue
end
end
if inToxicGas then
local isEquippingGasmask = self:IsEquippingGasmask(LocalPlayer())
local distance = LocalPlayer():EyePos():Distance(center)
ix.util.DrawBlurAt(0, 0, ScrW(), ScrH(), 1, 0.2, isEquippingGasmask and 50 or 255)
end
]]
end
end
ix.command.Add("AddToxicGas", {
description = "Adds a toxic gas box from where you're standing and where you're looking at.",
adminOnly = true,
OnRun = function(self, client)
local pos = client:GetPos()
local tr = client:GetEyeTrace()
if not tr then return end
local hitPos = tr.HitPos
table.insert(PLUGIN.positions, {
min = pos, max = hitPos
})
PLUGIN:SaveData()
return "Added toxic gas."
end
})
ix.command.Add("RemoveToxicGas", {
description = "Removes the closest toxic gas point relative to you.",
adminOnly = true,
OnRun = function(self, client)
local closestDistance = -1
local closestIndex = -1
for idx, gasBox in pairs(PLUGIN.positions) do
local min, max = gasBox.min, gasBox.max
local center = min + ((max - min) / 2)
local distance = client:GetPos():Distance(center)
if closestDistance == -1 or distance < closestDistance then
closestDistance = distance
closestIndex = idx
end
end
if closestIndex ~= -1 then
table.remove(PLUGIN.positions, closestIndex)
if PLUGIN.smokeStacks[closestIndex] then
for k, v in pairs(PLUGIN.smokeStacks[closestIndex].stacks) do
v:Remove()
end
table.remove(PLUGIN.smokeStacks, closestIndex)
end
PLUGIN:SaveData()
return "Removed 1 toxic gas box."
else
return "Could not find any toxic gas to remove!"
end
end
})
I Really hope someone can help me with that as im trying since 2 days now
Try replacing for y, item in pairs(items) do with for item, _ in pairs(items) do.
Reason: there is a chance that items is a set, i.e., a Lua table, in which keys are set members and values are true.
change line 44
if item.uniqueID == config.maskItem
either by refusing boolean values
if type(item) ~= 'boolean' and item.uniqueID == config.maskItem
or only allowing tables, because they could possibly contain .uniqueID
if type(item) == 'table' and item.uniqueID == config.maskItem
Is there a way if a string is close to a string in a table it will replace it with the one in the table?
Like a spellcheck function, that searches through a table and if the input is close to one in the table it will fix it , so the one in the table and the string is the same?
You can use this code :) Reference code is from here : https://github.com/badarsh2/Algorithm-Implementations/blob/master/Levenshtein_distance/Lua/Yonaba/levenshtein.lua
local function min(a, b, c)
return math.min(math.min(a, b), c)
end
local function matrix(row,col)
local m = {}
for i = 1,row do m[i] = {}
for j = 1,col do m[i][j] = 0 end
end
return m
end
local function lev(strA,strB)
local M = matrix(#strA+1,#strB+1)
local i, j, cost
local row, col = #M, #M[1]
for i = 1, row do M[i][1] = i - 1 end
for j = 1, col do M[1][j] = j - 1 end
for i = 2, row do
for j = 2, col do
if (strA:sub(i - 1, i - 1) == strB:sub(j - 1, j - 1)) then cost = 0
else cost = 1
end
M[i][j] = min(M[i-1][j] + 1,M[i][j - 1] + 1,M[i - 1][j - 1] + cost)
end
end
return M[row][col]
end
local refTable = {"hell", "screen"}
local function getClosestWord(pInput, pTable, threesold)
cDist = -1
cWord = ""
for key, val in pairs(pTable) do
local levRes = lev(pInput, val)
if levRes < cDist or cDist == -1 then
cDist = levRes
cWord = val
end
end
print(cDist)
if cDist <= threesold then
return cWord
else
return pInput
end
end
a = getClosestWord("hello", refTable, 3)
b = getClosestWord("screw", refTable, 3)
print(a, b)
Third parameter is threesold, if min distance is higher than threesold, word is not replaced.
I'm new to Lua and coding in general so I decided to write a Chess Program to learn. I have setup a class and created objects from it to represent the pieces. Now I want to begin moving the pieces with my mouse. I looked at a tutorial, but it only handled one rectangle. My first though was to use a "for" loop in the love.mousePressed() function to go though each of the objects until it found an object with a matching x, y coordinate. This obviously did not work the way I did it. Instead, it only goes to the next object every time the mouse is pressed or at least it would if the program didn't immediately crash once the button was released. So my question is, what is the right way to be going about this?
local blackPawn = love.graphics.newImage("Textures/Blackpawn.png")
local blackRook = love.graphics.newImage("Textures/Blackrook.png")
local blackKnight = love.graphics.newImage("Textures/Blackknight.png")
local blackBishop = love.graphics.newImage("Textures/Blackbishop.png")
local blackQueen = love.graphics.newImage("Textures/Blackqueen.png")
local blackKing = love.graphics.newImage("Textures/BlackKing.png")
local whitePawn = love.graphics.newImage("Textures/Whitepawn.png")
local whiteRook = love.graphics.newImage("Textures/Whiterook.png")
local whiteKnight = love.graphics.newImage("Textures/Whiteknight.png")
local whiteBishop = love.graphics.newImage("Textures/Whitebishop.png")
local whiteQueen = love.graphics.newImage("Textures/Whitequeen.png")
local whiteKing = love.graphics.newImage("Textures/WhiteKing.png")
local chessboard = love.graphics.newImage("Textures/ChessBoard.png")
local register = {}
local id = 0
piece = {
xSquare = 0, ySquare = 0,
x = 0, y = 0,
height = 64, width = 64,
pawn = false,
Rook = false,
Knight = false,
Bishop = false,
Queen = false,
King = false,
color = "",
texture = whitePawn,
dragging = {active = false, diffx = 0, diffy = 0}
}
function piece.new()
newPiece = {}
for k, v in pairs(piece) do
newPiece[k] = v
end
return newPiece
end
function piece:draw()
end
function getMouse()
local x, y = love.mouse.getPosition()
local isDown = love.mouse.isDown(1,2)
return x, y, isDown
end
function createBoard(id)
for x = 1, 8 do
for y = 1, 8 do
if y ~= 3 and y ~= 4 and y ~=5 and y ~= 6 then
id = id + 1
register[id] = piece.new()
register[id].x = x * 64 - 48
register[id].y = (y - 1) * 64
if y == 2 then
register[id].pawn = true
register[id].color = "white"
register[id].texture = whitePawn
print("item " .. id .. " is here x = " .. register[id].x .. " y = " .. register[id].y .. " Is pawn = " .. tostring(register[id].pawn) ..
" Color is " .. register[id].color)
elseif y == 7 then
register[id].pawn = true
register[id].color = "black"
register[id].texture = blackPawn
print("item " .. id .. " is here x = " .. register[id].x .. " y = " .. register[id].y .. " Is pawn = " .. tostring(register[id].pawn) ..
" Color is " .. register[id].color)
elseif y == 1 then
register[id].color = "white"
if x == 1 or x == 8 then
register[id].Rook = true
register[id].texture = whiteRook
elseif x == 2 or x == 7 then
register[id].Knight = true
register[id].texture = whiteKnight
print("knight is here")
elseif x == 3 or x == 6 then
register[id].Bishop = true
register[id].texture = whiteBishop
elseif x == 5 then
register[id].King = true
register[id].texture = whiteKing
elseif x == 4 then
register[id].Queen = true
register[id].texture = whiteQueen
end
elseif y == 8 then
register[id].color = "black"
if x == 1 or x == 8 then
register[id].Rook = true
register[id].texture = blackRook
elseif x == 2 or x == 7 then
register[id].Knight = true
register[id].texture = blackKnight
elseif x == 3 or x == 6 then
register[id].Bishop = true
register[id].texture = blackBishop
elseif x == 5 then
register[id].King = true
register[id].texture = blackKing
elseif x == 4 then
register[id].Queen = true
register[id].texture = blackQueen
end
end
end
end
end
end
function drawBoard(id, register)
love.graphics.draw(chessboard, 0, 0)
for id = 1, 32 do
love.graphics.draw(register[id].texture, register[id].x, register[id].y)
end
end
function love.load()
createBoard(id)
end
function love.update(dt)
for id = 1, 32 do
if register[id].dragging.active == true then
register[id].x = love.mouse.getX() - register[id].dragging.diffx
register[id].y = love.mouse.getY() - register[id].dragging.diffy
end
end
end
function love.draw()
drawBoard(id, register)
end
function love.mousepressed(x, y, button)
for id = 1, 32 do
if (button == 1 or button == 2)
and x > register[id].x and x < register[id].x + register[id].width
and y > register[id].y and y < register[id].y + register[id].height
then
register[id].dragging.active = true
register[id].dragging.diffx = x - register[id].x
register[id].dragging.diffy = y - register[id].y
end
end
end
function love.mousereleased(x, y, button)
for id = 1, 32 do
if button == 1 or button == 2 then register[id].dragging.active = false end
end
end
function love.keypressed(key, unicode)
end
function love.keyreleased(key)
end
function love.focus(bool)
end
function love.quit()
end
Update:
I fixed the crashing, but I still have the weird bug where it changes the dragged piece into a different piece
Update 2: After a little more debugging I have figured out that the major issue is that it for some reason does not correctly check if the dragging is active. As the code stands right now I need an else dragging.active = false after to correctly set it, but now that it is correctly set it won't drag anything at all despite the correct object have dragging set to active (unless I try and drag the object with value 32 where it drags everything at once). I am very confused as to what's wrong. Why isn't Lua able to check value like this?
First, I'd create a global boolean for if a piece has been selected and then a variable to hold the piece selected
local selected = false
local selectedPiece = {}
Then create a playing board and split it into a grid, with each square being of equal size. Something like this
board = {
size = { 8, 8 }, -- 8x8 grid
squareSize = 40, -- 40 pixels long sides
pieces = {
{ -- First row contains which pieces?
Piece:Rook(),
Piece:Bishop(),
...
},
{ -- Second row
Piece:Pawn(),
...
},
{ -- etc.
Piece:Empty(),
...
}
}
}
I advise not using nil in your table for empty squares due to the odd behavior of tables with nil indexes.
In your love.mousepressed() method, you check where the click was based on its position (this is assuming the board takes up the whole window)
function love.mousepressed(x, y, btn)
-- If a piece hasn't been clicked on.
if (not selected) then
-- This line is assuming that since all board squares are equal size, then the mouse click has to be in at least one square.
-- Therefore, if we take the floor of the position/board.squareSize, we will always get a value from 0 - 7 (8 values) on the board.
local piece = board.pieces[math.floor(x/board.squareSize)][math.floor(y/board.squareSize)]
-- If there is a piece here.
if (piece:isNotAnEmpty()) then
selectedPiece = piece -- Select the piece.
selected = not selected -- Notify program that a piece is selected to handle such things accordingly in other methods.
end
else
-- Assuming you wrote a method that determines if a piece can be moved to a certain spot on the board.
if (board:CanMovePieceHere(selectedPiece, x/board.size, y/board.size)) then
-- Do your stuff here.
...
-- Eventually, reset your variables.
selected = not selected
selectedPiece = {}
end
end
end
This is how I'd approach it, but your question is very open to interpretation.
So I'm trying to program a space invaders like game in lua using löve2d, the first wave of enemies runs smoothly but once i try adding another wave to the levelctrl table i get this error: bad argument #1 to 'pairs' (table expected, got nil) on line 235 (even when i populate a second table)
function love.load()
hero = {}
hero.x = 400 - 16
hero.y = 450
hero.speedx = 300
hero.speedy = 50
hero.shots = {}
bgx = 0
bgs = .25
fleet1 = {}
f1x = 0
f1f = 0
lost = 0
score = 0
game = 0
menu = 1
startup = 1
--Images
bg = love.graphics.newImage("img/space.png")
bullet = love.graphics.newImage("img/shot.png")
player = love.graphics.newImage("img/player.png")
trail = love.graphics.newImage("img/trail.png")
ship1 = love.graphics.newImage("img/enemy1.png")
looser = love.graphics.newImage("img/looser.png")
boomp1 = love.graphics.newImage("img/boomp1.png")
boomp2 = love.graphics.newImage("img/boomp2.png")
boomp3 = love.graphics.newImage("img/boomp3.png")
boomp4 = love.graphics.newImage("img/boomp4.png")
boom1 = love.graphics.newImage("img/boom1.png")
boom2 = love.graphics.newImage("img/boom2.png")
boom3 = love.graphics.newImage("img/boom3.png")
boom4 = love.graphics.newImage("img/boom4.png")
winner = love.graphics.newImage("img/winner.png")
title = love.graphics.newImage("img/title.png")
message = love.graphics.newImage("img/message.png")
restart = love.graphics.newImage("img/restart.png")
icon = love.graphics.newImage("img/icon.gif")
boomtimer=0
isdead=0
boom={}
bgs = .25
bgx = 0
menublink = 0
menuf = 0
end
function love.update(dt)
if bgx < 600 then
bgx = bgx + bgs
else
bgx = -599
end
if bgs > .30 then
bgs = bgs - 2*dt
end
if menublink < 48 and menuf==0 then
menublink = menublink + 1
else
menuf=1
menublink = menublink -1
if menublink == 0 then
menuf=0
end
end
if menu == 1 then
hero = {}
hero.x = 400 - 16
hero.y = 450
hero.speedx = 300
hero.speedy = 50
hero.shots = {}
f1x = 0
f1f = 0
lost = 0
score = 0
boomtimer=0
isdead=0
won=0
boom={}
fleet1 = {}
for i=0,7 do
enemy = {}
enemy.width = 32
enemy.height = 16
enemy.img = ship1
enemy.x = i * (enemy.width + 64) + 48
if i<4 then
if i % 2 == 0 then
enemy.y = 0 - enemy.height
else
enemy.y = -16 - enemy.height
end
else
if i % 2 == 0 then
enemy.y = -16 - enemy.height
else
enemy.y = 0 - enemy.height
end
end
table.insert(fleet1, enemy)
end
boss = {}
level = 1
levelctrl = {}
table.insert(levelctrl, fleet1)
if love.keyboard.isDown(" ") then
menu = 0
game = 1
end
elseif game == 1 then
if isdead==0 then
if love.keyboard.isDown("left") then
if hero.x > 0 then
hero.x = hero.x - hero.speedx*dt
end
elseif love.keyboard.isDown("right") then
if hero.x < 800-32 then
hero.x = hero.x + hero.speedx*dt
end
end
if love.keyboard.isDown("up") then
if hero.y > 300 then
hero.y = hero.y - hero.speedy*dt
up=1
else
up=0
end
if bgs < 4 then
bgs = bgs + 5*dt
end
elseif love.keyboard.isDown("down") then
if hero.y < 600-64 then
hero.y = hero.y + hero.speedy*2*dt
end
else
up=0
end
end
for i,v in ipairs(hero.shots) do
v.y = v.y - dt * 300
end
if won == 0 then
local remShot = {}
local remEnemy = {}
for i,v in ipairs(hero.shots) do
if v.y < 0 then
table.insert(remShot, i)
end
for ii,vv in ipairs(levelctrl[1]) do
if CheckCollision(v.x,v.y,32,32,vv.x,vv.y,vv.width,vv.height) then
x = {}
x.x = vv.x
x.y = vv.y
x.t = 0
table.insert(boom, x)
table.insert(remEnemy, ii)
table.insert(remShot, i)
end
end
end
for i,v in ipairs(levelctrl[1]) do
if CheckCollision(hero.x,hero.y,32,64,v.x,v.y,v.width,v.height) then
lost = 1
end
end
for i,v in ipairs(remShot) do
table.remove(hero.shots, v)
end
for i,v in ipairs(remEnemy) do
table.remove(levelctrl[1], v)
score = score + 1
end
if level == 1 then
for i,v in ipairs(levelctrl[1]) do
v.y = v.y + dt * 12
if v.y > 512 then
lost = 1
end
if v.x>0 and v.x < 768 then
if f1f == 0 then
if f1x<3 then
f1x = f1x + 1 * dt
v.x = v.x + 1
else
f1f = 1
end
else
if f1x>-3 then
f1x = f1x - 1 * dt
v.x = v.x - 1
else
f1f = 0
end
end
end
end
end
end
if empty(levelctrl[1]) == true and won == 0 then
level = level + 1
table.remove(levelctrl, 1)
if remEnemy ~= nil then
for k in pairs (remEnemy) do
remEnemy[k] = nil
end
end
end
if won == 1 and love.keyboard.isDown("return") then
menu = 1
game = 0
elseif lost == 1 and love.keyboard.isDown("return") then
menu = 1
game = 0
end
end
end
function love.draw()
love.graphics.setIcon(icon)
love.graphics.setColor(255,255,255,255)
love.graphics.draw(bg, 0, bgx)
love.graphics.draw(bg, 0, bgx-1199)
if menu == 1 then
love.graphics.draw(title)
if menuf == 1 then
love.graphics.draw(message)
end
elseif game == 1 then
for i,v in ipairs(hero.shots) do
love.graphics.draw(bullet, v.x, v.y)
end
if up==1 then
love.graphics.draw(trail, hero.x, hero.y)
end
for i,v in ipairs(levelctrl[1]) do
love.graphics.draw(v.img, v.x, v.y)
end
if lost == 0 then
love.graphics.draw(player, hero.x, hero.y)
else
isdead=1
if boomtimer<8 then
love.graphics.draw(boomp1, hero.x-16, hero.y)
boomtimer = boomtimer + 1
elseif boomtimer<16 then
love.graphics.draw(boomp2, hero.x-16, hero.y)
boomtimer = boomtimer + 1
elseif boomtimer<24 then
love.graphics.draw(boomp3, hero.x-16, hero.y)
boomtimer = boomtimer + 1
elseif boomtimer<32 then
love.graphics.draw(boomp4, hero.x-16, hero.y)
boomtimer = boomtimer + 1
else
love.graphics.draw(looser)
if menuf == 1 then
love.graphics.draw(restart, 0, 20)
end
end
end
for i,v in ipairs(boom) do
if v.t<8 then
love.graphics.draw(boom1, v.x, v.y-8)
v.t = v.t + 1
elseif v.t<16 then
love.graphics.draw(boom2, v.x, v.y-8)
v.t = v.t + 1
elseif v.t<24 then
love.graphics.draw(boom3, v.x, v.y-8)
v.t = v.t + 1
elseif v.t<32 then
love.graphics.draw(boom4, v.x, v.y-8)
v.t = v.t + 1
else
table.remove(boom, i)
end
end
if won == 0 then
if empty(levelctrl) then
won = 1
end
end
if won == 1 then
love.graphics.draw(winner)
if menuf == 1 then
love.graphics.draw(restart, 0, 20)
end
end
end
end
function shoot()
local shot = {}
shot.x = hero.x
shot.y = hero.y - 4
table.insert(hero.shots, shot)
end
function CheckCollision(ax1,ay1,aw,ah, bx1,by1,bw,bh)
local ax2 = ax1 + aw
local ay2 = ay1 + ah
local bx2 = bx1 + bw
local by2 = by1 + bh
return ax1 < bx2 and ax2 > bx1 and ay1 < by2 and ay2 > by1
end
function love.keyreleased(key)
if isdead==0 then
if (key == " ") then
shoot()
end
end
end
function empty(self)
for _, _ in pairs(self) do
return false
end
return true
end
that's all the code and more specifically i get a problem with this:
for i,v in ipairs(levelctrl[1]) do
love.graphics.draw(v.img, v.x, v.y)
end
levelctrl initially has 2 tables inside so after i remove the first one to bump the second one down, I recieve the bad argument error
The problem seems to be around line 200:
if empty(levelctrl[1]) == true and won == 0 then
level = level + 1
table.remove(levelctrl, 1)
Here you remove the table from levelctrl when it's empty and increase the level. Since the table is empty already, can't you just re-use it instead of removing it (causing crashes on next rendering)? Removing the table.remove call should help.
I see
levelctrl = {}
table.insert(levelctrl, fleet1)
So levelctrl = {fleet1}
and some time later when you win,
if empty(levelctrl[1]) == true and won == 0 then
level = level + 1
table.remove(levelctrl, 1)
So levelctrl = {}
won is still 0, and game is still 1.
Then in your draw function
for i,v in ipairs(levelctrl[1]) do
love.graphics.draw(v.img, v.x, v.y)
end
At this point levelctrl = {} and levelctrl[1] = nil.
One solution would be to surround that bit of your draw function with
if not empty(levelctrl)
Also if you were trying to add fleet1 to levelctrl multiple times,
levelctrl = {}
table.insert(levelctrl, fleet1)
table.insert(levelctrl, fleet1)
table.insert(levelctrl, fleet1)
Then levelctrl would have three instances of the same table, and removing something from levelctrl[1] would remove it from fleet1 => all of the levels become empty at the same time.