package fpscontrols import ( "math" "github.com/go-gl/glfw/v3.3/glfw" "github.com/go-gl/mathgl/mgl32" ) type FPSControls struct { lookSpeed float32 moveSpeed float32 position mgl32.Vec3 rotation mgl32.Vec2 currentMove mgl32.Vec3 currentLook mgl32.Vec2 lastMousePos mgl32.Vec2 view mgl32.Mat4 lastTime float64 } var instance *FPSControls func (c *FPSControls) Update() { time := glfw.GetTime() deltaTime := time - c.lastTime c.lastTime = time forward, right, up := c.directions() globalUp := mgl32.Vec3{0, 1, 0} move := right.Mul(c.currentMove.X()).Add(globalUp.Mul(c.currentMove.Y())).Add(forward.Mul(c.currentMove.Z())) c.position = c.position.Add(move.Mul(float32(deltaTime) * c.moveSpeed)) c.rotation = c.rotation.Add(c.currentLook.Mul(float32(deltaTime) * c.lookSpeed)) c.currentLook = mgl32.Vec2{} c.view = mgl32.LookAtV(c.position, c.position.Add(forward), up) } func Get(lookSpeed, moveSpeed float32, position mgl32.Vec3, rotation mgl32.Vec2, window *glfw.Window) *FPSControls { if instance != nil { return instance } instance = &FPSControls{ moveSpeed: moveSpeed, lookSpeed: lookSpeed, position: position, rotation: rotation, } window.SetKeyCallback(func(window *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) { var val float32 switch action { case glfw.Repeat: return case glfw.Press: val = 1 case glfw.Release: val = 0 } switch key { case glfw.KeyW: instance.currentMove[2] = val case glfw.KeyS: instance.currentMove[2] = -val case glfw.KeyA: instance.currentMove[0] = val case glfw.KeyD: instance.currentMove[0] = -val case glfw.KeySpace: instance.currentMove[1] = val case glfw.KeyLeftShift: instance.currentMove[1] = -val } }) window.SetCursorPosCallback(func(window *glfw.Window, y float64, x float64) { pos := mgl32.Vec2{float32(x), float32(y)} instance.currentLook = instance.lastMousePos.Sub(pos) instance.currentLook[0] *= -1 instance.lastMousePos = pos }) window.SetInputMode(glfw.CursorMode, glfw.CursorDisabled) return instance } func (c *FPSControls) directions() (mgl32.Vec3, mgl32.Vec3, mgl32.Vec3) { rad := mgl32.Vec2{ mgl32.DegToRad(c.rotation.X()), mgl32.DegToRad(c.rotation.Y()), } sin := mgl32.Vec2{ float32(math.Sin(float64(rad.X()))), float32(math.Sin(float64(rad.Y()))), } cos := mgl32.Vec2{ float32(math.Cos(float64(rad.X()))), float32(math.Cos(float64(rad.Y()))), } forward := mgl32.Vec3{ cos.X() * sin.Y(), -sin.X(), cos.X() * cos.Y(), } right := mgl32.Vec3{ cos.Y(), 0, -sin.Y(), } up := forward.Cross(right) return forward, right, up } func (c *FPSControls) View() mgl32.Mat4 { return c.view } func (c *FPSControls) Position() mgl32.Vec3 { return c.position } func (c *FPSControls) Rotation() mgl32.Vec2 { return c.rotation }