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 thisScreenshot from 2015-02-08 21:28:35

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

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *