[GO] Sample to draw a simple clock using ebiten

A program that just draws a simple clock

A sample that draws a clock using a game engine called ebiten

時計のイメージ

The clock is simple.

Source code

main.go



package main

import (
	. "clock"
	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/inpututil"
	"log"
	"time"
)

type Game struct {
	time time.Time
	stop bool
}

func (g *Game) Update(screen *ebiten.Image) error {
	if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
		g.stop = !g.stop
	}
	if !g.stop {
		g.time = time.Now()
	}
	return nil
}

func (g *Game) Draw(screen *ebiten.Image) {
	m := ClockImage(g.time)
	em, _ := ebiten.NewImageFromImage(m, ebiten.FilterDefault)
	screen.DrawImage(em, &ebiten.DrawImageOptions{})
}

func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
	return 320, 320
}

func main() {
	game := &Game{}

	ebiten.SetWindowSize(320, 320)
	ebiten.SetWindowTitle("Hello, World!")
	if err := ebiten.RunGame(game); err != nil {
		log.Fatal(err)
	}
}

With the meaning of a sample, you can stop the clock by pressing the escape key.

I'm not thinking about how to use it.

Implementation of ClockImage

A program that generates the essential clock image

clock.go


package clock

import (
	"image"
	"github.com/fogleman/gg"
	"github.com/golang/freetype/truetype"
	"golang.org/x/image/font/gofont/gomedium"
	"time"
)

func ClockImage(t time.Time) image.Image {
	const (
		R       = 160
		Long    = 108 //Second
		Midium  = 85  // Minute
		Short   = 50  // Hour
		Width   = R*2 + 1
		Height  = R*2 + 1
		CenterX = Width / 2
		CenterY = Height / 2
		M       = 15 //Other memory line segments
		M5      = 26 //5 minute memory line segment
	)
	dc := gg.NewContext(Width, Height)

	dc.SetHexColor("#ffffff")
	dc.Clear()

    //Memory drawing
	dc.Push()
	dc.SetHexColor("#000000")
	for i := 0; i < 60; i++ {
		dc.Push()
		var m float64 = M
		if i%5 == 0 {
			dc.SetLineWidth(2)
			m = M5
		}
		dc.MoveTo(CenterX, CenterY-R+m)
		dc.LineTo(CenterX, 0)
		dc.Stroke()
		dc.Pop()
		dc.RotateAbout(gg.Radians(float64(6)), CenterX, CenterY)
	}
	dc.Pop()

	dc.SetHexColor("#000")
        
    // AM /PM drawing
	var AMPM = "AM"
	if t.Hour() >= 12 {
		AMPM = "PM"
	}
	f, _ := truetype.Parse(gomedium.TTF)
	face := truetype.NewFace(f, &truetype.Options{Size: 34})
	dc.SetFontFace(face)
	dc.DrawString(AMPM, CenterX+37, CenterY+7)

    //Angle of the hour hand at 0 o'clock=Since we want to set it to 0 degrees, rotate it 90 degrees counterclockwise in advance.
	dc.RotateAbout(gg.Radians(-90), CenterX, CenterY)

	dc.DrawCircle(CenterX, CenterY, R)
	dc.Stroke()

    //Drawing of the short hand
	dc.Push()
	dc.SetLineWidth(8)
	dc.MoveTo(CenterX, CenterY)
	HD := t.Hour()%12*30 + int(float64(t.Minute())*0.5) //t.Hour() range [0,23] 360/12 == 30
	if HD != 0 {
		dc.RotateAbout(gg.Radians(float64(HD)), CenterX, CenterY)
	}
	dc.LineTo(CenterX+Short, CenterY)
	dc.Stroke()
	dc.Pop()

    //Drawing of the long hand
	dc.Push()
	dc.SetLineWidth(4)
	dc.MoveTo(CenterX, CenterY)
	MD := t.Minute() * 6 // t.Minute() range [0,59] 360/60 == 6
	if MD != 0 {
		dc.RotateAbout(gg.Radians(float64(MD)), CenterX, CenterY)
	}
	dc.LineTo(CenterX+Midium, CenterY)
	dc.Stroke()
	dc.Pop()

    //Drawing the second hand
	dc.Push()
	dc.SetLineWidth(2)
	dc.MoveTo(CenterX, CenterY)
	SD := t.Second() * 6 // t.Second() range [0,59] 360/60 == 6
	if SD != 0 {
		dc.RotateAbout(gg.Radians(float64(SD)), CenterX, CenterY)
	}
	dc.LineTo(CenterX+Long, CenterY)
	dc.Stroke()
	dc.Pop()

	return dc.Image()
}

Passes time and returns a clock image showing that time

in conclusion

There is almost no explanation, but I would like to update it if I can think of a more understandable explanation.

Personally, I think Go is an easy-to-write language, but type conversion tends to be redundant.

Will there be fewer bugs by eliminating implicit type conversions, or will more code be written ...

Recommended Posts

Sample to draw a simple clock using ebiten
How to draw a graph using Matplotlib
I tried to draw a configuration diagram using Diagrams
A simple sample of pivot_table.
Time measurement using a clock
I tried to make a simple text editor using PyQt
Try to draw a Bezier curve
Creating a simple table using prettytable
How to install a package using a repository
A simple IDAPython script to name a function
How to get a sample report from a hash value using VirusTotal's API
Draw a tree in Python 3 using graphviz
I tried to create a sample to access Salesforce using Python and Bottle
A simple example of how to use ArgumentParser
A story about simple machine learning using TensorFlow
How to code a drone using image recognition
How to draw a 2-axis graph with pyplot
How to draw a 3D graph before optimization
Randomly sample MNIST data to create a dataset
Try to draw a life curve with python
AWS Step Functions to learn with a sample
[Python] How to draw a histogram in Matplotlib
How to upload to a shared drive using pydrive
How to uninstall a module installed using setup.py
[PyTorch] Sample ⑧ ~ How to build a complex model ~
I tried to make a ○ ✕ game using TensorFlow
How to write a GUI using the maya command
[Python] How to draw a line graph with Matplotlib
How to set up a Python environment using pyenv
(Python) Try to develop a web application using Django
I tried to draw a route map with Python
I tried hosting a Pytorch sample model using TorchServe
How to hold a hands-on seminar using Jupyter using docker
[GCP] Try a sample to authenticate users with Firebase
I want to randomly sample a file in Python
How to make a Python package using VS Code
[Simple procedure] To log in to ssh without a password
A sample to try Factorization Machines quickly with fastFM
How to create a simple TCP server / client script
I decided to do a simple regression analysis manually-1-
How to execute a command using subprocess in Python
[Python] How to draw a scatter plot with Matplotlib
Derivatives learned using Python-(2) Draw a yield curve (JPYLibor curve)-
An introduction to machine learning from a simple perceptron
How to easily draw the structure of a neural network on Google Colaboratory using "convnet-drawer"