Trying to add horizontal movement to my game in love2d - lua

I have tried to add horizontal movement into my game in love, but I haven't found a way yet. This is my code.
PADDLE_SPEED = 200
player1 = Paddle(10, 30, 5, 20)
player1 = Paddle(10, 30, 5, 20)
player2 = Paddle(VIRTUAL_WIDTH - 15, VIRTUAL_HEIGHT - 30, 5, 20)
player3 = Paddle(30, 10, 20, 5)
player4 = Paddle(VIRTUAL_WIDTH - 30, VIRTUAL_HEIGHT - 15, 20, 5)
ball = Ball(VIRTUAL_WIDTH / 2 - 2, VIRTUAL_HEIGHT / 2 - 2, 4, 4)
if love.keyboard.isDown('w') then
player1.dy = -PADDLE_SPEED
elseif love.keyboard.isDown('s') then
player1.dy = PADDLE_SPEED
else
player1.dy = 0
end
if love.keyboard.isDown('a') then
player1.dx = PADDLE_SPEED
elseif love.keyboard.isDown('d') then
player1.dx = -PADDLE_SPEED
else
player1.dx = 0
end
if love.keyboard.isDown('a') then
player1.dx = -PADDLE_SPEED
elseif love.keyboard.isDown('d') then
player1.dy = PADDLE_SPEED
else
player1.dx = 0
end
if love.keyboard.isDown('up') then
player2.dy = -PADDLE_SPEED
elseif love.keyboard.isDown('down') then
player2.dy = PADDLE_SPEED
else
player2.dy = 0
end
if love.keyboard.isDown('i') then
player3.dy = -PADDLE_SPEED
elseif love.keyboard.isDown('k') then
player3.dy = PADDLE_SPEED
else
player3.dy = 0
end
if love.keyboard.isDown('g') then
player4.dy = -PADDLE_SPEED
elseif love.keyboard.isDown('b') then
player4.dy = PADDLE_SPEED
else
player4.dy = 0
end
This is my class that I call Paddle
Paddle = Class{}
function Paddle:init(x, y, width, height)
self.x = x
self.y = y
self.width = width
self.height = height
self.dy = 0
self.dx = 0
end
function Paddle:update(dt)
if self.dy < 0 then
self.y = math.max(0, self.y + self.dy * dt)
else
self.y = math.min(VIRTUAL_HEIGHT - self.height, self.y + self.dy * dt)
end
end
function Paddle:render()
love.graphics.rectangle('fill', self.x, self.y, self.width, self.height)
end
I would try drawing the rectangles individually, but I would have to remove all the code that includes player1-4. Is there any way that I can set a variable like PADDLE_SPEED to a number?

