Friday, August 28, 2020

Lua quick start guide

Quick start guide to lua

Introduction

This is my quick and basic introduction to lua.
In this guide i will quickly walk you through the basics of lua.

What this guide is not

This guide is not a step by step introduction to programming.
Nor will this guide cover a bunch of computer science concepts.

What this guide is

This guide assume you have some understating of programming and computer science.
This guide is simply a quick introduction to the basics of lua.
This guide assumes you are familiar with basic programming and want to cover the basics of lua.

Install basics

This guide wont go into the details of installation and running a lua program.
That information is pretty well conveyed by the lua website.
once you have lua set up you can continue the rest of this guide.

The Basics of variables

The very first thing to learn is how lua handles variables.
With lua there is no type declarations or even a var keyword.
To use a variable, simple use the variable name and assign it a value, as seen in example below
You can find all the example code used in this guide over on github.

Variables in lua
Example of using variables in lua

Variables can be assigned to any type of data, int, floats, strings, etc.
Variables can also be reassigned to a different type.
For example, a variable holding a string can then be assigned to hold an int.
By default all variables are global. To make a variable local, use the local keyword.

Local variables in lua
local variables.

Functions

Functions are declared by using the function keyword.
Return types are not declared as they are in languages such as C.
Functions are closed with the end keyword.

functions in lua
functions in lua.

Functions declared local have their scope limited the same as variables.
Local functions can only be called below them in the file.
Local functions can be quicker than non local function.

Functions can return no data, a single variable, or many variables.
Functions return multiple items as separate variables.
If you try to assign more variables to a function than it returns, the excess variables are assigned the value nil

tables

Tables are lua's storage device.
Understanding tables is a very big key to being good at lua.
Tables can be used as dynamic arrays are used in other languages.
Tables can also be used like associative arrays or dictionaries.
You can store almost anything you want in a table,and aren't limited to a single data type per table.
One thing to keep in mind: Tables start at 1 not 0.

tables in lua
Tables in lua.

Inserting data into tables

inserting elements into tables
Inserting elements into a table.

There are two main ways to insert data into an array: using an index and using table.insert()
There are two forms of table.insert():

  • table.insert(mytable,element)
    • This will place the element at the end of the given table.
  • table.insert(mytable,index,element)
    • this one inserts the element at the given index into the table.

You can also assign the return data from a function to be elements in a table.
When assigning from a function returning multiple items, each item will be a sequential element in the table.

Retrieving data from table

Accessing elements in tables
Retrieving data from a table.

Retrieving data from a table used as an array is simple: just use the index like you would in most other language.
For tables used as associative array/dictionaries, you have two options:

  • use the key in mytable[key] like using an index.
  • Use mytable.key.

Removing elements from a table

Removing items from a table is easy, just use table.remove(mytable,index).
For an associative array/dictionary table, set the key to nil to remove the key,value pair.

Removing elements from a table
Removing elements from a table.

sorting tables

Sorting tables is pretty easy. lua includes a built in quicksort for this.

sorting tables in lua
sorting tables.
  • table.sort(mytable)
    • This sorts the elements in the given table numerically.
  • table.sort(mytable,compr)
    • this version takes in a function to do the comparison.
    • Using a custom compare function lets you sort elements in a table however you like.

That covers the basics of using tables. But to get really good, you should read up on metatables.
Metatables cover the inner workings and properties of a table.
You can get tables to do some interesting things by changing its metatable.

Printing

Printing to stdout is fairly simple
The standard way to do so is to use io.write()
Lua does have a print() function, but io.write() is the standard one to use.

printing to STDOUT in lua
Print to stdout.

Control flow

If you are familiar with any other modern programming language, then this section should be familiar.
Only things to note are lua syntax specific things such as:

  • if statements need an end just like functions.
  • Lua uses and for logic AND.
  • Lua uses or for logic OR.
  • Lua uses ~= for not equal to.
  • Lua uses not for logical NOT.
  • elseif is one word.
