Page 1 of 1

Run'N'Jump: A Vague clone of chrome://dino

Posted: Mon Dec 07, 2020 6:05 am
by PackerMan
Here is
Run'N'Jump_fix2.love
(9.31 KiB) Downloaded 260 times
a fruit of my efforts towards learning GameDev.

How it Came to be?
I had lofty ambitions of creating a 1:1 clone of chrome://dino, the No internet game in Chrome and Chromium browsers, but eventually realised my limits and this is what I ended up with. I'm mostly learning programming as a hobby and this was an effort to test my abilities to make a game.

What I need?
Help and feedback. I revised the code about 3 times so this is probably the best code I can write, but I'm facing a few issues...
  • Sometimes, the red circles shift to the right. I'm not sure if my eyes are playing tricks or there is a bug.
    Fixed thanks to pgimeno. Thank you.
  • The text looks awful... How do I fix it?
    Fixed thanks to Andiac028. Thank you.
  • Any general advice for improvements will be appreciated.
Thank you for your time.

Original file:
Run'N'Jump.love
(8.46 KiB) Downloaded 214 times

Re: Run'N'Jump: A Vague clone of chrome://dino

Posted: Mon Dec 07, 2020 5:03 pm
by Andlac028
Hi and welcome to the forums!
PackerMan wrote: Mon Dec 07, 2020 6:05 am The text looks awful... How do I fix it?
You are scaling default font (which has size 12) five times and that's why it looks so awful. You can create new font in love.load (with bigger size, eg: ourFont=love.graphics.newFont(size) and set it in love.draw (eg: love.graphics.setFont(ourFont)) and remove scaling from love.graphics.print and that will make the text normal.

Re: Run'N'Jump: A Vague clone of chrome://dino

Posted: Tue Dec 08, 2020 12:25 pm
by PackerMan
Andlac028 wrote: Mon Dec 07, 2020 5:03 pm Hi and welcome to the forums!
PackerMan wrote: Mon Dec 07, 2020 6:05 am The text looks awful... How do I fix it?
You are scaling default font (which has size 12) five times and that's why it looks so awful. You can create new font in love.load (with bigger size, eg: ourFont=love.graphics.newFont(size) and set it in love.draw (eg: love.graphics.setFont(ourFont)) and remove scaling from love.graphics.print and that will make the text normal.
Thank you... I'll try that and get back.

Edit: I did just that and now it looks crisp. If only I could figure out why the bullets shift. :?

Re: Run'N'Jump: A Vague clone of chrome://dino

Posted: Wed Dec 09, 2020 2:49 pm
by pgimeno
PackerMan wrote: Tue Dec 08, 2020 12:25 pm Edit: I did just that and now it looks crisp. If only I could figure out why the bullets shift. :?
It's probably because you're deleting the bullets in the ipairs loop, causing some to not be updated.

Imagine you have 3 bullets, and the first one is to be deleted.

Code: Select all

  for i,v in ipairs(bullets) do  -- this sets i to 1, then to 2, then to 3
    v:update(dt) -- when i = 1, we're assuming that this marks it for deletion
    if v.dead then -- will be true when i = 1
      table.remove(bullets, i)  -- this deletes bullets[1] BUT it also shifts bullets[2] to bullets[1] and bullets[3] to bullets[2]
      score = score + 1
    end
    ... -- irrelevant part
    -- Now, on the next loop, i will be = 2, but because bullet[2] became bullet[1],
    -- that one won't be updated! That's what causes the shift.
  end
The easiest solution is to loop backwards:

Code: Select all

  for i = #bullets, 1, -1 do  -- this sets i to 3, then to 2, then to 1
    local v = bullets[i]
    v:update(dt) -- when i = 3, we're assuming that this marks it for deletion
    if v.dead then -- will be true when i = 3
      table.remove(bullets, i)  -- this deletes bullets[3], shifting everything above index 3,
                                -- and leaves bullets[2] and bullets[1] unmodified
      score = score + 1
    end
    ...
    -- Now, on the next loop, i will be = 2 and everything will Just Work™.
  end
