mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-06-09 18:14:06 +09:00
433 lines
15 KiB
Kotlin
433 lines
15 KiB
Kotlin
package net.torvald.terrarum.gamecontroller
|
|
|
|
import com.badlogic.gdx.Gdx
|
|
import com.badlogic.gdx.Input
|
|
import com.badlogic.gdx.Input.Keys
|
|
import com.badlogic.gdx.InputAdapter
|
|
import com.badlogic.gdx.controllers.Controllers
|
|
import com.badlogic.gdx.utils.GdxRuntimeException
|
|
import net.torvald.terrarum.*
|
|
import net.torvald.terrarum.App
|
|
import net.torvald.terrarum.App.printdbg
|
|
import net.torvald.terrarum.App.printdbgerr
|
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
|
import net.torvald.terrarum.controller.TerrarumController
|
|
import net.torvald.terrarum.floorInt
|
|
import net.torvald.terrarum.gameactors.AVKey
|
|
import net.torvald.terrarum.gameitem.GameItem
|
|
import net.torvald.terrarum.gameworld.fmod
|
|
import net.torvald.terrarum.modulebasegame.TerrarumIngame
|
|
import net.torvald.terrarum.worlddrawer.WorldCamera
|
|
import java.util.*
|
|
|
|
/**
|
|
* Created by minjaesong on 2015-12-31.
|
|
*/
|
|
class IngameController(val terrarumIngame: TerrarumIngame) : InputAdapter() {
|
|
|
|
|
|
val hasGamepad: Boolean
|
|
get() = gamepad != null
|
|
var gamepad: TerrarumController? = null
|
|
|
|
// these four values can also be accessed with GameContainer.<varname>
|
|
// e.g. gc.mouseTileX
|
|
|
|
/** position of the mouse (pixelwise) relative to the world (also, currently pointing world-wise coordinate, if the world coordinate is pixel-wise) */
|
|
val mouseX: Float
|
|
get() = WorldCamera.x + Gdx.input.x / (terrarumIngame.screenZoom)
|
|
/** position of the mouse (pixelwise) relative to the world (also, currently pointing world-wise coordinate, if the world coordinate is pixel-wise)*/
|
|
val mouseY: Float
|
|
get() = WorldCamera.y + Gdx.input.y / (terrarumIngame.screenZoom)
|
|
/** currently pointing tile coordinate */
|
|
val mouseTileX: Int
|
|
get() = (mouseX / TILE_SIZE).floorInt()
|
|
/** currently pointing tile coordinate */
|
|
val mouseTileY: Int
|
|
get() = (mouseY / TILE_SIZE).floorInt()
|
|
|
|
init {
|
|
try {
|
|
if (Controllers.getControllers().size == 0) {
|
|
printdbg(this, "Controller not found")
|
|
}
|
|
}
|
|
catch (e: GdxRuntimeException) {
|
|
printdbgerr(this, "Error initialising controller: ${e.message}")
|
|
e.stackTrace.forEach { printdbgerr(this, "\t$it") }
|
|
}
|
|
}
|
|
|
|
private var worldPrimaryClickLatched = false
|
|
|
|
private val keyStatus = BitSet(256)
|
|
private var inputMouseX = -1
|
|
private var inputMouseY = -1
|
|
private val mouseStatus = BitSet(8)
|
|
private val controllerButtonStatus = BitSet(64)
|
|
|
|
private fun updateKeyboard() {
|
|
/////////////////////
|
|
// GAMEPAD CONTROL //
|
|
/////////////////////
|
|
|
|
|
|
//////////////////////
|
|
// KEYBOARD CONTROL //
|
|
//////////////////////
|
|
|
|
//KeyToggler.update(terrarumIngame.canPlayerControl)
|
|
//printdbg(this, terrarumIngame.canPlayerControl)
|
|
|
|
// control key events
|
|
var noKeyHeldDown = true
|
|
for (key in 1..Input.Keys.MAX_KEYCODE) {
|
|
val keyDown = Gdx.input.isKeyPressed(key)
|
|
|
|
noKeyHeldDown = noKeyHeldDown and keyDown
|
|
|
|
if (keyDown && !keyStatus[key])
|
|
tKeyDown(key)
|
|
else if (!keyDown && keyStatus[key])
|
|
tKeyUp(key)
|
|
|
|
keyStatus[key] = keyDown
|
|
}
|
|
// control mouse/touch events
|
|
val newmx = Gdx.input.x
|
|
val newmy = Gdx.input.y
|
|
for (touch in 0..4) {
|
|
val touchDown = Gdx.input.isButtonPressed(touch)
|
|
|
|
if (touchDown && !mouseStatus[touch])
|
|
tTouchDown(newmx, newmy, 0, touch)
|
|
else if (!touchDown && keyStatus[touch])
|
|
tTouchUp(newmx, newmy, 0, touch)
|
|
|
|
if (touchDown && mouseStatus.bitCount() != 0) {
|
|
tTouchDragged(newmx, newmy, 0)
|
|
}
|
|
|
|
mouseStatus[touch] = touchDown
|
|
}
|
|
|
|
inputMouseX = newmx
|
|
inputMouseY = newmy
|
|
}
|
|
|
|
fun update() {
|
|
|
|
///////////////////
|
|
// MOUSE CONTROL //
|
|
///////////////////
|
|
|
|
// Use item: assuming the player has only one effective grip (EquipPosition.HAND_GRIP)
|
|
// don't separate Player from this! Physics will break, esp. airborne manoeuvre
|
|
if (!terrarumIngame.paused) {
|
|
// fire world click events; the event is defined as Ingame's (or any others') WorldClick event
|
|
|
|
// DON'T DO UI-FILTERING HERE; they're already done on ingame.worldPrimaryClickStart
|
|
// also, some UIs should NOT affect item usage (e.g. quickslot) and ingame's uiOpened property is doing
|
|
// the very job.
|
|
|
|
if (Gdx.input.isButtonPressed(App.getConfigInt("config_mouseprimary")) && !worldPrimaryClickLatched) {
|
|
terrarumIngame.worldPrimaryClickStart(App.UPDATE_RATE)
|
|
worldPrimaryClickLatched = true
|
|
}
|
|
/*if Gdx.input.isButtonPressed(AppLoader.getConfigInt("config_mousesecondary")) {
|
|
ingame.worldSecondaryClickStart(AppLoader.UPDATE_RATE)
|
|
}*/
|
|
|
|
// unlatch when:
|
|
// - not clicking anymore
|
|
// - using any item that is not fixture (blocks, picks)
|
|
if (!Gdx.input.isButtonPressed(App.getConfigInt("config_mouseprimary")) ||
|
|
GameItem.Category.FIXTURE != ItemCodex.get(terrarumIngame.actorNowPlaying?.inventory?.itemEquipped?.get(GameItem.EquipPosition.HAND_GRIP))?.inventoryCategory) {
|
|
worldPrimaryClickLatched = false
|
|
}
|
|
|
|
}
|
|
|
|
|
|
updateKeyboard()
|
|
}
|
|
|
|
private var f12Down = false
|
|
|
|
private fun tKeyDown(keycode: Int): Boolean {
|
|
|
|
if (!terrarumIngame.paused) {
|
|
terrarumIngame.actorNowPlaying?.keyDown(keycode)
|
|
|
|
// quickslot by number keys
|
|
val quickslotKeys = App.getConfigIntArray("config_keyquickslots")
|
|
if (keycode in quickslotKeys) {
|
|
terrarumIngame.actorNowPlaying?.actorValue?.set(AVKey.__PLAYER_QUICKSLOTSEL, quickslotKeys.indexOf(keycode))
|
|
}
|
|
|
|
// pie menu
|
|
if (App.getConfigIntArray("config_keyquickselalt").contains(keycode)
|
|
|| keycode == App.getConfigInt("config_keyquicksel")) {
|
|
terrarumIngame.uiPieMenu.setAsOpen()
|
|
terrarumIngame.uiQuickBar.setAsClose()
|
|
}
|
|
}
|
|
|
|
terrarumIngame.uiContainer.forEach { it?.keyDown(keycode) } // for KeyboardControlled UIcanvases
|
|
|
|
// Debug UIs
|
|
if (keycode == Input.Keys.GRAVE) {
|
|
terrarumIngame.consoleHandler.toggleOpening()
|
|
}
|
|
|
|
|
|
// screenshot key
|
|
if (keycode == Input.Keys.F12 && !f12Down) {
|
|
App.requestScreenshot()
|
|
f12Down = true
|
|
println("Screenshot taken.")
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
private fun tKeyUp(keycode: Int): Boolean {
|
|
if (App.getConfigIntArray("config_keyquickselalt").contains(keycode)
|
|
|| keycode == App.getConfigInt("config_keyquicksel")) {
|
|
terrarumIngame.uiPieMenu.setAsClose()
|
|
terrarumIngame.uiQuickBar.setAsOpen()
|
|
}
|
|
|
|
terrarumIngame.uiContainer.forEach { it?.keyUp(keycode) } // for KeyboardControlled UIcanvases
|
|
|
|
// screenshot key
|
|
if (keycode == Input.Keys.F12) f12Down = false
|
|
|
|
|
|
return true
|
|
}
|
|
|
|
override fun keyTyped(character: Char): Boolean {
|
|
terrarumIngame.uiContainer.forEach { if (it?.isVisible == true) it.keyTyped(character) }
|
|
return true
|
|
}
|
|
|
|
private fun tTouchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
|
// don't separate Player from this! Physics will break, esp. airborne manoeuvre
|
|
if (!terrarumIngame.paused) {
|
|
// fire world click events; the event is defined as Ingame's (or any others') WorldClick event
|
|
if (terrarumIngame.uiContainer.map { if ((it?.isOpening == true || it?.isOpened == true) && it.mouseUp) 1 else 0 }.sum() == 0) { // no UI on the mouse, right?
|
|
|
|
if (
|
|
button == App.getConfigInt("config_mouseprimary") ||
|
|
button == App.getConfigInt("config_mousesecondary")) {
|
|
terrarumIngame.worldPrimaryClickEnd(App.UPDATE_RATE)
|
|
}
|
|
/*if (button == AppLoader.getConfigInt("config_mousesecondary")) {
|
|
ingame.worldSecondaryClickEnd(AppLoader.UPDATE_RATE)
|
|
}*/
|
|
}
|
|
}
|
|
|
|
// pie menu
|
|
if (button == App.getConfigInt("config_mousequicksel")) {
|
|
terrarumIngame.uiPieMenu.setAsClose()
|
|
terrarumIngame.uiQuickBar.setAsOpen()
|
|
}
|
|
|
|
terrarumIngame.uiContainer.forEach { it?.touchUp(screenX, screenY, pointer, button) } // for MouseControlled UIcanvases
|
|
return true
|
|
}
|
|
|
|
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
|
if (!terrarumIngame.paused) {
|
|
// quickslot by wheel
|
|
if (terrarumIngame.actorNowPlaying != null) {
|
|
terrarumIngame.actorNowPlaying!!.actorValue.set(
|
|
AVKey.__PLAYER_QUICKSLOTSEL,
|
|
(terrarumIngame.actorNowPlaying!!.actorValue.getAsInt(AVKey.__PLAYER_QUICKSLOTSEL)!! - amountY.toInt()) fmod terrarumIngame.actorNowPlaying!!.inventory.quickSlot.size
|
|
)
|
|
}
|
|
}
|
|
|
|
terrarumIngame.uiContainer.forEach { it?.scrolled(amountX, amountY) }
|
|
return true
|
|
}
|
|
|
|
private fun tTouchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
|
terrarumIngame.uiContainer.forEach { it?.touchDragged(screenX, screenY, pointer) }
|
|
return true
|
|
}
|
|
|
|
private fun tTouchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
|
terrarumIngame.uiContainer.forEach { it?.touchDown(screenX, screenY, pointer, button) }
|
|
|
|
// pie menu
|
|
if (button == App.getConfigInt("config_mousequicksel")) {
|
|
terrarumIngame.uiPieMenu.setAsOpen()
|
|
terrarumIngame.uiQuickBar.setAsClose()
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
companion object {
|
|
const val KEY_DELAY = 0.2f
|
|
const val KEY_REPEAT = 1f / 40f
|
|
val KEYCODE_TO_CHAR = hashMapOf<Int, Char>(
|
|
Keys.NUM_1 to '1',
|
|
Keys.NUM_2 to '2',
|
|
Keys.NUM_3 to '3',
|
|
Keys.NUM_4 to '4',
|
|
Keys.NUM_5 to '5',
|
|
Keys.NUM_6 to '6',
|
|
Keys.NUM_7 to '7',
|
|
Keys.NUM_8 to '8',
|
|
Keys.NUM_9 to '9',
|
|
Keys.NUM_0 to '0',
|
|
|
|
Keys.A to 'a',
|
|
Keys.B to 'b',
|
|
Keys.C to 'c',
|
|
Keys.D to 'd',
|
|
Keys.E to 'e',
|
|
Keys.F to 'f',
|
|
Keys.G to 'g',
|
|
Keys.H to 'h',
|
|
Keys.I to 'i',
|
|
Keys.J to 'j',
|
|
Keys.K to 'k',
|
|
Keys.L to 'l',
|
|
Keys.M to 'm',
|
|
Keys.N to 'n',
|
|
Keys.O to 'o',
|
|
Keys.P to 'p',
|
|
Keys.Q to 'q',
|
|
Keys.R to 'r',
|
|
Keys.S to 's',
|
|
Keys.T to 't',
|
|
Keys.U to 'u',
|
|
Keys.V to 'v',
|
|
Keys.W to 'w',
|
|
Keys.X to 'x',
|
|
Keys.Y to 'y',
|
|
Keys.Z to 'z',
|
|
|
|
Keys.GRAVE to '`',
|
|
Keys.MINUS to '-',
|
|
Keys.EQUALS to '=',
|
|
Keys.BACKSPACE to 8.toChar(),
|
|
|
|
Keys.LEFT_BRACKET to '[',
|
|
Keys.RIGHT_BRACKET to ']',
|
|
Keys.BACKSLASH to '\\',
|
|
|
|
Keys.SEMICOLON to ';',
|
|
Keys.APOSTROPHE to '\'',
|
|
Keys.ENTER to 10.toChar(),
|
|
|
|
Keys.COMMA to ',',
|
|
Keys.PERIOD to '.',
|
|
Keys.SLASH to '/',
|
|
|
|
Keys.SPACE to ' ',
|
|
|
|
Keys.NUMPAD_0 to '0',
|
|
Keys.NUMPAD_1 to '1',
|
|
Keys.NUMPAD_2 to '2',
|
|
Keys.NUMPAD_3 to '3',
|
|
Keys.NUMPAD_4 to '4',
|
|
Keys.NUMPAD_5 to '5',
|
|
Keys.NUMPAD_6 to '6',
|
|
Keys.NUMPAD_7 to '7',
|
|
Keys.NUMPAD_8 to '8',
|
|
Keys.NUMPAD_9 to '9',
|
|
|
|
Keys.NUMPAD_DIVIDE to '/',
|
|
Keys.NUMPAD_MULTIPLY to '*',
|
|
Keys.NUMPAD_SUBTRACT to '-',
|
|
Keys.NUMPAD_ADD to '+',
|
|
Keys.NUMPAD_DOT to '.',
|
|
Keys.NUMPAD_ENTER to 10.toChar()
|
|
)
|
|
val KEYCODE_TO_CHAR_SHIFT = hashMapOf<Int, Char>(
|
|
Keys.NUM_1 to '!',
|
|
Keys.NUM_2 to '@',
|
|
Keys.NUM_3 to '#',
|
|
Keys.NUM_4 to '$',
|
|
Keys.NUM_5 to '%',
|
|
Keys.NUM_6 to '^',
|
|
Keys.NUM_7 to '&',
|
|
Keys.NUM_8 to '*',
|
|
Keys.NUM_9 to '(',
|
|
Keys.NUM_0 to ')',
|
|
|
|
Keys.A to 'A',
|
|
Keys.B to 'B',
|
|
Keys.C to 'C',
|
|
Keys.D to 'D',
|
|
Keys.E to 'E',
|
|
Keys.F to 'F',
|
|
Keys.G to 'G',
|
|
Keys.H to 'H',
|
|
Keys.I to 'I',
|
|
Keys.J to 'J',
|
|
Keys.K to 'K',
|
|
Keys.L to 'L',
|
|
Keys.M to 'M',
|
|
Keys.N to 'N',
|
|
Keys.O to 'O',
|
|
Keys.P to 'P',
|
|
Keys.Q to 'Q',
|
|
Keys.R to 'R',
|
|
Keys.S to 'S',
|
|
Keys.T to 'T',
|
|
Keys.U to 'U',
|
|
Keys.V to 'V',
|
|
Keys.W to 'W',
|
|
Keys.X to 'X',
|
|
Keys.Y to 'Y',
|
|
Keys.Z to 'Z',
|
|
|
|
Keys.GRAVE to '~',
|
|
Keys.MINUS to '_',
|
|
Keys.EQUALS to '+',
|
|
Keys.BACKSPACE to 8.toChar(),
|
|
|
|
Keys.LEFT_BRACKET to '{',
|
|
Keys.RIGHT_BRACKET to '}',
|
|
Keys.BACKSLASH to '|',
|
|
|
|
Keys.SEMICOLON to ':',
|
|
Keys.APOSTROPHE to '"',
|
|
Keys.ENTER to 10.toChar(),
|
|
|
|
Keys.COMMA to '<',
|
|
Keys.PERIOD to '>',
|
|
Keys.SLASH to '?',
|
|
|
|
Keys.SPACE to ' ',
|
|
|
|
Keys.NUMPAD_0 to '0',
|
|
Keys.NUMPAD_1 to '1',
|
|
Keys.NUMPAD_2 to '2',
|
|
Keys.NUMPAD_3 to '3',
|
|
Keys.NUMPAD_4 to '4',
|
|
Keys.NUMPAD_5 to '5',
|
|
Keys.NUMPAD_6 to '6',
|
|
Keys.NUMPAD_7 to '7',
|
|
Keys.NUMPAD_8 to '8',
|
|
Keys.NUMPAD_9 to '9',
|
|
|
|
Keys.NUMPAD_DIVIDE to '/',
|
|
Keys.NUMPAD_MULTIPLY to '*',
|
|
Keys.NUMPAD_SUBTRACT to '-',
|
|
Keys.NUMPAD_ADD to '+',
|
|
Keys.NUMPAD_DOT to '.',
|
|
Keys.NUMPAD_ENTER to 10.toChar()
|
|
)
|
|
}
|
|
|
|
private inline fun BitSet.bitCount() = this.cardinality()
|
|
|
|
} |