1) The thruster rotates around the very center of the image. I'd like to to rotate around the very back of it, but I can't seem to figure that out...
You can do this with some basic trig. Since you have the direction of the thrust, all you have to do turn it into a vector and then multiply that by the distance you want to offset the thrusters.
Code: Select all
local direction = particleSystem:getDirection()
local x = math.cos( direction ) * distance
local y = math.sin( direction ) * distance
particleSystem:setPosition( player.x + x, player.y + y)
2) The particles eat up memory if I'm not careful. It's pretty stable on my computer with the current setup, but is there a way to make it a bit more efficient? Or do I just have to sacrifice having a lot of particles?
You do seem to be using a lot of particles for effects. It's ultimately up to you but I suggest decreasing the particles to a reasonable amount.
3)The stars in the background. As you'll see in data.lua, they're dynamically drawn. All 500 of them. I had 1000 but that was eating resources fairly bad so I cut it. I'm asking if there's a simpler way of drawing the same type of stars with a bit more efficiency. If not, I don't think it'll kill a game as small as this is meant to be.
I don't think that your star creation code is doing what you think it is. For the first 500 seconds of the game you will create one star every update (regardless of the amount of time that has actually passed). So if you're running at a constant 120 fps you'll end up making 60,000 stars over about 8 minutes, which is why you're probably getting the slow down. I'm guessing you only wanted to make 500 stars but tried to make one per second for performance. Making 500 tables is nearly instantaneous so you should just make them all at once.
4)Does love.audio not let me play overlapping sounds? In geowars, the shooting sound happens for every bullet at the proper pitch. Is there a way to do this with love without pitching the sound up like I've done? If not it's no huge deal. It also applies to the scroll wheel sound too.
I believe only one sound can be playing per source. The love.audio module is pretty low level and does not manage things automatically. There are libraries that do this for you such as
TEsound.
5) I know my functions, tables and variables could be more efficient but I don't know enough about this stuff to do it. Any suggestions are very welcome.
You really only need to worry about efficiency when it becomes a problem. Make it work first and then worry about efficiency if you get slowdowns. When you do get a slowdown is most likely going to be inside of a loop. Use a profiler instead of guess work to determine where your bottlenecks are. I recommend
ProFi. But don't stress too much about optimization. You're still a beginner and no matter what you do you're going to get better and trash your old code. Just use this time to learn and have fun.
6) The particles should carry out their business and then fade, even if the color was changed. Notice, when you shoot a wall while red, then switch to blue, the explosion that already happened changes to blue. Idk how to get rid of that. I suspect it has something to do with tables or OOP or something...
No, I believe that's just the way the particle systems were designed. When you switch the colors it affects all of the particles in the system immediately. One trick to get around it is to have a separate, identical particle system for each color you're going to use.
7) The "walls." When the ship hits one of the designated "walls," it sort of gets "stuck" for a second. It's a bit annoying. I don't know much about OOP(I'm trying to figure out how it works...) but I suspect it'd be better to make some sort of "wall class" where everything to do with the walls of the game are in there. If player hits it, wall does this to player. If bullet hits it, wall does this to bullet. Any deep explanation of this sort of system would be awesome.
I haven't looked at the code but that sounds like you're not setting your velocity to 0 when you hit the wall. The wall is pushing the player out but the velocity is still pushing the player toward the wall so it gets "stuck". Flexible collision systems can be pretty complicated. I suggest using
HardonCollider.
8) I have a really shitty box made out of 3 rectangles. There are 3 to increase the line size. You'll notice that if you move while near the right side or the bottom, the lines really mess up and it's a bit of a headache. I think this could be fixed with this "wall class" that I mentioned above. Idk how to implement that correctly.
See
love.graphics.setLineWidth
9)I've left the files fairly commented on different things. If you've got a minute and see something in my code that could help me make this game better and my knowledge of Lua/Love expand, I'd be very appreciative.
You're a beginner but you ask really great questions. You have the right mindset, just not the experience.
Use globals sparingly. Ideally, only have one global table that you store all of your global values into. The problem is that globals are hard to track down and keep up with. Restricting everything to local makes sure that everything happens in one place and is easy to find. You may wonder how you can get access to data in other files if you can't declare things globally and the answer is that files are actually ran as functions and can return values. So the common thing to do is simply define everything in a local table and then return that. This is a lot less confusing than it sounds and cleans up your code a lot.
A good example of this is your background stars. Instead of declaring them globally and putting them in a very generic file named "data.lua" put them in in a local table their own lua file called "stars.lua" and return that table.
Example:
Code: Select all
-- Inside stars.lua
-- Put all functions in this table
local stars = {}
-- Define the functions
function stars.create() ...end
function stars.spawn() ... end
function stars.draw() ... end
-- Return the functions in one table
return stars
------------------------------------------------------------------------------------------------
-- Inside main.lua:
-- Get the stars table returned in stars.lua
local stars = require("stars")
-- Loads the stars
function love.load()
stars.create()
end
-- Draw the stars
function love.draw()
stars.draw()
end
You seem a little confused about OOP. What you keep referencing is "instancing" which is one aspect of OOP. Instancing is where you have a table with shared functions but independent data. For example, you can have the same type of enemy in two different locations with two different levels of health because they have their own location and health variables. However they have the same functions so they behave exactly the same.
You can accomplish this easily in lua using the __index metamethod. Metamethods are special functions that can be used to define a metatable. A metatable can be used to change the behavior of another table. They're very powerful but can be a little confusing at first. This is how you set a metatable:
Code: Select all
local meta = {}
local t = {}
setmetatable(t, meta)
After that code, "meta" is now the metatable of "t" but it doesn't do anything yet because we haven't defined any metamethods. So let's define __index. When the table can't find a stored value in a normal table it will attempt to look in it's metatable's __index for it.
Code: Select all
print( t.text) -- Prints nil
meta.__index = { text = "hello" }
print( t.text ) -- Prints "hello"
On the third line of the above code snippet, t.text isn't found so it looks inside of the meta.__index table. There, a value of "hello" is found it's returned as if it had been contained inside of t. You can also set the metatable's __index to itself.
Code: Select all
print( t.text ) -- Prints "hello"
meta.__index = meta
meta.text = "there"
print( t.text ) -- Prints "there"
If you're confused at this point, that's ok. You'll figure it out eventually. Now let's make a full-fledged class using what we just learned:
Code: Select all
-- Create a metatable and set the __index to itself.
local Person = {}
Person.__index = Person
-- A function to create a new person with independent x and y values and "Person" as the metatable.
function newperson(x, y)
local instance = setmetatable({}, Person) --Creates a new table, sets it's metatable to person then returns it
instance.x = x
instance.y = y
return instance
end
-- This function is shared between "Persons"
function Person:move(x,y)
self.x = self.x + x
self.y = self.y + y
end
-- Note how there is a colon (:) instead of a period (.) in-between the table and the function in the above code.
-- This causes the value "self" to become whatever the first parameter is. It is equivalent to the following function:
function Person.move(self, x, y)
self.x = self.x + x
self.y = self.y + y
end
-- Similarly, if you call a function using a colon instead of a period the table will become the first parameter.
-- These two function calls are exactly the same:
Person.move( Person, x, y )
Person:move( x, y )
-- Now, create two new people, both at location 0,0
local p1 = newperson(0,0)
local p2 = newperson(0,0)
-- Move them. They both have "Person" as their metatable so they use Person.move() but their x and y values are different.
p1:move(5,5)
p1:move(10,10)
-- Now they are at two different locations
print(p1.x, p1.y) -- Prints "5 5"
print(p2.x, p2.y) -- Prints "10 10"
I know that was a huge TLDR, but I hope it cleared some things up. None of this code is tested so sorry if it doesn't work correctly.