mirror of
https://github.com/GayPizzaSpecifications/voxelotl-engine.git
synced 2025-08-03 13:11:33 +00:00
add mouse support
This commit is contained in:
@ -71,6 +71,7 @@ public class Application {
|
|||||||
private func beginHandleEvents() {
|
private func beginHandleEvents() {
|
||||||
Keyboard.instance.newFrame()
|
Keyboard.instance.newFrame()
|
||||||
GameController.instance.newFrame()
|
GameController.instance.newFrame()
|
||||||
|
Mouse.instance.newFrame(window!)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleEvent(_ event: SDL_Event) -> ApplicationExecutionState {
|
private func handleEvent(_ event: SDL_Event) -> ApplicationExecutionState {
|
||||||
@ -108,6 +109,17 @@ public class Application {
|
|||||||
btn: SDL_GamepadButton(Int32(event.gbutton.button)), state: event.gbutton.state)
|
btn: SDL_GamepadButton(Int32(event.gbutton.button)), state: event.gbutton.state)
|
||||||
return .running
|
return .running
|
||||||
|
|
||||||
|
case SDL_EVENT_MOUSE_BUTTON_DOWN, SDL_EVENT_MOUSE_BUTTON_UP:
|
||||||
|
Mouse.instance.buttonEvent(
|
||||||
|
btn: UInt32(event.button.button),
|
||||||
|
state: event.button.state)
|
||||||
|
return .running
|
||||||
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
|
Mouse.instance.motionEvent(
|
||||||
|
absolute: SIMD2(event.motion.x, event.motion.y),
|
||||||
|
relative: SIMD2(event.motion.xrel, event.motion.yrel))
|
||||||
|
return .running
|
||||||
|
|
||||||
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
|
||||||
let backBufferSize = Size(Int(event.window.data1), Int(event.window.data2))
|
let backBufferSize = Size(Int(event.window.data1), Int(event.window.data2))
|
||||||
self.renderer!.resize(size: backBufferSize)
|
self.renderer!.resize(size: backBufferSize)
|
||||||
|
@ -26,12 +26,15 @@ add_executable(Voxelotl MACOSX_BUNDLE
|
|||||||
# Resource classes
|
# Resource classes
|
||||||
NSImageLoader.swift
|
NSImageLoader.swift
|
||||||
|
|
||||||
|
# Input wrappers
|
||||||
|
Input/Keyboard.swift
|
||||||
|
Input/GameController.swift
|
||||||
|
Input/Mouse.swift
|
||||||
|
|
||||||
# Core utility classes
|
# Core utility classes
|
||||||
Color.swift
|
Color.swift
|
||||||
Camera.swift
|
Camera.swift
|
||||||
Renderer.swift
|
Renderer.swift
|
||||||
Keyboard.swift
|
|
||||||
GameController.swift
|
|
||||||
FPSCalculator.swift
|
FPSCalculator.swift
|
||||||
GameDelegate.swift
|
GameDelegate.swift
|
||||||
Application.swift
|
Application.swift
|
||||||
@ -81,3 +84,4 @@ source_group("Resources" FILES Assets.xcassets test.png)
|
|||||||
source_group("Source Files" REGULAR_EXPRESSION "\\.(swift|metal)$")
|
source_group("Source Files" REGULAR_EXPRESSION "\\.(swift|metal)$")
|
||||||
source_group("Source Files\\Random" REGULAR_EXPRESSION "Random/")
|
source_group("Source Files\\Random" REGULAR_EXPRESSION "Random/")
|
||||||
source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
|
source_group("Source Files\\Math" REGULAR_EXPRESSION "Math/")
|
||||||
|
source_group("Source Files\\Input" REGULAR_EXPRESSION "Input/")
|
||||||
|
81
Sources/Voxelotl/Input/Mouse.swift
Normal file
81
Sources/Voxelotl/Input/Mouse.swift
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import SDL3
|
||||||
|
|
||||||
|
public class Mouse {
|
||||||
|
public struct Buttons: OptionSet {
|
||||||
|
public let rawValue: UInt32
|
||||||
|
public init(rawValue: UInt32) { self.rawValue = rawValue }
|
||||||
|
|
||||||
|
static let left = Self(rawValue: UInt32(SDL_BUTTON_LEFT).buttonMask)
|
||||||
|
static let middle = Self(rawValue: UInt32(SDL_BUTTON_MIDDLE).buttonMask)
|
||||||
|
static let right = Self(rawValue: UInt32(SDL_BUTTON_RIGHT).buttonMask)
|
||||||
|
static let button4 = Self(rawValue: UInt32(SDL_BUTTON_X1).buttonMask)
|
||||||
|
static let button5 = Self(rawValue: UInt32(SDL_BUTTON_X2).buttonMask)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static var capture: Bool {
|
||||||
|
get { self._instance.getCapture() }
|
||||||
|
set { self._instance.setCapture(newValue) }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static var position: SIMD2<Float> { self._instance.getAbsolute() }
|
||||||
|
public static var relative: SIMD2<Float> { self._instance.getDelta() }
|
||||||
|
|
||||||
|
public static func down(_ btn: Buttons) -> Bool {
|
||||||
|
btn.isSubset(of: self._instance._btns)
|
||||||
|
}
|
||||||
|
public static func pressed(_ btn: Buttons) -> Bool {
|
||||||
|
btn.isSubset(of: self._instance._btns.intersection(self._instance._btnImpulse))
|
||||||
|
}
|
||||||
|
public static func released(_ btn: Buttons) -> Bool {
|
||||||
|
btn.isSubset(of: self._instance._btnImpulse.subtracting(self._instance._btns))
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: - Private
|
||||||
|
|
||||||
|
private static let _instance = Mouse()
|
||||||
|
public static var instance: Mouse { self._instance }
|
||||||
|
|
||||||
|
private var _window: OpaquePointer!
|
||||||
|
private var _captured: Bool = false
|
||||||
|
private var _abs: SIMD2<Float> = .zero, _delta: SIMD2<Float> = .zero
|
||||||
|
private var _btns: Buttons = [], _btnImpulse: Buttons = []
|
||||||
|
|
||||||
|
private func getCapture() -> Bool { self._captured }
|
||||||
|
private func setCapture(_ toggle: Bool) {
|
||||||
|
let sdlBool = toggle ? SDL_TRUE : SDL_FALSE
|
||||||
|
if SDL_SetRelativeMouseMode(sdlBool) >= 0 && SDL_SetWindowMouseGrab(self._window, sdlBool) >= 0 {
|
||||||
|
self._captured = toggle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getAbsolute() -> SIMD2<Float> { self._abs }
|
||||||
|
private func getDelta() -> SIMD2<Float> { self._delta }
|
||||||
|
|
||||||
|
internal func buttonEvent(btn: UInt32, state: UInt8) {
|
||||||
|
if state == SDL_PRESSED {
|
||||||
|
self._btns.formUnion(.init(rawValue: btn.buttonMask))
|
||||||
|
} else {
|
||||||
|
self._btns.subtract(.init(rawValue: btn.buttonMask))
|
||||||
|
}
|
||||||
|
self._btnImpulse.formUnion(.init(rawValue: btn.buttonMask))
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func motionEvent(absolute: SIMD2<Float>, relative: SIMD2<Float>) {
|
||||||
|
self._abs = absolute
|
||||||
|
self._delta += relative
|
||||||
|
}
|
||||||
|
|
||||||
|
internal func newFrame(_ window: OpaquePointer) {
|
||||||
|
self._window = window
|
||||||
|
|
||||||
|
let grabbedFlag = SDL_WindowFlags(SDL_WINDOW_MOUSE_GRABBED)
|
||||||
|
self._captured = (SDL_GetWindowFlags(window) & grabbedFlag) == grabbedFlag
|
||||||
|
|
||||||
|
self._delta = .zero
|
||||||
|
self._btnImpulse = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate extension UInt32 {
|
||||||
|
var buttonMask: UInt32 { 1 &<< (self &- 1) }
|
||||||
|
}
|
@ -50,7 +50,7 @@ struct Player {
|
|||||||
// Read controller input (if one is plugged in)
|
// Read controller input (if one is plugged in)
|
||||||
if let pad = GameController.current?.state {
|
if let pad = GameController.current?.state {
|
||||||
turning += pad.rightStick.radialDeadzone(min: 0.1, max: 1)
|
turning += pad.rightStick.radialDeadzone(min: 0.1, max: 1)
|
||||||
movement += pad.leftStick.cardinalDeadzone(min: 0.1, max: 1)
|
movement = pad.leftStick.cardinalDeadzone(min: 0.1, max: 1)
|
||||||
flying += (pad.down(.rightBumper) ? 1 : 0) - (pad.down(.leftBumper) ? 1 : 0)
|
flying += (pad.down(.rightBumper) ? 1 : 0) - (pad.down(.leftBumper) ? 1 : 0)
|
||||||
if pad.pressed(.east) {
|
if pad.pressed(.east) {
|
||||||
jumpInput = .press
|
jumpInput = .press
|
||||||
@ -72,19 +72,22 @@ struct Player {
|
|||||||
if Keyboard.down(.s) { movement.y += 1 }
|
if Keyboard.down(.s) { movement.y += 1 }
|
||||||
if Keyboard.down(.a) { movement.x -= 1 }
|
if Keyboard.down(.a) { movement.x -= 1 }
|
||||||
if Keyboard.down(.d) { movement.x += 1 }
|
if Keyboard.down(.d) { movement.x += 1 }
|
||||||
if Keyboard.down(.up) { turning.y -= 1 }
|
if Keyboard.down(.q) { flying += 1 }
|
||||||
if Keyboard.down(.down) { turning.y += 1 }
|
if Keyboard.down(.e) { flying -= 1 }
|
||||||
if Keyboard.down(.left) { turning.x -= 1 }
|
if Keyboard.pressed(.tab) { Mouse.capture = !Mouse.capture }
|
||||||
if Keyboard.down(.right) { turning.x += 1 }
|
|
||||||
if Keyboard.down(.tab) { flying += 1 }
|
|
||||||
if Keyboard.pressed(.q) { place = true }
|
|
||||||
if Keyboard.pressed(.e) { destroy = true }
|
|
||||||
if Keyboard.pressed(.space) {
|
if Keyboard.pressed(.space) {
|
||||||
jumpInput = .press
|
jumpInput = .press
|
||||||
} else if jumpInput != .press && Keyboard.down(.space) {
|
} else if jumpInput != .press && Keyboard.down(.space) {
|
||||||
jumpInput = .held
|
jumpInput = .held
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read mouse input
|
||||||
|
if Mouse.pressed(.left) { destroy = true }
|
||||||
|
if Mouse.pressed(.right) { place = true }
|
||||||
|
if Mouse.capture {
|
||||||
|
self._rotation += Mouse.relative / 2048 * Float.pi
|
||||||
|
}
|
||||||
|
|
||||||
// Turning input
|
// Turning input
|
||||||
self._rotation += turning * deltaTime * 3.0
|
self._rotation += turning * deltaTime * 3.0
|
||||||
if self._rotation.x < 0.0 {
|
if self._rotation.x < 0.0 {
|
||||||
|
Reference in New Issue
Block a user