Beginner Help? - General Help and Game Help

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Sola
Prole
Posts: 2
Joined: Fri Dec 07, 2018 9:24 am

Beginner Help? - General Help and Game Help

Post by Sola »

Sorry if the title isn't very descriptive.

I'm a beginner to programming (I know pretty much all of the basics in Python and am just confused about a few things in Lua) and I am trying to learn how to make games on my own, without just following tutorials and copying code.

The game I'm trying to create for practice is where you essentially dodge shapes with your mouse and if you hit one you die and it restarts. The shapes are all different sizes speeds. So far I have a green circle that sticks to your mouse coordinates and a single random rectangle that spawns above the screen and falls down.

But I could not figure out anything beyond that. Looking all of my problems up online just gave me answers very specific to other's code that I couldn't understand.

So I have quite a few questions here. The first one being:

1. Where do I put things in my code?
In a tutorial I watched to get the basics of Love, they brought up the main 3 'game functions' (for lack of better terminology) but they didn't really explain it. The

Code: Select all

function love.load()
,

Code: Select all

function love.update(dt)
,

Code: Select all

function love.draw()
.

I vaguely understand where to put basic things, like drawing rectangles in the love.draw function and dealing with movement/controls in the love.update function but when I'm trying to do more complex things I get lost. Such as new functions. Do you/can you write functions inside of functions? (Should you do that? (Most of the time I try to put functions at the top but I always get nil values.)) Furthermore, is love.load, update, and draw even that important? I.e.: Is it more like a guideline or does stuff just not work if you don't have it?

And now the more specific problems:

Spawning multiple objects, collision, and a game over sequence?
These are mainly the things I said I couldn't find good examples of online. For collision, I have no idea what love.physics is; it looks crazy complex and complicated at a glance. For the game over sequence, I haven't actually tried. I know how to do such in Pygame, for the most part, but again, not sure where I would put it. (Or if I can/could actually do it in the same way.)

https://pastebin.com/vJ6HeRhM
^ Here's what I have so far. (Sorry if pastebin links are frowned upon - I don't know how to 'package' my game)

Further things, more with Lua, is that I don't quite understand tables. If I could get some explanation of this as well or if someone could direct me to a great (free) place for learning Lua then that would be much appreciated!

Sorry for such a long post. I try not to post my questions online until I'm totally stuck and I'd rather not post multiple at once.
User avatar
CogentInvalid
Prole
Posts: 27
Joined: Sat Dec 14, 2013 12:15 am

Re: Beginner Help? - General Help and Game Help

Post by CogentInvalid »

1. You can put functions inside of functions, but you don't really need to in most circumstances. You can define them outside and then call them from inside other functions:

Code: Select all

function love.load()
    playerX = 100
    playerY = 100
end

function updatePlayer(dt)
    playerX = playerX + 100*dt
end

function love.update(dt)
    updatePlayer(dt)
end

function love.draw()
    love.graphics.rectangle("fill", playerX, playerY, 200, 200)
end
You also don't have to define love.load, love.update, or love.draw, but if love.update is missing nothing will happen in your game, and if love.draw is missing nothing will show up onscreen. Essentially, all the update code needs to either be in love.update, or in a function that gets called from love.update. Likewise with love.draw.

2. For simple games, love.physics isn't really necessary; it's more for accurate 2d physics simulation.

For spawning objects, you can create a table to keep track of your objects and then update them one-by-one with a for loop in love.update:

Code: Select all

function love.load()
    objects = {}
end

