Jump to content
  • Advertisement
  • Remove ads and support GameDev.net for only $3. Learn more: The New GDNet+: No Ads!

  • 08/09/17 10:51 AM

    Make a Shooter in Lua/Love2D - Setup and Player Movement

    General and Gameplay Programming


    Hello! This will be the first in a series of posts on developing a simple shoot 'em up game using the Lua programming language and the Love2D framework. I decided to make this game as a bit of a break from another game project that I've been working on for a while. I chose Lua and Love2D due to their focus on simplicity and efficiency. I will be writing these posts as I learn.

    Getting started

    In order to run the game we are making, you need to install the Love2D framework from https://love2d.org. You might also want to use an IDE or a plugin for your favorite text editor to get things such as autocomplete and syntax checking. Here is a list of such [tools](http://www.gamefromscratch.com/post/2016/01/25/Editors-and-IDEs-for-Lua-and-Love-Development.aspx). Personally I went with the Atom Editor plugin, since Atom is currently my favorite text editor.

    Let's write some code!

    After we have our tools set up, the first thing we'll do is simply create a folder containing a file named main.lua. This is where the Love2D executable will look for the game code's entry point. This is where we will put all our code for now.

    We will start by writing three very important functions:

    • love.load()
    • love.draw()
    • love.update()

    These functions are called by the Love2D engine and are required to get any of our code to run at all. The load() function is called exactly once, when the game is started. The draw() function is called continuously once the game is running and is where any graphics code should be placed. The update() function is also called continuously and is where the state of the game should be updated.


    function love.load()
      xPos = 0
      yPos = 0
      playerWidth = 64
      playerHeight = 64
      playerSpeed = 200
      submarineImage = love.graphics.newImage("resources/images/submarine.png")

    The load() function is the perfect place for all kinds of initialization code. We start by defining some integer values for the position, size and speed of the player. We then load an image located on the hard drive - I'm using [this little pixel art submarine I drew](https://github.com/jeansberg/GreatDeep/blob/master/resources/images/submarine.png). This image will represent the player in our game. Note that Lua is a dynamically typed language so we don't need to declare any types for these variables. 


    function love.draw()
      love.graphics.draw(submarineImage, xPos, yPos, 0, 2, 2)

    For now, our draw() function will contain a single line of code to draw the image at the player's current position. Normally you would only need the image, x-position and y-position parameters. The three last parameters are there because I wanted to make my tiny 32x32 pixel image a little bit bigger. The 0 means that the image will not be rotated and the 2s mean that the image's width and height are doubled.


    function love.update(dt)
      downUp = love.keyboard.isDown("down") or love.keyboard.isDown("up")
      leftRight = love.keyboard.isDown("left") or love.keyboard.isDown("right")
      speed = playerSpeed
      if(downUp and leftRight) then
        speed = speed / math.sqrt(2)
      if love.keyboard.isDown("down") and yPos<love.graphics.getHeight()-playerHeight then
        yPos = yPos + dt * speed
      elseif love.keyboard.isDown("up") and yPos>0 then
        yPos = yPos - dt * speed
      if love.keyboard.isDown("right") and xPos<love.graphics.getWidth()-playerWidth then
        xPos = xPos + dt * speed
      elseif love.keyboard.isDown("left") and xPos>0 then
        xPos = xPos - dt * speed

    The update() function will contain code for listening to keyboard input and moving the player around. You probably noticed that this function takes a parameter called dt. This is passed to the function by the Love2D engine and indicates how much time has passed since the last update() call. This is used as a multiplier to determine how much our variables should change. Without this adjustment, the speed of our game would directly depend on the speed of the computer running it!

    Input handling

    We begin by using the built in keyboard.isDown() function to check if any arrow keys are currently being pressed. We store this information in two variables. One will indicate whether the down or up key is being pressed. The other one will do the same for the left and right keys. If both of these values are true, it means the player will be moving diagonally. In that case we need to divide the speed value with the square root of two before we apply it to the x- and y-positions. Otherwise diagonal movement would be much faster than horizontal or vertical movement.

    Movement constraints

    We then check whether the down or up key is being pressed again (not the most optimal code, but sufficient for a tutorial!). If the down key is being pressed, we increment the y-position, since the y-coordinates start at 0 at the top of the screen. We use dt as a multiplier as mentioned above. It's not enough to merely check the player input however. We don't want the submarine to disappear below the screen, so we make sure the yPos variable is never greater than the height of the screen minus the height of the player (the player width and height are 64 pixels since I doubled the width and height of the image when drawing it). Similarly, we want to make sure that the submarine doesn't go above the screen so we check that yPos is greater than zero. The code for horizontal movement is very similar. 


    You can now use love.exe which comes with the Love2D install to run the game! Just make sure you give it the path to the folder containing your main.lua file as a parameter. You should be able to control the submarine with the arrow keys on your keyboard. If you're on a laptop without arrow keys, simply change the "down", "up", "left" and "right" parameters to some letter keys.

    In the following post we will take a look at some shooting, so stay tuned!



    Source code for this part
    Finished source code

      Report Article

    User Feedback

    There are no comments to display.

    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now

  • Advertisement
  • Advertisement
  • Latest Featured Articles

  • Featured Blogs

  • Popular Now

  • Similar Content

    • By Seer
      I have programmed an implementation of the Separating Axis Theorem to handle collisions between 2D convex polygons. It is written in Processing and can be viewed on Github here. There are a couple of issues with it that I would like some help in resolving.
      In the construction of Polygon objects, you specify the width and height of the polygon and the initial rotation offset by which the vertices will be placed around the polygon. If the rotation offset is 0, the first vertex is placed directly to the right of the object. If higher or lower, the first vertex is placed clockwise or counter-clockwise, respectively, around the circumference of the object by the rotation amount. The rest of the vertices follow by a consistent offset of TWO_PI / number of vertices. While this places the vertices at the correct angle around the polygon, the problem is that if the rotation is anything other than 0, the width and height of the polygon are no longer the values specified. They are reduced because the vertices are placed around the polygon using the sin and cos functions, which often return values other than 1 or -1. Of course, when the half width and half height are multiplied by a sin or cos value other than 1 or -1, they are reduced. This is my issue. How can I place an arbitrary number of vertices at an arbitrary rotation around the polygon, while maintaining both the intended shape specified by the number of vertices (triangle, hexagon, octagon), and the intended width and height of the polygon as specified by the parameter values in the constructor?
      The Polygon code:
      class Polygon { PVector position; PShape shape; int w, h, halfW, halfH; color c; ArrayList<PVector> vertexOffsets; Polygon(PVector position, int numVertices, int w, int h, float rotation) { this.position = position; this.w = w; this.h = h; this.halfW = w / 2; this.halfH = h / 2; this.c = color(255); vertexOffsets = new ArrayList<PVector>(); if(numVertices < 3) numVertices = 3; shape = createShape(); shape.beginShape(); shape.fill(255); shape.stroke(255); for(int i = 0; i < numVertices; ++i) { PVector vertex = new PVector(position.x + cos(rotation) * halfW, position.y + sin(rotation) * halfH); shape.vertex(vertex.x, vertex.y); rotation += TWO_PI / numVertices; PVector vertexOffset = vertex.sub(position); vertexOffsets.add(vertexOffset); } shape.endShape(CLOSE); } void move(float x, float y) { position.set(x, y); for(int i = 0; i < shape.getVertexCount(); ++i) { PVector vertexOffset = vertexOffsets.get(i); shape.setVertex(i, position.x + vertexOffset.x, position.y + vertexOffset.y); } } void rotate(float angle) { for(int i = 0; i < shape.getVertexCount(); ++i) { PVector vertexOffset = vertexOffsets.get(i); vertexOffset.rotate(angle); shape.setVertex(i, position.x + vertexOffset.x, position.y + vertexOffset.y); } } void setColour(color c) { this.c = c; } void render() { shape.setFill(c); shape(shape); } }  
      My other issue is that when two polygons with three vertices each collide, they are not always moved out of collision smoothly by the Minimum Translation Vector returned by the SAT algorithm. The polygon moved out of collision by the MTV does not rest against the other polygon as it should, it instead jumps back a small distance. I find this very strange as I have been unable to replicate this behaviour when resolving collisions between polygons of other vertex quantities and I cannot find the flaw in the implementation, though it must be there. What could be causing this incorrect collision resolution, which from my testing appears to only occur between polygons of three vertices?
      Any help you can provide on these issues would be greatly appreciated. Thank you.
    • By ggenije
      Important: I am trying to realize in scrtach which is performance very low due to it's "virutal level" scrtach->flashplayer->java...
      Also i'm new to this forum so i'm sorry if I missed group (like last time)
      Like a title is saying:
      I have project ,and I get negative feedback on it because some people need 30 min to complete it (what is the planned time)
      but problem is that some people need EVEN 5 hours…(game is incremental/idle/upgrade type so it's important to keep same time ...)
      Of course people with slower computer will have less fps so game will be slower for them,
      so I have created TimeDelta system for each frame to calculate something to do per second
      for example
        Update(){move(TimeDelta*speed)}  so that mean it will be moving speed number of pixels(or units) per second so it will be same for almost each user.

      But problem is next:
      I have to change ySpeed by jumpPower (#PlayerJump in my project)
      when any jump button is pressed
      then in each frame decrease ySpeed by gravity it is(-10 * TimeDelta)
      but when someone have lower fps it will have higher TimeDelta and will fall faster but with same jump it turns out to jump significantly lower that changes core of game
      BUT even worse if fps suddenly in moment of jump then timeDelta would be 1 so player will jump much much MUCH higher , then fall much slower because timeDelta changed in meanwhile…(and the point of my game is about upgrading jump not complete game in first fps drop)


      Then I got an idea to fix TimeDelta (like in unity for rigibody) so it will be rounded like
      if calculated TimeDelta is 0.01834 it will be 0.02 fixed
      if weaker computer is using it the TImeDelta will be 0.143 so runded to 0.14 and so on…

      I did not manage to realize it… i tried to calculate it before main initialization of game objects
      but I'm afraid to fps will drop in moment that is calculating so it will be much diffirent…
      I was trying with empty loop(400)(in scrtach even this is taking time) to calculate it but i'm not sure is it right

      So is there good way to realize this fixed TimeDelta
      I only have timer function to use and time difference between frames
    • By Kamal Wafi
      Hi there,
      i recently start learning unity and im working in my first game ,
      I was wondering if unity had functions to support the motion control effect (tilting screen to move character) you see
      in doodle jump (which is 2d game) ? If it exists, what are they called? and how it works ?

    • By 3dmodelerguy
      For reference I am use Unity as my game engine and the A* Pathfinding Project for path finding as there is no chance I would be able to create anything close to as performant as that in any reasonable amount of time.
      So I am looking to build a game that is going to have a very similar style as Prison Architect / Rim World / SimAirport / etc. One of the things that I assume is going to effect performance is path finding. Decisions about the game I have already made that I think relate to this are:
      1. While I am going to be using Colliders, all of them will be trigger colliders so everything can pass through each other and I will not be use physics for anything else as it has no relevance for my game
      2. I am going to want to have a soft cap at the map size being 300x300 (90,000 tiles), I might allow bigger sizes but do something like Rim World does in warning the player about possible side effect (whether it be performance or gameplay)
      3. The map will be somewhat dynamic in that the user will be able to build / gather stuff from the map but outside of that, it should not change very much
      Now I am going to build my game around the idea that users would be in control of no more than 50 pawns at any given time (which is something I can probably enforce through the game play) but I am also going to want to have number other pawns that are AI controlled on the map (NPCs, animals, etc.) that would also need path finding enabled. Now I did a basic test in which I have X number of pawns pick a random location in the 300 x 300 map. move towards it, and then change the location every 3-5 seconds. My initial test was pretty slow (not surprising as I was calculating the path every frame for each pawn) so I decided to cache the calculated path results and only update it ever 2 seconds which got me:
      100 pawns: 250 - 450 FPS
      150 pawns: 160 - 300 FPS
      200 pawns: 90 - 150 FPS
      250 pawns: 50 - 100 FPS
      There is very little extra happening in the game outside of rendering the tilemap.
      I would imagine the most pawns on the map at a given time that need path finding might be a 1000 (and I would probably be able to make due with like 500 - 600). Now obviously I would not need all the pawn to be calculation paths every 2 seconds nor would they need to be calculating paths that are so long but even at a 5 second path refresh rate and paths that are up to 10 tiles long, I am still only able to get to about 400 pawns before I start to see some big performance issues. The issue with reducing the refresh rate is that there are going to be cases where maybe a wall is built before the pawns path is refreshed having them walk through the wall but not sure if there is a clean way to update the path only when needed.
      I am sure when I don't run the game in the Unity editor I will see increase performance but I am just trying to figure out what things I could be doing to make sure path finding is as smaller of a performance hit as possible as there is a lot of other simulation stuff I am going to want to run on top of the path finding.
    • By phil67rpg
      well I am able to get my sprites to rotate and move in all directions, I have drawn two plane sprites, I am also able to shoot a bullet in the up direction, I want to shoot bullets in all directions just like my plane rotates, I just need a hint on how to proceed, go easy on me this is new stuff to me. However I am making progress.
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!