Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?
@Natsukawa-Nagomi

ebitenを使ったシンプルな時計を描画するサンプル

ただシンプルな時計を描画するだけのプログラム

ebiten というゲームエンジンを使って、時計を描画するサンプル

時計のイメージ

時計はとにかくシンプルなもの。

ソースコード

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)
    }
}

サンプルという意味を込めて、エスケープキーを押すと時計を止めることができるようになっています。

使い道は考えていませんが。

ClockImageの実装

肝心の時計の画像を生成するプログラム

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 //その他メモリの線分
        M5      = 26 //5分メモリの線分
    )
    dc := gg.NewContext(Width, Height)

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

    // メモリの描画
    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 の描画
    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)

    // 0時の時の短針の角度=0度としたいため、あらかじめ90度反時計周りに回転
    dc.RotateAbout(gg.Radians(-90), CenterX, CenterY)

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

    // 短針の描画
    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()

    // 長針の描画
    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()

    // 秒針の描画
    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()
}

時間を渡してその時間を示す時計の画像を返す

おわりに

説明もほとんどないですが、もっとわかりやすい解説を思いつけば更新したいと思います。

個人的には、Goは書きやすい言語だとは思いますが、どうしても型変換が冗長になってしまいがちですね。

暗黙の型変換をなくしてバグが減るのか、コードを書く量が増えるか......

1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
1
Help us understand the problem. What is going on with this article?