function love.keypressed(key)
    -- add an object to the list when the player presses a key
    objects[#objects+1] = {x = math.random()*500, y = 0}
end

function love.update(dt)
    for i=1, #objects do
        objects[i].y = objects[i].y + 100*dt
    end
end

function love.draw()
    for i=1, #objects do
        love.graphics.rectangle("fill", objects[i].x, objects[i].y, 50, 50)
    end
end
There are better ways to structure your data for more complex games, but for your first game, this is a good way to get started.

Tables are pretty simple when you get used to them: they associate a key, which is usually either a number or string, with a value. This allows them to behave like both arrays and hashmaps. There are a few ways to define tables, some of which are shown below:

Code: Select all

t = {"a", "b", "c"}
-- t[1] = "a", t[2] = "b", t[3] = "c"

t = {x = 400, y = 300}
-- t.x = 400, t.y = 300

-- this table contains other tables
t = {a = {33, 44}, b = {a = "yes", b = "no"}}
-- t.a[1] = 33, t.a[2] = 44, t.b.a = "yes", t.b.b = "no"
You can find some resources on tables here: https://www.lua.org/pil/2.5.html, https://www.lua.org/pil/3.6.html, http://lua-users.org/wiki/TablesTutorial

For collisions in your game, your best bet would be to write a function that detects overlap between two rectangles, or to use an existing one. Here's one from the wiki:

Code: Select all

-- Collision detection function;
-- Returns true if two boxes overlap, false if they don't;
-- x1,y1 are the top-left coords of the first box, while w1,h1 are its width and height;
-- x2,y2,w2 & h2 are the same, but for the second box.
function CheckCollision(x1,y1,w1,h1, x2,y2,w2,h2)
  return x1 < x2+w2 and
         x2 < x1+w1 and
         y1 < y2+h2 and
         y2 < y1+h1
end
Each frame, you can call this function with the player and each of the obstacles to test if they are colliding.

As for a game over screen, the canonical way to do it would probably be to create two separate states (as tables with their own update and draw functions attached), and switch from the "game" state to the "game over" state when you lose the game - but for your first game in Love2D it would be simpler to have a variable called "gameOver" which is either true or false, and don't run the game's update or draw code if gameOver is true (instead, draw the words GAME OVER, or whatever).
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: Beginner Help? - General Help and Game Help

Post by pgimeno »

Just two things to add to CogentInvalid's excellent and elaborate answer.

1. I'd advise you to get more acquainted with Lua before trying to write a game. The PIL (Programming In Lua) book mentioned by CogentInvalid is a good book. You don't need to read it all at once, but read at least some chapters to get a decent grasp of how the language works. https://www.lua.org/pil/contents.html . For example, you need to know that Lua functions are values in the same sense that numbers or strings are, and named functions are variables whose value is a function. Therefore, these two are totally equivalent:

Code: Select all

function add(a, b)
  return a + b
end

add = function (a, b)
  return a + b
end
Python has a similar construct, except defining an anonymous function is limited to a single expression. For example, in Python these are equivalent:

Code: Select all

def add(a, b):
   return a + b

add = lambda a, b: a + b
2. Collision is a topic that seems so simple in the surface, but in practice is very hard to implement except for the simplest cases. LÖVE does not have built-in collision detection libraries except through love.physics. I'm only aware of two libraries that can handle what you're attempting to handle (collision between rectangle and circle), namely love.physics and HC. You'll need to learn how to use one of them for your purpose, or switch your shapes to something for which it's simpler to detect collisions, like all circles, or even all axis-aligned rectangles like CogentInvalid suggested.
Sola
Prole
Posts: 2
Joined: Fri Dec 07, 2018 9:24 am

Re: Beginner Help? - General Help and Game Help

Post by Sola »

Wow, I didn't expect such detailed answers, thank you all! I'll be sure to reference this thread going onward.

Just one problem though - I can't do anything in HC. I tried copying some code from the HC docs that worked perfectly (had a circle attached to mouse and a rotating rectangle and collisions registered(but only printed text)) but I couldn't figure out how to make the rectangles move - they just wouldn't and I have no idea why because I did it in the same way I always do. After a bit of fidgeting with it I reverted back to my original code and tried to just implement the collision but then I got:
Error

HC/init.lua:103: attempt to call method 'bbox' (a nil value)


Traceback

HC/init.lua:103: in function 'neighbors'
HC/init.lua:109: in function 'collisions'
main.lua:36: in function 'update'
[C]: in function 'xpcall'
(I'm starting to have ptsd from "attempt to call method '...' (a nil value)"

I'm beginning to think I'm just not cut out for this. :P
User avatar
CogentInvalid
Prole
Posts: 27
Joined: Sat Dec 14, 2013 12:15 am

Re: Beginner Help? - General Help and Game Help

Post by CogentInvalid »

Nil values are definitely the bane of Lua programming. 80% of the time, it means that some code is expecting a table with certain values, but is getting a table that's missing those values, instead. For example:

Code: Select all

a = {}
a.x = 3
a.y = 5

b = {}
function b.update()
    print("success")
end

a.x = a.x + 1 -- works correctly
b.x = b.x + 1 -- error: attempt to perform arithmetic on field 'x' (a nil value)

b.update() -- outputs "success"
a.update() -- error: attempt to call field 'update' (a nil value)
Looking at the traceback and at HC's code, it looks like in your update function you're calling HC.collisions(shape), which in turn calls HC.neighbors(shape), and then crashes because shape doesn't have a function called "bbox" attached to it.

So, the place to look would be line 36 of main.lua. What value are you passing into HC.collisions? HC expects you to pass in an instance of the Shape class, but you're probably passing in something different.

As for why you weren't able to make the shapes move earlier, maybe you needed to use the function Shape:move? I haven't used HC, so I wouldn't know for sure.
Post Reply

Who is online

Users browsing this forum: Amazon [Bot], Bing [Bot], Google [Bot] and 6 guests