Control flow in lua
control flow in lua.

Loops

Loops in lua should be easy to grasp for anyone with programming experience.

  • Syntax for a standard for loop is var=start,stop,increment do.
  • repeat until("condition") loops until condition in until() is true
    • So you can think of it like a do while() loop but the condtion is reversed
  • ipairs() iterates over a table giving you an index and element on each iteration.
  • pairs() iterates over a table giving you a key and value on each iteration.
  • loops need an end just like functions and if statements.
Loops in lua
Loops in lua.

File I/O

Basic file I/O is fairly simple.
The example code pretty much sums up the basics.
There are a few functions such as fseek() and flush() which are not covered here.
I felt that those functions were beyond the scope of my very basic introduction guide.

Reading files in lua
Reading files in lua.
Writing files in lua
writing to files in lua.

Math functions

The math library for lua has the typical math functions you'd expect.
Again, if you have any programming experience then you probably already know these.
These are the basics, but lua has a few more.

Loops in lua
Math functions in lua.

String Functions

Some of the more commonly used and useful string functions in lua.
The only thing to take note of is that the regex flavor used by lua may differ a bit from what you find elsewhere.
Needles to say, but a look at the lua reference on regex would be beneficial.

String functions in lua
string functions in lua.

Final remarks

Thank you for checking out my basic introduction to programming in lua.
I intentionally left out things which I felt were beyond the basic scope and goal of this guide.
Two big things which are missing are metatables and OOP.
I felt that there is just too much to cover for those topics and they each deserve their own separate posts.
You can find all the example code used in this guide over on github.

Simple Platformer - Part 4

Getting started with Love2d - part 4

Introduction

Welcome to part 4 of my ongoing series about game dev using Love2d.
In this part we will expand upon the work we did previously.
First we will slightly alter how we draw images to screen.
Then we will better organize our code to move the player.
Lastly we will add the ability to run into enemies and destroy them.

Working with offsets

The typical way that love2d draws an image onto screen is to use x,y coordinates.
So far the way we have been using them, love2d has been using x,y as the upper left corner of the image.
We would like to change this so that x,y refer to the center of the image.
We will place the offsets in two variables in CHARACTER class as ox, and oy.
We will set the value to these variables using the love2d functions getHeight() and getWidth()

Updated CHRACTER constructor
New variable in CHARACTER class

We will now update our draw function to accommodate these offsets.
As you can see from the image below, .draw() now has a bunch of new arguments.
If you want to know what each of them are, please see the Love2d reference

udated draw function
Updated draw function

You will now see that the program draws the player character a bit off screen.
You can fix this by adjusting the x and y values you use when creating him.
You will also notice that our bounds checking is slightly off now. Don't worry, we will soon fix this.

Improving movement

The first thing we are going to do is break up our current keypress function into smaller functions.
We are going to create one function per direction: up,down,left,and right.
Since no other object in the game uses these functions, we make them belong to PLAYER class.
We place these functions in our Characters.lua file.

new player movement functions
Player movement functions

We can now clean up our keypress function.
We can simply call the corresponding function to move player that direction.

Updated keypress function
Updated keypress function

If you test it out, this now works just as before, but much better organized.
But wouldn't it be nice to be able to move around by holding down the key?
I think it would, so we can replace our love.keypress() by a new function.
We make our keyboardInput() and use the function love.keyboard.isDown("key").
After making keyboardInput we call it at the end of love.update()

keyboardInput function
our new keyboard input function

You should now be able to move the player character around by holding down a movement key.
The speed at which he moves is governed by the speed variable inside of CHARACTER class.
We next need to slightly adjust our enemy move function to account for the offsets.
Once that is done you should now see the game working as it should.

Updated enemy move function
Updated ENEMY:move()

Collision detection

We are now going to add the ability to collide into an enemy.
When player character collides into an enemy, the enemy is removed from the game.
We need to check for four conditions to account for a collision:

  • player's head is above the enemy's feet.
  • The player's feet are below the enemy's head.
  • Player's left side is to the left of the enemy's right side.
  • Player's right side is to the right of the enemy's left side.

