Resolv v0.6.0
pkg.go.dev
What is Resolv?
Resolv is a 2D collision detection and resolution library, specifically created for simpler, arcade-y (non-realistic) video games. Resolv is written in Go, but the core concepts are fairly straightforward and could be easily adapted for use with other languages or game development frameworks.
Basically: It allows you to do simple physics easier, without actually doing the physics part - that's still on you.
Why is it called that?
Because it's like... You know, collision resolution? To resolve a collision? So... That's the name. I juste took an e off because I seem to have misplaced it.
Why did you create Resolv?
Because I was making games in Go and found that existing frameworks tend to omit collision testing and resolution code. Collision testing isn't too hard, but it's done frequently enough, and most games need simple enough physics that it makes sense to make a library to handle collision testing and resolution for simple, "arcade-y" games; if you need realistic physics, you have other options like Box2D or something.
As an aside, this actually used to be quite different; I decided to rework it when I was less than satisfied with my previous efforts, and after a few attempts over several months, I got it to this state (which, I think, is largely better). That said, there are breaking changes between the previous version, v0.4, and the current one (v0.5). These changes were necessary, in my opinion, to improve the library.
In comparison to the previous version of Resolv, v0.5 includes, among other things:
- A redesigned API from scratch.
- The usage of floats instead of ints for position and movement, simplifying real usage of the library dramatically.
- Broadphase grid-based collision testing and querying for simple collisions, which means solid performance gains.
- ConvexPolygons for SAT intersection tests.
It's still a work-in-progress, but should be solid enough for usage in the field.
How do I get it?
go get github.com/solarlune/resolv
How do I use it?
There's a couple of ways to use Resolv.
Firstly, you can create a Space, create Objects, add them to the Space, check the Space for collisions / intersections, and finally update the Objects as they move.
In Resolv v0.5, a Space represents a limited, bounded area which is separated into even Cells of predetermined size. Any Objects added to the Space fill at least one Cell (as long as the Object is within the Space). By checking a position in the Space, you can tell which Cells are occupied and so, where objects generally are. This is the broadphase, simpler portion of Resolv.
Here's an example:
var space *resolv.Space
var playerObj *resolv.Object
func Init() {
space = resolv.NewSpace(640, 480, 16, 16)
space.Add(
resolv.NewObject(0, 0, 640, 16),
resolv.NewObject(0, 480-16, 640, 16),
resolv.NewObject(0, 16, 16, 480-32),
resolv.NewObject(640-16, 16, 16, 480-32),
)
playerObj = resolv.NewObject(32, 32, 16, 16)
space.Add(playerObj)
}
func Update() {
dx := 2.0
if collision := playerObj.Check(dx, 0); collision != nil {
dx = collision.ContactWithObject(collision.Objects[0]).X()
}
playerObj.X += dx
playerObj.Update()
onlySolidOrHazardous := playerObj.Check(dx, 0, "hazard", "solid")
}
The second way to use Resolv is to check for a more accurate shape intersection test by assigning two Objects Shapes, and then checking for an intersection between them. Checking for an intersection between Shapes internally performs separating axis theorum (SAT) collision testing (when checking against ConvexPolygons), and represents the more inefficient narrow-phase portion of Resolv. If you can get by without doing Shape-based intersection testing, it would be most performant to do so.
playerObj *resolv.Object
stairs *resolv.Object
space *resolv.Space
func Init() {
space = resolv.NewSpace(640, 480, 16, 16)
playerObj = resolv.NewObject(32, 128, 16, 16)
playerObj.SetShape(resolv.NewRectangle(0, 0, 16, 16))
space.Add(playerObj)
stairs = resolv.NewObject(96, 128, 16, 16)
stairs.SetShape(resolv.NewConvexPolygon(
0, 0,
16, 0,
16, 16,
0, 16,
))
space.Add(stairs)
}
func Update() {
dx := 1.0
if intersection := playerObj.Shape.Intersection(dx, 0, stairs.Shape); intersection != nil {
dx = intersection.MTV.X()
}
playerObj.X += dx
playerObj.Update()
}
Welp, that's about it. If you want to see more info, feel free to examine the examples in the examples
folder; the worldPlatformer.go
example is particularly in-depth when it comes to movement and collision response. You can run them by just calling go run .
from the examples folder.
You can check out the documentation here, as well.
Dependencies?
Resolv requires just quartercastle's nice and clean vector library, and the built-in math
package. For the examples, ebiten, as well as tanema's gween library are also required.
Shout-out Time!
Thanks to the people who stopped by on my YouTube Golang gamedev streams - they helped out a lot with a couple of the technical aspects of getting Go to do what I needed to, haha.
If you want to support development, feel free to throw me a couple of bones over on my Patreon or itch.io / Steam pages. I really appreciate it - thanks!