0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

V言語のggでProcessingっぽく遊ぶ

Last updated at Posted at 2025-09-10

当記事はGIFアニメーションを多く含みます。自動再生されないときは画像をタップしてください。

画面収録 2025-09-10 9.34.21.gif

(↑GIFアニメ)

V言語について

2021年頃に一度話題になったV言語ですが、その時点ではちょっと誇大広告気味だったのもあってか、その後下火になりあまり話題にならなくなりました。

2025年になって改めてウォッチしてみると、言語としての安定度も高まってきており 1GCがデフォルトでオンになっていたり 2、当時OpenGLだけ標準でサポートされていたのが、Metal, D3D11, WebGL2などに対応できるSokolベースのggというフレームワークができたり、それをベースにした新たなGUIフレームワークができたりと、気づかぬうちにいろいろ進化しています。

gg について

画面収録 2025-09-10 10.40.52.gif

(↑ examples/gg/stars.v、GIFアニメ)

ggは、Sokolベースの描画フレームワークで、基本的に2D用ですが、Sokol GL (sgl) というOpenGL互換(OpenGL風)レイヤーの上に構築されているので、3Dにも対応できます。基本的にSokolにできることはggでもできます。

なんとなくp5.js (Processing、Proce55ing) に似たAPIになっていて、それが今回の記事の動機になっています。

V言語は爆速かつ省メモリなので、ggと合わせて、ProcessingやopenFrameworks に代わる(あるいはLÖVE 2Dの代替など)、新たな存在となる可能性もあるように私は感じています。

開発環境について

V言語のインストール自体は簡単で、

$ git clone --depth=1 https://github.com/vlang/v
$ cd v
$ make
$ ./v symlink

ですぐに完了します。makeとありますが、makeは内包されているので何も他にインストールする必要はありません。gccなどの別のコンパイラも基本的には要りません。TCC(Tiny C Compiler)というコンパイラが自動で内包されます。 1

あとは v と打つと、インタプリタ(対話環境)で遊べます。

スクリーンショット 2025-09-10 9.12.05.png

v run hello.v でファイルを実行することもできます。

IDEがほしいときは、VSCodeにv-analyzerをインストールすれば、もうバッチリです。3

スクリーンショット 2025-09-10 9.18.48.png

v-analyzerのバイナリのインストールが途中で促されますが、環境によっては失敗してしまうこともあるので、その場合はv-analyzer/releasesからダウンロードして解凍してPATHに配置すればOKです。

(v-analyzer、たまにおかしな現象に見舞われるので、詳しくは脚注 3 を参照のこと。)

Hello World

百聞は一見に如かずなので、Hello Worldを書いてみます。

スクリーンショット 2025-09-10 9.26.30.png

現時点でV言語はQiitaではシンタックスハイライトされないようです。

スクリーンショット 2025-09-10 11.28.41.png

import gg

const win_width = 600
const win_height = 300

struct App {
mut:
	gg    &gg.Context = unsafe { nil }
}

fn main() {
	mut app := &App{}
	app.gg = gg.new_context(
		bg_color:      gg.white
		width:         win_width
		height:        win_height
		create_window: true
		window_title:  'Hello'
		frame_fn:      frame
		user_data:     app
	)
	app.gg.run()
}

fn frame(mut app App) {
	app.gg.begin()
	app.draw()
	app.gg.end()
}

fn (mut app App) draw() {
	g := app.gg
	g.draw_text_def(10, 10, 'hello world!')
	g.draw_rect_filled(30, 30, 40, 40, gg.blue)
	g.draw_rect_empty(25, 25, 50, 50, gg.black)
}

v run hello.v で実行することができます。

基本的には最後の draw() の中身だけ見ればOKです。

スクリーンショット 2025-09-10 11.29.42.png

fn (mut app App) draw() {
	g := app.gg
	g.draw_text_def(10, 10, 'hello world!')
	g.draw_rect_filled(30, 30, 40, 40, gg.blue)
	g.draw_rect_empty(25, 25, 50, 50, gg.black)
}

ggでは draw_xxx_filled で塗りつぶし図形の描画、draw_xxx_empty で枠線だけの図形描画になるようです。

マウスに追従させてみる

画面収録 2025-09-10 9.34.21.gif

(↑GIFアニメ)

スクリーンショット 2025-09-10 11.36.10.png

