My second LÖVE project is close to being completed. This time I am working on a remake of Mortal Pongbat, but with one major new feature: multiplayer peer-to-peer networking.

Pongbat

I am happy to say the code quality of Pongbat is quite improved over Paratrooper, in part due to more programming experience with LÖVE and Lua. In part due to the addition of several high quality LÖVE libraries.

Development on Pongbat started on April 16 (~10 days ago). My time was not fully devoted on Pongbat, as I also spent time working for my Australian client. My daughter was also having a school holiday during this period, so I also spent plenty of time with my daughter.

I am very happy with the progress I made in this short period of time. LÖVE feels extremely productive. LÖVE becomes especially productive once you filter out quality libraries to use in your game and once you establish your own best development practices. I’d like to discuss both topics in this post.

Pongbat Dependencies

Now I will discuss in short what libraries I use in Pongbat and for which purposes:

Best Practices: The Good, The Bad & The Ugly

I am still improving myself as a Lua / LÖVE developer. My code quality has definitly improved compared to my previous project. However there are still areas in which my code quality could improve further. I will not spend time improving the code quality of Pongbat, since I feel this time would be spent better working on a new project. Instead, I will just try to write better code in my next project, based on lessons learned from my work on Pongbat.

The Good

The libraries mentioned previously simplified my codebase in a big way. I will keep using these libraries in future project as each library is of high quality. I do make sure to fork every library on Github, which hopefully guarantees me that I can rebuild Pongbat even if these libraries would disappear in the future.

I’ve added these libraries to Pongbat as git submodules. I know git submodules receive much have, but perhaps in private projects one should encounter few issues.

I’ve added a few utility classes that should be mostly reusable in future projects, though some additional changes might be needed. I’ve added classes to simplify networking and to generate animations.

With regards to classes, I did figure out a way to add private methods. A class with public and private methods I implement as such:

local state = Class {} -- hump.class is used here

-- private method
local function doSomethingPrivate(state, arg1)
 	-- body
end

-- constructor
function state:init(arg1, arg2, ...)
	-- body
end

-- public method
function state:doSomethingPublic(arg1, arg2, ...)
	doSomethingPrivate(self, arg1)
end

return state

With regards to assets, I’ve also had a great experience using Blender to create 3D models and turning these into sprites using Aseprite. I might document my approach in a future post. Sprites designed using this approach are used for the balls in game.

The Bad

My project contains a constants file which is basically a huge list of globals. While this single list makes it easy to modify many aspects of the game, like paddle speed, ball speed, beam duration, etc… it does make the code more intertwined. Globals are generally linked to entities. For example a part of my constants file currently looks as such:

...

-- paddle configuration
PADDLE_WIDTH = 15
PADDLE_HEIGHT = 150
PADDLE_SPEED = 180
PADDLE_ATTACK_DELAY = 5.0
...

-- beam configuration
BEAM_SIZE_MIN = 1
BEAM_SIZE_MAX = 6
BEAM_HEIGHT = 6
BEAM_WIDTH = VIRTUAL_WIDTH - 30
BEAM_FIRE_DURATION = 0.5
...

-- ball configuration
BALL_SPEED_MIN = 200
BALL_SPEED_MAX = 500
BALL_ANGLE = 75
BALL_WIDTH = 20
...

In the future I will move constants to their respective entity classes and as a result my code will cope better with change.

The Ugly

I didn’t find a good solution for private fields, at least not while using a object oriented development approach. Figuring out accessiblity of fields can become confusing as class fields are always public, even if not meant to be.

For my next project I will prefix all fields that are meant to be private with an underscore. I will enforce on myself to never directly change private fields outside a class, instead I will add public method to modify privately marked fields as needed.

Conclusion

Making games with LÖVE has been a very productive and fun experience for me. I’ve tried several other game development frameworks in the past, but never did I really manage to finish a project. With other frameworks I had to put in more effort to get similar results. Also, just being able to develop just using a “simple” text editor as compared to a full-blown IDE has been a breath of fresh air to me.

One of the game development frameworks I’ve used in the past was SpriteKit. While SpriteKit was fun as well, its main disadvantage compared to LÖVE is that one can only write games for Apple platforms. LÖVE allows one to create games that support macOS, Windows, Linux, iOS & Android.