mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-15 16:16:10 +09:00
670 lines
23 KiB
Kotlin
670 lines
23 KiB
Kotlin
package net.torvald.terrarum.modulebasegame
|
|
|
|
import com.badlogic.gdx.Gdx
|
|
import com.badlogic.gdx.Input
|
|
import com.badlogic.gdx.InputAdapter
|
|
import com.badlogic.gdx.graphics.Color
|
|
import com.badlogic.gdx.graphics.OrthographicCamera
|
|
import com.badlogic.gdx.graphics.Texture
|
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch
|
|
import com.badlogic.gdx.graphics.g2d.TextureRegion
|
|
import com.badlogic.gdx.graphics.glutils.Float16FrameBuffer
|
|
import com.jme3.math.FastMath
|
|
import net.torvald.random.HQRNG
|
|
import net.torvald.terrarum.*
|
|
import net.torvald.terrarum.App.printdbg
|
|
import net.torvald.terrarum.App.printdbgerr
|
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE
|
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
|
|
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZEF
|
|
import net.torvald.terrarum.clut.Skybox
|
|
import net.torvald.terrarum.console.CommandDict
|
|
import net.torvald.terrarum.gameactors.*
|
|
import net.torvald.terrarum.gameactors.ai.ActorAI
|
|
import net.torvald.terrarum.gamecontroller.KeyToggler
|
|
import net.torvald.terrarum.gamecontroller.TerrarumKeyboardEvent
|
|
import net.torvald.terrarum.gameparticles.ParticleBase
|
|
import net.torvald.terrarum.gameworld.GameWorld
|
|
import net.torvald.terrarum.gameworld.WorldTime
|
|
import net.torvald.terrarum.gameworld.fmod
|
|
import net.torvald.terrarum.langpack.Lang
|
|
import net.torvald.terrarum.modulebasegame.ui.UILoadGovernor
|
|
import net.torvald.terrarum.modulebasegame.ui.UIRemoCon
|
|
import net.torvald.terrarum.modulebasegame.ui.UITitleRemoConYaml
|
|
import net.torvald.terrarum.realestate.LandUtil
|
|
import net.torvald.terrarum.serialise.ReadSimpleWorld
|
|
import net.torvald.terrarum.ui.Toolkit
|
|
import net.torvald.terrarum.ui.UICanvas
|
|
import net.torvald.terrarum.weather.WeatherMixer
|
|
import net.torvald.terrarum.worlddrawer.WorldCamera
|
|
import net.torvald.util.CircularArray
|
|
import java.io.IOException
|
|
import kotlin.math.atan2
|
|
import kotlin.math.cos
|
|
import kotlin.math.sin
|
|
|
|
/**
|
|
* Created by minjaesong on 2017-09-02.
|
|
*/
|
|
class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
|
|
|
|
// todo register titlescreen as the ingame, similar in a way that the buildingmaker did
|
|
|
|
var camera = OrthographicCamera(App.scr.wf, App.scr.hf)
|
|
|
|
// invert Y
|
|
fun initViewPort(width: Int, height: Int) {
|
|
// Set Y to point downwards
|
|
camera.setToOrtho(true, width.toFloat(), height.toFloat())
|
|
|
|
// Update camera matrix
|
|
camera.update()
|
|
|
|
// Set viewport to restrict drawing
|
|
Gdx.gl20.glViewport(0, 0, width, height)
|
|
}
|
|
|
|
|
|
//private var loadDone = false // not required; draw-while-loading is implemented in the AppLoader
|
|
|
|
private lateinit var demoWorld: GameWorld
|
|
private lateinit var cameraNodes: FloatArray // camera Y-pos
|
|
private val cameraNodeWidth = 15
|
|
private val lookaheadDist = cameraNodeWidth * TILE_SIZED
|
|
private fun getPointAt(px: Double): Double {
|
|
val ww = TILE_SIZEF * demoWorld.width
|
|
val x = px % ww
|
|
|
|
val indexThis = ((x / ww * cameraNodes.size).floorToInt())
|
|
val xwstart: Double = indexThis.toDouble() / cameraNodes.size * ww
|
|
val xwend: Double = ((indexThis + 1).toDouble() / cameraNodes.size) * ww
|
|
val xw: Double = xwend - xwstart
|
|
val xperc: Double = (x - xwstart) / xw
|
|
|
|
// return FastMath.interpolateLinear(xperc.toFloat(), cameraNodes[indexThis fmod cameraNodes.size], cameraNodes[(indexThis + 1) fmod cameraNodes.size]).toDouble()
|
|
return FastMath.interpolateCatmullRom(xperc.toFloat(), 1.0f, // somehow T=1 works really well thanks to my other smoothing technique
|
|
cameraNodes[(indexThis - 1) fmod cameraNodes.size],
|
|
cameraNodes[(indexThis - 0) fmod cameraNodes.size],
|
|
cameraNodes[(indexThis + 1) fmod cameraNodes.size],
|
|
cameraNodes[(indexThis + 2) fmod cameraNodes.size]
|
|
).toDouble()
|
|
}
|
|
private val cameraAI = object : ActorAI {
|
|
private var firstTime = true
|
|
|
|
|
|
override fun update(actor: Actor, delta: Float) {
|
|
val ww = TILE_SIZEF * demoWorld.width
|
|
val actor = actor as CameraPlayer
|
|
|
|
val stride = cos(actor.bearing1A) * actor.actorValue.getAsDouble(AVKey.SPEED)!!
|
|
|
|
val x1 = actor.hitbox.startX// + stride
|
|
val y1 = actor.hitbox.startY
|
|
|
|
val px1L = x1 - lookaheadDist
|
|
val px1C = x1
|
|
val px1R = x1 + lookaheadDist
|
|
val py1L = getPointAt(px1L)
|
|
val py1C = getPointAt(px1C)
|
|
val py1R = getPointAt(px1R)
|
|
|
|
val px2L = (px1L + px1C) / 2.0
|
|
val px2R = (px1C + px1R) / 2.0
|
|
val py2L = (py1L + py1C) / 2.0
|
|
val py2R = (py1C + py1R) / 2.0
|
|
|
|
val x2 = (px2L + px2R) / 2
|
|
val y2 = (py2L + py2R) / 2
|
|
|
|
val theta = atan2(py2R - py2L, px2R - px2L)
|
|
|
|
if (firstTime) {
|
|
firstTime = false
|
|
actor.hitbox.setPosition(x1, getPointAt(x1))
|
|
}
|
|
else {
|
|
actor.bearing1A = atan2(py1C - py1L, px1C - px1L)
|
|
actor.bearing1B = atan2(py1R - py1C, px1R - px1C)
|
|
actor.bearing2A = atan2(py2R - py2L, px2R - px2L)
|
|
actor.moveTo(theta)
|
|
// actor.hitbox.setPosition(x2, y2) // there is no reason it would work -- speed is wildly inconsistent as the angle reaches 90deg
|
|
}
|
|
|
|
if (actor.hitbox.startX > ww) {
|
|
actor.hitbox.translatePosX(-ww.toDouble())
|
|
}
|
|
|
|
}
|
|
}
|
|
private lateinit var cameraPlayer: ActorWithBody
|
|
|
|
private val gradWhiteTop = Color(0xf8f8f8ff.toInt())
|
|
private val gradWhiteBottom = Color(0xd8d8d8ff.toInt())
|
|
|
|
|
|
internal lateinit var uiRemoCon: UIRemoCon
|
|
internal lateinit var uiFakeBlurOverlay: UICanvas
|
|
|
|
private lateinit var worldFBO: Float16FrameBuffer
|
|
|
|
private val warning32bitJavaIcon = TextureRegion(Texture(Gdx.files.internal("assets/graphics/gui/32_bit_warning.tga")))
|
|
private val warningAppleRosettaIcon = TextureRegion(Texture(Gdx.files.internal("assets/graphics/gui/apple_rosetta_warning.tga")))
|
|
|
|
init {
|
|
gameUpdateGovernor = ConsistentUpdateRate.also { it.reset() }
|
|
}
|
|
|
|
private fun loadThingsWhileIntroIsVisible() {
|
|
printdbg(this, "Intro pre-load")
|
|
|
|
|
|
try {
|
|
val file = ModMgr.getFile("basegame", "demoworld")
|
|
val reader = java.io.FileReader(file)
|
|
//ReadWorld.readWorldAndSetNewWorld(Terrarum.ingame!! as TerrarumIngame, reader)
|
|
val world = ReadSimpleWorld(reader, file)
|
|
demoWorld = world
|
|
demoWorld.worldTime.timeDelta = 30
|
|
printdbg(this, "Demo world loaded")
|
|
}
|
|
catch (e: IOException) {
|
|
demoWorld = GameWorld(LandUtil.CHUNK_W, LandUtil.CHUNK_H, 0L, 0L)
|
|
demoWorld.worldTime.timeDelta = 30
|
|
printdbg(this, "Demo world not found, using empty world")
|
|
}
|
|
|
|
demoWorld.renumberTilesAfterLoad()
|
|
this.world = demoWorld
|
|
|
|
// set initial time to summer
|
|
demoWorld.worldTime.addTime(WorldTime.DAY_LENGTH * 32)
|
|
|
|
// construct camera nodes
|
|
val nodeCount = demoWorld.width / cameraNodeWidth
|
|
cameraNodes = kotlin.FloatArray(nodeCount) {
|
|
val tileXPos = (demoWorld.width.toFloat() * it / nodeCount).floorToInt()
|
|
var travelDownCounter = 0
|
|
while (travelDownCounter < demoWorld.height &&
|
|
!BlockCodex[demoWorld.getTileFromTerrain(tileXPos, travelDownCounter)].isSolid
|
|
// !BlockCodex[demoWorld.getTileFromWall(tileXPos, travelDownCounter)].isSolid
|
|
) {
|
|
travelDownCounter += 2
|
|
}
|
|
travelDownCounter * TILE_SIZEF
|
|
}
|
|
// apply gaussian blur to the camera nodes
|
|
for (i in cameraNodes.indices) {
|
|
// val offM2 = cameraNodes[(i-2) fmod cameraNodes.size] * 1f
|
|
val offM1 = cameraNodes[(i-1) fmod cameraNodes.size] * 1f
|
|
val off0 = cameraNodes[i] * 2f
|
|
val off1 = cameraNodes[(i+1) fmod cameraNodes.size] * 1f
|
|
// val off2 = cameraNodes[(i+2) fmod cameraNodes.size] * 1f
|
|
|
|
// cameraNodes[i] = (offM2 + offM1 + off0 + off1 + off2) / 16f
|
|
cameraNodes[i] = (offM1 + off0 + off1) / 4f
|
|
}
|
|
|
|
|
|
|
|
cameraPlayer = CameraPlayer(demoWorld, cameraAI)
|
|
|
|
|
|
IngameRenderer.setRenderedWorld(demoWorld)
|
|
WeatherMixer.internalReset(this)
|
|
WeatherMixer.titleScreenInitWeather(demoWorld.weatherbox)
|
|
|
|
|
|
// load a half-gradient texture that would be used throughout the titlescreen and its sub UIs
|
|
CommonResourcePool.addToLoadingList("title_halfgrad") {
|
|
Texture(Gdx.files.internal("./assets/graphics/halfgrad.tga")).also {
|
|
it.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear)
|
|
}
|
|
}
|
|
CommonResourcePool.loadAll()
|
|
|
|
|
|
// fake UI for gradient overlay
|
|
val uiFakeGradOverlay = UIFakeGradOverlay()
|
|
uiFakeGradOverlay.setPosition(0, 0)
|
|
uiContainer.add(uiFakeGradOverlay)
|
|
|
|
|
|
// fake UI for blur
|
|
uiFakeBlurOverlay = UIFakeBlurOverlay(1f, false)
|
|
uiFakeBlurOverlay.setPosition(0,0)
|
|
uiContainer.add(uiFakeBlurOverlay)
|
|
|
|
|
|
uiRemoCon = UIRemoCon(this, UITitleRemoConYaml(App.savegamePlayers.isNotEmpty()))
|
|
uiRemoCon.setPosition(0, 0)
|
|
uiRemoCon.setAsOpen()
|
|
|
|
|
|
uiContainer.add(uiRemoCon)
|
|
|
|
CommandDict // invoke
|
|
Skybox.loadlut() // invoke
|
|
// Skybox.initiate() // invoke the lengthy calculation
|
|
// TODO add console here
|
|
|
|
|
|
//loadDone = true
|
|
|
|
// measure bogoflops here
|
|
val st = System.nanoTime()
|
|
var sc = st
|
|
var bogoflopf = Math.random()
|
|
var bogoflops = 0L
|
|
while (sc - st < 100000000L) {
|
|
bogoflopf *= Math.random()
|
|
bogoflops++
|
|
sc = System.nanoTime()
|
|
}
|
|
bogoflops = Math.round(bogoflops.toDouble() * (1000000000.0 / (sc - st)))
|
|
printdbg(this, "Bogoflops old: ${App.bogoflops} new: $bogoflops")
|
|
App.bogoflops = maxOf(App.bogoflops, bogoflops)
|
|
|
|
|
|
listOf(App.audioMixer.ambientTrack1, App.audioMixer.ambientTrack2).forEach {
|
|
it.stop()
|
|
it.currentTrack = null
|
|
it.nextTrack = null
|
|
}
|
|
App.audioMixer.reset()
|
|
|
|
}
|
|
|
|
|
|
override fun hide() {
|
|
}
|
|
|
|
override fun show() {
|
|
printdbg(this, "show() called")
|
|
|
|
for (k in Input.Keys.F1..Input.Keys.F12) {
|
|
KeyToggler.forceSet(k, false)
|
|
}
|
|
|
|
initViewPort(App.scr.width, App.scr.height)
|
|
|
|
|
|
Gdx.input.inputProcessor = TitleScreenController(this)
|
|
|
|
|
|
worldFBO = Float16FrameBuffer(App.scr.width, App.scr.height, false)
|
|
|
|
// load list of savegames
|
|
printdbg(this, "update list of savegames")
|
|
// to show "Continue" and "Load" on the titlescreen, uncomment this line
|
|
App.updateListOfSavegames()
|
|
UILoadGovernor.reset()
|
|
|
|
loadThingsWhileIntroIsVisible()
|
|
printdbg(this, "show() exit")
|
|
}
|
|
|
|
|
|
private val introUncoverTime: Second = 0.3f
|
|
private var introUncoverDeltaCounter = 0f
|
|
|
|
override fun render(updateRate: Float) {
|
|
super.render(updateRate)
|
|
// async update and render
|
|
gameUpdateGovernor.update(Gdx.graphics.deltaTime, App.UPDATE_RATE, updateScreen, renderScreen)
|
|
}
|
|
|
|
private val updateScreen = { delta: Float ->
|
|
|
|
demoWorld.globalLight = WeatherMixer.globalLightNow
|
|
demoWorld.updateWorldTime(delta)
|
|
WeatherMixer.update(delta, cameraPlayer, demoWorld)
|
|
cameraPlayer.update(delta)
|
|
|
|
// worldcamera update AFTER cameraplayer in this case; the other way is just an exception for actual ingame SFX
|
|
WorldCamera.update(demoWorld, cameraPlayer)
|
|
|
|
// update UIs //
|
|
uiContainer.forEach { it?.update(delta) }
|
|
}
|
|
|
|
private val particles = CircularArray<ParticleBase>(16, true)
|
|
|
|
private fun drawLineOnWorld(x1: Float, y1: Float, x2: Float, y2: Float) {
|
|
val w = 2.0f
|
|
App.shapeRender.rectLine(
|
|
x1 - WorldCamera.x, App.scr.height - (y1 - WorldCamera.y),
|
|
x2 - WorldCamera.x, App.scr.height - (y2 - WorldCamera.y),
|
|
w
|
|
)
|
|
}
|
|
private fun drawLineOnWorld(x1: Double, y1: Double, x2: Double, y2: Double) {
|
|
val ww = demoWorld.width * TILE_SIZE
|
|
drawLineOnWorld(x1.toFloat(), y1.toFloat(), x2.toFloat(), y2.toFloat())
|
|
drawLineOnWorld(x1.toFloat() + ww, y1.toFloat(), x2.toFloat() + ww, y2.toFloat())
|
|
}
|
|
|
|
private val baseSlopeCol = Color(0f, 0.9f, 0.85f, 1f)
|
|
private val firstOrderSlopeCol = Color(0f, 0.4f, 0f, 1f)
|
|
private val secondOrderSlopeCol = Color(1f, 0.3f, 0.6f, 1f)
|
|
|
|
private val renderScreen = { delta: Float ->
|
|
Gdx.graphics.setTitle(TerrarumIngame.getCanonicalTitle())
|
|
|
|
|
|
//camera.setToOrtho(true, AppLoader.terrarumAppConfig.screenWf, AppLoader.terrarumAppConfig.screenHf)
|
|
|
|
// render world
|
|
gdxClearAndEnableBlend(.64f, .754f, .84f, 1f)
|
|
|
|
|
|
if (!demoWorld.layerTerrain.ptr.destroyed) { // FIXME q&d hack to circumvent the dangling pointer issue #26
|
|
IngameRenderer.invoke(
|
|
delta,
|
|
false,
|
|
1f,
|
|
listOf(),
|
|
listOf(),
|
|
listOf(),
|
|
listOf(),
|
|
listOf(),
|
|
particles,
|
|
uiContainer = uiContainer
|
|
)
|
|
|
|
if (KeyToggler.isOn(Input.Keys.F10)) {
|
|
App.shapeRender.inUse {
|
|
|
|
val actor = cameraPlayer as CameraPlayer
|
|
|
|
val x1 = actor.hitbox.startX
|
|
val y1 = actor.hitbox.startY
|
|
|
|
val px1L = x1 - lookaheadDist// * cos(actor.bearing1A)
|
|
val px1C = x1
|
|
val px1R = x1 + lookaheadDist// * cos(actor.bearing1B)
|
|
val py1L = getPointAt(px1L)
|
|
val py1C = getPointAt(px1C)
|
|
val py1R = getPointAt(px1R)
|
|
|
|
val px2L = (px1L + px1C) / 2.0
|
|
val px2R = (px1C + px1R) / 2.0
|
|
val py2L = (py1L + py1C) / 2.0
|
|
val py2R = (py1C + py1R) / 2.0
|
|
|
|
it.color = firstOrderSlopeCol
|
|
drawLineOnWorld(px1L, py1L, px1C, py1C)
|
|
drawLineOnWorld(px1C, py1C, px1R, py1R)
|
|
|
|
/*(1..cameraNodes.lastIndex + 16).forEach { index0 ->
|
|
val x1 = (index0 - 1) * cameraNodeWidth * TILE_SIZEF; val x2 = (index0 - 0) * cameraNodeWidth * TILE_SIZEF
|
|
val y1 = cameraNodes[(index0 - 1) fmod cameraNodes.size]; val y2 = cameraNodes[index0 fmod cameraNodes.size]
|
|
drawLineOnWorld(x1, y1, x2, y2)
|
|
}*/
|
|
it.color = baseSlopeCol
|
|
val points = (0..App.scr.width).map { x ->
|
|
val worldX = (WorldCamera.x + x).toDouble()
|
|
worldX to getPointAt(worldX)
|
|
}
|
|
points.forEachIndexed { index, (x, y) ->
|
|
if (index > 0) {
|
|
drawLineOnWorld(points[index - 1].first, points[index - 1].second, x, y)
|
|
}
|
|
}
|
|
|
|
it.color = secondOrderSlopeCol
|
|
drawLineOnWorld(px2L, py2L, px2R, py2R)
|
|
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
printdbgerr(this, "Demoworld is already been destroyed")
|
|
}
|
|
|
|
|
|
batch.inUse {
|
|
setCameraPosition(0f, 0f)
|
|
batch.shader = null
|
|
batch.color = Color.WHITE
|
|
renderOverlayTexts()
|
|
}
|
|
}
|
|
|
|
private fun renderOverlayTexts() {
|
|
setCameraPosition(0f, 0f)
|
|
blendNormalStraightAlpha(batch)
|
|
batch.shader = null
|
|
|
|
batch.color = Color.LIGHT_GRAY
|
|
|
|
val COPYTING = arrayOf(
|
|
TerrarumAppConfiguration.COPYRIGHT_DATE_NAME,
|
|
TerrarumAppConfiguration.COPYRIGHT_LICENSE
|
|
)
|
|
val drawWidth = Toolkit.drawWidth
|
|
|
|
COPYTING.forEachIndexed { index, s ->
|
|
val textWidth = App.fontGame.getWidth(s)
|
|
App.fontGame.draw(batch, s,
|
|
(drawWidth - textWidth - 1f).toInt().toFloat(),
|
|
(App.scr.height - App.fontGame.lineHeight * (COPYTING.size - index) - 1f).toInt().toFloat()
|
|
)
|
|
}
|
|
|
|
batch.color = if (App.IS_DEVELOPMENT_BUILD) Toolkit.Theme.COL_MOUSE_UP else Color.LIGHT_GRAY
|
|
App.fontGame.draw(batch, TerrarumPostProcessor.thisIsDebugStr, 5f, App.scr.height - 24f)
|
|
|
|
|
|
|
|
batch.color = Color.WHITE
|
|
|
|
val linegap = 4
|
|
val imgTxtGap = 10
|
|
val yoff = App.scr.height - App.scr.tvSafeGraphicsHeight - 64 - (3*(20+linegap)) - imgTxtGap - 9
|
|
if (uiRemoCon.currentRemoConContents.parent == null) {
|
|
// warn: 32-bit
|
|
var texts = emptyList<String>()
|
|
var textcols = emptyList<Color>()
|
|
if (App.is32BitJVM) {
|
|
Toolkit.drawCentered(batch, warning32bitJavaIcon, yoff)
|
|
texts = (1..3).map { Lang.get("GAME_32BIT_WARNING$it", (it != 3)) }
|
|
textcols = (1..3).map { if (it == 3) Toolkit.Theme.COL_SELECTED else Color.WHITE }
|
|
}
|
|
// warn: rosetta on Apple M-chips
|
|
else if (App.getUndesirableConditions() == "apple_execution_through_rosetta") {
|
|
Toolkit.drawCentered(batch, warningAppleRosettaIcon, yoff)
|
|
texts = (1..2).map { Lang.get("GAME_APPLE_ROSETTA_WARNING$it") }
|
|
textcols = texts.map { Color.WHITE }
|
|
}
|
|
|
|
|
|
texts.forEachIndexed { i, text ->
|
|
batch.color = textcols[i]
|
|
App.fontGame.draw(
|
|
batch,
|
|
text,
|
|
((drawWidth - App.fontGame.getWidth(text)) / 2).toFloat(),
|
|
yoff + imgTxtGap + 64f + linegap + i * (20 + linegap)
|
|
)
|
|
}
|
|
|
|
|
|
// update available!
|
|
if (App.hasUpdate) {
|
|
batch.color = Toolkit.Theme.COL_SELECTED
|
|
App.fontGame.draw(
|
|
batch,
|
|
Lang["MENU_UPDATE_UPDATE_AVAILABLE"],
|
|
UIRemoCon.menubarOffX + UIRemoCon.UIRemoConElement.paddingLeft / 2 + uiRemoCon.posX,
|
|
UIRemoCon.menubarOffY - uiRemoCon.height + uiRemoCon.posY
|
|
)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
override fun pause() {
|
|
}
|
|
|
|
override fun resume() {
|
|
}
|
|
|
|
override fun resize(width: Int, height: Int) {
|
|
printdbg(this, "resize() called")
|
|
printdbg(this, "called by:")
|
|
printStackTrace(this)
|
|
|
|
// Set up viewport when window is resized
|
|
initViewPort(App.scr.width, App.scr.height)
|
|
|
|
|
|
// resize UI by re-creating it (!!)
|
|
uiRemoCon.resize(App.scr.width, App.scr.height)
|
|
// TODO I forgot what the fuck kind of hack I was talking about
|
|
//uiMenu.setPosition(0, UITitleRemoConRoot.menubarOffY)
|
|
uiRemoCon.setPosition(0, 0) // shitty hack. Could be:
|
|
// 1: Init code and resize code are different
|
|
// 2: The UI is coded shit
|
|
|
|
|
|
IngameRenderer.resize(App.scr.width, App.scr.height)
|
|
|
|
printdbg(this, "resize() exit")
|
|
}
|
|
|
|
override fun dispose() {
|
|
uiRemoCon.dispose()
|
|
demoWorld.dispose()
|
|
warning32bitJavaIcon.texture.dispose()
|
|
warningAppleRosettaIcon.texture.dispose()
|
|
}
|
|
|
|
override fun inputStrobed(e: TerrarumKeyboardEvent) {
|
|
uiContainer.forEach { it?.inputStrobed(e) }
|
|
}
|
|
|
|
|
|
|
|
fun setCameraPosition(newX: Float, newY: Float) {
|
|
TerrarumIngame.setCameraPosition(batch, App.shapeRender, camera, newX, newY)
|
|
}
|
|
|
|
|
|
|
|
class TitleScreenController(val screen: TitleScreen) : InputAdapter() {
|
|
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
|
screen.uiContainer.forEach { it?.touchUp(screenX, screenY, pointer, button) }
|
|
return true
|
|
}
|
|
|
|
override fun keyTyped(character: Char): Boolean {
|
|
screen.uiContainer.forEach { it?.keyTyped(character) }
|
|
return true
|
|
}
|
|
|
|
override fun scrolled(amountX: Float, amountY: Float): Boolean {
|
|
screen.uiContainer.forEach { it?.scrolled(amountX, amountY) }
|
|
return true
|
|
}
|
|
|
|
override fun keyUp(keycode: Int): Boolean {
|
|
screen.uiContainer.forEach { it?.keyUp(keycode) }
|
|
return true
|
|
}
|
|
|
|
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
|
|
screen.uiContainer.forEach { it?.touchDragged(screenX, screenY, pointer) }
|
|
return true
|
|
}
|
|
|
|
override fun keyDown(keycode: Int): Boolean {
|
|
screen.uiContainer.forEach { it?.keyDown(keycode) }
|
|
return true
|
|
}
|
|
|
|
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
|
|
screen.uiContainer.forEach { it?.touchDown(screenX, screenY, pointer, button) }
|
|
return true
|
|
}
|
|
}
|
|
|
|
private class CameraPlayer(val demoWorld: GameWorld, override var ai: ActorAI) : ActorWithBody(RenderOrder.FRONT, physProp = PhysProperties.MOBILE_OBJECT), AIControlled {
|
|
|
|
override val hitbox = Hitbox(0.0, 0.0, 2.0, 2.0)
|
|
|
|
init {
|
|
actorValue[AVKey.SPEED] = 1.666 * (if (Math.random() < 1.0 / 65536.0) -1 else 1) // some easter egg
|
|
hitbox.setPosition(
|
|
HQRNG().nextInt(demoWorld.width) * TILE_SIZED,
|
|
0.0 // Y pos: placeholder; camera AI will take it over
|
|
)
|
|
}
|
|
|
|
override fun drawBody(frameDelta: Float, batch: SpriteBatch) { }
|
|
override fun drawGlow(frameDelta: Float, batch: SpriteBatch) { }
|
|
|
|
override fun update(delta: Float) {
|
|
ai.update(this, delta)
|
|
}
|
|
|
|
override fun onActorValueChange(key: String, value: Any?) { }
|
|
override fun dispose() { }
|
|
|
|
override fun run() { TODO("not implemented") }
|
|
|
|
override fun moveLeft(amount: Float) {
|
|
TODO("not implemented")
|
|
}
|
|
|
|
override fun moveRight(amount: Float) {
|
|
TODO("not implemented")
|
|
}
|
|
|
|
override fun moveUp(amount: Float) {
|
|
TODO("not implemented")
|
|
}
|
|
|
|
override fun moveDown(amount: Float) {
|
|
TODO("not implemented")
|
|
}
|
|
|
|
override fun moveJump(amount: Float) {
|
|
TODO("not implemented")
|
|
}
|
|
|
|
var targetBearing = 0.0
|
|
var currentBearing = 0.0
|
|
|
|
var bearing1A = 0.0
|
|
var bearing1B = 0.0
|
|
var bearing1C = 0.0
|
|
var bearing2A = 0.0
|
|
var bearing2B = 0.0
|
|
var bearing3A = 0.0
|
|
|
|
override fun moveTo(bearing: Double) {
|
|
targetBearing = bearing
|
|
if (currentBearing.isNaN()) currentBearing = bearing
|
|
val v = actorValue.getAsDouble(AVKey.SPEED)!!
|
|
|
|
//currentBearing = interpolateLinear(1.0 / 22.0, currentBearing, targetBearing)
|
|
currentBearing = targetBearing
|
|
hitbox.translate(v * cos(currentBearing), v * sin(currentBearing))
|
|
}
|
|
|
|
override fun moveTo(toX: Double, toY: Double) {
|
|
val ww = TILE_SIZED * demoWorld.width
|
|
// select appropriate toX because ROUNDWORLD
|
|
val xdiff1 = toX - hitbox.canonicalX
|
|
val xdiff2 = (toX + ww) - hitbox.canonicalX
|
|
|
|
val xdiff = if (xdiff1 < 0) xdiff2 else xdiff1
|
|
val ydiff = toY - hitbox.canonicalY
|
|
|
|
moveTo(atan2(ydiff, xdiff))
|
|
hitbox.setPositionX(hitbox.canonicalX % ww)
|
|
}
|
|
}
|
|
|
|
} |