Another solution is to loop manually, and only increment i when not deleting:

Code: Select all

  local i = 1
  while i <= #bullets do
    local v = bullets[i]
    v:update(dt) -- when i = 1, we're assuming that this marks it for deletion

    if v.dead then -- will be true when i = 1
      table.remove(bullets, i)  -- this deletes bullets[1], shifting bullets[2] to bullets[1] and bullets[3] to bullets[2]
      -- we don't increment i in this branch, therefore i will still be 1 on the next loop, therefore bullets[1] will be correctly updated
      score = score + 1
    else
      i = i + 1 -- No deletion - increment i
    end
    ...
  end
By the way, my best score so far:
Image

Re: Run'N'Jump: A Vague clone of chrome://dino

Posted: Thu Dec 10, 2020 4:18 am
by PackerMan
pgimeno wrote: Wed Dec 09, 2020 2:49 pm The easiest solution is to loop backwards:
I remember the Sheepolution tutorial saying loop backwards but it was a chapter after the main ones so I just glanced over it. It makes sense now. But looping backwards will result in a nil loop whenever a bullet dies, right?? Since the end of the table is moving faster than the counter. So, while loop is better I think.

I'll get back when I try things.

I always top out at the 30s even though it is my game, lol. :ultrahappy:

Edit: First I tried the "in place" solution of decrementing i by one everytime a bullet is removed, didn't work. I tried the reverse for loop and it threw me an error about trying to call something with number on the for loop line. So I went with the while loop and it made the gameplay looks clean.
Run'N'Jump_fix2.love
(9.31 KiB) Downloaded 206 times
Thank you pgimeno

Re: Run'N'Jump: A Vague clone of chrome://dino

Posted: Thu Dec 10, 2020 3:11 pm
by pgimeno
PackerMan wrote: Thu Dec 10, 2020 4:18 am But looping backwards will result in a nil loop whenever a bullet dies, right?? Since the end of the table is moving faster than the counter.
It isn't moving faster. At most it's moving at exactly the same speed.

Imagine you have bullets b1, b2, b3, b4 and b5, in positions 1, 2, 3, 4 and 5 respectively. Say you had to remove all except 5. Then you would have this:
  1. i = 5. Bullet b5 is checked, it does not need to be deleted.
  2. i = 4. Bullet b4 is checked, it needs to be deleted. You delete position 4, so the array becomes: 1:b1, 2:b2, 3:b3, 4:b5.
  3. i = 3. Bullet b3 is checked, it needs to be deleted. You delete position 3, so the array becomes: 1:b1, 2:b2, 3:b5.
  4. i = 2. Bullet b2 is checked, it needs to be deleted. You delete position 2, so the array becomes: 1:b1, 2:b5.
  5. i = 1. Bullet b1 is checked, it needs to be deleted. You delete position 1, so the array becomes: 1:b5.
And everyone is happy.

Notice that every time you delete a bullet, all bullets after it are scrolled/shifted, but the ones you will check next are the bullets before that one, so you're safe.

PackerMan wrote: Thu Dec 10, 2020 4:18 am Edit: First I tried the "in place" solution of decrementing i by one everytime a bullet is removed, didn't work. I tried the reverse for loop and it threw me an error about trying to call something with number on the for loop line. So I went with the while loop and it made the gameplay looks clean.
It's weird that looping backwards didn't work. Looping backwards has one more advantage: the length of the table is only calculated once. With the while method, it's calculated as many times as there are elements in the table. I mentioned it because sometimes, order is important, and looping backwards is not viable. In these cases, the while method can be used.

Edit: Ok, I made a typo, I wrote "for i in #bullets, 1, -1" and I should have written "for i = #bullets, 1, -1" (i.e. with "=" instead of "in"). That would explain the error. I've fixed it above.