actors now use 'updateImpl'; static sound for smelter and furnace

This commit is contained in:
minjaesong
2024-02-12 04:48:25 +09:00
parent 7ac6bd6a9c
commit 7d871c5d49
24 changed files with 164 additions and 64 deletions

View File

@@ -138,15 +138,16 @@ class MixerTrackProcessor(bufferSize: Int, val rate: Int, val track: TerrarumAud
(track.filters[DS_FLTIDX_PAN] as BinoPan).earDist = App.audioMixer.listenerHeadSize
if (App.audioMixer.actorNowPlaying != null) {
if (track.trackingTarget == null || track.trackingTarget == App.audioMixer.actorNowPlaying) {
val trackingTarget = track.trackingTarget
if (trackingTarget == null || trackingTarget == App.audioMixer.actorNowPlaying) {
// "reset" the track
track.volume = track.maxVolume
(track.filters[DS_FLTIDX_PAN] as BinoPan).pan = 0f
(track.filters[DS_FLTIDX_LOW] as Lowpass).setCutoff(SAMPLING_RATE / 2f)
}
else if (track.trackingTarget is ActorWithBody) {
val relativeXpos = relativeXposition(App.audioMixer.actorNowPlaying!!, track.trackingTarget as ActorWithBody)
val distFromActor = distBetweenActors(App.audioMixer.actorNowPlaying!!, track.trackingTarget as ActorWithBody)
else if (trackingTarget is ActorWithBody) {
val relativeXpos = relativeXposition(App.audioMixer.actorNowPlaying!!, trackingTarget as ActorWithBody)
val distFromActor = distBetweenActors(App.audioMixer.actorNowPlaying!!, trackingTarget as ActorWithBody)
val vol = track.maxVolume * getVolFun(distFromActor / distFalloff).coerceAtLeast(0.0)
track.volume = vol
(track.filters[DS_FLTIDX_PAN] as BinoPan).pan = (1.3f * relativeXpos / distFalloff).toFloat()
@@ -154,11 +155,11 @@ class MixerTrackProcessor(bufferSize: Int, val rate: Int, val track: TerrarumAud
(SAMPLING_RATED*0.5) / (24.0 * (distFromActor / distFalloff).sqr() + 1.0)
)
val sourceVec = (track.trackingTarget as ActorWithBody).let { it.externalV + (it.controllerV ?: Vector2()) }
val sourceVec = (trackingTarget as ActorWithBody).let { it.externalV + (it.controllerV ?: Vector2()) }
val listenerVec = App.audioMixer.actorNowPlaying!!.let { it.externalV + (it.controllerV ?: Vector2()) }
val distFromActorNext = distBetweenPoints(
App.audioMixer.actorNowPlaying!!.centrePosVector + listenerVec,
(track.trackingTarget as ActorWithBody).centrePosVector + sourceVec
(trackingTarget as ActorWithBody).centrePosVector + sourceVec
)
val isApproaching = if (distFromActorNext <= distFromActor) 1.0 else -1.0
val relativeSpeed = (sourceVec - listenerVec).magnitude * GAME_TO_SI_VELO * isApproaching

View File

@@ -6,11 +6,13 @@ import com.badlogic.gdx.backends.lwjgl3.audio.Mp3
import com.badlogic.gdx.backends.lwjgl3.audio.Ogg
import com.badlogic.gdx.backends.lwjgl3.audio.OggInputStream
import com.badlogic.gdx.backends.lwjgl3.audio.Wav
import com.badlogic.gdx.utils.Disposable
import com.jcraft.jorbis.VorbisFile
import javazoom.jl.decoder.Bitstream
import net.torvald.reflection.extortField
import net.torvald.reflection.forceInvoke
import net.torvald.terrarum.App
import net.torvald.terrarum.tryDispose
import java.io.File
import java.io.FileInputStream
import javax.sound.sampled.AudioSystem
@@ -20,7 +22,7 @@ data class MusicContainer(
val file: File,
val gdxMusic: Music,
internal var songFinishedHook: (Music) -> Unit = {}
) {
): Disposable {
val samplingRate: Int
val codec: String
@@ -132,4 +134,8 @@ data class MusicContainer(
}
override fun equals(other: Any?) = this.file.path == (other as MusicContainer).file.path
override fun dispose() {
gdxMusic.dispose()
}
}

View File

@@ -7,6 +7,7 @@ import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.audio.MusicContainer
import net.torvald.terrarum.audio.TerrarumAudioMixerTrack
import net.torvald.terrarum.audio.TrackVolume
import net.torvald.terrarum.audio.dsp.NullFilter
import net.torvald.terrarum.modulebasegame.gameactors.ActorHumanoid
import net.torvald.terrarum.modulebasegame.gameactors.Pocketed
import net.torvald.terrarum.savegame.toBigEndian
@@ -51,14 +52,19 @@ abstract class Actor : Comparable<Actor>, Runnable {
OVERLAY // screen overlay, not affected by lightmap
}
open fun update(delta: Float) {
fun update(delta: Float) {
if (!canBeDespawned) flagDespawn = false // actively deny despawning request if cannot be despawned
if (canBeDespawned && flagDespawn) {
despawn()
despawned = true
}
if (!despawned) {
updateImpl(delta)
}
}
open fun updateImpl(delta: Float) {}
var actorValue = ActorValue(this)
@Volatile var flagDespawn = false
@Transient var despawnHook: (Actor) -> Unit = {}
@@ -95,6 +101,15 @@ abstract class Actor : Comparable<Actor>, Runnable {
open fun despawn() {
if (canBeDespawned) {
musicTracks1.forEach { name ->
val it = App.audioMixer.dynamicTracks[name.substring(2).toInt() - 1]
println("stop track $name")
it.stop()
it.filters[0] = NullFilter
it.filters[1] = NullFilter
}
despawnHook(this)
}
}
@@ -108,6 +123,7 @@ abstract class Actor : Comparable<Actor>, Runnable {
// @Transient val soundTracks = HashMap<Sound, TerrarumAudioMixerTrack>()
@Transient val musicTracks = HashMap<MusicContainer, TerrarumAudioMixerTrack>()
@Transient private val musicTracks1 = ArrayList<String>()
/*open fun startAudio(sound: Sound) {
getTrackByAudio(sound)?.let {
@@ -117,7 +133,7 @@ abstract class Actor : Comparable<Actor>, Runnable {
}
}*/
private fun getTrackByAudio(music: MusicContainer): TerrarumAudioMixerTrack? {
fun getTrackByAudio(music: MusicContainer): TerrarumAudioMixerTrack? {
// get existing track
var track = musicTracks[music]
@@ -130,6 +146,7 @@ abstract class Actor : Comparable<Actor>, Runnable {
// if the request was successful, put it into the hashmap
if (track != null) {
musicTracks[music] = track
musicTracks1.add(track.name)
}
}
@@ -138,6 +155,9 @@ abstract class Actor : Comparable<Actor>, Runnable {
return track
}
/**
* To loop the audio, set `music.gdxMusic.isLooping` to `true`
*/
open fun startAudio(music: MusicContainer, volume: TrackVolume = 1.0, doSomethingWithTrack: (TerrarumAudioMixerTrack) -> Unit = {}) {
getTrackByAudio(music)?.let {
it.stop()

View File

@@ -19,6 +19,9 @@ open class ActorMovingPlatform() : ActorWithBody() {
setHitboxDimension(TILE_SIZE * tilewiseWidth, TILE_SIZE, 0, 0)
}
override fun updateImpl(delta: Float) {
TODO("Not yet implemented")
}
/**
* Make the actor its externalV controlled by this platform

View File

@@ -517,9 +517,7 @@ open class ActorWithBody : Actor {
feetPosTile.set(hIntTilewiseHitbox.centeredX.floorToInt(), hIntTilewiseHitbox.endY.floorToInt())
}
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
// re-scale hitbox
// it's just much better to poll them than use perfectly-timed setter because latter simply cannot exist
hitbox.canonicalResize(baseHitboxW * scale, baseHitboxH * scale)

View File

@@ -93,7 +93,7 @@ class BlockMarkerActor : ActorWithBody(Actor.RenderOrder.OVERLAY, physProp = Phy
override fun dispose() {
}
override fun update(delta: Float) {
override fun updateImpl(delta: Float) {
if (isVisible) {
val hbx = (Terrarum.mouseTileX - floor((hitbox.width - 0.5).div(2) / TILE_SIZED)) * TILE_SIZED
val hby = (Terrarum.mouseTileY - floor((hitbox.height - 0.5) / TILE_SIZED)) * TILE_SIZED

View File

@@ -69,7 +69,7 @@ class WireActor : ActorWithBody, NoSerialise {
)
}
override fun update(delta: Float) {
override fun updateImpl(delta: Float) {
}
override fun drawBody(frameDelta: Float, batch: SpriteBatch) {

View File

@@ -125,7 +125,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
override fun dispose() {
}
override fun update(delta: Float) {
override fun updateImpl(delta: Float) {
hitbox.setPosition(
Terrarum.mouseTileX * 16.0,
Terrarum.mouseTileY * 16.0
@@ -187,7 +187,7 @@ class BuildingMaker(batch: FlippingSpriteBatch) : IngameInstance(batch) {
override fun drawGlow(frameDelta: Float, batch: SpriteBatch) { }
override fun update(delta: Float) { }
override fun updateImpl(delta: Float) { }
override fun onActorValueChange(key: String, value: Any?) { }
@@ -688,9 +688,7 @@ class MovableWorldCamera(val parent: BuildingMaker) : ActorHumanoid(0, physProp
parent.world.height * TILE_SIZE - (App.scr.height - hitbox.height) / 2.0
)
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
// confine the camera so it won't wrap
this.hitbox.hitboxStart.setCoerceIn(coerceInStart, coerceInEnd)
}

View File

@@ -606,7 +606,7 @@ class TitleScreen(batch: FlippingSpriteBatch) : IngameInstance(batch) {
override fun drawBody(frameDelta: Float, batch: SpriteBatch) { }
override fun drawGlow(frameDelta: Float, batch: SpriteBatch) { }
override fun update(delta: Float) {
override fun updateImpl(delta: Float) {
ai.update(this, delta)
}

View File

@@ -201,13 +201,13 @@ open class ActorHumanoid : ActorWithBody, Controllable, Pocketed, Factionable, L
}
}
override fun update(delta: Float) {
override fun updateImpl(delta: Float) {
// update lightbox
lightBoxList[0].light = actorValueColour
shadeBoxList[0].light = actorValueShade
super.update(delta)
super.updateImpl(delta)
if (vehicleRiding is IngamePlayer)
throw Error("Attempted to 'ride' player object. ($vehicleRiding)")

View File

@@ -67,8 +67,8 @@ open class SaplingBase(val species: Int) : Cultivable(72000) {
}
}
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
// these have to run every frame to make the sprite static
(sprite as SheetSpriteAnimation).currentRow = species

View File

@@ -140,15 +140,13 @@ open class DroppedItem : ActorWithBody {
}
}
override fun update(delta: Float) {
override fun updateImpl(delta: Float) {
renderOrder = RenderOrder.OVERLAY // for some reason the "overlaying" won't work without this
if (this.itemID.isBlock() || this.itemID.isItem()) {
this.lightBoxList[0].light = getLum(this.itemID)
}
super.update(delta)
timeSinceSpawned += delta
// merge into the already existing droppeditem with isStationary==true if one is detected

View File

@@ -116,8 +116,8 @@ open class Electric : FixtureBase {
}
}
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
oldSinkStatus.indices.forEach { index ->
val wx = (index % blockBox.width) + intTilewiseHitbox.startX.toInt()
val wy = (index / blockBox.width) + intTilewiseHitbox.startY.toInt()
@@ -478,7 +478,8 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
wireConsumption.clear()
}
despawnHook(this)
super.despawn()
}
else {
printdbg(this, "failed to despawn at T${INGAME.WORLD_UPDATE_TIMER}: ${nameFun()}")
@@ -494,8 +495,8 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
/**
* This function MUST BE super-called for make despawn call to work at all.
*/
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
}
/**
@@ -511,7 +512,7 @@ open class FixtureBase : ActorWithBody, CuedByTerrainChange {
despawned = true
}
// actual actor removal is performed by the TerrarumIngame.killOrKnockdownActors
super.update(delta)
super.updateImpl(delta)
}
override fun flagDespawn() {

View File

@@ -1,8 +1,13 @@
package net.torvald.terrarum.modulebasegame.gameactors
import com.badlogic.gdx.Gdx
import net.torvald.gdx.graphics.Cvec
import net.torvald.spriteanimation.SheetSpriteAnimation
import net.torvald.terrarum.*
import net.torvald.terrarum.audio.MusicContainer
import net.torvald.terrarum.audio.decibelsToFullscale
import net.torvald.terrarum.audio.dsp.Gain
import net.torvald.terrarum.audio.dsp.NullFilter
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gameactors.Hitbox
@@ -47,8 +52,20 @@ class FixtureFurnaceAndAnvil : FixtureBase, CraftingStation {
}
actorValue[AVKey.BASEMASS] = 100.0
despawnHook = {
stopAudio(static) {
it.filters[filterIndex] = NullFilter
}
}
}
@Transient val static = MusicContainer("bonfire", ModMgr.getFile("basegame", "audio/effects/static/bonfire.ogg"), Gdx.audio.newMusic(
ModMgr.getGdxFile("basegame", "audio/effects/static/bonfire.ogg")
).also {
it.isLooping = true
})
@Transient override var lightBoxList = arrayListOf(Lightbox(Hitbox(0.0, 0.0, TerrarumAppConfiguration.TILE_SIZED * 2, TerrarumAppConfiguration.TILE_SIZED * 2), Cvec(0.5f, 0.18f, 0f, 0f)))
@Transient private val actorBlocks = arrayOf(
@@ -68,9 +85,8 @@ class FixtureFurnaceAndAnvil : FixtureBase, CraftingStation {
private var nextDelay = 0.25f
private var spawnTimer = 0f
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
// emit smokes TODO: only when hot
if (spawnTimer >= nextDelay) {
@@ -88,5 +104,28 @@ class FixtureFurnaceAndAnvil : FixtureBase, CraftingStation {
}
spawnTimer += delta
// manage audio
getTrackByAudio(static).let {
if (it != null && !it.isPlaying) {
startAudio(static) {
it.filters[filterIndex] = Gain(0f)
}
}
}
getTrackByAudio(static)?.let {
if (it.filters[filterIndex] !is Gain) // just in case...
it.filters[filterIndex] = Gain(0f)
(it.filters[filterIndex] as Gain).gain = 0.4f // TODO randomsied undulation
}
}
@Transient private val filterIndex = 0
override fun dispose() {
super.dispose()
static.dispose()
}
}

View File

@@ -103,8 +103,8 @@ class FixtureJukebox : Electric, PlaysMusic {
override val canBeDespawned: Boolean
get() = discInventory.isEmpty()
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
// supress the normal background music playback
if (musicIsPlaying && !flagDespawn) {

View File

@@ -70,8 +70,8 @@ class FixtureMusicalTurntable : Electric, PlaysMusic {
override val canBeDespawned: Boolean
get() = disc == null
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
// right click
if (mouseUp) {

View File

@@ -1,5 +1,6 @@
package net.torvald.terrarum.modulebasegame.gameactors
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Input
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.SpriteBatch
@@ -9,6 +10,9 @@ import net.torvald.spriteanimation.SheetSpriteAnimation
import net.torvald.terrarum.*
import net.torvald.terrarum.App.printdbg
import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZED
import net.torvald.terrarum.audio.MusicContainer
import net.torvald.terrarum.audio.dsp.Gain
import net.torvald.terrarum.audio.dsp.NullFilter
import net.torvald.terrarum.blockproperties.Block
import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gameactors.Hitbox
@@ -77,6 +81,12 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
this.mainUI = UISmelterBasic(this)
}
@Transient val static = MusicContainer("bonfire", ModMgr.getFile("basegame", "audio/effects/static/bonfire.ogg"), Gdx.audio.newMusic(
ModMgr.getGdxFile("basegame", "audio/effects/static/bonfire.ogg")
).also {
it.isLooping = true
})
@Transient val light = Cvec(0.5f, 0.18f, 0f, 0f)
@Transient override var lightBoxList = arrayListOf(Lightbox(Hitbox(0.0, 2*TILE_SIZED, TILE_SIZED * 2, TILE_SIZED * 2), Cvec(0.5f, 0.18f, 0f, 0f)))
@@ -190,8 +200,8 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
}
}
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
val oreItemProp = ItemCodex[oreItem?.itm]
val fuelItemProp = ItemCodex[fireboxItem?.itm]
@@ -277,6 +287,35 @@ class FixtureSmelterBasic : FixtureBase, CraftingStation {
spawnTimer += delta
else
spawnTimer = 0f
// manage audio
getTrackByAudio(static).let {
if (it == null || (temperature > 0f && !it.isPlaying)) {
startAudio(static) {
it.filters[filterIndex] = Gain(0f)
}
}
else if (it != null && it.isPlaying && temperature <= 0f) {
stopAudio(static) {
it.filters[filterIndex] = NullFilter
}
}
}
getTrackByAudio(static)?.let {
if (it.filters[filterIndex] !is Gain) // just in case...
it.filters[filterIndex] = Gain(0f)
(it.filters[filterIndex] as Gain).gain = (it.maxVolume * temperature).toFloat() // TODO randomsied undulation
}
}
@Transient private val filterIndex = 0
override fun dispose() {
super.dispose()
static.dispose()
}
}

View File

@@ -366,9 +366,8 @@ open class FixtureSwingingDoorBase : FixtureBase {
private var lastDoorHandler = 0 // 0: automatic, 1: manual
private var doorCloseQueueHandler = 0
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
// debug colouring
// this.sprite?.colourFilter =

View File

@@ -51,10 +51,10 @@ internal class FixtureTikiTorch : FixtureBase {
private var nextDelay = 0.25f
private var spawnTimer = 0f
override fun update(delta: Float) {
lightBoxList[0].light = BlockCodex[Block.TORCH].getLumCol(rndHash1, rndHash2)
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
super.update(delta)
lightBoxList[0].light = BlockCodex[Block.TORCH].getLumCol(rndHash1, rndHash2)
if (spawnTimer >= nextDelay) {
(Terrarum.ingame as TerrarumIngame).addParticle(ParticleVanishingSprite(

View File

@@ -38,8 +38,8 @@ class FixtureTypewriter : FixtureBase {
actorValue[AVKey.BASEMASS] = 3.6
}
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
(sprite as SheetSpriteAnimation).currentRow = 1 + (carriagePosition.toFloat() / TYPEWRITER_COLUMNS * 10).roundToInt()
}

View File

@@ -84,9 +84,9 @@ open class HumanoidNPC : ActorHumanoid, AIControlled, CanBeAnItem {
isVisible = true
}
override fun update(delta: Float) {
override fun updateImpl(delta: Float) {
super.updateImpl(delta)
ai.update(this, delta)
super.update(delta)
}
override fun moveLeft(amount: Float) { // hit the buttons on the controller box

View File

@@ -29,9 +29,7 @@ class PhysTestLuarLander : ActorWithBody(RenderOrder.MIDTOP, PhysProperties.PHYS
super.run()
}
override fun update(delta: Float) {
super.update(delta)
override fun updateImpl(delta: Float) {
if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
controllerV!!.y = avSpeedCap
}

View File

@@ -75,7 +75,7 @@ open class ProjectileSimple : ActorWithBody, Projectile {
collisionType = COLLISION_KINEMATIC
}
override fun update(delta: Float) {
override fun updateImpl(delta: Float) {
// hit something and despawn
lifetimeCounter += delta
if (walledTop || walledBottom || walledRight || walledLeft || lifetimeCounter >= lifetimeMax ||
@@ -86,8 +86,6 @@ open class ProjectileSimple : ActorWithBody, Projectile {
}
posPre.set(centrePosPoint)
super.update(delta)
}
/**

View File

@@ -546,13 +546,15 @@ class BasicDebugInfoWindow : UICanvas() {
// Toolkit.fillArea(batch, x - stripGap, y - stripGap, strips.size * (stripW + stripGap) + stripGap, stripH + 2*stripGap)
strips.forEachIndexed { index, track ->
// get clipping status
track.processor.hasClipping.forEachIndexed { channel, b ->
if (b) mixerLastTimeHadClipping[index][channel] = System.currentTimeMillis()
}
if (index < trackCount) {
// get clipping status
track.processor.hasClipping.forEachIndexed { channel, b ->
if (b) mixerLastTimeHadClipping[index][channel] = System.currentTimeMillis()
}
// draw
drawStrip(batch, x + index * (STRIP_W + stripGap), y, track, index)
// draw
drawStrip(batch, x + index * (STRIP_W + stripGap), y, track, index)
}
}
}