I god a bold question, can somebody enhance my code and/or give me hints to code better?

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
weitnow
Prole
Posts: 18
Joined: Mon Oct 31, 2016 4:49 pm

I god a bold question, can somebody enhance my code and/or give me hints to code better?

Post by weitnow » Fri Jul 21, 2017 1:49 pm

Hello together

My name is christian. I am swiss, so forgive me my bad englisch. I got a bold question. Since I am a kid, it was my dream to code a own game. I have no education in computer-science/programming. I just started to teach myself python some months ago, then changed to java/libgdx. It became to difficult and i abandoned my project. Then i found lua and love....an i started coding my first game. Its now in very early alpha stage...As a beginner I choose a simple super-mario like platformer. I tried to code as much as possible by myself, without following a tutorial. Now i got the feeling, that my code is very very messy....and there are probably plenty ways to do it better...but without advice, its difficult to improve. So I wonder, if somebody could look through my code and give my any hints how i could to it better. I will attach my small prototype (game.love). If you jump on the enemy, the enemy gets killed and the screen will shake (buggy). If the enemy runs into you, you get killed and game over.

here is a link to a short Video of the game: https://drive.google.com/file/d/0B9MAaF ... Vna3c/view

main.lua

Code: Select all

require ("assets.ProtoPlattform")
require ("assets.ProtoPlayer")
require ("assets.Visualeffects")
require ("assets.Killenemy")
gameover = false
test = 0
shakeron = false

player_contact_enemy = function (self, dt, enemies)
    local contact = false
    for k, v in pairs(enemies) do
        if self.x2 > v.x and self.x < v.x2 and self.y2 > v.y and self.y < v.y2 then
            contact = true
        end
    end
    return contact
end

draw_gameover_screen = function()
    love.graphics.setColor(255,0,0)
    love.graphics.rectangle('fill', 0, 0, love.graphics.getWidth(), love.graphics.getHeight())
    love.graphics.setColor(0,0,0)
    love.graphics.print('game over!', love.graphics.getWidth()/2 -150, love.graphics.getHeight()/2, 0, 4, 4)
end

function love.load()

    player = ProtoPlayer.new(love.graphics.getWidth() / 2, love.graphics.getHeight()-160)
    player.setcolor('green')

    enemy = ProtoPlayer.new(love.graphics.getWidth() / 2, 20)
    enemy.setcolor('red')
    enemy.speed = 80

    enemy2 = ProtoPlayer.new(50, 20)
    enemy2.setcolor('red')
    enemy2.speed = 50

    enemy3 = ProtoPlayer.new(love.graphics.getWidth() -100, 20)
    enemy3.setcolor('red')
    enemy3.speed = 100

    enemies = {enemy, enemy2, enemy3}
    plattforms = {
        ProtoPlattform.new(300, 500, 500, 20, 'plat1'),
        ProtoPlattform.new(0, 370, 200, 20, 'plat2'),
        ProtoPlattform.new(400, 280, 200, 20, 'plat3'),
        ProtoPlattform.new(50, 200, 200, 20, 'plat4'),
        ProtoPlattform.new(500, 100, 200, 20, 'plat5')
    }
end

function love.update(dt)

    if (shakeron) then
        shake(dt)

     end

    player:move(dt)
    player:physic(dt, plattforms)

    for _k, e in pairs(enemies) do
        e:physic(dt, plattforms)
        e:ai(dt, player, plattforms) end

    checkifkill(player, enemies, dt)
    if (player_contact_enemy(player, dt, enemies)) then gameover = true end

end

function love.draw()

    for k, v in pairs(plattforms) do
        v:draw()
    end

    for k, v in pairs(enemies) do
        v:draw()
    end
    player:draw()

    if gameover then draw_gameover_screen() end

end
ProtoPlayer.lua

Code: Select all

ProtoPlayer = {}


