titlescreen: camera follows terraini undulation

This commit is contained in:
minjaesong
2017-07-22 18:27:58 +09:00
parent 116b4cc390
commit d753365e54
9 changed files with 305 additions and 144 deletions

View File

@@ -17,6 +17,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
----
*Terrarum Sans Bitmap*
Copyright (c) 2017 Minjae Song (Torvald) and the contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
----
*Simplex Noise Generator*, version 2012-03-09 by Stefan Gustavson
Released as public domain
@@ -64,7 +88,7 @@ Copyright (C) 2011 Joshua Tippetts
----
*Vector2*
*Vector2.java*, *Epsilon.java*
Copyright (c) 2010-2015 William Bittle http://www.dyn4j.org/
All rights reserved.

View File

@@ -1,3 +1,4 @@
{
"MENU_MODULES" : "Modules"
"MENU_MODULES" : "Modules",
"MENU_CREDIT_GPL_DNT" : "GPL"
}

View File

@@ -17,6 +17,7 @@ Copyright Informations
Terrarum
Copyright (C) 2013-2017 Torvald (minjaesong)
@@ -38,6 +39,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
Terrarum Sans Bitmap
Copyright (c) 2017 Minjae Song (Torvald) and the contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*Simplex Noise Generator*, version 2012-03-09 by Stefan Gustavson
Released as public domain
@@ -48,7 +75,7 @@ Released as public domain
Joise
opyright (C) 2013 Jason Taylor
Copyright (C) 2013 Jason Taylor
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -89,7 +116,7 @@ Copyright (C) 2011 Joshua Tippetts
Vector2
Vector2.java, Epsilon.java
Copyright (c) 2010-2015 William Bittle http://www.dyn4j.org/
All rights reserved.
@@ -113,6 +140,7 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVI
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Kotlin translated and modified code Copyright (C) 2016 Minjaesong (Torvald)

View File

