Why does my LOVE2D program keep resetting the score? - lua

So, I'm currently in a problem with updating my Super Mario Bros. Yeah, sure, it works fine, but the problem is this:
Whenever I touch the flagpole at the end, it literally resets my score.
It makes no sense with this program since I made a params for PlayState:enter, and I don't exactly know why my score goes back to 0.
This shows up in PlayState.lua:
function PlayState:enter(params)
self.score = params.score
self.lastLevelWidth = params.lastLevelWidth
if self.lastLevelWidth == 0 then
self.lastLevelWidth = 100
else
self.lastLevelWidth = self.lastLevelWidth + 50
end
self.camX = 0
self.camY = 0
self.level = LevelMaker.generate(100, 10)
self.tileMap = self.level.tileMap
self.background = math.random(3)
self.backgroundX = 0
self.gravityOn = true
self.gravityAmount = 6
self.player = Player({
x = 0, y = 0,
width = 16, height = 20,
texture = 'green-alien',
stateMachine = StateMachine {
['idle'] = function() return PlayerIdleState(self.player) end,
['walking'] = function() return PlayerWalkingState(self.player) end,
['jump'] = function() return PlayerJumpState(self.player, self.gravityAmount) end,
['falling'] = function() return PlayerFallingState(self.player, self.gravityAmount) end
},
map = self.tileMap,
level = self.level,
})
self:spawnEnemies()
self.player:changeState('falling')
end
I used the params to get to a new score, 0, but I don't want it to let it stay like that. This is what I have done in LevelMaker.lua:
keyCollected = false
function LevelMaker.generate(width, height)
local tiles = {}
local entities = {}
local objects = {}
local tileID = TILE_ID_GROUND
-- whether we should draw our tiles with toppers
local topper = true
local tileset = math.random(20)
local topperset = math.random(20)
-- insert blank tables into tiles for later access
for x = 1, height do
table.insert(tiles, {})
end
-- make positions for the lock box and key in the level
local lockBoxPosition = math.random(1, width)
local keyPosition = math.random(1, width)
local keySkin = math.random(1, 4)
-- column by column generation instead of row; sometimes better for platformers
for x = 1, width do
local tileID = TILE_ID_EMPTY
-- lay out the empty space
for y = 1, 6 do
table.insert(tiles[y],
Tile(x, y, tileID, nil, tileset, topperset))
end
-- chance to just be emptiness
if math.random(7) == 1 and x ~= 1 and lockBoxPosition ~= x and keyPosition ~= x then
for y = 7, height do
table.insert(tiles[y],
Tile(x, y, tileID, nil, tileset, topperset))
end
else
tileID = TILE_ID_GROUND
local blockHeight = 4
for y = 7, height do
table.insert(tiles[y],
Tile(x, y, tileID, y == 7 and topper or nil, tileset, topperset))
end
-- chance to generate a pillar
if math.random(8) == 1 then
blockHeight = 2
-- chance to generate bush on pillar
if math.random(8) == 1 then
table.insert(objects,
GameObject {
texture = 'bushes',
x = (x - 1) * TILE_SIZE,
y = (4 - 1) * TILE_SIZE,
width = 16,
height = 16,
-- select random frame from bush_ids whitelist, then random row for variance
frame = BUSH_IDS[math.random(#BUSH_IDS)] + (math.random(4) - 1) * 7
}
)
end
-- pillar tiles
tiles[5][x] = Tile(x, 5, tileID, topper, tileset, topperset)
tiles[6][x] = Tile(x, 6, tileID, nil, tileset, topperset)
tiles[7][x].topper = nil
-- chance to generate bushes
elseif math.random(8) == 1 and keyPosition ~= 1 then
table.insert(objects,
GameObject {
texture = 'bushes',
x = (x - 1) * TILE_SIZE,
y = (6 - 1) * TILE_SIZE,
width = 16,
height = 16,
frame = BUSH_IDS[math.random(#BUSH_IDS)] + (math.random(4) - 1) * 7,
collidable = false
}
)
end
if x == keyPosition then
table.insert(objects,
GameObject {
texture = 'keys-and-locks',
x = (x - 1) * TILE_SIZE,
y = (blockHeight + 1) * TILE_SIZE,
width = 16,
height = 16,
frame = keySkin,
collidable = true,
consumable = true,
solid = false,
onConsume = function(player, object)
gSounds['pickup']:play()
player.score = player.score + 500
keyCollected = true
end
}
)
end
if x == lockBoxPosition then
table.insert(objects,
GameObject {
texture = 'keys-and-locks',
x = (x - 1) * TILE_SIZE,
y = (blockHeight - 1) * TILE_SIZE,
width = 16,
height = 16,
frame = keySkin + 4,
collidable = true,
consumable = true,
hit = false,
solid = true,
lockedBox = false,
objectRemove = false,
onCollide = function(obj)
if not obj.hit then
if keyCollected then
gSounds['pickup']:play()
obj.hit = true
obj.objectRemove = true
obj.consumable = true
local pole = GameObject {
texture = 'poles',
x = (width * TILE_SIZE) - 32,
y = (blockHeight - 1) * TILE_SIZE,
width = 16,
height = 48,
frame = math.random(#POLES),
collidable = true,
consumable = true,
solid = false,
onConsume = function(player, object)
gSounds['pickup']:play()
player.score = player.score + 1000
gStateMachine:change('play', {
score = player.score,
lastLevelWidth = width
})
end
}
local flag = GameObject {
texture = 'flags',
x = (width * TILE_SIZE) - 32 + 6,
y = blockHeight * TILE_SIZE,
width = 16,
height = 10,
frame = 1,
collidable = true,
consumable = true,
solid = false,
onConsume = function(player, object)
gSounds['pickup']:play()
player.score = player.score + 1000
gStateMachine:change('play', {
score = player.score,
lastLevelWidth = width
})
end
}
Timer.tween(2.0 , {
[flag] = {y = ((blockHeight - 1) * TILE_SIZE) + 4}
})
gSounds['powerup-reveal']:play()
table.insert(objects, pole)
table.insert(objects, flag)
end
keyCollected = false
end
gSounds['empty-block']:play()
end
}
)
-- chance to spawn a block
elseif math.random(10) == 1 then
table.insert(objects,
-- jump block
GameObject {
texture = 'jump-blocks',
x = (x - 1) * TILE_SIZE,
y = (blockHeight - 1) * TILE_SIZE,
width = 16,
height = 16,
-- make it a random variant
frame = math.random(#JUMP_BLOCKS),
collidable = true,
hit = false,
solid = true,
-- collision function takes itself
onCollide = function(obj)
-- spawn a gem if we haven't already hit the block
if not obj.hit then
-- chance to spawn gem, not guaranteed
if math.random(5) == 1 then
-- maintain reference so we can set it to nil
local gem = GameObject {
texture = 'gems',
x = (x - 1) * TILE_SIZE,
y = (blockHeight - 1) * TILE_SIZE - 4,
width = 16,
height = 16,
frame = math.random(#GEMS),
collidable = true,
consumable = true,
solid = false,
-- gem has its own function to add to the player's score
onConsume = function(player, object)
gSounds['pickup']:play()
player.score = player.score + 100
end
}
-- make the gem move up from the block and play a sound
Timer.tween(0.1, {
[gem] = {y = (blockHeight - 2) * TILE_SIZE}
})
gSounds['powerup-reveal']:play()
table.insert(objects, gem)
end
obj.hit = true
end
gSounds['empty-block']:play()
end
}
)
end
end
end
local map = TileMap(width, height)
map.tiles = tiles
return GameLevel(entities, objects, map)
end
What's supposed to happen is that when I collected the key and unlocked the lock block, I get a flag, and when I collide with the flag at the end of the map, I get to a new level, with the same score, but not 0. Sadly, everytime I get to a new level, it turns into 0.
I don't know if the problem is in StartState.lua:
function StartState:update(dt)
if love.keyboard.wasPressed('enter') or love.keyboard.wasPressed('return') then
gStateMachine:change('play', {
score = 0,
lastLevelWidth = 0
})
end
end
Any ideas why it's like this?

If you collide with the pole and then change to StartState, then that is the problem. I suggest feeding the score through start with: function StartState:enter(params) self.score = params.score end
Then just pass self.score through to the playstate

Related

Cannot change the boolean in table lua love2d

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.

Lua, Love2D, why i'm getting an error on GameObject?

im doing the CS50 game development course and after creating the key and locked block required when i get close to the locked block i get an error saying GameObject.lua 28: attempted to perform arithmetic on field 'y' (nil value)
here is my code for level maker
LevelMaker = Class{}
keyCollected = false
function LevelMaker.generate(width, height)
local tiles = {}
local entities = {}
local objects = {}
local tileID = TILE_ID_GROUND
-- whether we should draw our tiles with toppers
local topper = true
local tileset = math.random(20)
local topperset = math.random(20)
-- insert blank tables into tiles for later access
for x = 1, height do
table.insert(tiles, {})
end
--generate one locked box and one locked key in a random position position
local lockBoxPosition = math.random(1, width)
local keyPosition = math.random(1, width)
local keyColor = math.random(1, 4) --for reference for the color skin used
-- column by column generation instead of row; sometimes better for platformers
for x = 1, width do
local tileID = TILE_ID_EMPTY
-- lay out the empty space
for y = 1, 6 do
table.insert(tiles[y],
Tile(x, y, tileID, nil, tileset, topperset))
end
-- chance to just be emptiness (to be sure to not generate a key and locked box above a chasm)
if math.random(7) == 1 and x ~= 1 and lockBoxPosition ~= x and keyPosition ~= x then
for y = 7, height do
table.insert(tiles[y],
Tile(x, y, tileID, nil, tileset, topperset))
end
else
tileID = TILE_ID_GROUND
-- height at which we would spawn a potential jump block
local blockHeight = 4
for y = 7, height do
table.insert(tiles[y],
Tile(x, y, tileID, y == 7 and topper or nil, tileset, topperset))
end
-- chance to generate a pillar
if math.random(8) == 1 then
blockHeight = 2
-- chance to generate bush on pillar
if math.random(8) == 1 then
table.insert(objects,
GameObject {
texture = 'bushes',
x = (x - 1) * TILE_SIZE,
y = (4 - 1) * TILE_SIZE,
width = 16,
height = 16,
-- select random frame from bush_ids whitelist, then random row for variance
frame = BUSH_IDS[math.random(#BUSH_IDS)] + (math.random(4) - 1) * 7,
collidable = false
}
)
end
-- pillar tiles
tiles[5][x] = Tile(x, 5, tileID, topper, tileset, topperset)
tiles[6][x] = Tile(x, 6, tileID, nil, tileset, topperset)
tiles[7][x].topper = nil
-- chance to generate bushes
elseif math.random(8) == 1 and keyPosition ~= x then
table.insert(objects,
GameObject {
texture = 'bushes',
x = (x - 1) * TILE_SIZE,
y = (6 - 1) * TILE_SIZE,
width = 16,
height = 16,
frame = BUSH_IDS[math.random(#BUSH_IDS)] + (math.random(4) - 1) * 7,
collidable = false
}
)
end
--spawn the key
if x == keyPosition then
table.insert(objects,
GameObject {
texture = 'key-lock',
x = (x - 1) * TILE_SIZE,
y = (blockHeight+1) * TILE_SIZE,
width = 16,
height = 16,
frame = keyColor,
collidable = true,
consumable = true,
solid = false,
--key has its own function to add to the player score
onConsume = function(player, object)
gSounds['pickup']:play()
player.score = player.score + 500
keyCollected = true
end
})
end
--spawn the locked box
if x == lockBoxPosition then
table.insert(objects,
--locked box
GameObject{
texture = 'key-lock',
x = (x-1) * TILE_SIZE,
Y = (blockHeight - 1) * TILE_SIZE,
width = 16,
height = 16,
--make it a random variant
frame = keyColor + 4,
collidable = true,
hit = false,
solid = true,
lockedBox = false,
--collision function
onCollide = function(obj)
if not obj.hit then
if keyCollected then
gSounds['pickup']:play()
obj.hit = true
--spawn flag post
local flagpost = GameObject {
texture = 'flagposts',
x = obj.x + 4,
y = (blockHeight - 4) * TILE_SIZE,
width = 8,
height = 48,
frame = 1,
collidable = true,
consumable = true,
solid = false,
onConsume = function(player, object)
gSounds['pickup']:play()
player.score = player.score + 1000
--end of the level
gStateMachine:change('play', {score = player.score, lastLevelWidth = width})
end
}
--spawn flag
local flag = GameObject {
texture = 'flags',
x = obj.x + 6,
y = (blockHeight - 2) * TILE_SIZE,
width = 16,
height = 10,
frame = 1,
collidable = true,
consumable = true,
solid = false,
onConsume = function(player, object)
gSounds['pickup']:play()
player.score = player.score + 1000
--end of the level
gStateMachine:change('play', {score = player.score, lastLevelWidth = width})
end
}
--raise the flag
Timer.tween(2.0, {
[flag] = {y = ((blockHeight - 4) * TILE_SIZE) + 4}
})
gSounds['powerup-reveal']:play()
table.insert(objects, flagpost)
table.insert(objects, flag)
end
end
gSounds['empty-block']:play()
end
}
)
end
-- chance to spawn a block
if math.random(10) == 1 then
table.insert(objects,
-- jump block
GameObject {
texture = 'jump-blocks',
x = (x - 1) * TILE_SIZE,
y = (blockHeight - 1) * TILE_SIZE,
width = 16,
height = 16,
-- make it a random variant
frame = math.random(#JUMP_BLOCKS),
collidable = true,
hit = false,
solid = true,
-- collision function takes itself
onCollide = function(obj)
-- spawn a gem if we haven't already hit the block
if not obj.hit then
-- chance to spawn gem, not guaranteed
if math.random(5) == 1 then
-- maintain reference so we can set it to nil
local gem = GameObject {
texture = 'gems',
x = (x - 1) * TILE_SIZE,
y = (blockHeight - 1) * TILE_SIZE - 4,
width = 16,
height = 16,
frame = math.random(#GEMS),
collidable = true,
consumable = true,
solid = false,
-- gem has its own function to add to the player's score
onConsume = function(player, object)
gSounds['pickup']:play()
player.score = player.score + 100
end
}
-- make the gem move up from the block and play a sound
Timer.tween(0.1, {
[gem] = {y = (blockHeight - 2) * TILE_SIZE}
})
gSounds['powerup-reveal']:play()
table.insert(objects, gem)
end
obj.hit = true
end
gSounds['empty-block']:play()
end
}
)
end
end
end
local map = TileMap(width, height)
map.tiles = tiles
return GameLevel(entities, objects, map)
end
and here is GameObject
GameObject = Class{}
function GameObject:init(def)
self.x = def.x
self.y = def.y
self.texture = def.texture
self.width = def.width
self.height = def.height
self.frame = def.frame
self.solid = def.solid
self.collidable = def.collidable
self.consumable = def.consumable
self.onCollide = def.onCollide
self.onConsume = def.onConsume
self.hit = def.hit
end
function GameObject:collides(target)
return not (target.x > self.x + self.width or self.x > target.x + target.width or
target.y > self.y + self.height or self.y > target.y + target.height)
end
function GameObject:update(dt)
end
function GameObject:render()
love.graphics.draw(gTextures[self.texture], gFrames[self.texture][self.frame], self.x, self.y)
end
the issue is supossedly in line 28 of GameObject

Issue with a Lua Script

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

Why does unequipping this tool relocates the player to the center of the map in Roblox?

This gear was inserted from the Catalog. It relocates the player to the center of the map when it's unequipped by clicking on the thumbnail. At 1st, I tested in a game I made. Everytime I unequipped it, the player kept falling through the baseplate and dying. I noticed it is the same position over and over. I moved the baseplate's position lower and the player falls down onto the baseplate instead of dying. Then I tested the gear in a new empty baseplate, unequipping it, the player moves to the center, too. I check the position of the both the Handle and the player's Torso, but that axis does not match any position in the script. Can someone point this out for me so that I can change it to the last position that the player stops?
Tool = script.Parent
Handle = Tool:WaitForChild("Handle")
Players = game:GetService("Players")
Debris = game:GetService("Debris")
Assets = require(Tool:WaitForChild("Assets"))
Data = Assets.Data
BaseUrl = Assets.BaseUrl
BasePart = Instance.new("Part")
BasePart.Material = Enum.Material.Plastic
BasePart.Shape = Enum.PartType.Block
BasePart.TopSurface = Enum.SurfaceType.Smooth
BasePart.BottomSurface = Enum.SurfaceType.Smooth
BasePart.FormFactor = Enum.FormFactor.Custom
BasePart.Size = Vector3.new(0.2, 0.2, 0.2)
BasePart.Anchored = false
BasePart.CanCollide = true
BasePart.Locked = true
Animations = {
Hold = {Animation = Tool:WaitForChild("Hold"), FadeTime = nil, Weight = nil, Speed = nil}
}
Sounds = {
Honk = Handle:WaitForChild("Honk"),
Engine = Handle:WaitForChild("Running")
}
Controls = {
Forward = {Key = "w", ByteKey = 17, Mode = false},
Backward = {Key = "s", ByteKey = 18, Mode = false},
Left = {Key = "a", ByteKey = 20, Mode = false},
Right = {Key = "d", ByteKey = 19, Mode = false}
}
Rate = (1 / 60)
Gravity = 196.20
PoseOffset = CFrame.new(0, -1.5125, -0.3) * CFrame.Angles(0, 0, 0) --The offset your character is from the center of the vehicle.
SpeedBoost = {
Allowed = false,
Active = false,
Enabled = true,
Duration = 10,
ReloadTime = 30
}
Special = {
Allowed = false,
Enabled = true,
Active = false,
Duration = 0,
ReloadTime = 60
}
Speed = {
Acceleration = {
Normal = 30,
Boost = 30
},
Deceleration = {
Normal = 30,
Boost = 30
},
MovementSpeed = {
Normal = {Min = 20, Max = 70},
Boost = {Min = 20, Max = 70}
},
TurnSpeed = {
Speed = {Min = 5, Max = 5},
TurnAlpha = 0.30,
AlphaDampening = 0.2
},
}
MaxSpeed = { --Maximum speed which the vehicle can move and turn at.
Movement = Speed.MovementSpeed.Normal,
Turn = Speed.TurnSpeed.Speed,
Acceleration = Speed.Acceleration.Normal,
Deceleration = Speed.Deceleration.Normal
}
CurrentSpeed = { --The speed which the vehicle is moving and turning at.
Movement = 0,
Turn = 0
}
Honk = {
Honking = false,
LastHonk = 0,
ReloadTime = 1
}
Jump = {
Jumping = false,
LastJump = 0,
ReloadTime = 1.25,
JumpForce = 30
}
ToolEquipped = false
ServerControl = (Tool:FindFirstChild("ServerControl") or Instance.new("RemoteFunction"))
ServerControl.Name = "ServerControl"
ServerControl.Parent = Tool
ClientControl = (Tool:FindFirstChild("ClientControl") or Instance.new("RemoteFunction"))
ClientControl.Name = "ClientControl"
ClientControl.Parent = Tool
Tool.Enabled = true
function RayCast(Position, Direction, MaxDistance, IgnoreList)
local IgnoreList = ((type(IgnoreList) == "table" and IgnoreList) or {IgnoreList})
return game:GetService("Workspace"):FindPartOnRayWithIgnoreList(Ray.new(Position, Direction.unit * (MaxDistance or 999.999)), IgnoreList)
end
function GetAllConnectedParts(Object)
local Parts = {}
local function GetConnectedParts(Object)
for i, v in pairs(Object:GetConnectedParts()) do
local Ignore = false
for ii, vv in pairs(Parts) do
if v == vv then
Ignore = true
end
end
if not Ignore then
table.insert(Parts, v)
GetConnectedParts(v)
end
end
end
GetConnectedParts(Object)
return Parts
end
function EnableFirstPersonView()
if not CheckIfAlive() or not ToolEquipped then
return
end
local Limbs = {"LeftHand", "RightHand"}
for i, v in pairs(Limbs) do
local Limb = Character:FindFirstChild(v)
if Limb:IsA("BasePart") then
Spawn(function()
InvokeClient("SetLocalTransparencyModifier", {Object = Limb, Transparency = 0, AutoUpdate = false})
end)
end
end
end
function ThrustUpdater()
for i, v in pairs(CurrentSpeed) do
CurrentSpeed[i] = 0
end
for i, v in pairs(Controls) do
Controls[i].Mode = false
end
while ToolEquipped and Body and Body.Parent and CheckIfAlive() and RotationForce and RotationForce.Parent and ThrustForce and ThrustForce.Parent and TurnGyro and TurnGyro.Parent do
RotationForce.angularvelocity = Vector3.new(0, CurrentSpeed.Turn, 0)
if math.abs(CurrentSpeed.Turn) > Speed.TurnSpeed.AlphaDampening then
CurrentSpeed.Turn = (CurrentSpeed.Turn - (Speed.TurnSpeed.AlphaDampening * (math.abs(CurrentSpeed.Turn) / CurrentSpeed.Turn)))
else
CurrentSpeed.Turn = 0
end
if not Controls.Forward.Mode or Controls.Backward.Mode then --Slow down if not controlling.
CurrentSpeed.Movement = (CurrentSpeed.Movement * 0.99)
end
local MySpeed = Vector3.new(Body.Velocity.X, 0, Body.Velocity.Z).magnitude
local VelocityDifference = math.abs((MySpeed - (ThrustForce.velocity.magnitude)))
if MySpeed > 3 and ThrustForce.velocity.magnitude > 3 and VelocityDifference > (0.7 * ThrustForce.velocity.magnitude) then
CurrentSpeed.Movement = (CurrentSpeed.Movement * 0.9)
end
if Controls.Forward.Mode then --Handle acceleration
CurrentSpeed.Movement = math.min(MaxSpeed.Movement.Max, (CurrentSpeed.Movement + (MaxSpeed.Acceleration * Rate)))
end
if Controls.Backward.Mode then --Handle deceleration, if speed is more than 0, decrease quicker.
CurrentSpeed.Movement = math.max(-MaxSpeed.Movement.Min, (CurrentSpeed.Movement - (MaxSpeed.Deceleration * ((CurrentSpeed.Movement > 0 and 2.8) or 1) * Rate)))
end
if Controls.Left.Mode then --Handle left turn speed
CurrentSpeed.Turn = math.min(Speed.TurnSpeed.Speed.Max, (CurrentSpeed.Turn + (Speed.TurnSpeed.TurnAlpha)))
end
if Controls.Right.Mode then --Handle right turn speed
CurrentSpeed.Turn = math.max(-Speed.TurnSpeed.Speed.Min, (CurrentSpeed.Turn - (Speed.TurnSpeed.TurnAlpha)))
end
local Direction = UpperTorso.CFrame.lookVector
Direction = Vector3.new(Direction.x, 0, Direction.z).unit
local Velocity = (Direction * CurrentSpeed.Movement) --The thrust force which you move.
ThrustForce.velocity = Vector3.new(Velocity.X, ThrustForce.velocity.Y, Velocity.Z)
local LeanAmount = (-CurrentSpeed.Turn * (math.pi / 6) / 4) --Amount your character leans over.
local XZAngle = math.atan2(UpperTorso.CFrame.lookVector.z, 0, UpperTorso.CFrame.lookVector.x) --Handle rotation
TurnGyro.cframe = CFrame.Angles((LeanAmount * Direction.x), 0, (LeanAmount * Direction.z))
--Wheel animation
local DesiredAngle = (999999999 * (-CurrentSpeed.Movement / math.abs(CurrentSpeed.Movement)))
local MaxVelocity = (CurrentSpeed.Movement / 250)
for i, v in pairs({FrontMotor, BackMotor}) do
if v and v.Parent then
v.DesiredAngle = DesiredAngle
v.MaxVelocity = MaxVelocity
end
end
--Smoke exhaust from vehicle running.
for i, v in pairs(ExhaustSmoke) do
if v and v.Parent then
v.Opacity = ((math.min(math.abs(CurrentSpeed.Movement), 10) / 10) * 0.5)
end
end
--Engine running sound which pitch changes while in motion.
Sounds.Engine.Pitch = (1 + (math.abs(CurrentSpeed.Movement / MaxSpeed.Movement.Max) * 1))
wait(Rate)
end
end
function SpawnVehicle()
Handle.Transparency = 1
Spawn(function()
InvokeClient("PlaySound", Sounds.Engine)
InvokeClient("PlayAnimation", Animations.Hold)
end)
Humanoid.PlatformStand = true
local VehicleData = Assets.CreateVehicle()
Body = VehicleData.Vehicle
local ParticleTable = VehicleData.Tables
--FrontMotor = Body.FrontMotor
--BackMotor = Body.BackMotor
ExhaustSmoke = ParticleTable.ExhaustSmoke
Lights = ParticleTable.Lights
Sparkles = ParticleTable.Sparkles
if SpeedBoost.Active then
for i, v in pairs(Sparkles) do
if v and v.Parent then
v.Enabled = true
end
end
end
local UpperTorsoWeld = Instance.new("Weld")
UpperTorsoWeld.C0 = PoseOffset
UpperTorsoWeld.Part0 = UpperTorso
UpperTorsoWeld.Part1 = Body
UpperTorsoWeld.Parent = Body
Body.CanCollide = true
RotationForce = Instance.new("BodyAngularVelocity")
RotationForce.maxTorque = Vector3.new(0, math.huge, 0)
RotationForce.angularvelocity = Vector3.new(0, 0, 0)
RotationForce.Parent = UpperTorso
ThrustForce = Instance.new("BodyVelocity")
ThrustForce.maxForce = Vector3.new(math.huge, 0, math.huge)
ThrustForce.velocity = Vector3.new(0, 0, 0)
ThrustForce.P = 100
ThrustForce.Parent = UpperTorso
TurnGyro = Instance.new("BodyGyro")
TurnGyro.maxTorque = Vector3.new(5000, 0, 5000)
TurnGyro.P = 300
TurnGyro.D = 100
TurnGyro.Parent = UpperTorso
Body.Parent = Tool
local RayHit, RayPos, RayNormal = RayCast(UpperTorso.Position, Vector3.new(0, -1, 0), (UpperTorso.Size.Y * 2), {Character})
if RayHit then
UpperTorso.CFrame = UpperTorso.CFrame + Vector3.new(0, ((Character:GetModelSize().Y / 2) + 1.5), 0)
end
Spawn(ThrustUpdater)
end
function FreezePlayer()
if CheckIfAlive() then
local FreezePart = BasePart:Clone()
FreezePart.Name = "FreezePart"
FreezePart.Transparency = 1
FreezePart.Anchored = true
FreezePart.CanCollide = false
local FreezeWeld = Instance.new("Weld")
FreezeWeld.Part0 = UpperTorso
FreezeWeld.Part1 = FreezePart
FreezeWeld.Parent = FreezePart
Debris:AddItem(FreezePart, 0.125)
FreezePart.Parent = Character
UpperTorso.Velocity = Vector3.new(0, -25, 0)
UpperTorso.RotVelocity = Vector3.new(0, 0, 0)
end
end
function CleanUp()
Handle.Velocity = Vector3.new(0, 0, 0)
Handle.RotVelocity = Vector3.new(0, 0, 0)
for i, v in pairs({}) do
if v then
v:disconnect()
end
end
for i, v in pairs({Body, RotationForce, ThrustForce, TurnGyro}) do
if v and v.Parent then
v:Destroy()
end
end
for i, v in pairs(Tool:GetChildren()) do
if v:IsA("BasePart") and v ~= Handle then
v:Destroy()
end
end
end
function CheckIfAlive()
return (((Character and Character.Parent and Humanoid and Humanoid.Parent and Humanoid.Health > 0 and UpperTorso and UpperTorso.Parent and Player and Player.Parent) and true) or false)
end
function Equipped(Mouse)
Character = Tool.Parent
Player = Players:GetPlayerFromCharacter(Character)
Humanoid = Character:FindFirstChild("Humanoid")
UpperTorso = Character:FindFirstChild("UpperTorso")
if not CheckIfAlive() then
return
end
Spawn(CleanUp)
Spawn(EnableFirstPersonView)
Spawn(SpawnVehicle)
ToolEquipped = true
end
function Unequipped()
Spawn(CleanUp)
Spawn(FreezePlayer)
for i, v in pairs(Sounds) do
v:Stop()
Spawn(function()
InvokeClient("StopSound", v)
end)
end
if CheckIfAlive() then
Humanoid.PlatformStand = false
end
Handle.Transparency = 0
ToolEquipped = false
end
function OnServerInvoke(player, mode, value)
if player == Player and ToolEquipped and value and CheckIfAlive() then
if mode == "KeyPress" then
local Down = value.Down
local Key = value.Key
local ByteKey = string.byte(Key)
for i, v in pairs(Controls) do
if Key == v.Key or ByteKey == v.ByteKey then
Controls[i].Mode = Down
end
end
if Key == " " and Down then --Jump controller
if math.abs(tick() - Jump.LastJump) > Jump.ReloadTime and not Jump.Jumping and ThrustForce and ThrustForce.Parent then
Jump.Jumping = true
local Parts = GetAllConnectedParts(Body)
local Mass = 0
for i, v in pairs(Parts) do
Mass = (Mass + v:GetMass())
end
ThrustForce.maxForce = Vector3.new(ThrustForce.maxForce.X, ((Mass * Gravity) * 100), ThrustForce.maxForce.Z)
ThrustForce.velocity = (Vector3.new(0, 1, 0) * Jump.JumpForce) + Vector3.new(ThrustForce.velocity.X, 0, ThrustForce.velocity.Z)
wait(0.1)
ThrustForce.maxForce = Vector3.new(ThrustForce.maxForce.X, 0, ThrustForce.maxForce.Z)
ThrustForce.velocity = Vector3.new(ThrustForce.velocity.X, 0, ThrustForce.velocity.Z)
Jump.LastJump = tick()
Jump.Jumping = false
end
elseif Key == "x" and Down then --Toggle light(s) on/off.
for i, v in pairs(Lights) do
if v and v.Parent then
v.Enabled = not v.Enabled
end
end
elseif Key == "h" and Down then --Play honk sound.
local Sound = Sounds.Honk
if (tick() - Honk.LastHonk) >= (Sound.TimeLength + Honk.ReloadTime) and not Honk.Honking then
Honk.Honking = true
local TempSound = Sound:Clone()
Debris:AddItem(TempSound, Sound.TimeLength)
TempSound.Parent = Body
TempSound:Play()
Honk.LastHonk = tick()
Honk.Honking = false
end
elseif Key == "q" and Down then --Activate special.
if not Special.Allowed or not Special.Enabled or Special.Active then
return
end
Special.Enabled = false
Special.Active = true
wait(Special.Duration)
Special.Active = false
wait(Special.ReloadTime)
Special.Enabled = true
elseif ByteKey == 48 and Down then --Activate speed boost.
if not SpeedBoost.Allowed or not SpeedBoost.Enabled or SpeedBoost.Active then
return
end
SpeedBoost.Enabled = false
SpeedBoost.Active = true
for i, v in pairs(Sparkles) do
if v and v.Parent then
v.Enabled = true
end
end
MaxSpeed.Acceleration = Speed.Acceleration.Boost
MaxSpeed.Deceleration = Speed.Deceleration.Boost
MaxSpeed.Movement = Speed.MovementSpeed.Boost
wait(SpeedBoost.Duration)
MaxSpeed.Acceleration = Speed.Acceleration.Normal
MaxSpeed.Deceleration = Speed.Deceleration.Normal
MaxSpeed.Movement = Speed.MovementSpeed.Normal
for i, v in pairs(Sparkles) do
if v and v.Parent then
v.Enabled = false
end
end
SpeedBoost.Active = false
wait(SpeedBoost.ReloadTime)
SpeedBoost.Enabled = true
end
end
end
end
function InvokeClient(Mode, Value)
local ClientReturn = nil
pcall(function()
ClientReturn = ClientControl:InvokeClient(Player, Mode, Value)
end)
return ClientReturn
end
Spawn(CleanUp)
ServerControl.OnServerInvoke = OnServerInvoke
Tool.Equipped:connect(Equipped)
Tool.Unequipped:connect(Unequipped)
I found it. Freezingplayer is the culprit. I took out "Spawn(FreezePlayer)" when it is unequipped and it works.
function Unequipped()
Spawn(CleanUp)
---Spawn(FreezePlayer)

Lua Create multiple collisions

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.

Resources