ProtoPlayer.new = function(x, y)
    local self = {}
    self.name = 'noname'
    self.x = x
    self.y = y
    self.width = 50
    self.height = 50
    self.x2 = self.x + self.width
    self.y2 = self.y + self.height
    self.speed = 200
    self.y_velocity = 0
    self.jump_height = -400
    self.gravity = -500
    self.color = {255, 0, 0}
    self.direction = 1
    self.hightesplat = love.graphics.getHeight() + 150
    self.hightesplat_height = 0

    self.draw = function ()
        love.graphics.setColor(unpack(self.color))
        love.graphics.rectangle('fill', self.x, self.y, self.width, self.height)
        love.graphics.setColor({0,0,0})
        love.graphics.print( 'x: ' .. round(self.x,0), self.x, self.y)
        love.graphics.print( 'x2 ' .. round(self.x2,0), self.x, self.y +10)
    end

    self.setcolor = function (color)
        if color == 'blue' then
            self.color = {0, 0, 255}
        elseif color == 'red' then
            self.color = {255, 0, 0}
        else self.color = {0, 255, 0} end
    end


    self.move = function (self, dt)
        if love.keyboard.isDown('d') then
            if self.x < (love.graphics.getWidth() - 50) then
                self.x = self.x + (self.speed * dt)
            end
        elseif love.keyboard.isDown('a') then
            if self.x > 0 then
                self.x = self.x - (self.speed * dt)
            end
        end

        if love.keyboard.isDown('space') then
            if self.y_velocity == 0 then
                self.y_velocity = self.jump_height
            end
        end
    end


    self.physic = function (self, dt, plattforms)

        if self.y2 > love.graphics.getHeight() then gameover = true end -- if player falls below the screen = gameover

        self.x2 = self.x + self.width -- update self.x2
        self.y2 = self.y + self.height -- update self.y2

        self.y = self.y + self.y_velocity * dt
        self.y_velocity = self.y_velocity - self.gravity * dt
        self.highestplat = love.graphics.getHeight() + 150
        for _k, plat in pairs(plattforms) do
            if self.x2 > plat.x and self.x < plat.x2 then
                if self.y + self.height <= plat.y + plat.height then
                    if plat.y < self.highestplat then self.highestplat, self.highestplat_height = plat.y, plat.height end
                end
            end
        end
        if self.y + self.height >= self.highestplat then
            self.y_velocity = 0
            self.y = self.highestplat - self.height
        end
    end

    local emptyplatform = ProtoPlattform.new(0,0,0,0, 'no ground') -- create empty platform object for return with self.contact if there is no valid real platform
    self.contact = function (self, dt, plattforms)
        local platobject
        for k, v in pairs(plattforms) do
            if self.x2 > v.x and self.x < v.x2 and self.y <= v.ground then
                platobject = v
            end
        end
        if platobject == nil then platobject = emptyplatform  end
        return platobject
    end


    self.switchdirection = function(self)
        if self.direction == 1 then self.direction = -1
        else self.direction = 1 end
    end

    self.ai = function (self, dt, player, plattforms)
        local platobject = self:contact(dt, plattforms)

        if self.x < platobject.x or self.x2 > platobject.x2 then
            self:switchdirection()
        end
        -- walking
        self.x = self.x + self.direction * (self.speed * dt)

    end

    return self
end
ProtoPlatform.lua

Code: Select all

ProtoPlattform = {}

ProtoPlattform.new = function(x, y, width, height, name)
    local self = {}
    self.name = name
    self.width = width
    self.height = height
    self.x = x
    self.y = y
    self.x2 = x + width
    self.y2 = y + height
    self.ground = self.y
    self.draw = function()
        love.graphics.setColor(0, 255, 180)
        love.graphics.rectangle('fill', self.x, self.y, self.width, self.height)
        --debug points
        --x/y
        love.graphics.setColor(0, 0, 255)
        love.graphics.rectangle('fill', self.x, self.y, 2, 2)
        --x2/y2
        love.graphics.setColor(255, 0, 0)
        love.graphics.rectangle('fill', self.x2, self.y2, 2, 2)
        --ground
        love.graphics.setColor(0, 255, 255)
        love.graphics.rectangle('fill', self.x + width/2, self.ground - 1, 2, 2)
        -- x/y numbers
        love.graphics.setColor(0, 0, 0)
        love.graphics.print( 'x: ' .. round(self.x,0) .. ' x2: ' .. round(self.x2,0), self.x, self.y)
        -- print plat name
        love.graphics.setColor(0, 0, 0)
        love.graphics.print(self.name, self.x + 100, self.y)

    end

    function round(num, numDecimalPlaces)
        local mult = 10^(numDecimalPlaces or 0)
        return math.floor(num * mult + 0.5) / mult
    end

    return self

end
KillEnemy.lua

Code: Select all

function checkifkill(player, enemies, dt)
        for index, enemy in pairs(enemies) do
            if player.x2 > enemy.x + 15 and player.x < enemy.x2 - 15 and player.y2 > enemy.y - 40 and player.y < enemy.y2 - 40 then
                table.remove(enemies,index)
                shakeron = true
            end
        end

end
Visualeffects.lua

Code: Select all

local counter = 1
local shaketime = 100

function shake(dt)
        for _k, plat in pairs(plattforms) do
            if counter > 5 then
                plat.x = plat.x - (200 * dt)
                plat.x2 = plat.x2 - (200 * dt)
            else
                plat.x = plat.x + (200 * dt)
                plat.x2 = plat.x2 + (200 * dt)
            end
        end
        counter = counter + 1
        shaketime = shaketime - 1
        if counter == 10 then counter = 1 end
        if shaketime < 1 then shakeron = false shaketime = 100 end
end

Attachments
game.love
(3.18 KiB) Downloaded 24 times

User avatar
CaptainMaelstrom
Party member
Posts: 157
Joined: Sat Jan 05, 2013 10:38 pm

Re: I god a bold question, can somebody enhance my code and/or give me hints to code better?

Post by CaptainMaelstrom » Fri Jul 21, 2017 2:23 pm

You're on the right track by starting small with the scope of your game. The reason why I can't enhance your code is because I don't know what you want it to do better.

Do you want it to be less buggy? Then pick 1 bug at a time and fix it. If you don't know how, you can google the bug or maybe post a topic in the help subforums about what specifically is wrong.

