🐀
Go版slコマンド「og」を作った
作ったもの
ターミナルでgo
を間違えてog
と打ったときに、逆さまのGopherくんが空から降ってくるコマンドを作りました。
sl
コマンドはターミナル上に蒸気機関車が表示されますが、このコマンドは画面上にGopherくんが表示されます。
環境
- MacOS: バージョン14.2.1(23C71)
- チップ: Apple M1
go version go1.21.5 darwin/arm64
インストール
$ git clone https://github.com/hamao0820/og.git
$ cd og
$ go install
cgoの関係で、GoReleaserがうまく使えませんでした。
何かわかる方はコメントで教えていただきたいです。
試したこと
以下の記事を参考にしました。
.goreleaser.yaml
builds:
- env:
- - CGO_ENABLED=0
+ - CGO_ENABLED=1
goos:
- - linux
- windows
- darwin
とすると、
goreleaser release --snapshot --rm-dist
は動くのですが、GitHub上では
⨯ release failed after 32s error=failed to build for darwin_amd64_v1: exit status 1: # runtime/cgo
clang: error: argument unused during compilation: '-arch x86_64' [-Werror,-Wunused-command-line-argument]
というエラーが発生します。
使い方
og
Macで実行すると、ターミナルがフルスクリーンの場合はうまく表示されないので、注意してください。
実装
Gopherくんの表示には、Ebitengineを使用しています。
main.go
の全文を載せておきます。
コード
main.go
package main
import (
"bytes"
"embed"
"image"
_ "image/png"
"log"
"math"
"math/rand"
"os"
"github.com/hajimehoshi/ebiten/v2"
)
//go:embed images/*
var fs embed.FS
type Game struct {
image *ebiten.Image
x, y int
}
const (
width = 370
height = 320
)
var (
screenwidth, screenHeight = ebiten.ScreenSizeInFullscreen()
)
func NewGame() (*Game, error) {
names := []string{"cry", "faint", "scare"}
name := names[rand.Intn(len(names))]
b, err := fs.ReadFile("images/" + name + ".png")
if err != nil {
return nil, err
}
img, _, err := image.Decode(bytes.NewReader(b))
if err != nil {
return nil, err
}
reversed := ebiten.NewImage(width, height)
// Rotate 180 degrees
op := &ebiten.DrawImageOptions{}
op.GeoM.Rotate(math.Pi)
op.GeoM.Translate(width, height)
reversed.DrawImage(ebiten.NewImageFromImage(img), op)
return &Game{
image: reversed,
x: screenwidth/2 - width/2,
y: -height,
}, nil
}
func (g *Game) Update() error {
g.y += 10
ebiten.SetWindowPosition(g.x, g.y)
if g.y > screenHeight {
// 画面の外に出たら終了
os.Exit(0)
}
return nil
}
func (g *Game) Draw(screen *ebiten.Image) {
op := &ebiten.DrawImageOptions{}
if g.y < 0 {
op.GeoM.Translate(0, float64(g.y))
}
screen.DrawImage(g.image, op)
}
func (g *Game) Layout(w, h int) (int, int) {
return width, height
}
func main() {
game, err := NewGame()
if err != nil {
log.Fatal(err)
}
ebiten.SetWindowSize(width, height)
ebiten.SetWindowDecorated(false)
ebiten.SetWindowMousePassthrough(true)
ebiten.SetWindowFloating(true)
ebiten.SetWindowClosingHandled(true)
op := &ebiten.RunGameOptions{}
op.ScreenTransparent = true
if err := ebiten.RunGameWithOptions(game, op); err != nil {
log.Fatal(err)
}
}
ライセンス
今回使用した画像は、tenntennさんが作成したものです。
オリジナルのThe Go gopher(Gopherくん)は、Renée Frenchによってデザインされました。
まとめ
かなりシンプルな実装になりました。
sl
コマンドと違って、signalまわりの実装はしていません。
リリースについてわかる方がいましたら教えていただけるとありがたいです。
参考記事
Discussion