Beathoven DevBlog 1

Beathoven DevBlog 1

Developing a rhythm game with LÖVE

Last week at the end of that article I mentioned that I was working on a game in order to explore LÖVE. That game is called Beathoven. It is a rhythm game based on the remix sound of the 5th symphony of Beethoven made Lionel Yu and Nicolas Chazarre.

Instead of using a piano like controller, I wanted to use something a bit more like those music arcade game with button spread around the screen.

MaiMai.png

And I went with 4 buttons spread as a diamond. 4 buttons means 4 fingers game play, which sounds not too overwhelming, but still fun.

Some screenshots

image (17).png

title.png

timer.png

image (18).png

Current features

  • Splash screen
  • Title screen
  • Timer before actual rhythm game starts
  • Gameplay with 4 buttons (tracks) with instant pressed notes only
  • Scoring at each right note
  • HP reducing at each wrong note
  • Note streaking tracking with different messages at different levels

Planned features/work

  • Game Over screen with scoring and retry button
  • Finalizing the notes balancing and rhythm
  • Adding more animation in the UI
  • Game responsive
  • Game introduction
  • Better particles effects
  • Long notes with kept-pressed buttons

🤝 Some sharing

It’s difficult to reduce multiple hours and several thousands lines of code in one blog article, so I’ll share a couple of things.

📬 Tracks’ queue

In order to save the notes currently on the track of a button, I made this Queue class (based on the classes.lua I shared in my last article.)

local classes = require "classes"

local Queue = classes.class()

function Queue:init()
    self.first = 0
    self.last = -1
    self.items = {}
end

function Queue:count()
  local count = 0
  for _ in pairs(self.items) do count = count + 1 end
  return count
end

function Queue:enqueue(value)
    self.last = self.last + 1
    self.items[self.last] = value
end

function Queue:dequeue()
  if self:count() == 0 then
    return nil
  end

  local first = self.first
  local value = self.items[first]

  self.items[first] = nil        -- to allow garbage collection
  self.first = self.first + 1

  return value
end

function Queue:deleteFirst(value)
  local i = -1
  for k = self.first,self.last,1
  do
    if self.items[k] == value then
      self.items[k] = nil
      i = k
    end
  end

  -- Value not found
  if i == -1 then
    return
  end

  for k = i,self.last,1
  do
    self.items[k] = self.items[k+1]
  end
  self.items[self.last] = nil
  self.last = self.last - 1
end

function Queue:print()
  local res = "Queue: { "
  for k,v in pairs(self.items) do
      res = res..k..": "..v..", "
  end  
  print(res.." }")
end

return Queue

When I press a button, a note is dequeued, and we check if the note was overlapping the button. If it was, then it’s a success and if not, then it’s an early miss.

🥁 Beat Finder

A rhythm game means playing with the rhythm/beat of a music.

In order to do that, I could think of several solutions:

  • Using Fast Fourier Transformations on the sound data to detect high frequencies peak and put a note at that moment
  • Using the 5th symphony partition
  • Using a tool like Audacity to automatically detect the beat

I went with the latter, knowing that I would still have a lot of manually editing to do, to make things fun.

If you load a sound in audacity, you can click then on Analyze > Beat Finder

audacity.png

This will add a label track with a label on each beat detected. You can export it then File > Export > Export Labels. It’ll provide you a text format easily parsable.

Conclusion

If you were looking to making a rhythm game on your own, I hope that my findings can help you to get kick-started quickly. If you are interested in Beathoven and/or would like to participate in the dev, let me know. For now, the game is not open source, but once I am happy with the state of the code and game I’ll share it.

Did you find this article valuable?

Support Sonny Alves Dias by becoming a sponsor. Any amount is appreciated!