Upload
moriyoshi-koizumi
View
2.532
Download
3
Embed Size (px)
Citation preview
趣味は処理系の魔改造です
~/src/go$ grep -n 'Moriyoshi' CONTRIBUTORS
$ php -r 'phpcredits();' | grep 'Moriyoshi'
http://d.hatena.ne.jp/moriyoshi/20091114/1258204128<?phpfunction sub($i, $ch) { for (;;) { $a = <- [$ch]; printf("%d:", $i); var_dump($a); }}
$ch = thread_message_queue_create();for ($i = 0; $i < 10; $i++) { thread_create('sub', $i, $ch);}
$i = 0;for (;;) { [$ch] <- $i++; usleep(50000);}?>
今日はPHPでchannelを利用する方法は説明しません
goでゲームを作るためのライブラリ
描画
SDL系: go-sdl / gosdl
OpenGL系: gl / GoGL
音: portaudio-go / go-openal / pulsego など
入力はSDL系は標準でできる。OpenGL系では Go-GLUT / glfw などを使える。
独断と偏見
GoGL https://github.com/chsc/GoGL
go-glfw https://github.com/go-gl/glfw
この組み合わせがよさそう
SUPER HEXAGONhttp://superhexagon.com/
デモ動画
http://www.youtube.com/&v=2sz0mI_6tLQ
これを題材にゲームを作ってみる
What you’ll get
初期化package main
import (! gl "github.com/chsc/gogl/gl21"! "github.com/jteeuwen/glfw"}
...
func main() {! if err := glfw.Init(); err != nil {! ! showError(err)! ! return! }! defer glfw.Terminate()
! launch(Game{ 640, 480, "HexaGOn" })}
glfwを初期化
glfwの後始末
ウィンドウを生成func launch(game Game) {! glfw.OpenWindowHint(glfw.WindowNoResize, 1)
! if err := glfw.OpenWindow(game.width, game.height, 0, 0, 0, 0, 16, 0, glfw.Windowed); err != nil {! ! showError(err)! ! return! }! defer glfw.CloseWindow()
! glfw.SetWindowTitle(game.title) ...
ウィンドウを生成
ゲーム処理本体func launch(game Game) { ...
! if err := gl.Init(); err != nil { showError(err) return! }
if err := gameMain(game); err != nil { showError(err) return }}
OpenGLコンテキストを生成
gameMainfunc gameMain(game Game) error {! if err := initScene(game); err != nil {! ! return err! }! defer destroyScene()
... game.Run(func () { drawScene() ... }) return nil}
メインループの中身
game.Run(func () { drawScene() ... if (game.KeyPressed('Z')) { myPosition += .06 } if (game.KeyPressed('X')) { myPosition -= .06 } })
func (game Game) Run(f func()) {! for glfw.WindowParam(glfw.Opened) == 1 {! ! f()! ! glfw.SwapBuffers()! }}
ウィンドウが開かれている間は1
フレームバッファを入れ替え
game.Run
game.KeyPressfunc (game Game) KeyPressed(key int) bool { return glfw.Key(key) == glfw.KeyPress} 該当キーの押下があった場合 glfw.KeyPressが返る
package main
import ( "math" "math/rand" gl "github.com/chsc/gogl/gl21")
type Wall struct { segment int position float64 width float64}
var ( rotz float64 rotSpeed float64 = math.Pi * 0.02 bgdivision int = 6 bgcolor []gl.Float = []gl.Float{1, 1, 0} bgradius float64 = 20 hexradius float64 = .5 perturbation float64 = .04 walls []Wall = nil pog float64 = 0. myPosition float64 = 0. myDistance float64 = .1)
func initScene(game Game) (err error) { gl.Enable(gl.TEXTURE_2D) gl.Enable(gl.DEPTH_TEST)
gl.ClearColor(0., 0., 0., 0.) gl.ClearDepth(1) gl.DepthFunc(gl.LEQUAL)
gl.Viewport(0, 0, gl.Sizei(game.width), gl.Sizei(game.height)) gl.MatrixMode(gl.PROJECTION) gl.LoadIdentity() gl.Frustum(-1, 1, -1, 1, 1.0, 10.0) gl.MatrixMode(gl.MODELVIEW) gl.LoadIdentity()
return}
func destroyScene() {}
func drawBackground() {! gl.Begin(gl.TRIANGLES) defer gl.End()
for i := 0; i < bgdivision; i += 1 { x1, y1 := gl.Float(math.Cos(float64(i) * math.Pi * 2 / float64(bgdivision)) * bgradius), gl.Float(math.Sin(float64(i) * math.Pi * 2 / float64(bgdivision)) * bgradius) x2, y2 := gl.Float(math.Cos(float64(i + 1) * math.Pi * 2/ float64(bgdivision)) * bgradius), gl.Float(math.Sin(float64(i + 1) * math.Pi * 2 / float64(bgdivision)) * bgradius)
{ var brightness gl.Float if i % 2 == 0 { brightness = .5 } else { brightness = .8 } gl.Color4f(bgcolor[0] * brightness, bgcolor[1] * brightness, bgcolor[2] * brightness, 1) }
gl.Normal3f(0, 0, 1) gl.TexCoord2f(0, 0) gl.Vertex3f(0, 0, 1) gl.TexCoord2f(1, 0) gl.Vertex3f(x1, y1, 1) gl.TexCoord2f(1, 1) gl.Vertex3f(x2, y2, 1) }}
func drawCentralHexagon() {! gl.Begin(gl.LINE_LOOP)! defer gl.End() gl.Color4f(bgcolor[0], bgcolor[1], bgcolor[2], 1.) gl.LineWidth(16.)
for i := 0; i < bgdivision; i += 1 { x, y := gl.Float(math.Cos(float64(i) * math.Pi * 2 / float64(bgdivision)) * hexradius), gl.Float(math.Sin(float64(i) * math.Pi * 2 / float64(bgdivision)) * hexradius) gl.Vertex3f(x, y, 1) }}
func drawWalls() {! gl.Begin(gl.QUADS)! defer gl.End()
gl.Color4f(bgcolor[0], bgcolor[1], bgcolor[2], 1.)
for i := 0; i < len(walls); i += 1 { wall := walls[i] segment := wall.segment offset := wall.position - pog width := wall.width if offset < bgradius && offset + width >= 0. { x1, y1 := gl.Float(math.Cos(float64(segment) * math.Pi * 2 / float64(bgdivision)) * math.Max(offset, hexradius)), gl.Float(math.Sin(float64(segment) * math.Pi * 2 / float64(bgdivision)) * math.Max(offset, hexradius)) x2, y2 := gl.Float(math.Cos(float64(segment + 1) * math.Pi * 2/ float64(bgdivision)) * math.Max(offset, hexradius)), gl.Float(math.Sin(float64(segment + 1) * math.Pi * 2 / float64(bgdivision)) * math.Max(offset, hexradius)) x3, y3 := gl.Float(math.Cos(float64(segment) * math.Pi * 2 / float64(bgdivision)) * math.Max((offset + width), hexradius)), gl.Float(math.Sin(float64(segment) * math.Pi * 2 / float64(bgdivision)) * math.Max((offset + width), hexradius)) x4, y4 := gl.Float(math.Cos(float64(segment + 1) * math.Pi * 2/ float64(bgdivision)) * math.Max((offset + width), hexradius)), gl.Float(math.Sin(float64(segment + 1) * math.Pi * 2 / float64(bgdivision)) * math.Max((offset + width), hexradius)) gl.Vertex3f(x1, y1, 1) gl.Vertex3f(x3, y3, 1) gl.Vertex3f(x4, y4, 1) gl.Vertex3f(x2, y2, 1) } }}
func drawMyTriangle() {! gl.Begin(gl.TRIANGLES)! defer gl.End()
p := myPosition o := hexradius + myDistance s := .05 x1, y1 := math.Cos((p - s) * math.Pi * 2 / float64(bgdivision)) * o, math.Sin((p - s) * math.Pi * 2 / float64(bgdivision)) * o x2, y2 := math.Cos((p + s) * math.Pi * 2 / float64(bgdivision)) * o, math.Sin((p + s) * math.Pi * 2 / float64(bgdivision)) * o z := math.Sqrt(math.Pow(x1 - x2, 2) + math.Pow(y1 - y2, 2)) x3, y3 := math.Cos(p * math.Pi * 2 / float64(bgdivision)) * (o + z), math.Sin(p * math.Pi * 2 / float64(bgdivision)) * (o + z)
gl.Color4f(bgcolor[0], bgcolor[1], bgcolor[2], 1.) gl.Vertex3f(gl.Float(x1), gl.Float(y1), 1) gl.Vertex3f(gl.Float(x2), gl.Float(y2), 1) gl.Vertex3f(gl.Float(x3), gl.Float(y3), 1)}
func drawScene() {! gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
! gl.MatrixMode(gl.MODELVIEW)! gl.LoadIdentity()! gl.Rotatef(gl.Float(rotz), 0, 0, 1)! gl.Translatef(0, 0, gl.Float(-3. + rand.Float64() * perturbation))
! rotz += rotSpeed * 180 / math.Pi pog += .02
drawBackground() drawCentralHexagon() drawWalls() drawMyTriangle()}
func gameMain(game Game) error {! if err := initScene(game); err != nil {! ! return err! }! defer destroyScene()
walls = make([]Wall, 100) var j int = 0 for i := 0; i < len(walls) / 2; i += 1 { walls[j] = Wall { i % 6, float64(i) * .7, .15 }; j += 1 walls[j] = Wall { (i + 3) % 6, float64(i) * .7, .15 }; j += 1 } game.Run(func () { drawScene() // rotate against the rotation so the triangle virtually pauses // at the same position myPosition -= rotSpeed * 0.95 if (game.KeyPressed('Z')) { myPosition += .06 } if (game.KeyPressed('X')) { myPosition -= .06 } }) return nil}
initScene / destroyScene / drawScene
func drawScene() {! gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
! gl.MatrixMode(gl.MODELVIEW)! gl.LoadIdentity()! gl.Rotatef(gl.Float(rotz), 0, 0, 1)! gl.Translatef(0, 0, gl.Float(-3. + rand.Float64() * perturbation))
! rotz += rotSpeed * 180 / math.Pi pog += .02
drawBackground() drawCentralHexagon() drawWalls() drawMyTriangle()}
1フレーム分の描画処理
何もGoらしいことはありません
まとめと課題Goでゲームは作れる
http://github.com/moriyoshi/gohex
defer便利
画面の更新は同期的に行う必要があるのでGoroutineなどの活用がむずかしい