1.Window #

Your program has precisely one window. The window has no title or any other decorations. To close the window, you can either stop the program or use keyboard shortcuts, for instance, Alt+F4 in Windows.

To create the window, you must create an object of Window class. You also should pass the width and height of the window as arguments. Example:

val wnd = Window(1027, 768)
Yes No

2.Drawing #

2.1.Turtle #

Detailed API documentation.

The easiest way to write a program drawing something on a screen is turtle graphics. I saw a five-year-old kid doing it.

You command the imaginary robot called “turtle” using very simple commands: forward, turnLeft, turnRight, backward. The turtle moves drawing line on the screen. You also can use commands: penUp and penDown to move it without drawing.

Turtle graphics was originally created as part of Logo programming language in the 1967 year and accepted as a great way to learn Programming.

Using ToyGraphics you can combine good old turtle graphics with a modern programming language (Kotlin).

If you use turtle graphics you may skip “Coordinate system” and “Graphics” in this manual.

Turtle graphics is very easy to use but has its own limitations.
If you need to write a game or use a Cartesian coordinate system you have to use Graphics class.

To use turtle graphics you have to create an object of the Turtle class passing the window as an argument. Like this:

val turtle = Turtle(wnd)

You create several turtles and move them independently.

Here are some complete examples and results on the screen:

// Draws a square. For absolute beginners.

package demos.turtle
import com.anysolo.toyGraphics.*

fun main() {
    val wnd = Window(800, 600)
    val turtle = Turtle(wnd)

    turtle.forward(100)
    turtle.turnRight(90.0)

    turtle.forward(100)
    turtle.turnRight(90.0)

    turtle.forward(100)
    turtle.turnRight(90.0)

    turtle.forward(100)
    turtle.turnRight(90.0)
}
// Draw a square spiral using a loop

package demos.turtle
import com.anysolo.toyGraphics.*

fun main() {
val wnd = Window(1024, 768)
val turtle = Turtle(wnd)

var step = 10

repeat(50) {
turtle.forward(step)
turtle.turnRight(90.0)

step += 10
}
}
Yes No

2.2.Coordinate system #

ToyGraphics uses the usual type of coordinate system in Computer graphics. Y-axis goes from up to down. X-axis goes from left to right. Top left corner has coordinates 0,0
Here is an article: Coordinate System of a Screen

The unit of measure is a pixel. Display resolution at Wikipedia.

You specify a point by pair of integer numbers, Int type in Kotlin. If you calculate a coordinate using floating-point arithmetics (Double type in Kotlin) then you have to use roundToInt() to round a Double number to Int. Example:

val distance = 10000.0
val screenRatio = 10.0
val x = distance/screenRatio.roundToInt()

Look at the example below and you see how it works.

package demos
import com.anysolo.toyGraphics.*

fun main() {
    val wnd = Window(800, 600)
    val gc = Graphics(wnd)

    gc.color = Pal16.red
    gc.drawRect(0, 0, 50, 50, fill = true)

    gc.color = Pal16.blue
    gc.setStrokeWidth(5.0)
    gc.drawLine(25, 0, 25, wnd.height-1)

    gc.color = Pal16.green
    gc.setStrokeWidth(5.0)
    gc.drawLine(0, 25, wnd.width-1, 25)
}
Yes No

2.3.Graphics #

Detailed API documentation.

Graphics class is like a pen you use to draw on the window using a Cartesian coordinate system. Thus, you have to read the Coordinate System.

You create an object of Graphics class passing the window as an argument and use its methods to do the drawing. Here is an example:

import com.anysolo.toyGraphics.*

fun main() {
    val wnd = Window(500, 500)
    val gc = Graphics(wnd)

    gc.drawRect(50, 50, 100, 50)

    gc.color = Pal16.red
    gc.setStrokeWidth(2)
    gc.drawLine(50, 350, 400, 450)

    gc.color = Pal16.blue
    gc.setStrokeWidth(4)
    gc.drawOval(350, 300, 100, 50)

    gc.color = Pal16.green
    gc.setFontSize(32)
    gc.drawText(150, 200, "Some text")
}

Read API documentation to learn more about Graphics methods.

Yes No

2.4.Game graphics. #

Now we are going to learn how to draw graphics when you are writing a game with some moving objects, like a Tenis, Arcanoid or Lode runner.

In such games, you have to redraw the window many times per second. One update of the window called “frame”. Frames per second or FPS means how many times you redraw the window during one second. Like with movies when you look at the game working with FPS >= 25 you see smooth motion.

There is a catch. If you try something straightforward like the example bellow you see annoying flickering.

// Flying object with flickering
// A wrong way to draw moving objects!

package demos
import com.anysolo.toyGraphics.*

fun main() {
    val wnd = Window(1920, 1080)
    val gc = Graphics(wnd)

    val objectSize = 50
    val y = wnd.height / 2 - objectSize/2
    var x = 0

    while(true) {
        gc.clear()
        gc.setStrokeWidth(6)
        gc.drawRect(x, y, objectSize, objectSize)

        x = if(x < wnd.width) x + 1 else 0
        sleep(5)
    }
}

To get rid of flickering you have to use the buffered mode of the window. When the window is in the buffered mode you do not drow directly on the window. Instead, you draw on the memory buffer. Then when you call close() method of Graphics class the memory buffer rendered on the window. The example below works without flickering.

// Flying object without flickering

package demos
import com.anysolo.toyGraphics.*

