Kotlin Game Development: Creating a Scene

Every game is different but, luckily for us, all video games share a common set of components and patterns. There are things that may be specific to a certain genre but on a high level all games are more or less the same and they all have the following components:

  • Screen. Player has to be able to see what’s going on in the game and using a screen is a convenient way to provide visual feedback. It can be a TV screen, computer screen, mobile screen or even a VR headset. Technically, there are two screens in a VR headset but we don’t have to worry about that, most of the required adjustments are handled automatically by headset hardware.

  • Controller. It’s the device that can be used to interact with video games. Many devices can be used as controllers: keyboards, computer mice, joysticks and a variety of more exotic devices such as steering wheels or fighter jet controllers.

  • Game objects. Anything that exists in a game is a game object. Some objects are static, such as the walls, and some are more dynamic, such as the player’s game character or his friends and enemies.

This is the second part of the “Kotlin Game Development” series and it’s better if you read it in chronological order:

  1. Part 1 - Introduction
  2. Part 2 - Creating a Scene (you are here)
  3. Part 3 - Controller Input
  4. Part 4 - Game Loop
  5. Part 5 - Game Factory
  6. Part 6 - Main Menu
  7. Part 7 - Model
  8. Part 8 - Game Scene
  9. Part 9 - Finalizing The Game

A Window Into Virtual Worlds

Let’s start with implementing a screen component. A typical desktop app consists of several windows and every window has its own purpose and separating concerns is usually beneficial for the app users and the developers alike. App users may have a better focus and feel less overwhelmed since there is a separate window for each specific task and the developers can split the application logic between those screens which makes it easier to maintain the code base.

Video games don’t have a window system by default but it doesn’t mean we can’t implement it but I think that we shouldn’t use the name ‘window’ when we’re making a game. “Level” seems to be a good name, many games do look like a series of levels but, in my opinion, this name is not abstract enough. For instance, a main menu or a settings screen are visually separated from the rest of the game and it’s confusing to treat them as “levels” but they also have a lot in common with the rest of the screens: they usually display something and process the input events from the game controllers. So let’s call it a scene, it will be easier to understand that any kind of action can happen here as long as it has something to show to the player. Obviously, we don’t want the player to stare at an empty scene, it’s no fun at all.

Here is our Scene class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package com.bubelov.snake.engine

import java.awt.Graphics2D

abstract class Scene(val game: Game) {
    fun updateAndDraw(nanosecondsPassed: Long, graphics: Graphics2D) {
        update(nanosecondsPassed)
        draw(graphics)
    }

    protected abstract fun update(nanosecondsPassed: Long)

    protected abstract fun draw(graphics: Graphics2D)
}

How Does It Work?

The update method is supposed to be called each time we want the scene to update it’s state but in order to perform the update, the scene needs to know how much time has passed since the last update. That’s why we require the caller to provide us with the nanosecondsPassed value. For instance if we have a moving car on the scene there is no way to tell how far it should move unless we know both its speed and the amount of time that has passed since the last update. The updateAndDraw method should be called at least 30 times per second to make sure that all of the game objects are moving smoothly. That’s why if you try to launch a resource intensive game on old hardware it would look like a slide show, it means that the hardware is unable to update and render the scene fast enough to make it look ‘real’.

The only purpose of the update method is to update the game state to reflect the amount of time passed since the last time this method was invoked. We still need to draw a new state on our scene to make it visible to our players. That’s why we also have introduced the draw method, it supposed to be called immediately after update.

Conclusion

Now we have our way to separate the game into a set of scenes but it’s only one of the core game components we need. In the next piece we will make a component which will handle the input events from our players. It’s fun to see the objects moving but it’s even more fun to be able to control them.