Do you want to add a feature? Define what it is you want to add and try to implement it. If it causes bugs, see step 1.

If it's your dream to program your own video game, you will have to get really good at steps 1 and 2.

User avatar
ivan
Party member
Posts: 1546
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: I god a bold question, can somebody enhance my code and/or give me hints to code better?

Post by ivan » Fri Jul 21, 2017 2:32 pm

Hello and welcome to the Love2d forums.
Learning any programming language takes time so don't get discouraged by criticism.
Ok, so briefly going over the code, I have to say that it needs more work.
First of all you want to get rid of the globals - they make it harder to tell what's going on since they can be called from anywhere.
Ideally you want to be able to look any Lua file and understand the script without referring to external files.
Your object-orientation code could be much cleaner if you learned to use metatables.
Level data such as the following should be separated from the rest of the code:

Code: Select all

        ProtoPlattform.new(300, 500, 500, 20, 'plat1'),
        ProtoPlattform.new(0, 370, 200, 20, 'plat2'),
        ProtoPlattform.new(400, 280, 200, 20, 'plat3'),
        ProtoPlattform.new(50, 200, 200, 20, 'plat4'),
        ProtoPlattform.new(500, 100, 200, 20, 'plat5')
You need to study how tables, work: generally we use table.remove for lists and pairs for indexed tables.
But we never use both like the following example:

Code: Select all

for index, enemy in pairs(enemies) do
            ...
                table.remove(enemies,index)
In this case, you probably need reverse iteration: for index = #enemies, 1, -1 do

These are just a few things off the top of my head.
It's not a big deal as long as your project is small, but if you want to make something bigger then these suggestions might be helpful.
Good luck!

User avatar
weitnow
Prole
Posts: 18
Joined: Mon Oct 31, 2016 4:49 pm

Re: I god a bold question, can somebody enhance my code and/or give me hints to code better?

Post by weitnow » Fri Jul 21, 2017 2:49 pm

Hello CaptainMaeistrom, hello ivan

Thank you both for your response :)

@CaptainMaeistrom:
Hm, i guess i am looking for general advice. I try to split up my code in diffrent lua-files. If the project grows, that is still manageble. But to be honest, i have no Idea, how to split up the code in the best way. ivan gave some good and general advice. I hope to get more of them.

@ivan:
Thank you. I will try to change the code according what you told me. What I still do not really understand, how to split up the code. For example, should i make a Levelfile with the data like:

Code: Select all

ProtoPlattform.new(300, 500, 500, 20, 'plat1'),
        ProtoPlattform.new(0, 370, 200, 20, 'plat2'),
        ProtoPlattform.new(400, 280, 200, 20, 'plat3'),
        ProtoPlattform.new(50, 200, 200, 20, 'plat4'),
        ProtoPlattform.new(500, 100, 200, 20, 'plat5')
and then a file with data like the enemies in form of a table? If so, how would I for example delete an enemy from a table in enemy.lua without using global variables if the code for killing an enemy is in annother lua-file.

User avatar
ivan
Party member
Posts: 1546
Joined: Fri Mar 07, 2008 1:39 pm
Contact:

Re: I god a bold question, can somebody enhance my code and/or give me hints to code better?

Post by ivan » Fri Jul 21, 2017 3:55 pm

Typically, you want to have some sort of level format, so that your level data is not dependent on your game's API.
Level data should be just that: data and you should hopefully be able to easily edit each level (either through an editor or the file format should be human-readable).
The idea is to read that data and initialize the level based on that - ideally separating data from code.

As for reducing the use of globals you can use the following technique:
enemy.lua (encapsulation):

Code: Select all

local enemyManager = {}
...
return enemyManager
game.lua (nesting):

Code: Select all

local game = {}
game.enemies = require('enemy')
return game
main.lua (example):

Code: Select all

myGame = require('game')
myGame.enemies:doStuff()
Note that you only need to require each of these files only once -
WHERE you require each file determines the scope or what is accessible.

User avatar
weitnow
Prole
Posts: 18
Joined: Mon Oct 31, 2016 4:49 pm

Re: I god a bold question, can somebody enhance my code and/or give me hints to code better?

Post by weitnow » Fri Jul 21, 2017 4:53 pm

Thank you ivan...I apreciate the time you took to help me. I have the feeling, I start understandig how I should do it. I will try your concept and will post my updated code. Have a great day :)

User avatar
weitnow
Prole
Posts: 18
Joined: Mon Oct 31, 2016 4:49 pm

Re: I god a bold question, can somebody enhance my code and/or give me hints to code better?

Post by weitnow » Mon Jul 24, 2017 7:52 am

hello together

I found a good tutorial for my problem. I realized, that my previous code was somehow badly organized. The main problem was, that when the project grows, the code will become messy. I found a good tutorial: https://www.youtube.com/channel/UCSs-Hz ... RQCdHuAxAg
There is a video about how to build an entity-system. I am trying now to recode my simple game and using this approach, which should make my game more future-proof when more enemies, more platforms etc will be added.

Post Reply

Who is online

Users browsing this forum: No registered users and 4 guests