If you walk through these four steps, maybe even draw out a diagram, you will see that it accounts for a collision between the player and enemy.
We will add a function in Character.lua to account for this.
We make this function belong to ENEMY class.
You can see that it checks for a collision and returns true if player and enemy collide.

function which checks for a collision with an enemy
function to check for a collision

Now that we can check for a collision between a player and a single enemy, we need to expand this for all enemies.
We accomplish this by writing a function in main.lua to loop through ENEMY_LIST.
This functions checks for collision with the player on each and every enemy in ENEMY_LIST.
If a collision is detected with an enemy, we remove that enemy object from ENEMY_LIST.
Once we have this function, we need to call it at the bottom of our love.update() function.

Checking each enemy for a collision
function to check all enemies for a collision

With everything in place we should now be able to touch an enemy and have them removed from the game.

Final remarks

Thank you for checking our part 4 of my series on Love2d.
Continue on to part 5
As always, you can get the complete code from github.

Thursday, August 27, 2020

Simple Platformer - Part 3

Getting started with Love2d - part 3

Introduction

This is part 3 of my ongoing series on making a simple platformer using Love2d.
For this part we are going to continue our adventure into OOP and further improve our code.
We will make a dedicated player class,start doing some polymorphism, and create some more enemies.

get organized

The first thing we will do is get better organized.
In the directory where main.lua is, make a new directory named 'images'
We will now put our character images here to help keep us organized.
In the code where we load images, we need to change 'player.png' to '/images/player.png'
Do the same for the enemy image as well.

making a player class

The next thing we need to do is create a player class. This is identical to how we made an enemy class
So far we have no unique variables or functions for player but we will change that later on.

Player class
player class

Now that we have a player class we need a constructor functions.
This is also similar to what we did with enemy class.

constructor for player objects
player constructor

We now need to change one line in main.lua to make player a PLAYER object.

updates love.load()
making player object in main.lua

We now have a working separate class for our player

Making multiple enemies

We will now make multiple enemies in our game.
To easily handle this we are going to create a table to hold enemy objects.
And to make this even easier, we make a function to populate this list for us.
So we have ENEMY_LIST to hold our enemies and makeEnemies() to populate our table with enemy objects

tabel to hold multiple enemy objects.
making list of enemies

We now have multiple enemies in our game. This can easily be expanded to make as many as we want.
Notice that the i*100 in our function just places the enemies 100 pixels a part.
Also notice that the WIDTH has been increased to accommodate these new enemies.

Drawing characters

We will now go further with our OOP adventure.
To do this we need to create a function to draw character objects to screen.
Since both player and enemy are subclasses of character, this function will work for both of them.
Hurray for polymorphism.

function to draw character to screen
function to draw character objects to screen

We now need to make a function to go through enemy_list and print each enemy to screen.
To accomplish this we just need a loop to go through enemy_list, pretty simple stuff.
Notice we make use of our newly made draw function.

loop through enemy_list and draw each enemy to screen
function to draw enemies to screen

Now that we have our function to draw objects to screen and a loop to go through each enemy, we need to update love.draw().
With just these two lines we can now print both the player and all the enemies to screen on each frame.

updated love.draw()
updated our love.draw() function

We now have the capability to print a player and any number of enemies to screen.
so far the enemies don't do anything, but we are about to change that.

Moving Enemies

We will now make our enemies move back and forth as we previously did with a single enemy.
To do this we need a function to go through ENEMY_LIST.
With each enemy object in the loop we call the move function which we previous made

function to move enemies
function to move each enemy on screen

We now need to update our code in love.update to call this new function.

updated love.update()
updated love.update()

we should now have three enemies moving across the screen and a player who can also move around

The game so far.
Enemies moving around

Final remarks