So your not quite instantiating your Paddle class correctly. Based on Lua's documentation, I changed some things in your paddle class.
Paddle.lua
Paddle={x=0,y=0,width=0,height=0}
function Paddle:new(o)
o = o or {}
setmetatable(o, self)
self.__index = self
return o
end
function Paddle:update(dt)
if self.dy < 0 then
self.y = math.max(0, self.y + self.dy * dt)
else
self.y = math.min(VIRTUAL_HEIGHT - self.height, self.y + self.dy * dt)
end
end
function Paddle:render()
love.graphics.rectangle('fill', self.x, self.y, self.width, self.height)
end
Also I'm not sure what you just didn't include in you question, but I set up your core 3 functions (love.load(), love.update(dt), and love.draw()), set values for VIRTUAL_WIDTH AND VIRTUAL_HEIGHT, and instantiated your player classes according to how the Lua documentation specifies
The main thing that might be your problem is that your assigning the speeds to your player objects dy and dx values. These are made up values that you've created for your player object. They don't do anything unless you later access them and use them somehow. I think what you are trying to do is change the x and y position of your player objects. You can do this by taking the players current x or y position and adding or subtracting the PADDLE_SPEED * dt(the number of seconds that have passed since the last execution of love.update(dt)
main.lua
require('Paddle')
function love.load()
--initial graphics setup
love.graphics.setBackgroundColor(0.41, 0.53, 0.97)
love.window.setMode(1000, 600)
PADDLE_SPEED = 200
VIRTUAL_WIDTH = 30
VIRTUAL_HEIGHT = 30
player1 = Paddle:new{x=10, y=30, width=5, height=20}
player2 = Paddle:new{x=VIRTUAL_WIDTH-15, y=VIRTUAL_HEIGHT-30, width=5, height=20}
player3 = Paddle:new{x=30, y=10, width=20, height=5}
player4 = Paddle:new{x=VIRTUAL_WIDTH-30, y=VIRTUAL_HEIGHT-15, width=20, height=5}
-- ball = Ball(VIRTUAL_WIDTH / 2 - 2, VIRTUAL_HEIGHT / 2 - 2, 4, 4)
end
function love.update(dt)
if love.keyboard.isDown('w') then
player1.y = player1.y + PADDLE_SPEED * dt
elseif love.keyboard.isDown('s') then
player1.y = player1.y - PADDLE_SPEED * dt
end
if love.keyboard.isDown('a') then
player1.x = player1.x + PADDLE_SPEED * dt
elseif love.keyboard.isDown('d') then
player1.x = player1.x - PADDLE_SPEED * dt
end
if love.keyboard.isDown('a') then
player2.x = player2.x - PADDLE_SPEED * dt
elseif love.keyboard.isDown('d') then
player2.x = player2.x + PADDLE_SPEED * dt
end
if love.keyboard.isDown('up') then
player2.y = player2.y - PADDLE_SPEED * dt
elseif love.keyboard.isDown('down') then
player2.y = player2.y + PADDLE_SPEED * dt
end
if love.keyboard.isDown('i') then
player3.y = player3.y - PADDLE_SPEED * dt
elseif love.keyboard.isDown('k') then
player3.y = player3.y + PADDLE_SPEED * dt
end
if love.keyboard.isDown('g') then
player4.y = player4.y - PADDLE_SPEED * dt
elseif love.keyboard.isDown('b') then
player4.y = player4.y + PADDLE_SPEED * dt
end
end
function love.draw()
player1:render()
player2:render()
player3:render()
player4:render()
end
So your ball won't work, because I don't know exactly what you want with it, and your Paddle:update(dt) still won't work because I don't know exactly what you want. When you do get Paddle:update(dt) working make sure you include player1:update(dt), player2:update(dt) ... inside your love:update(dt) function or else none of your players will update.
You should get horizontal and vertical movement of your blocks though
P.S. If you post a question a again, you should make sure that you specify exactly what isn't working. Some of your details were missing, and I wasn't sure if that was the part you were asking about, or you had those details in your original code and were asking about something else.
It seems like you probably want to deal with collisions. Here's another answer where i kind of explain collisions, but I would probably recommend love.physics for this type of scenario

Related

Error ball.lua:21: attempt to call global 'checkcollision' (a nil value)

Having this problem with my code and i don't get it
basically trying to make a small game as an excercise, but failing when trying the ecollision part
from my beginners knowledge, there is a problem in line 21 (if checkcollision()) inside the "Ball" file, but don't know what thee problem is
This is my "Ball" code
Ball = {}
function Ball:load()
self.x = love.graphics.getWidth() / 2
self.y = love.graphics.getHeight() / 2
self.width = 20
self.height = 20
self.speed = 200
self.xvel = -self.speed
self.yvel = 0
end
function Ball:update(dt)
self:move(dt)
self:collide()
end
function Ball:collide()
if checkcollision(self, Player) then
self.xvel = self.speed
local middleBall = self.y + self.height / 2
local middlePlayer = Player.y + Player.height / 2
local CollisionPosition = middleBall - middlePlayer
self.yvel = CollisionPosition * 5
end
end
function Ball:move(dt)
self.x = self.x + self.xvel * dt
self.y = self.y + self.yvel * dt
end
function Ball:draw()
love.graphics.rectangle("fill",self.x, self.y, self.width, self.height)
end
This is my "main" code
require("player")
require("ball")
function love.load()
Player:load()
Ball:load()
end
function love.update(dt)
Player:update(dt)
Ball:update(dt)
end
function love.draw()
Player:draw()
Ball:draw()
end
function checkcollision(a, b)
if a.x + a.width > b.x and a.x < b.x + b.width and a.y + a.height > b.y and a.y < b.height then
return true
else
return false
end
end
My "player" code
Player = {}
function Player:load()
self.x = 50
self.y = love.graphics.getHeight() / 2
self.width = 25
self.height = 100
self.speed = 500
end
function Player:update(dt)
self:move(dt)
self:checkbounderies()
end
function Player:move(dt)
if love.keyboard.isDown("w") then
self.y = self.y - self.speed * dt
elseif love.keyboard.isDown("s") then
self.y = self.y + self.speed * dt
end
end
function Player:checkbounderies()
if self.y < 0 then
self.y = 0
elseif self.y + self.height > love.graphics.getHeight() then
self.y = love.graphics.getHeight() - self.height
end
end
function Player:draw()
love.graphics.rectangle("fill", self.x, self.y, self.width, self.height)
end
can someone point me to the right direction
You require Ball code which uses checkcollision function as upvalue before defining checkcollision function.
Basically you need to define checkcollision before using it anywhere; just reorder your imports.
But to solve it the right way, it would be better to move the checkcollision function to a separate file:
-- checkcollision.lua
local function checkcollision(a, b) ....... end
return checkcollision
and then require it in any file you want:
-- Ball.lua
local checkcollision = require "checkcollision"
function Ball:collide()
if checkcollision(self, Player) then
.......

Love2D trying to generate a chunk that has blocks inside it, but after moving a few chunks away it renders more chunks then intended

I have created a basic chunk generator, a chunk is area filled with squares, when the player moves a few blocks away from 0,0 it works correctly but after moving 4 chunks away it renders more then one chunk instead of one, I am not sure what I am doing wrong, I have given it a go changing some values, but I am left head scratching.
here is the full code, you can copy and paste into VSCODE with love2D to see what happens.
I think the main issue is somewhere around check_boarders function since that is what checks if the player is inside a chunk.
function Key_input(key)
if love.keyboard.isDown(key) then
return 1
else
return 0
end
end
function love.load()
Camera = require "camera"
Cam = Camera()
Basic_Player = {}
Basic_Player.X = 100
Basic_Player.Y = 100
Basic_Player.Speed = 15
Movement = {}
end
function love.update(dt)
Movement.X = Key_input("d") - Key_input("a")
Movement.Y = Key_input("s") - Key_input("w")
Basic_Player.X = Basic_Player.X + Movement.X * Basic_Player.Speed
Basic_Player.Y = Basic_Player.Y + Movement.Y * Basic_Player.Speed
Cam:lookAt(Basic_Player.X,Basic_Player.Y)
X, Y = Cam:position() -- Set cam position to global values
end
function love.draw()
love.graphics.setBackgroundColor(0.5,0.5,0.9)
Cam:attach() -- Renders the player and world inside its own scene
generate_world(10,0)
love.graphics.setColor( 0,0,1, 1 )
love.graphics.rectangle("fill",Basic_Player.X,Basic_Player.Y,30,30)
love.graphics.setColor( 1,1,1, 1 )
Cam:detach()
love.graphics.setColor( 1,0,0, 1 ) --Stays on the screen
love.graphics.print(X .. " / " .. Y ,300,400)
love.graphics.print(love.timer.getFPS( ) ,300,450)
love.graphics.setColor( 1,1,1, 1 )
end
function old_generate_world(_world_size, _seed) -- Before optimization
local _chunk_size = 30
local _block_size = 30
for i = 0, _world_size - 1 do
for f = 0, _world_size - 1 do
local x_val = (_chunk_size * _block_size) * i -- Position value for actually building the chunks
local y_val = (_chunk_size * _block_size) * f
gen_chunk(_chunk_size,_block_size,_seed,{X = x_val ,Y = y_val })
end
end
end
function generate_world(_world_size, _seed)
local _chunk_size = 10 -- Chunk size width and height
local _block_size = 30 -- block size inside the chunk
for i = 0, _world_size - 1 do -- loop through world size
for f = 0, _world_size - 1 do
local x_val = (_chunk_size * _block_size) * i -- Position value for actually building the chunks
local y_val = (_chunk_size * _block_size) * f
local chunk_x_local_size = 0 -- To make sure we get a length for when i and f = 0
local chunk_y_local_size = 0
if i == 0 then -- To make sure the size of the chunk isnt zero
chunk_x_local_size = _chunk_size * _block_size -- Get length of chunk when i = 0
else
chunk_x_local_size = x_val
end
if f == 0 then -- ditto
chunk_y_local_size = _chunk_size * _block_size
else
chunk_y_local_size = y_val
end
-- Checks if the player is inside a chunk if true draw it.
if Check_boarders({X = X,Y = Y},{X = x_val,Y = y_val}, {X = chunk_x_local_size, Y = chunk_y_local_size}) then
gen_chunk(_chunk_size,_block_size,_seed,{X = x_val ,Y = y_val }) -- Actually generate the chunk
end
love.graphics.setColor( 0,1,0, 1 )
love.graphics.rectangle("fill",x_val,y_val,15,15)
love.graphics.setColor( 1,1,1, 1 )
end
end
end
function Check_boarders(player_pos, boarder_pos, chunk_length) -- Checks player position is inside the boarder of the currently generated chunk
if player_pos.X > boarder_pos.X and player_pos.X < boarder_pos.X + chunk_length.X then -- Check if the player is greater then top left and less then top right
if player_pos.Y > boarder_pos.Y and player_pos.Y < boarder_pos.Y + chunk_length.Y then -- check if player is greater then top and less then bottom left
return true
end
end
return false
end
function gen_chunk(chunk_size,block_size,seed,position) -- chunk size is how many blocks inside the chunk, block size is self explain, seed n/a, pos starting chunk position
for i = 0, chunk_size - 1 do
for e = 0, chunk_size - 1 do -- loop until chunk size is met this is the amount of blocks being created
love.graphics.rectangle("fill",position.X + i * block_size,position.Y + e * block_size,block_size - 1,block_size - 1)
end
end
love.graphics.setColor( 1,0,0, 1 )
love.graphics.rectangle("fill",position.X ,position.Y,6,6)
love.graphics.setColor( 1,1,1, 1 )
end
You will need this camera.lua script just create it and paste this into it:
local _PATH = (...):match('^(.*[%./])[^%.%/]+$') or ''
local cos, sin = math.cos, math.sin
local camera = {}
camera.__index = camera
-- Movement interpolators (for camera locking/windowing)
camera.smooth = {}
function camera.smooth.none()
return function(dx,dy) return dx,dy end
end
function camera.smooth.linear(speed)
assert(type(speed) == "number", "Invalid parameter: speed = "..tostring(speed))
return function(dx,dy, s)
-- normalize direction
local d = math.sqrt(dx*dx+dy*dy)
local dts = math.min((s or speed) * love.timer.getDelta(), d) -- prevent overshooting the goal
if d > 0 then
dx,dy = dx/d, dy/d
end
return dx*dts, dy*dts
end
end
function camera.smooth.damped(stiffness)
assert(type(stiffness) == "number", "Invalid parameter: stiffness = "..tostring(stiffness))
return function(dx,dy, s)
local dts = love.timer.getDelta() * (s or stiffness)
return dx*dts, dy*dts
end
end
local function new(x,y, zoom, rot, smoother)
x,y = x or love.graphics.getWidth()/2, y or love.graphics.getHeight()/2
zoom = zoom or 1
rot = rot or 0
smoother = smoother or camera.smooth.none() -- for locking, see below
return setmetatable({x = x, y = y, scale = zoom, rot = rot, smoother = smoother}, camera)
end
function camera:lookAt(x,y)
self.x, self.y = x, y
return self
end
function camera:move(dx,dy)
self.x, self.y = self.x + dx, self.y + dy
return self
end
function camera:position()
return self.x, self.y
end
function camera:rotate(phi)
self.rot = self.rot + phi
return self
end
function camera:rotateTo(phi)
self.rot = phi
return self
end
function camera:zoom(mul)
self.scale = self.scale * mul
return self
end
function camera:zoomTo(zoom)
self.scale = zoom
return self
end
function camera:attach(x,y,w,h, noclip)
x,y = x or 0, y or 0
w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight()
self._sx,self._sy,self._sw,self._sh = love.graphics.getScissor()
if not noclip then
love.graphics.setScissor(x,y,w,h)
end
local cx,cy = x+w/2, y+h/2
love.graphics.push()
love.graphics.translate(cx, cy)
love.graphics.scale(self.scale)
love.graphics.rotate(self.rot)
love.graphics.translate(-self.x, -self.y)
end
function camera:detach()
love.graphics.pop()
love.graphics.setScissor(self._sx,self._sy,self._sw,self._sh)
end
function camera:draw(...)
local x,y,w,h,noclip,func
local nargs = select("#", ...)
if nargs == 1 then
func = ...
elseif nargs == 5 then
x,y,w,h,func = ...
elseif nargs == 6 then
x,y,w,h,noclip,func = ...
else
error("Invalid arguments to camera:draw()")
end
self:attach(x,y,w,h,noclip)
func()
self:detach()
end
-- world coordinates to camera coordinates
function camera:cameraCoords(x,y, ox,oy,w,h)
ox, oy = ox or 0, oy or 0
w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight()
-- x,y = ((x,y) - (self.x, self.y)):rotated(self.rot) * self.scale + center
local c,s = cos(self.rot), sin(self.rot)
x,y = x - self.x, y - self.y
x,y = c*x - s*y, s*x + c*y
return x*self.scale + w/2 + ox, y*self.scale + h/2 + oy
end
-- camera coordinates to world coordinates
function camera:worldCoords(x,y, ox,oy,w,h)
ox, oy = ox or 0, oy or 0
w,h = w or love.graphics.getWidth(), h or love.graphics.getHeight()
-- x,y = (((x,y) - center) / self.scale):rotated(-self.rot) + (self.x,self.y)
local c,s = cos(-self.rot), sin(-self.rot)
x,y = (x - w/2 - ox) / self.scale, (y - h/2 - oy) / self.scale
x,y = c*x - s*y, s*x + c*y
return x+self.x, y+self.y
end
function camera:mousePosition(ox,oy,w,h)
local mx,my = love.mouse.getPosition()
return self:worldCoords(mx,my, ox,oy,w,h)
end
-- camera scrolling utilities
function camera:lockX(x, smoother, ...)
local dx, dy = (smoother or self.smoother)(x - self.x, self.y, ...)
self.x = self.x + dx
return self
end
function camera:lockY(y, smoother, ...)
local dx, dy = (smoother or self.smoother)(self.x, y - self.y, ...)
self.y = self.y + dy
return self
end
function camera:lockPosition(x,y, smoother, ...)
return self:move((smoother or self.smoother)(x - self.x, y - self.y, ...))
end
function camera:lockWindow(x, y, x_min, x_max, y_min, y_max, smoother, ...)
-- figure out displacement in camera coordinates
x,y = self:cameraCoords(x,y)
local dx, dy = 0,0
if x < x_min then
dx = x - x_min
elseif x > x_max then
dx = x - x_max
end
if y < y_min then
dy = y - y_min
elseif y > y_max then
dy = y - y_max
end
-- transform displacement to movement in world coordinates
local c,s = cos(-self.rot), sin(-self.rot)
dx,dy = (c*dx - s*dy) / self.scale, (s*dx + c*dy) / self.scale
-- move
self:move((smoother or self.smoother)(dx,dy,...))
end
-- the module
return setmetatable({new = new, smooth = camera.smooth},
{__call = function(_, ...) return new(...) end})

ERROR: "attempt to index global 'self' (a nil value)

I'm very slowly working my way through the games track of cs50, and I am stuck on Mario3. In the video he just talks about the code, but I wanted to write it into my own that I am writing alongside the video. I have the exact same code that he does, but I keep getting this error and I cannot figure out why. I will post the code below, but as far as I can tell, I have already assigned self.mapWidth = 30, so I don't know why it keeps saying that it is a nil value.
Here is the error
Error code
Here is the map.lua code
require 'Util'
Map = Class{}
TILE_BRICK = 1
TILE_EMPTY = 4
--cloud tiles
CLOUD_LEFT = 6
CLOUD_RIGHT = 7
SCROLL_SPEED = 62
function Map:init()
self.spritesheet = love.graphics.newImage('graphics/spritesheet.png')
self.tileWidth = 16
self.tileHeight = 16
self.mapWidth = 30
self.mapHeight = 28
self.tiles = {}
self.camX = 0
self.camY = 0
self.mapWidthPixels = self.mapWidth * self.tileWidth
self.mapHeightPixels = self.mapHeight * self.tileHeight
self.tileSprites = generateQuads(self.spritesheet, self.tileWidth, self.tileHeight)
--fill map with empty tiles--
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
self:setTile(x, y, TILE_EMPTY)
end
end
for y =self.mapHeight / 2, self.mapHeight do
for x = 1, self.mapWidth do
self:setTile(x, y, TILE_BRICK)
end
end
end
function Map:setTile(x, y, tile)
self.tiles[(y - 1) * self.mapWidth + x] = tile
end
function Map:getTile(x, y)
return self.tiles[(y -1) * self.mapWidth + x]
end
local x = 1
while x < self.mapWidth do
if math.random(20) == 1 then
local cloudStart = math.random(self.mapHeight / 2 -6)
self.setTile(x, cloudStart, CLOUD_LEFT)
self:setTile(x + 1, cloudStart, CLOUD_RIGHT)
end
end
function Map:update(dt)
if love.keyboard.isDown('w') then
self.camY = math.max(0, math.floor(self.camY - SCROLL_SPEED * dt))
elseif love.keyboard.isDown('s') then
self.camY = math.min(self.mapHeightPixels - VIRTUAL_HEIGHT, math.floor(self.camY + SCROLL_SPEED * dt))
elseif love.keyboard.isDown('a') then
self.camX = math.max(0, math.floor(self.camX - SCROLL_SPEED *dt))
elseif love.keyboard.isDown('d') then
self.camX = math.min(self.mapWidthPixels - VIRTUAL_WIDTH, math.floor(self.camX + SCROLL_SPEED * dt))
end
end
function Map:render()
for y = 1, self.mapHeight do
for x = 1, self.mapWidth do
love.graphics.draw(self.spritesheet, self.tileSprites[self:getTile(x, y)],
(x - 1) * self.tileWidth, (y - 1) * self.tileHeight)
end
end
end
and in case you need it, here is my main.lua code
WINDOW_WIDTH = 1200
WINDOW_HEIGHT = 720
VIRTUAL_WIDTH = 432
VIRTUAL_HEIGHT = 243
Class = require 'class'
push = require 'push'
require 'Util'
require 'Map'
function love.load()
map = Map()
love.graphics.setDefaultFilter('nearest', 'nearest')
push:setupScreen(VIRTUAL_WIDTH,VIRTUAL_HEIGHT,WINDOW_WIDTH,WINDOW_HEIGHT, {
fullscreen = false,
resizable = false,
vsync = true
})
end
function love.update(dt)
map:update(dt)
if love.keyboard.isDown('escape') then
love.event.quit()
end
end
function love.draw()
push:apply('start')
love.graphics.translate(math.floor(-map.camX),math.floor(-map.camY))
love.graphics.clear(108/255, 140/255, 1, 1)
map:render()
push:apply('end')
end
Thanks in advance for any and all help.
function Map:SomeFunction() end is syntactic sugar for Map["SomeFunction"] = function(self) end
Therefor you can use self inside a function defined with the colon syntax.
Outside of such a function self is nil.
Yet you index self several times in this while loop where self is nil.
local x = 1
while x < self.mapWidth do
if math.random(20) == 1 then
local cloudStart = math.random(self.mapHeight / 2 -6)
self.setTile(x, cloudStart, CLOUD_LEFT)
self:setTile(x + 1, cloudStart, CLOUD_RIGHT)
end
end
which is an infinite loop btw.

attempt to index A nil Value in LUA for CS50 in a PONG game

I've trying to run this program, well, the main works just fine but when I try to run the reset function It says that Ball.lua:14: attempt to index global 'self'(a nil value)
I'm really new to LUA so I'm not sure how to fix it.
Thanks in advance.
Ball = Class{}
function Ball:init(x, y, width, height)
self.x = x
self.y = y
self.width = width
self.height = height
self.dx = math.random(2) == 1 and -100 or 100
self.dy = math.random(-50, 50)
end
function Ball.reset()
--start ball's position in middle
self.x = VIRTUAL_WIDTH / 2 - 2
self.y = VIRTUAL_HEIGHT / 2 - 2
self.dx = math.random(2) == 1 and -100 or 100
self.dy = math.random(-50, 50) * 1.5
end
function Ball:update(dt)
self.x = self.x + self.dx * dt
self.y = self.y + self.dy * dt
end
function Ball:render()
love.graphics.rectangle('fill', self.x, self.y, self.width, self.height)
end

"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()

Resources