Wiki

Clone wiki

SpecGine / MainMenu

Adding main menu

Creating state hierarchy

All menus in our game will share resources like GUI. That is why we start from creating StateGroup.

Creating state group

We create empty state group in file core/src/main/scala/Menus.scala.

#!scala
package com.specdevs.ping

import com.specdevs.specgine.core.StateGroup

class Menus extends StateGroup {
  def initialize() {}

  def create() {}

  def dispose() {}
}
Than we register this class in our game. We adjust initialize method in Ping class from core/src/main/scala/Ping.scala, so it looks like:

#!scala
  def initialize() {
    addGroup(new Menus, "Menus")
  }

This will register our group under name "Menus".

Main Menu state

Next we add an empty state representing main menu. We subclass MenuState in file core/src/main/scala/MainMenu.scala.

#!scala
package com.specdevs.ping

import com.specdevs.specgine.states.MenuState

class MainMenu extends MenuState {
  def initialize() {}

  def create() {}

  def dispose() {}
}
Now we add this state into initialize method in game class.

#!scala
  def initialize() {
    addGroup(new Menus, "Menus")
    addState(new MainMenu, "MainMenu", "Menus")
  }

Now we have one state called "MainMenu" in state group "Menus".

Shared resources

The first resource we will add to "Menus" group will be bitmap font. We will use default font that comes from Libgdx. This font is in file com/badlogic/gdx/utils/arial-15.fnt. We will apply linear texture filtering.

We add its name to Menus class and request loading of asset in its initialize method.

#!scala
//...
import com.specdevs.specgine.assets.gdx.BitmapFontDescriptor

import com.badlogic.gdx.graphics.Texture.TextureFilter.{Linear=>GdxLinear}

class Menus extends StateGroup {
  private val font = "com/badlogic/gdx/utils/arial-15.fnt"

  def initialize() {
    loadAsset(font, BitmapFontDescriptor(minFilter=Linear, magFilter=GdxLinear))
  }
  //...
}
SpecGine guarantees that inside create method resources will be already loaded so we can use it to create default skin for the menus. Menu skin below is based on UISimpleTest from Libgdx.

#!scala
import com.specdevs.specgine.assets.Asset
import com.specdevs.specgine.assets.gdx.{ImplicitBitmapFontAsset,ImplicitSkinAsset}

import com.badlogic.gdx.graphics.{Pixmap=>GdxPixmap,Texture=>GdxTexture,Color=>GdxColor}
import com.badlogic.gdx.graphics.Pixmap.{Format=>GdxPFormat}
import com.badlogic.gdx.graphics.g2d.{BitmapFont=>GdxBitmapFont}
import com.badlogic.gdx.scenes.scene2d.ui.{Skin=>GdxSkin}
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.{TextButtonStyle=>GdxTextButtonStyle}

//...
  def create() {
    val skin = new GdxSkin

    val pixmap = new GdxPixmap(1, 1, GdxPFormat.RGBA8888)
    pixmap.setColor(GdxColor.WHITE)
    pixmap.fill()
    skin.add("white", new GdxTexture(pixmap))

    skin.add("default", get[Asset,GdxBitmapFont](font))

    val textButtonStyle = new GdxTextButtonStyle
    textButtonStyle.up = skin.newDrawable("white", GdxColor.DARK_GRAY)
    textButtonStyle.down = skin.newDrawable("white", GdxColor.DARK_GRAY)
    textButtonStyle.over = skin.newDrawable("white", GdxColor.LIGHT_GRAY)
    textButtonStyle.font = skin.getFont("default")
    skin.add("default", textButtonStyle)

    set[Asset,GdxSkin]("defaultSkin", skin)
  }
We need to import ImplicitBitmapFontAsset and ImplicitSkinAsset to use get and set methods. We also need all Libgdx related stuff used to assemble skin. Ready resource is stored with name "defaultSkin". To read more about creating menus we invite you to read Libgdx documentation about Skin.

Note: We plan to add Scala DSL for GUIs in near future, but currently you are left with Libgdx features alone.

This allows us to use stored resources in all menu states in "Menus" group.

Implementing main menu

It remains to implement main menu itself. It will have one MenuScreen.

Creating empty menu screen

We create empty default screen in file core/src/main/scala/MainScreen.scala.

#!scala
package com.specdevs.ping

import com.specdevs.specgine.states.gdx.MenuScreen

class MainScreen extends MenuScreen {
  def initialize() {}

  def create() {}

  def dispose() {}
}
We need to inform about it our MainMenu state by registering screen inside MainMenu's initialize method.

#!scala
  def initialize() {
    addMenuScreen("Main", new MainScreen)
  } 
At this moment we should have working application which stays open when it is started. You can verify it by running desktop/run from SBT.

Setting screen size

Now we can see and set screen size. For our game we selected 800 x 480 as base size, which matches default set in project template.

We still need to inform our menu system about resolution, so bitmap fonts are properly scaled.Open file core/src/main/scala/MainScreen.scala and set width and height in constructor.

#!scala
//...
class MainScreen extends MenuScreen(width=Some(800), height=Some(480)) {
//...
}

Menu buttons

We will create two buttons in our menu. "New Game" will currently do nothing and "Quit" which will exit the game. We place our code in create method of MainScreen class.

#!scala
//...
import com.specdevs.specgine.assets.Asset
import com.specdevs.specgine.assets.gdx.ImplicitSkinAsset

import com.badlogic.gdx.scenes.scene2d.{Actor=>GdxActor}
import com.badlogic.gdx.scenes.scene2d.ui.{Skin=>GdxSkin,TextButton=>GdxTextButton}
import com.badlogic.gdx.scenes.scene2d.utils.{ChangeListener=>GdxChangeListener}
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.{ChangeEvent=>GdxChangeEvent}
//...
  def create() {
    val skin = get[Asset,GdxSkin]("defaultSkin")

    val button1 = new GdxTextButton("New game", skin)
    table.add(button1).width(120).pad(10)

    table.row()

    val button2 = new GdxTextButton("Quit", skin)
    table.add(button2).width(120).pad(10)
    button2.addListener(new GdxChangeListener {
      def changed(event: GdxChangeEvent, actor: GdxActor) {
        quit()
      }
    })
    ()
  }
//...
We first obtain default skin that was created inside "Menus" group. Next we add two buttons using standard Libgdx features. The first button is without callback, but the second one issues quit method that closes application. For more features of Libgdx widgets we recommend you to check scene2d.ui documentation on Libgdx page.

Note: We plan to add Scala DSL for GUIs in near future, but currently you are left with Libgdx features alone.

Now you should have fully working main menu. In next step we will add intro to our game.

Having troubles with this step?

Here you can download project with all above steps completed.

Updated