tiles with light level <= 1 will be rendered as black square, phys support for non-self-moving bodies (e.g. balls)

Former-commit-id: 5611e2d89f4601e57d014c45f0479600778217f6
Former-commit-id: d900c0733a6d1dcbd9aaed8e9f7f1671c3866624
This commit is contained in:
Song Minjae
2017-01-23 19:06:12 +09:00
parent e951a6285e
commit 1b83e7deb7
13 changed files with 236 additions and 137 deletions

View File

@@ -851,4 +851,16 @@ final public class FastMath {
for (int i = 1; i < f.length; i++) max = (f[i] > max) ? f[i] : max; for (int i = 1; i < f.length; i++) max = (f[i] > max) ? f[i] : max;
return max; return max;
} }
public static int min(int... f) {
int min = f[0];
for (int i = 1; i < f.length; i++) min = (f[i] < min) ? f[i] : min;
return min;
}
public static int max(int... f) {
int max = f[0];
for (int i = 1; i < f.length; i++) max = (f[i] > max) ? f[i] : max;
return max;
}
} }

View File

@@ -703,7 +703,7 @@ constructor() : Font {
Pair(0x14.toChar(), Color(0xFFA0E0)), //f uchsia Pair(0x14.toChar(), Color(0xFFA0E0)), //f uchsia
Pair(0x15.toChar(), Color(0xE0A0FF)), //*m agenta (purple) Pair(0x15.toChar(), Color(0xE0A0FF)), //*m agenta (purple)
Pair(0x16.toChar(), Color(0x8080FF)), //*b lue Pair(0x16.toChar(), Color(0x8080FF)), //*b lue
Pair(0x17.toChar(), Color(0xFF80FF)), //c yan Pair(0x17.toChar(), Color(0x80FFFF)), //c yan
Pair(0x18.toChar(), Color(0x80FF80)), //*g reen Pair(0x18.toChar(), Color(0x80FF80)), //*g reen
Pair(0x19.toChar(), Color(0x008000)), //v iridian Pair(0x19.toChar(), Color(0x008000)), //v iridian
Pair(0x1A.toChar(), Color(0x805030)), //x (khaki) Pair(0x1A.toChar(), Color(0x805030)), //x (khaki)

View File

@@ -381,15 +381,35 @@ constructor() : BasicGameState() {
actor.hitbox.posX.toFloat(), actor.hitbox.posX.toFloat(),
actor.hitbox.pointedY.toFloat() + 4 actor.hitbox.pointedY.toFloat() + 4
) )
}
}
}
// debug physics
if (KeyToggler.isOn(Key.F11)) {
actorContainer.forEachIndexed { i, actor ->
if (actor is ActorWithSprite) {
worldG.color = Color(1f, 0f, 1f, 1f)
worldG.font = Terrarum.fontSmallNumbers
worldG.lineWidth = 1f
worldG.drawRect(
actor.hitbox.posX.toFloat(),
actor.hitbox.posY.toFloat(),
actor.hitbox.width.toFloat(),
actor.hitbox.height.toFloat()
)
if (DEBUG_ARRAY) { // velocity
worldG.color = GameFontBase.codeToCol["g"] worldG.color = Color(0x80FFFF)
worldG.drawString( worldG.drawString(
i.toString(), "vX ${actor.velocity.x}", // doesn't work for NPCs/Player
actor.hitbox.posX.toFloat(), actor.hitbox.posX.toFloat(),
actor.hitbox.pointedY.toFloat() + 4 + 10 actor.hitbox.pointedY.toFloat() + 4 + 8
) )
} worldG.drawString(
"vY ${actor.velocity.y}",
actor.hitbox.posX.toFloat(),
actor.hitbox.pointedY.toFloat() + 4 + 8 * 2
)
} }
} }
} }
@@ -674,17 +694,30 @@ constructor() : BasicGameState() {
* Check for duplicates, append actor and sort the list * Check for duplicates, append actor and sort the list
*/ */
fun addActor(actor: Actor) { fun addActor(actor: Actor) {
if (hasActor(actor.referenceID)) if (hasActor(actor.referenceID)) {
throw RuntimeException("Actor with ID ${actor.referenceID} already exists.") println("[StateInGame] Replacing actor $actor")
actorContainer.add(actor) removeActor(actor)
insertionSortLastElem(actorContainer) // we can do this as we are only adding single actor addActor(actor)
}
else {
actorContainer.add(actor)
insertionSortLastElem(actorContainer) // we can do this as we are only adding single actor
if (actor is ActorVisible) { if (actor is ActorVisible) {
when (actor.renderOrder) { when (actor.renderOrder) {
ActorOrder.BEHIND -> { actorsRenderBehind.add(actor); insertionSortLastElemAV(actorsRenderBehind) } ActorOrder.BEHIND -> {
ActorOrder.MIDDLE -> { actorsRenderMiddle.add(actor); insertionSortLastElemAV(actorsRenderMiddle) } actorsRenderBehind.add(actor); insertionSortLastElemAV(actorsRenderBehind)
ActorOrder.MIDTOP -> { actorsRenderMidTop.add(actor); insertionSortLastElemAV(actorsRenderMidTop) } }
ActorOrder.FRONT -> { actorsRenderFront .add(actor); insertionSortLastElemAV(actorsRenderFront ) } ActorOrder.MIDDLE -> {
actorsRenderMiddle.add(actor); insertionSortLastElemAV(actorsRenderMiddle)
}
ActorOrder.MIDTOP -> {
actorsRenderMidTop.add(actor); insertionSortLastElemAV(actorsRenderMidTop)
}
ActorOrder.FRONT -> {
actorsRenderFront.add(actor); insertionSortLastElemAV(actorsRenderFront)
}
}
} }
} }
} }
@@ -693,11 +726,6 @@ constructor() : BasicGameState() {
particlesContainer.add(particle) particlesContainer.add(particle)
} }
/**
* Whether the game should display actorContainer elem number when F3 is on
*/
val DEBUG_ARRAY = false
fun getActorByID(ID: Int): Actor { fun getActorByID(ID: Int): Actor {
if (actorContainer.size == 0 && actorContainerInactive.size == 0) if (actorContainer.size == 0 && actorContainerInactive.size == 0)
throw IllegalArgumentException("Actor with ID $ID does not exist.") throw IllegalArgumentException("Actor with ID $ID does not exist.")
@@ -743,10 +771,11 @@ constructor() : BasicGameState() {
private fun ArrayList<out Actor>.binarySearch(ID: Int): Int { private fun ArrayList<out Actor>.binarySearch(ID: Int): Int {
// code from collections/Collections.kt // code from collections/Collections.kt
var low = 0 var low = 0
var high = actorContainer.size - 1 var high = this.size - 1
while (low <= high) { while (low <= high) {
val mid = (low + high).ushr(1) // safe from overflows val mid = (low + high).ushr(1) // safe from overflows
val midVal = get(mid) val midVal = get(mid)
if (ID > midVal.referenceID) if (ID > midVal.referenceID)

View File

@@ -6,6 +6,7 @@ import net.torvald.terrarum.gameactors.PhysTestBall
import net.torvald.terrarum.mapdrawer.TilesDrawer import net.torvald.terrarum.mapdrawer.TilesDrawer
import net.torvald.terrarum.Terrarum import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.mapdrawer.MapCamera import net.torvald.terrarum.mapdrawer.MapCamera
import org.dyn4j.geometry.Vector2
/** /**
* Created by minjaesong on 16-03-05. * Created by minjaesong on 16-03-05.
@@ -13,10 +14,26 @@ import net.torvald.terrarum.mapdrawer.MapCamera
internal object SpawnPhysTestBall : ConsoleCommand { internal object SpawnPhysTestBall : ConsoleCommand {
@Throws(Exception::class) @Throws(Exception::class)
override fun execute(args: Array<String>) { override fun execute(args: Array<String>) {
if (args.size == 2) { val mouseX = Terrarum.appgc.input.mouseX
val mouseX = Terrarum.appgc.input.mouseX val mouseY = Terrarum.appgc.input.mouseY
val mouseY = Terrarum.appgc.input.mouseY
if (args.size >= 3) {
val elasticity = args[1].toDouble()
val xvel = args[2].toDouble()
val yvel = if (args.size >= 4) args[3].toDouble() else 0.0
val ball = PhysTestBall()
ball.setPosition(
(mouseX + MapCamera.x).toDouble(),
(mouseY + MapCamera.y).toDouble()
)
ball.elasticity = elasticity
ball.applyForce(Vector2(xvel, yvel))
Terrarum.ingame.addActor(ball)
}
else if (args.size == 2) {
val elasticity = args[1].toDouble() val elasticity = args[1].toDouble()
val ball = PhysTestBall() val ball = PhysTestBall()
@@ -34,6 +51,6 @@ internal object SpawnPhysTestBall : ConsoleCommand {
} }
override fun printUsage() { override fun printUsage() {
Echo("usage: spawnball [elasticity]") Echo("usage: spawnball elasticity [x velocity] [y velocity]")
} }
} }

View File

@@ -16,6 +16,7 @@ import java.util.*
/** /**
* Humanoid actor class to provide same controlling function (such as work, jump) * Humanoid actor class to provide same controlling function (such as work, jump)
* Also applies unreal air friction for movement control
* *
* Created by minjaesong on 16-10-24. * Created by minjaesong on 16-10-24.
*/ */

View File

@@ -10,6 +10,7 @@ import net.torvald.spriteanimation.SpriteAnimation
import net.torvald.terrarum.gamecontroller.Key import net.torvald.terrarum.gamecontroller.Key
import net.torvald.terrarum.gamecontroller.KeyToggler import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.mapdrawer.FeaturesDrawer.TILE_SIZE import net.torvald.terrarum.mapdrawer.FeaturesDrawer.TILE_SIZE
import net.torvald.terrarum.mapdrawer.MapCamera
import net.torvald.terrarum.tileproperties.Tile import net.torvald.terrarum.tileproperties.Tile
import net.torvald.terrarum.tileproperties.TileProp import net.torvald.terrarum.tileproperties.TileProp
import org.dyn4j.Epsilon import org.dyn4j.Epsilon
@@ -19,17 +20,19 @@ import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics import org.newdawn.slick.Graphics
import org.newdawn.slick.Image import org.newdawn.slick.Image
import java.util.* import java.util.*
import kotlin.reflect.jvm.internal.impl.resolve.constants.DoubleValue
/** /**
* Base class for every actor that has animated sprites. This includes furnishings, paintings, gadgets, etc. * Base class for every actor that has animated sprites. This includes furnishings, paintings, gadgets, etc.
* Also has all the physics * Also has all the physics
* *
* @param renderOrder Rendering order (BEHIND, MIDDLE, MIDTOP, FRONT) * @param renderOrder Rendering order (BEHIND, MIDDLE, MIDTOP, FRONT)
* @param physics * @param immobileBody use realistic air friction (1/1000 of "unrealistic" canonical setup)
* @param physics use physics simulation
* *
* Created by minjaesong on 16-01-13. * Created by minjaesong on 16-01-13.
*/ */
open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : ActorVisible(renderOrder) { open class ActorWithSprite(renderOrder: ActorOrder, val immobileBody: Boolean = false, physics: Boolean = true) : ActorVisible(renderOrder) {
/** !! ActorValue macros are on the very bottom of the source !! **/ /** !! ActorValue macros are on the very bottom of the source !! **/
@@ -343,6 +346,8 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
velocity += acc.times(speedMultByTile) velocity += acc.times(speedMultByTile)
} }
private val bounceDampenVelThreshold = 0.5
override fun update(gc: GameContainer, delta: Int) { override fun update(gc: GameContainer, delta: Int) {
if (isUpdate && !flagDespawn) { if (isUpdate && !flagDespawn) {
@@ -388,7 +393,7 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
} }
setHorizontalFriction() setHorizontalFriction()
if (isPlayerNoClip) { // TODO also hanging on the rope, etc. if (immobileBody || isPlayerNoClip) { // TODO also hanging on the rope, etc.
setVerticalFriction() setVerticalFriction()
} }
@@ -424,28 +429,28 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
// decide whether to ignore walkX // decide whether to ignore walkX
if (!(isCollidingSide(hitbox, COLLIDING_LEFT) && walkX < 0) if (!(isCollidingSide(hitbox, COLLIDING_LEFT) && walkX < 0)
|| !(isCollidingSide(hitbox, COLLIDING_RIGHT) && walkX > 0) || !(isCollidingSide(hitbox, COLLIDING_RIGHT) && walkX > 0)
) { ) {
moveDelta.x = veloX + walkX moveDelta.x = veloX + walkX
} }
// decide whether to ignore walkY // decide whether to ignore walkY
if (!(isCollidingSide(hitbox, COLLIDING_TOP) && walkY < 0) if (!(isCollidingSide(hitbox, COLLIDING_TOP) && walkY < 0)
|| !(isCollidingSide(hitbox, COLLIDING_BOTTOM) && walkY > 0) || !(isCollidingSide(hitbox, COLLIDING_BOTTOM) && walkY > 0)
) { ) {
moveDelta.y = veloY + walkY moveDelta.y = veloY + walkY
} }
} }
else { else {
if (!isCollidingSide(hitbox, COLLIDING_LEFT) if (!isCollidingSide(hitbox, COLLIDING_LEFT)
|| !isCollidingSide(hitbox, COLLIDING_RIGHT) || !isCollidingSide(hitbox, COLLIDING_RIGHT)
) { ) {
moveDelta.x = veloX moveDelta.x = veloX
} }
// decide whether to ignore walkY // decide whether to ignore walkY
if (!isCollidingSide(hitbox, COLLIDING_TOP) if (!isCollidingSide(hitbox, COLLIDING_TOP)
|| !isCollidingSide(hitbox, COLLIDING_BOTTOM) || !isCollidingSide(hitbox, COLLIDING_BOTTOM)
) { ) {
moveDelta.y = veloY moveDelta.y = veloY
} }
} }
@@ -771,6 +776,13 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
return contactAreaCounter return contactAreaCounter
} }
private fun getTileFriction(tile: Int) =
if (immobileBody && tile == Tile.AIR)
TileCodex[Tile.AIR].friction.frictionToMult().div(1000)
.times(if (!grounded) elasticity else 1.0)
else
TileCodex[tile].friction.frictionToMult()
/** about stopping /** about stopping
* for about get moving, see updateMovementControl */ * for about get moving, see updateMovementControl */
private fun setHorizontalFriction() { private fun setHorizontalFriction() {
@@ -778,7 +790,7 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
BASE_FRICTION * TileCodex[Tile.STONE].friction.frictionToMult() BASE_FRICTION * TileCodex[Tile.STONE].friction.frictionToMult()
else { else {
// TODO status quo if !submerged else linearBlend(feetFriction, bodyFriction, submergedRatio) // TODO status quo if !submerged else linearBlend(feetFriction, bodyFriction, submergedRatio)
BASE_FRICTION * (if (grounded) feetFriction else bodyFriction).frictionToMult() BASE_FRICTION * if (grounded) feetFriction else bodyFriction
} }
if (veloX < 0) { if (veloX < 0) {
@@ -806,7 +818,7 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
val friction = if (isPlayerNoClip) val friction = if (isPlayerNoClip)
BASE_FRICTION * TileCodex[Tile.STONE].friction.frictionToMult() BASE_FRICTION * TileCodex[Tile.STONE].friction.frictionToMult()
else else
BASE_FRICTION * bodyFriction.frictionToMult() BASE_FRICTION * bodyFriction
if (veloY < 0) { if (veloY < 0) {
veloY += friction veloY += friction
@@ -859,22 +871,24 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
).toDouble() ).toDouble()
internal val bodyFriction: Int internal val bodyFriction: Double
get() { get() {
var friction = 0 var friction = 0.0
forEachOccupyingTile { // get max friction forEachOccupyingTileNum {
if (it?.friction ?: TileCodex[Tile.AIR].friction > friction) // get max friction
friction = it?.friction ?: TileCodex[Tile.AIR].friction if (getTileFriction(it ?: Tile.AIR) > friction)
friction = getTileFriction(it ?: Tile.AIR)
} }
return friction return friction
} }
internal val feetFriction: Int internal val feetFriction: Double
get() { get() {
var friction = 0 var friction = 0.0
forEachFeetTile { // get max friction forEachFeetTileNum {
if (it?.friction ?: TileCodex[Tile.AIR].friction > friction) // get max friction
friction = it?.friction ?: TileCodex[Tile.AIR].friction if (getTileFriction(it ?: Tile.AIR) > friction)
friction = getTileFriction(it ?: Tile.AIR)
} }
return friction return friction
@@ -885,7 +899,8 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
internal val bodyViscosity: Int internal val bodyViscosity: Int
get() { get() {
var viscosity = 0 var viscosity = 0
forEachOccupyingTile { // get max viscosity forEachOccupyingTile {
// get max viscosity
if (it?.viscosity ?: 0 > viscosity) if (it?.viscosity ?: 0 > viscosity)
viscosity = it?.viscosity ?: 0 viscosity = it?.viscosity ?: 0
} }
@@ -895,7 +910,8 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
internal val feetViscosity: Int internal val feetViscosity: Int
get() { get() {
var viscosity = 0 var viscosity = 0
forEachFeetTile { // get max viscosity forEachFeetTile {
// get max viscosity
if (it?.viscosity ?: 0 > viscosity) if (it?.viscosity ?: 0 > viscosity)
viscosity = it?.viscosity ?: 0 viscosity = it?.viscosity ?: 0
} }
@@ -921,9 +937,9 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
get() { get() {
if (!isPlayerNoClip) { if (!isPlayerNoClip) {
val notSubmergedAccel = if (grounded) val notSubmergedAccel = if (grounded)
feetFriction.frictionToMult() feetFriction
else else
bodyFriction.frictionToMult() bodyFriction
val normalisedViscocity = bodyViscosity.viscosityToMult() val normalisedViscocity = bodyViscosity.viscosityToMult()
return interpolateLinear(submergedRatio, notSubmergedAccel, normalisedViscocity) return interpolateLinear(submergedRatio, notSubmergedAccel, normalisedViscocity)
@@ -992,7 +1008,7 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
private fun updateHitbox() = hitbox.reassign(nextHitbox) private fun updateHitbox() = hitbox.reassign(nextHitbox)
override open fun drawGlow(g: Graphics) { override fun drawGlow(g: Graphics) {
if (isVisible && spriteGlow != null) { if (isVisible && spriteGlow != null) {
blendLightenOnly() blendLightenOnly()
@@ -1033,25 +1049,12 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
) )
} }
} }
// debug hitbox
if (KeyToggler.isOn(Key.F11)) {
g.color = Color(1f, 0f, 1f, 1f)
blendNormal()
g.lineWidth = 1f
g.drawRect(
hitbox.posX.toFloat(),
hitbox.posY.toFloat(),
hitbox.width.toFloat(),
hitbox.height.toFloat()
)
}
} }
override open fun drawBody(g: Graphics) { private val halfWorldW = world.width.times(TILE_SIZE).ushr(1)
if (isVisible && sprite != null) {
override fun drawBody(g: Graphics) {
if (isVisible && sprite != null) {
when (drawMode) { when (drawMode) {
BLEND_NORMAL -> blendNormal() BLEND_NORMAL -> blendNormal()
@@ -1282,7 +1285,9 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
var avBaseScale: Double // use canonical "scale" for apparent scale (base * buff) var avBaseScale: Double // use canonical "scale" for apparent scale (base * buff)
get() = actorValue.getAsDouble(AVKey.SCALE) ?: 1.0 get() = actorValue.getAsDouble(AVKey.SCALE) ?: 1.0
set(value) { actorValue[AVKey.SCALE] = value } set(value) {
actorValue[AVKey.SCALE] = value
}
/** Apparent strength */ /** Apparent strength */
var avStrength: Double var avStrength: Double
get() = (actorValue.getAsDouble(AVKey.STRENGTH) ?: 0.0) * get() = (actorValue.getAsDouble(AVKey.STRENGTH) ?: 0.0) *
@@ -1294,10 +1299,14 @@ open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : A
} }
var avBaseStrength: Double? var avBaseStrength: Double?
get() = actorValue.getAsDouble(AVKey.STRENGTH) get() = actorValue.getAsDouble(AVKey.STRENGTH)
set(value) { actorValue[AVKey.STRENGTH] = value!! } set(value) {
actorValue[AVKey.STRENGTH] = value!!
}
var avBaseMass: Double var avBaseMass: Double
get() = actorValue.getAsDouble(AVKey.BASEMASS) ?: MASS_DEFAULT get() = actorValue.getAsDouble(AVKey.BASEMASS) ?: MASS_DEFAULT
set(value) { actorValue[AVKey.BASEMASS] = value } set(value) {
actorValue[AVKey.BASEMASS] = value
}
val avAcceleration: Double val avAcceleration: Double
get() = actorValue.getAsDouble(AVKey.ACCEL)!! * get() = actorValue.getAsDouble(AVKey.ACCEL)!! *
actorValue.getAsDouble(AVKey.ACCELBUFF)!! * actorValue.getAsDouble(AVKey.ACCELBUFF)!! *

View File

@@ -5,7 +5,8 @@ import net.torvald.spriteanimation.SpriteAnimation
/** /**
* Created by minjaesong on 16-06-17. * Created by minjaesong on 16-06-17.
*/ */
open class FixtureBase(physics: Boolean = true) : ActorWithSprite(ActorOrder.BEHIND, physics) { open class FixtureBase(physics: Boolean = true) :
ActorWithSprite(ActorOrder.BEHIND, immobileBody = true, physics = physics) {
/** /**
* 0: Open * 0: Open
* 1: Blocked * 1: Blocked

View File

@@ -11,7 +11,7 @@ import org.newdawn.slick.Input
* *
* Created by minjaesong on 16-10-10. * Created by minjaesong on 16-10-10.
*/ */
open class HistoricalFigure(val born: GameDate, val dead: GameDate? = null) : ActorWithSprite(ActorOrder.MIDDLE) { open class HistoricalFigure(val born: GameDate, val dead: GameDate? = null, realAirFriction: Boolean = false) : ActorWithSprite(ActorOrder.MIDDLE, realAirFriction) {
init { init {
this.actorValue["_bornyear"] = born.year this.actorValue["_bornyear"] = born.year

View File

@@ -10,7 +10,7 @@ import org.newdawn.slick.Graphics
/** /**
* Created by minjaesong on 16-03-05. * Created by minjaesong on 16-03-05.
*/ */
class PhysTestBall : ActorWithSprite(ActorOrder.MIDDLE) { class PhysTestBall : ActorWithSprite(ActorOrder.MIDDLE, immobileBody = true) {
private var color = Color.orange private var color = Color.orange

View File

@@ -432,17 +432,12 @@ object LightmapRenderer {
if (darken < 0 || darken >= COLOUR_RANGE_SIZE) if (darken < 0 || darken >= COLOUR_RANGE_SIZE)
throw IllegalArgumentException("darken: out of range ($darken)") throw IllegalArgumentException("darken: out of range ($darken)")
// use equation with magic number 6.5: // use equation with magic number 9.0
// =>> val r = data.r() * (1f + brighten.r() * 6.5f) <<= // smooooooth
// gives 8-visible-tile penetration of sunlight, fairly smooth,
// DOES NOT GO BELOW (2,2,2)
val r = data.r() * (1f - darken.r() * 6.5f) val r = data.r() * (1f - darken.r() * 9.0f)
val g = data.g() * (1f - darken.g() * 6.5f) val g = data.g() * (1f - darken.g() * 9.0f)
val b = data.b() * (1f - darken.b() * 6.5f) val b = data.b() * (1f - darken.b() * 9.0f)
//val r = data.r() - darken.r()
//val g = data.g() - darken.g()
//val b = data.b() - darken.b()
return constructRGBFromFloat(r.clampZero(), g.clampZero(), b.clampZero()) return constructRGBFromFloat(r.clampZero(), g.clampZero(), b.clampZero())
} }
@@ -629,6 +624,13 @@ object LightmapRenderer {
private fun Float.clampChannel() = if (this > CHANNEL_MAX_DECIMAL) CHANNEL_MAX_DECIMAL else this private fun Float.clampChannel() = if (this > CHANNEL_MAX_DECIMAL) CHANNEL_MAX_DECIMAL else this
fun getValueFromMap(x: Int, y: Int): Int? = getLight(x, y) fun getValueFromMap(x: Int, y: Int): Int? = getLight(x, y)
fun getLowestRGB(x: Int, y: Int): Int? {
val value = getLight(x, y)
if (value == null)
return null
else
return FastMath.min(value.rawR(), value.rawG(), value.rawB())
}
private fun purgeLightmap() { private fun purgeLightmap() {
for (y in 0..LIGHTMAP_HEIGHT - 1) { for (y in 0..LIGHTMAP_HEIGHT - 1) {

View File

@@ -11,14 +11,18 @@ object MapCamera {
private val world: GameWorld = Terrarum.ingame.world private val world: GameWorld = Terrarum.ingame.world
private val TILE_SIZE = FeaturesDrawer.TILE_SIZE private val TILE_SIZE = FeaturesDrawer.TILE_SIZE
var x = 0 var x: Int = 0
private set private set
var y = 0 var y: Int = 0
private set private set
var width: Int = 0 var width: Int = 0
private set private set
var height: Int = 0 var height: Int = 0
private set private set
val xCentre: Int
get() = x + width.ushr(1)
val yCentre: Int
get() = y + height.ushr(1)
fun update() { fun update() {
val player = Terrarum.ingame.player val player = Terrarum.ingame.player

View File

@@ -278,6 +278,8 @@ object TilesDrawer {
blendNormal() blendNormal()
} }
private val tileDrawLightThreshold = 2
private fun drawTiles(g: Graphics, mode: Int, drawModeTilesBlendMul: Boolean) { private fun drawTiles(g: Graphics, mode: Int, drawModeTilesBlendMul: Boolean) {
val for_y_start = y / TILE_SIZE val for_y_start = y / TILE_SIZE
val for_y_end = TilesDrawer.clampHTile(for_y_start + (height / TILE_SIZE) + 2) val for_y_end = TilesDrawer.clampHTile(for_y_start + (height / TILE_SIZE) + 2)
@@ -305,59 +307,72 @@ object TilesDrawer {
// draw // draw
try { try {
if ( if ((mode == WALL || mode == TERRAIN) && // not an air tile
(mode == WALL || mode == TERRAIN) && // not an air tile (thisTile ?: 0) != Tile.AIR) {
(thisTile ?: 0) > 0) //&& // commented out: meh
// check if light level of nearby or this tile is illuminated // check if light level of nearby or this tile is illuminated
/*( LightmapRenderer.getValueFromMap(x, y) ?: 0 > 0 || if ( LightmapRenderer.getLowestRGB(x, y) ?: 0 >= tileDrawLightThreshold ||
LightmapRenderer.getValueFromMap(x - 1, y) ?: 0 > 0 || LightmapRenderer.getLowestRGB(x - 1, y) ?: 0 >= tileDrawLightThreshold ||
LightmapRenderer.getValueFromMap(x + 1, y) ?: 0 > 0 || LightmapRenderer.getLowestRGB(x + 1, y) ?: 0 >= tileDrawLightThreshold ||
LightmapRenderer.getValueFromMap(x, y - 1) ?: 0 > 0 || LightmapRenderer.getLowestRGB(x, y - 1) ?: 0 >= tileDrawLightThreshold ||
LightmapRenderer.getValueFromMap(x, y + 1) ?: 0 > 0 || LightmapRenderer.getLowestRGB(x, y + 1) ?: 0 >= tileDrawLightThreshold ||
LightmapRenderer.getValueFromMap(x - 1, y - 1) ?: 0 > 0 || LightmapRenderer.getLowestRGB(x - 1, y - 1) ?: 0 >= tileDrawLightThreshold ||
LightmapRenderer.getValueFromMap(x + 1, y + 1) ?: 0 > 0 || LightmapRenderer.getLowestRGB(x + 1, y + 1) ?: 0 >= tileDrawLightThreshold ||
LightmapRenderer.getValueFromMap(x + 1, y - 1) ?: 0 > 0 || LightmapRenderer.getLowestRGB(x + 1, y - 1) ?: 0 >= tileDrawLightThreshold ||
LightmapRenderer.getValueFromMap(x - 1, y + 1) ?: 0 > 0) LightmapRenderer.getLowestRGB(x - 1, y + 1) ?: 0 >= tileDrawLightThreshold) {
)*/ { // blackness
val nearbyTilesInfo: Int /*if (zeroTileCounter > 0) {
if (isPlatform(thisTile)) { g.color = Color.black
nearbyTilesInfo = getNearbyTilesInfoPlatform(x, y) g.fillRect(
} (x - zeroTileCounter) * TILE_SIZE.toFloat(), y * TILE_SIZE.toFloat(),
else if (isWallSticker(thisTile)) { zeroTileCounter * TILE_SIZE.toFloat(), TILE_SIZE.toFloat()
nearbyTilesInfo = getNearbyTilesInfoWallSticker(x, y) )
} g.color = Color.white
else if (isConnectMutual(thisTile)) { zeroTileCounter = 0
nearbyTilesInfo = getNearbyTilesInfoNonSolid(x, y, mode) }*/
}
else if (isConnectSelf(thisTile)) {
nearbyTilesInfo = getNearbyTilesInfo(x, y, mode, thisTile) val nearbyTilesInfo: Int
} if (isPlatform(thisTile)) {
nearbyTilesInfo = getNearbyTilesInfoPlatform(x, y)
}
else if (isWallSticker(thisTile)) {
nearbyTilesInfo = getNearbyTilesInfoWallSticker(x, y)
}
else if (isConnectMutual(thisTile)) {
nearbyTilesInfo = getNearbyTilesInfoNonSolid(x, y, mode)
}
else if (isConnectSelf(thisTile)) {
nearbyTilesInfo = getNearbyTilesInfo(x, y, mode, thisTile)
}
else {
nearbyTilesInfo = 0
}
val thisTileX: Int
if (!noDamageLayer)
thisTileX = PairedMapLayer.RANGE * ((thisTile ?: 0) % PairedMapLayer.RANGE) + nearbyTilesInfo
else
thisTileX = nearbyTilesInfo
val thisTileY = (thisTile ?: 0) / PairedMapLayer.RANGE
if (drawModeTilesBlendMul) {
if (TilesDrawer.isBlendMul(thisTile)) {
drawTile(mode, x, y, thisTileX, thisTileY)
}
}
else {
// do NOT add "if (!isBlendMul(thisTile))"!
// or else they will not look like they should be when backed with wall
drawTile(mode, x, y, thisTileX, thisTileY)
}
} // end if (is illuminated)
else { else {
nearbyTilesInfo = 0 zeroTileCounter++
drawTile(mode, x, y, 1, 0) // black patch
} }
} // end if (not an air)
val thisTileX: Int
if (!noDamageLayer)
thisTileX = PairedMapLayer.RANGE * ((thisTile ?: 0) % PairedMapLayer.RANGE) + nearbyTilesInfo
else
thisTileX = nearbyTilesInfo
val thisTileY = (thisTile ?: 0) / PairedMapLayer.RANGE
if (drawModeTilesBlendMul) {
if (TilesDrawer.isBlendMul(thisTile)) {
drawTile(mode, x, y, thisTileX, thisTileY)
}
} else {
// do NOT add "if (!isBlendMul(thisTile))"!
// or else they will not look like they should be when backed with wall
drawTile(mode, x, y, thisTileX, thisTileY)
}
} // end if (not an air and is illuminated)
else {
zeroTileCounter++
}
} catch (e: NullPointerException) { } catch (e: NullPointerException) {
// do nothing. WARNING: This exception handling may hide erratic behaviour completely. // do nothing. WARNING: This exception handling may hide erratic behaviour completely.
} }

View File

@@ -40,6 +40,7 @@ object WeatherMixer {
lateinit var mixedWeather: BaseModularWeather lateinit var mixedWeather: BaseModularWeather
val globalLightNow = Color(0) val globalLightNow = Color(0)
private val world = Terrarum.ingame.world
// Weather indices // Weather indices
const val WEATHER_GENERIC = "generic" const val WEATHER_GENERIC = "generic"
@@ -90,9 +91,17 @@ object WeatherMixer {
) )
Terrarum.ingame.addParticle(rainParticle) Terrarum.ingame.addParticle(rainParticle)
} }
globalLightNow.set(getGlobalLightOfTime(world.time.elapsedSeconds).darker(0.3f))
} }
} }
private fun Color.set(other: Color) {
this.r = other.r
this.g = other.g
this.b = other.b
this.a = other.a
}
fun render(g: Graphics) { fun render(g: Graphics) {
// we will not care for nextSkybox for now // we will not care for nextSkybox for now