With just a little bit of reorganizing and adding a tiny bit to our previous code we can now:

  • make multiple enemies in our game.
  • print them all to screen.
  • have each enemy move independent of each other.

It may not seem much, but it is progress we are making on our game.
The full code for this part is available on github
Thank you for checking out part 3 of my series on game dev.continue to part 4

Simple Platformer - Part 2

Getting started with Love2d - part 2

Introduction

This is part 2 of my ongoing journey to make a simple platformer utilizing Love2d.
In this part we will utilize basic OOP functionality and also make the enemy character move across the screen.

OOP

To improve upon our code, we are going to utilize basic principles of OOP(or as OOP as lua gets.)
The first thing we can do to improve our code is make a class for our characters.
The first step is to create a CHARACTER class followed by a constructor function:CHARACTER:new()
In the constructor we make a new character object then assign the variables in that object the correct values.
In a file called 'Characters.lua' we add the code:

Characters.lua
basic Character class

The next step is to make some changes in main.lua
When need to let lua know about our character class,so we add require "Characters"
Next we need to create character objects for the player and enemy, so we change the code in love.load()
The final bit of change is that we need to use the x and y in these objects therefore we alter the code in love.draw() and love.keypress()
The updated main.lua code can be seen below:

updated main.lua

Moving the enemy character

Now we can work on getting the enemy character to move left and right.
we want him to move right until he reaches the limit set by WIDTH, then have him move left till he hit the edge.then rinse repeat
To accomplish this we are going to add a function in Character.lua to handle this. CHARACTER:move() As long as move_r is true then the enemy should move to the right.
We employ the same bounds checking as we did in key.press in part 1.
When the enemy reaches the right hand boundary, we have to change his direction, that's where move_r = false comes into play.
And when the enemy reaches the left hand side, we simply set move_r back to true.
You can see the complete CHARACTER:move() function below.

moving enemy character
function to control enemy movement

We next need to update our code in main.lua
We need to use the function love.update()

  • This function updates at the start of each frame.
  • Put everything which needs to update or run with each frame here.

Inside this function we call the CHARACTER:move() function on the enemy object.
You can see our new function in the code below.

love.update()
love.update()

Improving our code further

To further improve our code we can employ encapsulation.
We can create an enemy class. The player character has no need for the move function nor move_r variable
So we create a class for the enemy object and attach that function and variable to it.
We have to modify our Characters.lua file to add the enemy class, constructor function, and a slight change to the move function.
We also need to make sure to set the metatable and index of the enemy class so that it is a subclass of the character class.
The code we added is below.

enemy class
Added enemy class

After adding our enemy class we need to make one slight change to our main.lua
just change the type of object for enemy in our love.load function.

making the enemy object
making enemy object

Final

We should now have a program which does the same thing as before, but now it is much more organize.
More importantly for our needs it can much more easily be expand and added to.
Using our class system we can now easily add many new objects and add or remove functions and variables to them.
as always, complete code can be found on github.

Thank you for sticking around for my part 2. Continue on to part 3

Wednesday, August 26, 2020

Simple Platformer - Part 1

Getting started with Love2d - part 1

Introduction

This is the first part of my atempt to learn Love2d by creating a small, simple platformer.

For this part, i set up a simple program which displays a player and enemies.
The player is then given the ability to move around.

Displaying characters to screen.

The first step to this program is creating and displaying the player character and enemies.

First thing is that i need to draw a character for the player and a character for the enemies.
I opened up GIMP and drew the characters.

For the player, i drew a simple stick man.

player
Player character

For the enemies, i drew a simple goomba looking dude.

enemy
Enemy character

To load the images, the Love2d code needed is love.graphics.newImage("path/to/image")
this loads image and allows you to save it to a variable.

To display the image, code needed is love.draw()
and also love.graphics.draw(icon,x,y,r,sx,sy,ox,oy)

love.load()

  • callback function which loads things at the very start of the game.

love.draw()

  • call back function whcih draws to screen every frame.

