Micro Dash made with Kotlin and Fly-Ko

Hi everyone

Recently my first self made game called Micro Dash is finished and has been published on Itch.io

Micro Dash is a Boulder Dash like game with metroidvania elements like power-ups, abilities, hidden rooms and secrets.

The Game was made for fun but also to test the 2D Entity-Component-System framework Fly-Ko that is an open source framework for 2D game development in Kotlin. If you are in game dev. with Kotlin, considering give it a try.

For the game Micro Dash, have a look at the game page. There is also a demo version for Windows and Linux available free to play.

Feedback is very welcome as this is my first self created game with Kotlin… and I love Kotlin!

Have fun!

cover_2

nano2

7 Likes

Congratulations on passing this particularly tricky milestone - most people never get this far!

Thanks @princec!

Since I’m a father and also have a full time job, it took me almost a year to completely finish it up. But it was also a good opportunity to learn Kotlin with motivation. And it was a lot of fun to play it with my son after we created some experimental caves together in the Tiled editor and played it afterwards.

So I can say, the first world is fun for children of younger age to play too, but while it gets harder with progression it can be frustrating for them. But it is always a challenge isn’t it?

And last but not least, it was a good proof of concept that it works out for me creating 2D games with Kotlin and Fly-Ko that can be delivered and published for and on the JVM.

And what are you working on these days?

Battledroid Skirmish, similar situation to you, kids & full time job in the way, but at least there’s three of us on the project. We’ve been on it a few years now…

2 Likes

Wow, looks very nice and polished already, as far as I can see it within this single screenshot. Is this a defense game or more a shooter one? Is there a demo available?

Right, developing in a team where everyone can concentrate on his/her key skills, is much better and efficient. I’m a good programmer and problem solver for example and can do a bit of pixel graphics too but I have to spend a lot of time for that and also creating sound is not my realm. But on the other hand, it is difficult to find the right people for a project especially if you need to have your on speed and cannot participate in regular time frames for a project.

Cheers!

It’s an auto-battler, which I think is now an actual genre of sorts, where you can either play as attackers or defenders on one or the other side of a tower defence setup. No demo yet, still many moons to go before we get that far :frowning:

I found that one of the best aspects of working with someone else is the massive boost in motivation it gives you, not to mention the potential to concentrate on the bits you’re best at. I’m not a technical programmer, I really just do “game” stuff - @theagentd does the gnarly clever engine stuff, and Chaz does all the graphics and UI layout. I suppose I still do the sound and overall production.

@Andrevv_76 I love the idea!! Kotlin is a dream to use and I think making a super nice 2D engine that just works well is super helpful. Maybe one day when I’m in a hackathon and want to make a game I’ll use this :slight_smile: My only suggestion would be to remove the ff_ prefix on everything, that seems like a C or C++ thing, not a Kotlin thing. It just makes the code a bit more boilerplatey.

Hi @cygnus and thanks for the reply.

Yes, try to use it whenever you want. There are also some tests that shows how basics work. And when i will find some time someday I also will continue with the documentation.

The ff_ prefix was invented by me to have helpful IDE code completion suggestion within the builder DSL. In the IDE when you are in a specific component builder context, say for example:

TextureAsset.build { 
   ff_
}

you can just type the ff_ prefix and the IDE will suggest you all the possible attributes of the component (TextureAsset in this case) and only this one. So you have just an overview of all possible attributes for the component suggested by the IDE and can choose one.

ide

But you are right, this makes the code a bit more boilerplatey but the IDE suggestions a bit less.

Hmm, honestly I think just typing this. works too?

When you know what you have and what you want yes. If not this is a helping index. Convenient if you are new or have hundreds of different components and not all of the possible attributes in mind.

But I will definitely think about that and maybe get rid of them in the next version.

Have you tried the @DslMarker annotation? It should help with the code completion.

Yes:

@DslMarker
annotation class ComponentDSL

@ComponentDSL
interface Component : Indexed {
    val componentId: CompId
    fun dispose()
}

this helps a bit but still a lot of suggestions from the IDE. Anyway, I think it is not that much boilerplate since it is just w small prefix that helps you to find you context and the code is still readable.

@cygnus @cylab You have convinced me to get rid of the ff prefixes. So I removed them for the release. Now the code looks something like this:

  // Create a TextureAsset and register it to the AssetSystem but not loading yet.
  //
  // WIth this method you are able to define all your assets in one place without
  // loading the assets into memory yet. When you need them you can simply load
  // them by calling FFContext.activate(TextureAsset, "logoTexture") and dispose them
  // with FFContext.dispose(TextureAsset, "logoTexture"). The asset definition is still
  // available and can be deleted with FFContext.delete(TextureAsset, "logoTexture")
  val texAssetId = TextureAsset.build {
      name = "logoTexture"
      resourceName = "firefly/logo.png"
  }

  // Create and activate/load a SpriteAsset with reference to the TextureAsset.
  // This also implicitly loads the TextureAsset if it is not already loaded.
  val spriteId = SpriteAsset.buildAndActivate {
      // It would also be possible to use the name of the texture asset here
      // instead of the identifier. But of corse, identifier (index) gives faster access
      texture(texAssetId)
      textureRegion(0,0,32,32)
      horizontalFlip = false
      verticalFlip = false
  }

  // Create an Entity positioned on the base View on x=50/y=150, and the formerly
  // created sprite with a tint color.
  // Add also two animation, one for the alpha of the tint color and one for the
  // position on the x axis and activate everything immediately.
  val entityId = Entity.buildAndActivate {

      // add a transform component to the entity that defines the orientation of the Entity
      component(ETransform) {
          view(BASE_VIEW)
          position(50, 150)
          scale(4f, 4f)
      }

      // add a sprite component to the entity
      component(ESprite) {
          sprite(spriteId)
          tint(1f, 1f, 1f, .5f)
      }

      // add an animation component to the entity that defines an animation based on
      // the alpha value of the color property of the sprite.
      //
      // Animations normally can work for itself and lifes in the AnimationSystem. But if
      // a property of an Entity-Component like ESprite defines a property value adapter,
      // an animation can be bound to this property directly to affecting the value of the property.
      component(EAnimation) {

          // with an active easing animation on the sprite alpha blending value...
          activeAnimation(EasedProperty) {
              easing = Easing.Type.LINEAR
              startValue = 0f
              endValue = 1f
              duration = 3000
              looping = true
              inverseOnLoop = true

              // that is connected to the alpha value of the sprite of the entity
              propertyRef = ESprite.Property.TINT_ALPHA
          }

          // and with an active easing animation on the sprites position on the x axis...
          activeAnimation(EasedProperty) {
              easing = Easing.Type.BACK_OUT
              startValue = 50f
              endValue = 400f
              duration = 1000
              looping = true
              inverseOnLoop = true

              // that is connected to the position value on the x axis of the entities transform data
              propertyRef = ETransform.Property.POSITION_X
          }
      }
  }