@@ -1,22 +1,23 @@
package net.torvald.terrarum
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.InputAdapter
import com.badlogic.gdx.Screen
import com.badlogic.gdx.graphics.*
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.graphics.glutils.FrameBuffer
import com.jme3.math.FastMath
import net.torvald.random.HQRNG
import net.torvald.terrarum.blockproperties.BlockCodex
import net.torvald.terrarum.gameactors.*
import net.torvald.terrarum.gameactors.ai.ActorAI
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.gameworld.fmod
import net.torvald.terrarum.langpack.Lang
import net.torvald.terrarum.serialise.ReadLayerData
import net.torvald.terrarum.ui.UICanvas
import net.torvald.terrarum.ui.UIHandler
import net.torvald.terrarum.ui.UIStartMenu
import net.torvald.terrarum.ui.UITitleRemoConRoot
import net.torvald.terrarum.weather.WeatherMixer
import net.torvald.terrarum.worlddrawer.BlocksDrawer
import net.torvald.terrarum.worlddrawer.FeaturesDrawer
@@ -47,11 +48,44 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
private var loadDone = false
private lateinit var demoWorld: GameWorld
private lateinit var cameraNodes: FloatArray // camera Y-pos
private val cameraAI = object : ActorAI {
private val axisMax = 1f
override fun update(actor: HumanoidNPC, delta: Float) {
// fuck
val avSpeed = 0.66 // FIXME camera goes faster when FPS is high
actor.actorValue[AVKey.SPEED] = avSpeed
actor.actorValue[AVKey.ACCEL] = avSpeed / 5.0
val tileSize = FeaturesDrawer.TILE_SIZE.toFloat()
val catmullRomTension = 1f
// pan camera
//actor.moveRight() // why no work?
actor.controllerMoveDelta!!.x = 0.5
actor.moveRight(axisMax)
val domainSize = demoWorld.width * tileSize
val codomainSize = cameraNodes.size
val x = actor.hitbox.canonicalX.toFloat()
val p1 = (x / (domainSize / codomainSize)).floorInt()
val p0 = (p1 - 1) fmod codomainSize
val p2 = (p1 + 1) fmod codomainSize
val p3 = (p1 + 2) fmod codomainSize
val u: Float = 1f - (p2 - (x / (domainSize / codomainSize))) / (p2 - p1)
val targetYPos = FastMath.interpolateCatmullRom(u, catmullRomTension, cameraNodes[p0], cameraNodes[p1], cameraNodes[p2], cameraNodes[p3])
val yDiff = targetYPos - actor.hitbox.canonicalY
actor.moveDown(yDiff.bipolarClamp(axisMax.toDouble()).toFloat())
println("${actor.hitbox.canonicalX}, ${actor.hitbox.canonicalY}")
//actor.hitbox.setPosition(actor.hitbox.canonicalX, yPos.toDouble())
}
}
private lateinit var cameraPlayer: HumanoidNPC
@@ -72,15 +106,26 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
demoWorld = ReadLayerData(FileInputStream(ModMgr.getFile("basegame", "demoworld")))
// construct camera nodes
val nodeCount = 150
cameraNodes = kotlin.FloatArray(nodeCount, { it ->
val tileXPos = (demoWorld.width.toFloat() * it / nodeCount).floorInt()
var travelDownCounter = 0
while (!BlockCodex[demoWorld.getTileFromTerrain(tileXPos, travelDownCounter)].isSolid) {
travelDownCounter += 4
}
travelDownCounter * FeaturesDrawer.TILE_SIZE.toFloat()
})
cameraPlayer = object : HumanoidNPC(demoWorld, cameraAI, GameDate(1, 1), usePhysics = false) {
init {
setHitboxDimension(2, 2, 0, 0)
hitbox.setPosition(
demoWorld.spawnX * FeaturesDrawer.TILE_SIZE.toDouble(),
HQRNG().nextInt(demoWorld.width) * FeaturesDrawer.TILE_SIZE.toDouble(),
(demoWorld.height / 3) * 0.75 * FeaturesDrawer.TILE_SIZE.toDouble()//demoWorld.spawnY * FeaturesDrawer.TILE_SIZE.toDouble()
)
actorValue[AVKey.SPEED] = 1.0
actorValue[AVKey.ACCEL] = 1.0
noClip = true
}
}
@@ -92,8 +137,8 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
FeaturesDrawer.world = demoWorld
uiMenu = UIHandler(UIStartMenu())
uiMenu.setPosition(0, UIStartMenu.menubarOffY)
uiMenu = UIHandler(UITitleRemoConRoot())
uiMenu.setPosition(0, UITitleRemoConRoot.menubarOffY)
uiMenu.setAsOpen()
@@ -271,7 +316,7 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
COPYTING.forEachIndexed { index, s ->
val textWidth = Terrarum.fontGame.getWidth(s)
Terrarum.fontGame.draw(batch, s,
Terrarum.WIDTH - textWidth - 1f - 0.667f,
Terrarum.WIDTH - textWidth - 1f - 0.2f,
Terrarum.HEIGHT - Terrarum.fontGame.lineHeight * (COPYTING.size - index) - 1f
)
}
@@ -291,7 +336,7 @@ class TitleScreen(val batch: SpriteBatch) : Screen {
if (loadDone) {
// resize UI by re-creating it (!!)
uiMenu.UI.resize(Terrarum.WIDTH, Terrarum.HEIGHT)
uiMenu.setPosition(0, UIStartMenu.menubarOffY)
uiMenu.setPosition(0, UITitleRemoConRoot.menubarOffY)
}
lightmapFboA.dispose()

View File

@@ -227,6 +227,12 @@ open class ActorHumanoid(
Terrarum.controller!!.isButtonPressed(GAMEPAD_JUMP)
}
}
else {
isUpDown = axisY < 0f
isDownDown = axisY > 0f
isLeftDown = axisX < 0f
isRightDown = axisX > 0f
}
}
private inline val hasController: Boolean
@@ -376,6 +382,13 @@ open class ActorHumanoid(
* @author minjaesong
*/
private fun walkHorizontal(left: Boolean, absAxisVal: Float) {
if (avAcceleration.isNaN()) {
throw Error("avAccelation is NaN")
}
if (left && walledLeft || !left && walledRight) return
@@ -383,20 +396,21 @@ open class ActorHumanoid(
if (absAxisVal == AXIS_KEYBOARD)
avAcceleration * applyVelo(walkCounterX) * (if (left) -1f else 1f)
else
avAcceleration * (if (left) -1f else 1f) * absAxisVal
avAcceleration * applyVelo(walkCounterX) * (if (left) -1f else 1f) * absAxisVal
if (absAxisVal != AXIS_KEYBOARD)
controllerMoveDelta?.x?.let { controllerMoveDelta!!.x = controllerMoveDelta!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap * absAxisVal) }
else
controllerMoveDelta?.x?.let { controllerMoveDelta!!.x = controllerMoveDelta!!.x.plus(readonly_totalX).bipolarClamp(avSpeedCap) }
if (absAxisVal == AXIS_KEYBOARD) {
walkCounterX += 1
if (walkCounterX < 1000000) {
walkCounterX += 1
}
isWalkingH = true
// Heading flag
walkHeading = if (left) LEFT else RIGHT
}
@@ -411,18 +425,23 @@ open class ActorHumanoid(
if (up && walledTop || !up && walledBottom) return
if (avAcceleration.isNaN()) {
throw Error("avAccelation is NaN")
}
readonly_totalY =
if (absAxisVal == AXIS_KEYBOARD)
avAcceleration * applyVelo(walkCounterY) * (if (up) -1f else 1f)
else
avAcceleration * (if (up) -1f else 1f) * absAxisVal
avAcceleration * applyVelo(walkCounterY) * (if (up) -1f else 1f) * absAxisVal
if (absAxisVal != AXIS_KEYBOARD)
controllerMoveDelta?.y?.let { controllerMoveDelta!!.y = controllerMoveDelta!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap * absAxisVal) }
else
controllerMoveDelta?.y?.let { controllerMoveDelta!!.y = controllerMoveDelta!!.y.plus(readonly_totalY).bipolarClamp(avSpeedCap) }
if (absAxisVal == AXIS_KEYBOARD) {
if (walkCounterY < 1000000) {
walkCounterY += 1
}

View File

@@ -155,7 +155,7 @@ open class ActorWithPhysics(val world: GameWorld, renderOrder: RenderOrder, val
*/
private inline val grounded: Boolean
get() = isPlayerNoClip ||
get() = isNoClip ||
(world.gravitation.y > 0 && isWalled(hitbox, COLLIDING_BOTTOM) ||
world.gravitation.y < 0 && isWalled(hitbox, COLLIDING_TOP))
/** Default to 'true' */
@@ -328,9 +328,9 @@ open class ActorWithPhysics(val world: GameWorld, renderOrder: RenderOrder, val
// make NoClip work for player
if (this is Player) {
isNoSubjectToGrav = isPlayerNoClip || COLLISION_TEST_MODE
isNoCollideWorld = isPlayerNoClip
isNoSubjectToFluidResistance = isPlayerNoClip
isNoSubjectToGrav = isNoClip || COLLISION_TEST_MODE
isNoCollideWorld = isNoClip
isNoSubjectToFluidResistance = isNoClip
}
if (!usePhysics) {
@@ -416,7 +416,7 @@ open class ActorWithPhysics(val world: GameWorld, renderOrder: RenderOrder, val
// FIXME asymmetry on friction
setHorizontalFriction() // friction SHOULD use and alter externalForce
//if (isPlayerNoClip) { // TODO also hanging on the rope, etc.
//if (isNoClip) { // TODO also hanging on the rope, etc.
setVerticalFriction()
//}
@@ -940,7 +940,7 @@ open class ActorWithPhysics(val world: GameWorld, renderOrder: RenderOrder, val
/** about stopping
* for about get moving, see updateMovementControl */
private fun setHorizontalFriction() {
val friction = if (isPlayerNoClip)
val friction = if (isNoClip)
BASE_FRICTION * BlockCodex[Block.STONE].friction.frictionToMult()
else {
// TODO status quo if !submerged else linearBlend(feetFriction, bodyFriction, submergedRatio)
@@ -969,7 +969,7 @@ open class ActorWithPhysics(val world: GameWorld, renderOrder: RenderOrder, val
}
private fun setVerticalFriction() {
val friction = if (isPlayerNoClip)
val friction = if (isNoClip)
BASE_FRICTION * BlockCodex[Block.STONE].friction.frictionToMult()
else
BASE_FRICTION * bodyFriction
@@ -1003,7 +1003,7 @@ open class ActorWithPhysics(val world: GameWorld, renderOrder: RenderOrder, val
val fluidDensity = tileDensity
val submergedVolume = submergedVolume
if (!isPlayerNoClip && !grounded) {
if (!isNoClip && !grounded) {
// System.out.println("density: "+density);
veloY -= ((fluidDensity - this.density).toDouble()
* map.gravitation.toDouble() * submergedVolume.toDouble()
@@ -1089,7 +1089,7 @@ open class ActorWithPhysics(val world: GameWorld, renderOrder: RenderOrder, val
* for about stopping, see setHorizontalFriction */
internal inline val accelMultMovement: Double
get() {
if (!isPlayerNoClip) {
if (!isNoSubjectToFluidResistance && !isNoSubjectToGrav && !isNoCollideWorld) {
val notSubmergedAccel = if (grounded)
feetFriction
else
@@ -1259,8 +1259,8 @@ open class ActorWithPhysics(val world: GameWorld, renderOrder: RenderOrder, val
if (x < 0) 0 else if (x >= world.height) world.height - 1 else x
private val isPlayerNoClip: Boolean
get() = this is Player && this.isNoClip()
private val isNoClip: Boolean
get() = this is ActorHumanoid && this.isNoClip()
private val AUTO_CLIMB_RATE: Int
get() = Math.min(TILE_SIZE / 8 * Math.sqrt(scale), TILE_SIZE.toDouble()).toInt()
@@ -1272,7 +1272,7 @@ open class ActorWithPhysics(val world: GameWorld, renderOrder: RenderOrder, val
// warnings
if (sprite == null && isVisible)
println("[ActorWithPhysics] Caution: actor ${this.javaClass.simpleName} is echo but the sprite was not set.")
println("[ActorWithPhysics] Caution: actor ${this.javaClass.simpleName} is visible but the sprite was not set.")
else if (sprite != null && !isVisible)
println("[ActorWithPhysics] Caution: actor ${this.javaClass.simpleName} is invisible but the sprite was given.")

View File

@@ -1,110 +0,0 @@
package net.torvald.terrarum.ui
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.Terrarum
class UIStartMenu : UICanvas() {
companion object {
/** Contains STRING_IDs */
val menuLabels = arrayOf(
"MENU_MODE_SINGLEPLAYER",
"MENU_OPTIONS",
"MENU_MODULES",
"MENU_LABEL_LANGUAGE",
"MENU_LABEL_CREDITS",
"MENU_LABEL_QUIT"
)
val menubarOffY: Int; get() = Terrarum.HEIGHT / 2 - (Terrarum.fontGame.lineHeight * 1.5).toInt()
}
override var width: Int = 240
override var height: Int = 36 * menuLabels.size.plus(1)
override var openCloseTime = 0f
private val menubar = UIItemTextButtonList(
this,
menuLabels,
240, this.height,
textAreaWidth = 240,
readFromLang = true,
activeBackCol = Color(0),
highlightBackCol = Color(0),
backgroundCol = Color(0),
inactiveCol = Color.WHITE,
defaultSelection = null
)
init {
uiItems.add(menubar)
// attach listeners
menubar.buttons[menuLabels.indexOf("MENU_LABEL_QUIT")].clickOnceListener = { _, _, _ -> System.exit(0) }
}
override fun update(delta: Float) {
menubar.update(delta)
}
override fun render(batch: SpriteBatch) {
menubar.render(batch)
}
override fun doOpening(delta: Float) {
}
override fun doClosing(delta: Float) {
}
override fun endOpening(delta: Float) {
}
override fun endClosing(delta: Float) {
}
override fun dispose() {
}
override fun mouseMoved(screenX: Int, screenY: Int): Boolean {
return super.mouseMoved(screenX, screenY)
}
override fun touchDragged(screenX: Int, screenY: Int, pointer: Int): Boolean {
return super.touchDragged(screenX, screenY, pointer)
}
override fun touchDown(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
return super.touchDown(screenX, screenY, pointer, button)
}
override fun touchUp(screenX: Int, screenY: Int, pointer: Int, button: Int): Boolean {
return super.touchUp(screenX, screenY, pointer, button)
}
override fun scrolled(amount: Int): Boolean {
return super.scrolled(amount)
}
override fun keyDown(keycode: Int): Boolean {
return super.keyDown(keycode)
}
override fun keyUp(keycode: Int): Boolean {
return super.keyUp(keycode)
}
override fun keyTyped(character: Char): Boolean {
return super.keyTyped(character)
}
}

View File

@@ -0,0 +1,68 @@
package net.torvald.terrarum.ui
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.gameactors.Second
class UITitleRemoConCredits(val superMenu: UICanvas) : UICanvas() {
val menuLabels = arrayOf(
"MENU_LABEL_CREDITS",
"MENU_CREDIT_GPL_DNT",
"MENU_LABEL_RETURN"
)
override var width: Int = UITitleRemoConRoot.remoConWidth
override var height: Int = UITitleRemoConRoot.getRemoConHeight(menuLabels)
override var openCloseTime: Second = 0f
private val menubar = UIItemTextButtonList(
this,
menuLabels,
this.width, this.height,
textAreaWidth = this.width,
readFromLang = true,
activeBackCol = Color(0),
highlightBackCol = Color(0),
backgroundCol = Color(0),
inactiveCol = Color.WHITE,
defaultSelection = null
)
init {
uiItems.add(menubar)
// attach listeners
menubar.buttons[menuLabels.indexOf("MENU_LABEL_RETURN")].clickOnceListener = { _, _, _ ->
superMenu.handler.setAsOpen()
this.handler.setAsClose()
}
}
override fun update(delta: Float) {
menubar.update(delta)
}
override fun render(batch: SpriteBatch) {
menubar.render(batch)
}
override fun doOpening(delta: Float) {
}
override fun doClosing(delta: Float) {
}
override fun endOpening(delta: Float) {
}
override fun endClosing(delta: Float) {
}
override fun dispose() {
}
}

View File

@@ -0,0 +1,86 @@
package net.torvald.terrarum.ui
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import net.torvald.terrarum.Terrarum
class UITitleRemoConRoot : UICanvas() {
companion object {
val remoConWidth = 240
fun getRemoConHeight(menu: Array<String>) = 36 * menu.size.plus(1)
val menubarOffY: Int; get() = Terrarum.HEIGHT / 2 - (Terrarum.fontGame.lineHeight * 1.5).toInt()
}
/** Contains STRING_IDs */
val menuLabels = arrayOf(
"MENU_MODE_SINGLEPLAYER",
"MENU_OPTIONS",
"MENU_MODULES",
"MENU_LABEL_LANGUAGE",
"MENU_LABEL_CREDITS",
"MENU_LABEL_QUIT"
)
override var width: Int = remoConWidth
override var height: Int = getRemoConHeight(menuLabels)
override var openCloseTime = 0f
private val menubar = UIItemTextButtonList(
this,
menuLabels,
this.width, this.height,
textAreaWidth = this.width,
readFromLang = true,
activeBackCol = Color(0),
highlightBackCol = Color(0),
backgroundCol = Color(0),
inactiveCol = Color.WHITE,
defaultSelection = null
)
//private val paneCredits = UIHandler()
private val remoConCredits = UIHandler(UITitleRemoConCredits(this))
init {
uiItems.add(menubar)
// attach listeners
menubar.buttons[menuLabels.indexOf("MENU_LABEL_QUIT")].clickOnceListener = { _, _, _ -> System.exit(0) }
}
override fun update(delta: Float) {
menubar.update(delta)
}
override fun render(batch: SpriteBatch) {
menubar.render(batch)
}
override fun doOpening(delta: Float) {
}
override fun doClosing(delta: Float) {
}
override fun endOpening(delta: Float) {
}
override fun endClosing(delta: Float) {
}
override fun dispose() {
}
}