fn (app &App) draw() {
	g := app.gg

	x := g.mouse_pos_x
	y := g.mouse_pos_y

	g.draw_text_def(x - 10, y - 20, 'hello world!')
	g.draw_rect_filled(x + 10, y + 10, 40, 40, gg.blue)
	g.draw_rect_empty(x + 5, y + 5, 50, 50, gg.black)
}

ノリはProcessingとそっくりですね。

キーボードを使う

画面収録 2025-09-10 11.00.12.gif

(↑GIFアニメ)

スクリーンショット 2025-09-10 11.33.23.png

fn (mut app App) draw() {
	mut g := app.gg
	
	if g.is_key_down(gg.KeyCode.space) {
		g.draw_text_def(10, 110, 'space key press')
		g.draw_rect_filled(10, 10, 100, 100, gg.blue)
	}else{
		g.draw_text_def(10, 110, 'space key release')
		g.draw_rect_empty(10, 10, 100, 100, gg.black)
	}
}

こちらもなんとなくProcessingと似ていますね。fn key_pressed() などのイベント関数はありませんが、必要なら作れそうな雰囲気です (【追記】 ドキュメントを読んでいると、コールバックはちゃんとありました: 参考frame_fn と同じように keyup_fn などを設定できます)。

回転させてみる

画面収録 2025-09-10 9.45.55.gif

(↑GIFアニメ)

ggだけでは回転できないので、sgl (Sokol GL) を呼び出します。コードの最上部に import sokol.sgl が要ります。

スクリーンショット 2025-09-10 11.34.39.png

fn (mut app App) draw() {
	g := app.gg
    
	r := g.mouse_pos_x
	sgl.translate(200, 200, 0)
	sgl.rotate(sgl.rad(r), 0, 0, 1)
	g.draw_text_def(0, 0, 'hello world!')
}

sglの関数一覧を見てみるとわかるのですが、できることは基本的にOpenGLと同じなので、例えば glPushMatrix()push_matrix であったりと、読み替えができる作りになっているようです。

まとめ

今回はこの辺で終わりたいと思いますが、sglのドキュメントや、ggのドキュメント をざっと眺めてみると、どんなことができるかなんとなくわかるかと思います。

ggのexamples (V言語インストール時のフォルダに v/examples/gg に入っている)には、3Dの例などもあるので、参考にされてみると良いかと思います。( v run xxx.v で実行可能。)

なお、V言語自体の情報は後述のように2021年に流行ったときとだいぶ変わっているので、英語の公式ドキュメントを参考にされることをおすすめします。

補足: V言語の当初との違いについて

補足になりますが、V言語ではグローバル変数はデフォルトでは無効になっていることなどもあり、2021年当初はV言語にはクロージャがないというのが懸念となっていたりもしていました。

しかし現時点ではクロージャは既に実装されています

スクリーンショット 2025-09-10 10.37.51.png

my_int := 1
my_closure := fn [my_int] () {
    println(my_int)
}
my_closure() // prints 1

このように、2021年頃にはあった様々な懸念事項の多くが、2025年現在では解消されているので、当時微妙だなと感じた方はまた改めてウォッチされてみると楽しいのではないかと思います。

  1. V言語のデフォルト(TCC)では、サードパーティのライブラリを使うときに、C言語のヘッダインクルード時(#include "xxx.h")に正しくパースされないというエラー報告がとても多い印象で、実際にそれで困ることもあるのですが、V言語というよりTCC(Tiny C Compiler)の問題なので、v -cc clangv -cc gcc などしてCコンパイラを切り替えれば(v runの代わりにv -cc clang runなど)、比較的安定して使えます。 2

  2. GCは重くなるなどいろんな懸念がある方もいるかと思いますが、開発者本人も当初はGCに懐疑的だった様子で、アンチGCだったらしいのですが、実際に導入してみると実用上全く問題なかったとのことで、導入が決まったようです。(GCはオフにすることもできますし、9割くらいを静的解析で自動開放できる -autofree もあります。)

  3. v-analyzerは、現時点では、module main など、main関数を持つvファイルが複数あると、アルファベット順で最初のファイル以外はどうやらパースがおかしくなってしまうようです。V言語の仕様なのかもしれないのですが、私は mkdir dev; ln -s ../xxx.v dev/xxx.v; code dev として、1つのファイルだけになるようにして回避したりしています。(あるいはアルファベット順で最初になるようにリネームして開発するなど。)【追記】 Go言語と同様に仕様のようなので、Go言語のmain.goと同じく、フォルダに1つにしたほうが良いようですね。init関数といい、よくわからないものはGo言語を参考にするとだいたい分かる感じのようです。 2

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?