Flawed game logic in Lua code - lua

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

Related

Hi, I am creating a simpleplatformer game with love2d, I got a problem in the collisions

In my player script. I called a function to check is if a tile is collided with the player.
The basic tile collisions has been made, but I got some problems.
When the player jump while colliding with the wall, the player stop.
When the player is falling while colliding with the wall, the player stop.
I think the problem is in the Y collision checking part, but I can't figure out how to solve it.
--------------------- Collision Check ----------------------
local box = Vt2:new(self.pos.x + self.vel.x * dt * self.dirXTemp,
self.pos.y + self.vel.y * dt)
for i = 1, #collTile do
local tile = collTile[i]
local isColl = BdBoxCollision(box, self.size, tile.pos, tile.size)
if
isColl[1] == true and
isColl[2] == true and
isColl[3] == true and
isColl[4] == true then
local isOnWall = false
if self.pos.y + self.size.y > tile.pos.y then -- X Collision
if box.x + self.size.x / 2 < tile.pos.x + tile.size.x / 2 then
if box.x + self.size.x > tile.pos.x then
if self.dirX == 1 then
self.vel.x = 0
isOnWall = true
end
end
end
if box.x + self.size.x / 2 > tile.pos.x + tile.size.x / 2 then
if box.x < tile.pos.x + tile.size.x then
if self.dirX == -1 then
self.vel.x = 0
isOnWall = true
end
end
end
end
if box.y + self.size.y / 2 < tile.pos.y + tile.size.y / 2 then -- Y Collision
if box.y + self.size.y > tile.pos.y and
self.pos.y + self.size.y < tile.pos.y + 8 then
if isOnWall == false then
self.pos.y = tile.pos.y - self.size.y
self.vel.y = 0
end
end
elseif box.y + self.size.y / 2 > tile.pos.y + tile.size.y / 2 then
if box.y < tile.pos.y + tile.size.y then
self.vel.y = self.gravity
end
end
end
end
::skip::
self.pos.x = self.pos.x + self.vel.x * dt
self.pos.y = self.pos.y + self.vel.y * dt

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.

How do I use lerp correctly, making sure it reaches the target value

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

"Attempt to index local 'self' (a nil value)" cant index variables of my classes

I know this question already exists a couple of times on this site, BUT my problem is a little different! So... see my problem is that im trying to get a value in a draw function i wrote for my player class but when im trying to get anything with self.such'n'such it says attempt to index local 'self' (a nil value) the functions arent important for my problem (I hope)
require"functions"
Acc = 2000
Decel = 2500
Maxspd = 900
Player = {}
Player.__index = Player
function Player:new(x,y)
local play = {}
setmetatable(play, Player)
play.inx = 0
play.iny = 0
play.dirx = 0
play.diry = 0
play.x = x
play.y = y
play.speedx = 0
play.speedy = 0
play.velx = 0
play.vely = 0
play.clr = "red"
play.hp = 100
play.rot = 0
play.size = 40
play.hoehe = math.sqrt(3) * (40 / 2)
return play
end
function love.load()
Main = Player:new(100,100)
end
function Player:update(d)
if love.keyboard.isDown("w") then self.iny = -1
elseif love.keyboard.isDown("s") then self.iny = 1 else self.iny = 0 end
if love.keyboard.isDown("d") then self.inx = 1
elseif love.keyboard.isDown("a") then self.inx = -1 else self.inx = 0 end
if self.inx == -self.dirx then self.speedx = self.speedx / 5 end
if self.iny == -self.diry then self.speedy = self.speedy / 5 end
self.dirx = self.inx
self.diry = self.iny
if self.inx ~= 0 then self.speedx = self.speedx + Acc * d
else self.speedx = self.speedx - Decel * d end
if self.iny ~= 0 then self.speedy = self.speedy + Acc * d
else self.speedy = self.speedy - Decel * d end
self.speedx = clamp(self.speedx,0,Maxspd)
self.speedy = clamp(self.speedy,0,Maxspd)
self.velx = self.speedx * d * self.dirx
self.vely = self.speedy * d * self.diry
self.x = self.x * d
self.y = self.y * d
end
function Player:getX() return self.x end
function Player:getY() return self.y end
function Player:switch()
if self.clr == "red" then self.clr = "blue" end
if self.clr == "blue" then self.clr = "red" end
end
function Player:draw()
local x1,x2,x3,y1,y2,y3 = 0,0,0,0,0,0
x1 = self.x - self.size / 2
y1 = self.y + self.hoehe / 2
x2 = self.x + self.size/2
y2 = self.y + self.hoehe / 2
x3 = self.x
y3 = self.y - self.hoehe / 2
x1, y1 = rotate_around_point(x1, y1, self.x, self.y, self.rot)
x2, y2 = rotate_around_point(x2, y2, self.x, self.y, self.rot)
x3, y3 = rotate_around_point(x3, y3, self.x, self.y, self.rot)
local verts = {x1,y1,x2,y2,x3,y3}
if self.clr == "blue" then love.graphics.setColor(0,255,0,1) end
if self.clr == "red" then love.graphics.setColor(255,0,0,1) end
love.graphics.polygon("fill",verts)
end
function love.keypressed(key,scancode,isrepeat)
if key == "space" then Main:switch() end
end
function love.update(d)
Main:update(d)
end
function love.draw()
Main.draw()
end
I had the same problem and #EgorSkriptunoff's answer was dead on; going to post here as an answer rather than a comment for posterity.
Probably, you are invoking your functions as x.f() instead of x:f()

bad argument #1 to 'pairs' (table expected, got nil)

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.

Resources