fun main() {
    val wnd = Window(1920, 1080, buffered = true)

    val objectSize = 50
    val y = wnd.height / 2 - objectSize/2
    var x = 0

    while(true) {
        // Start drawing into the buffer
        val gc = Graphics(wnd)

        gc.clear()
        gc.setStrokeWidth(6)
        gc.drawRect(x, y, objectSize, objectSize)

        // End the drawing and by closing Graphics
        gc.close()

        x = if(x < wnd.width) x + 1 else 0
        sleep(5)
    }
} 

Here is a better version using Kotlin use function instead of calling close() directly.

/* Flying a square using buffered window */

package demos
import com.anysolo.toyGraphics.*

fun main() {
    val wnd = Window(1920, 1080, buffered = true)

    val objectSize = 50
    val y = wnd.height / 2 - objectSize/2
    var x = 0

    while(true) {
        Graphics(wnd).use { gc ->
            gc.clear()
            gc.setStrokeWidth(6)
            gc.drawRect(x, y, objectSize, objectSize)
        }

        x = if(x < wnd.width) x + 1 else 0
        sleep(5)
    }
}

Yes No

3.Keyboard #

API documentation

To work with keyboard you have to create an object of Keyboard class passing the window as the argument.

val keyboard = Keyboard(wnd)

Keyboard keeps a queue from information about all pressed keys. You can get information about one key which was pressed the first by calling getPressedKey method:

val key = keyboard.getPressedKey()

After you got the key it is erased from the keyboard queue. And next call of getPressedKey returns the key which was pressed after the previous one. If the keyboard queue is empty, meaning there are not pressed keys to process, getPressedKey returns null. Here is an example showing how you can process pressed keys from the keyboard:

import com.anysolo.toyGraphics.*


fun main() {
    val wnd = Window(800, 600)
    val keyboard = Keyboard(wnd)

    while(true) {
        do {
            val key = keyboard.getPressedKey()

            if (key != null) {
                println(key)
                println("key: " + key.code)
            }

        } while(key != null)

        sleep(1)
    }
}

To understand why you need the inner loop “do” try to change sleep(1) to sleep(10). If you press several keys you see how they processed by that loop when 10 seconds of sleep is finished.

getPressedKey() returns an object of class Key. This object contains all information about what key was pressed and which modifiers (Ctrl, Shift, Alt) was pressed with it. The most important piece of information is “code” property. It contains an Int representing code of the key. You can compare it to one of the known codes from KeyCodes.

Here is an example waiting for Escape key to be pressed. It also shows how you can check key modifiers like shift, alt or control.

package demos

import com.anysolo.toyGraphics.*


fun main() {
    val wnd = Window(800, 600)
    val keyboard = Keyboard(wnd)

    while(true) {
        do {
            val key = keyboard.getPressedKey()

            if (key != null) {
                println(key)
                println("key: " + key.code)

                if(key.code == KeyCodes.ESCAPE)
                    println("Escape key. Does not matter shift or not shift")

                if(key.code == KeyCodes.ESCAPE && key.isShift)
                    println("Escape key + shift")

                if(key.code == KeyCodes.ESCAPE && !key.isShift)
                    println("Escape key. No shift")

                // An empty line before output from the next loop iteration
                println()
            }

        } while(key != null)

        sleep(1)
    }
}

KeyCodes contains only special key codes, like function keys, arrow and so on. If you want to check if some alphabetical key was pressed you can do like this example shows you:

package demos

import com.anysolo.toyGraphics.*


fun main() {
    val wnd = Window(800, 600)
    val keyboard = Keyboard(wnd)

    while(true) {
        do {
            val key = keyboard.getPressedKey()

            if (key != null) {
                println(key)
                println("key: " + key.code)

                if(key.code == 'Q'.toInt())
                    println("'Q' key. Does not matter Alt or not Alt")

                if(key.code == 'Q'.toInt() && key.isAlt)
                    println("'Q' key + Alt")

                if(key.code == 'Q'.toInt() && !key.isAlt)
                    println("'Q' key. No Alt")

                // An empty line before output from the next loop iteration
                println()
            }

        } while(key != null)

        sleep(1)
    }
}

Read API documentation to find more details about Keyboard, Key and KeyCodes classes.

Yes No

4.Images #

What if you need to use more complex graphics than you can easily build using Graphics class methods? In this case, you can create or find on the Internet an image file, load it into an object of Image class and draw using method Graphics.drawImage(). Here is an example:

package demos
import com.anysolo.toyGraphics.*

fun main() {
    val wnd = Window(300, 200)
    val gc = Graphics(wnd)

    val image = Image("graphicsFiles/brick-wall.jpg")
    gc.drawImage(50, 35, image)
}

Image class Image supports PNG, JPG and GIF files.

You can draw an image rotated to any degree. Be default it will be rotated around its top left corner, but you can specify the point you want to rotate your image around. Below you can see the example wich rotates UFO image around its center.

package com.anysolo.toyGraphics.samples

import com.anysolo.toyGraphics.*


fun main() {
    val wnd = Window(300, 300, background = Pal16.black, buffered = true)
    val image = Image("graphicsFiles/ufo-small.png")

    val x = wnd.width/2 - image.width/2
    val y = wnd.height/2 - image.height/2

    val maxAngle = Math.PI*2
    var angle = 0.0

    while(true) {
        Graphics(wnd).use {g ->
            g.clear()

            val anchorx = x + image.width/2
            val anchory = y + image.height/2

            g.drawImage(x, y, image, angle, anchorx, anchory)

            angle += maxAngle/360
            if(angle > maxAngle)
                angle = 0.0

            sleep(20)
        }
    }
}

.

Yes No