Simple 2d box physics in Golang with Chipmunk
I’m currently in the middle of writing a toy game server and needed something to compute the state of some very simple objects. After searching a bit I found chipmunk which is a pure go implementation of chipmunk-physics which purports to be faster than the traditional box2d engine. The game server is an attempt by me to evaluate using something like a high performance distributed log to compute game state across several machines to enable horizontal scaling of a single game area (I want my huge space battles with no time dilation please). Purely for fun (it probably won’t work the way I want it to, but that’s ok, I’m learning while failing).
Anyways, there are a couple things you need to get the go chipmunk library’s example running so I thought I would document them.
The main example we’re going to try and get running is located here and will end up looking like this
First you need to
go get github.com/vova616/chipmunk
You may hit a couple errors and here is how to resolve them.
Go 1.4 Related Problem
# github.com/vova616/chipmunk
../workspaces/go/src/github.com/vova616/chipmunk/collide.go:264: calling method reset with receiver con (type **Contact) requires explicit dereference
This is related to a breaking change in Go 1.4 which you can read about here. The fix is simple. On line 262 you just have to not take the pointer to what comes out of contacts.
Before
con := &contacts[0] pos := vect.Add(circle.Tc, vect.Mult(n, circle.Radius+dist*0.5)) con.reset(pos, n, dist, 0)
After
Change ln 262 to not grab the pointer
con := contacts[0] pos := vect.Add(circle.Tc, vect.Mult(n, circle.Radius+dist*0.5)) con.reset(pos, n, dist, 0)
Since this is a Go 1.4 specific problem and so easy to fix I did not put out a PR to change it in the master repo.
gl & glfw3 Dependency installation problems
When trying to go install the go-gl libraries (gl & glfw3) go will use cgo so you must have GLEW installed properly to be able to build binaries. I tried several pre-built packages for my distribution but they were always stale. If you happen to not have GLEW installed (because, everyone has open-GL dev bindings installed on their machines) you may run into an error when you try to install https://github.com/go-gl/gl which is used by the chipmunk demo to display the balls. The glfw3 package uses GLFW which is an Open Source, multi-platform library for creating windows with OpenGL contexts and receiving input and events.
The error may be this
GL/glew.h: No such file or directory
I ended up compiling it like so (I’m assuming you’ve installed git already) in order to be able to go install the go-gl libraries.
# Make sure glfw (or any previous version) is not already installed sudo apt-get update sudo apt-get install build-essential cmake xorg-dev libglu1-mesa-dev git clone https://github.com/glfw/glfw.git /tmp/glfw cd /tmp/glfw git checkout latest cmake . -DBUILD_SHARED_LIBS=ON make sudo make install sudo ldconfig rm -rf /tmp/glfw
You should be able to now go to chipmunk/examples/glfw3/bouncing_balls and run go run bouncing_balls.go
to be able to see balls falling from the sky and hitting a line in the middle of the screen.
Basic Example
Go chipmunk is very simple to get started with. Here are the main parts pulled out from the bouncing ball demo on how to create physic shapes and add them to the space. The ball created will log out its position as it drops through space. You can go run
this code.
package main import ( "log" "math" "math/rand" "time" "github.com/vova616/chipmunk" "github.com/vova616/chipmunk/vect" ) func main() { var space *chipmunk.Space space = chipmunk.NewSpace() space.Gravity = vect.Vect{0, -900} // Add a static body - lines etc. staticBody := chipmunk.NewBodyStatic() space.AddBody(staticBody) // Create a ball ball := chipmunk.NewCircle(vect.Vector_Zero, float32(10)) ball.SetElasticity(0.95) // Create a body for the ball body := chipmunk.NewBody(vect.Float(1), ball.Moment(float32(1))) body.SetPosition(vect.Vect{vect.Float(1), 600.0}) body.SetAngle(vect.Float(rand.Float32() * 2 * math.Pi)) body.AddShape(ball) space.AddBody(body) // I love tickers for this kind of stuff. We want to calc the state of the // space every 60th of a second. ticker := time.NewTicker(time.Second / 60) for { log.Printf("ball %+v", body.Position()) space.Step(vect.Float(1.0 / 60.0)) <-ticker.C // wait up to 1/60th of a second } }