love.graphics.draw(icon,x,y)

  • function which draws a given image to screen.
  • Arguments to function are:
    • icon
      • image to draw to screen.
      • image previously loaded with love.graphics.newImage
    • x
      • x postion of image
    • y
      • y image of image

combining all of these together into code, it should look a bit like this.

code to draw characters to screen
code which draws player and enemy to scren

giving us an output which looks like this:

two characters drawn to screen
player and enemy together on screen

Adding movement

Now that we can display the player onto the screen, we need to move him about.
To accomplish this, we will need to add a few things to our code.

The things needed are a variable for player x, a variable for player y.
We also need the function love.keypressed()

  • PLAYER_X and PLAYER_Y holds the location of player's x and y co-ordinates.
  • love.keypresed() function which handles keyboard input

We start by creating the global variables for player position. We next need to change the code in love.draw() to use these variables.

updated load and draw functions
updated load and draw functions.

the last thing needed is to set up the love.keypressed() function
We used the standard 'wasd' for movement.
We update the global variable for player x and player y when the corresponding key is pressed.

keypress function should look like:

keypress function
player can now move around

We next need to set boundary for the player. We don't want the player to wander off screen.
To accomplish this, we set up two global variables: HEIGHT and WIDTH
HEIGHT controls where the bottom of the screen is, and WIDTH controls where the right hand edge of screen is.
All we have to do is add an if statement to each of the movement keys checking if player is out of bounds.
The completed code should look like this:

final code
player can move around but can't go out of bounds.

full code can be found on github

Conclusion

We should now have a simple program which draws characters to the screen and allows the player to move around, but not to move out of bounds.We now know how to draw characters to screen, take in keyboard input, and use this keyboard input to update to change things in game.

Continue to part 2 of this walk through..

Simple Platformer - Introduction

Getting started with Love2d

Introduction

This is my journey to learn Love2d by making a very simplistic and basic platformer style game.
I'll document and talk about the parts of the game and my design decisions along the way.
This will mostly be for my benefit, but i hope that others can learn or gain something from it as well.

Why this stuff in particular?

Why did i choose to use lua and love2d for game dev?

Why lua?

  • I am fairly familiar with lua at this point.
  • I generally like working with lua. Liking the language is important when working on a decent sized project
  • I find the syntax of lua fairly easy to read. in general i like the syntax of lua.
  • There is a pretty well developed game dev ecosystem for the language.
    • Love2d is made for using lua. Since it is the framework i am using, it makes sense to use the language for it.

Why Love2d?

so why did i choose Love2d when there are other options?

  • I already have a tiny bit of knowledge and experience with Love2d.
    • Not much knowledge and experience though. Just what could be considered a hello world program for it.
  • It is a simple and easy to use framework.
    • Does what i need it to, and not much more.
    • It seems pretty straightforward. Nothing that even i couldn't understand.
  • Simple 2d games seem to be what it is intended for, and since that is what i'm making it seems the best tool to use.

Why a platformer

So why did i choose to make a platformer rather than a different genre of game.

  • It needed to be a 2d game
  • It needs to be more than a simple game that can be made in 200 lines of code or fewer.
    • If it is too simple of a game, I wont learn much or have much fun making it.
    • If it is too complicated, I will get burned out and not have fun making it.
  • The object isn't to make the funnest or most mind blowing game ever.
    • It needs to be something which I can handle. I'm no expert game dev nor expert programmer
    • It primarily serves as a learning opportunity for me.

So with all those criteria for the game, i decided that a platformer is the one which best fits my needs.It will not be the most advanced game ever made.
Nor will it be particular fun game to play, nor any revolutionary or breakthrough mechanics.
I cant even claim it will be programmed well or efficiently.
But i can say that it will definitely teach me a thing or two about game dev, programming, and using love2d.

Conclusion

Thank you for checking out my series on game dev. Please check back for the following articles where i will start developing the game.

you can view part 1 here

You can also view my quick start guide to using lua here