From f0f358a15cbb27b1327096e75826e3b92add3aa7 Mon Sep 17 00:00:00 2001 From: minjaesong Date: Tue, 16 Apr 2024 23:03:37 +0900 Subject: [PATCH] note particles --- .../gameactors/FixtureMechanicalTines.kt | 111 ++++++++++++++++-- 1 file changed, 98 insertions(+), 13 deletions(-) diff --git a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureMechanicalTines.kt b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureMechanicalTines.kt index 14a556dde..a63287a3c 100644 --- a/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureMechanicalTines.kt +++ b/src/net/torvald/terrarum/modulebasegame/gameactors/FixtureMechanicalTines.kt @@ -1,14 +1,24 @@ package net.torvald.terrarum.modulebasegame.gameactors +import com.badlogic.gdx.graphics.Color +import com.jme3.math.FastMath +import net.torvald.colourutil.HUSLColorConverter +import net.torvald.random.HQRNG import net.torvald.terrarum.App import net.torvald.terrarum.App.printdbg +import net.torvald.terrarum.CommonResourcePool import net.torvald.terrarum.INGAME +import net.torvald.terrarum.ModMgr import net.torvald.terrarum.TerrarumAppConfiguration.TILE_SIZE import net.torvald.terrarum.gameactors.AVKey +import net.torvald.terrarum.gameparticles.ParticleVanishingTexture import net.torvald.terrarum.langpack.Lang +import net.torvald.terrarum.modulebasegame.TerrarumIngame import net.torvald.terrarum.modulebasegame.audio.audiobank.AudioBankMusicBox import net.torvald.terrarum.modulebasegame.gameitems.FixtureItemBase import net.torvald.terrarumsansbitmap.gdx.TextureRegionPack +import org.dyn4j.geometry.Vector2 +import kotlin.math.pow /** * Created by minjaesong on 2024-04-15. @@ -60,13 +70,35 @@ class FixtureMechanicalTines : Electric { if (isSignalHigh(0, 1)) { // advance every tick - audioBank.sendMessage(testNotes[testRollCursor]) + testNotes[testRollCursor].let { + audioBank.sendMessage(it) + spewParticles(it) + } testRollCursor = (testRollCursor + 1) % testNotes.size } } + private fun spewParticles(noteBits: Long) { + if (noteBits == 0L) return + val notes = findSetBits(noteBits) + notes.forEach { + val particle = ParticleMusicalNoteFactory.makeRandomParticle(it, this.hitbox.canonVec) + (INGAME as TerrarumIngame).addParticle(particle) + } + } + + private fun findSetBits(num: Long): List { + val result = mutableListOf() + for (i in 0 until 61) { + if (num and (1L shl i) != 0L) { + result.add(i) + } + } + return result + } + companion object { @Transient private val TICK_DIVISOR = 10 @@ -108,23 +140,27 @@ class FixtureMechanicalTines : Electric { end3( 0,12,28,31,36) + List(16*TICK_DIVISOR - 5) { 0L } private fun prel(n1: Int, n2: Int, n3: Int, n4: Int, n5: Int): List { - return toPianoRoll2( - 1L shl n1, 1L shl n2, 1L shl n3, 1L shl n4, 1L shl n5, 1L shl n3, 1L shl n4, 1L shl n5, - 1L shl n1, 1L shl n2, 1L shl n3, 1L shl n4, 1L shl n5, 1L shl n3, 1L shl n4, 1L shl n5) + return toPianoRoll( + 1L shl n1 to TICK_DIVISOR+2, 1L shl n2 to TICK_DIVISOR, 1L shl n3 to TICK_DIVISOR, 1L shl n4 to TICK_DIVISOR, + 1L shl n5 to TICK_DIVISOR, 1L shl n3 to TICK_DIVISOR, 1L shl n4 to TICK_DIVISOR, 1L shl n5 to TICK_DIVISOR, + 1L shl n1 to TICK_DIVISOR, 1L shl n2 to TICK_DIVISOR, 1L shl n3 to TICK_DIVISOR, 1L shl n4 to TICK_DIVISOR, + 1L shl n5 to TICK_DIVISOR-1, 1L shl n3 to TICK_DIVISOR, 1L shl n4 to TICK_DIVISOR, 1L shl n5 to TICK_DIVISOR) } private fun end1(n1: Int, n2: Int, n3: Int, n4: Int, n5: Int, n6: Int, n7: Int, n8: Int, n9: Int): List { - return toPianoRoll2( - 1L shl n1, 1L shl n2, 1L shl n3, 1L shl n4, 1L shl n5, 1L shl n6, 1L shl n5, 1L shl n4, - 1L shl n5, 1L shl n7, 1L shl n8, 1L shl n7, 1L shl n8, 1L shl n9, 1L shl n8, 1L shl n9) + return toPianoRoll( + 1L shl n1 to TICK_DIVISOR+2, 1L shl n2 to TICK_DIVISOR, 1L shl n3 to TICK_DIVISOR, 1L shl n4 to TICK_DIVISOR, + 1L shl n5 to TICK_DIVISOR, 1L shl n6 to TICK_DIVISOR, 1L shl n5 to TICK_DIVISOR, 1L shl n4 to TICK_DIVISOR, + 1L shl n5 to TICK_DIVISOR, 1L shl n7 to TICK_DIVISOR, 1L shl n8 to TICK_DIVISOR, 1L shl n7 to TICK_DIVISOR, + 1L shl n8 to TICK_DIVISOR-1, 1L shl n9 to TICK_DIVISOR, 1L shl n8 to TICK_DIVISOR, 1L shl n9 to TICK_DIVISOR) } private fun end2(n1: Int, n2: Int, n3: Int, n4: Int, n5: Int, n6: Int, n7: Int, n8: Int, n9: Int): List { return toPianoRoll( - 1L shl n1 to TICK_DIVISOR, 1L shl n2 to TICK_DIVISOR+1, 1L shl n3 to TICK_DIVISOR+1, 1L shl n4 to TICK_DIVISOR+1, + 1L shl n1 to TICK_DIVISOR+2, 1L shl n2 to TICK_DIVISOR+1, 1L shl n3 to TICK_DIVISOR+1, 1L shl n4 to TICK_DIVISOR+1, 1L shl n5 to TICK_DIVISOR+1, 1L shl n6 to TICK_DIVISOR+2, 1L shl n5 to TICK_DIVISOR+2, 1L shl n4 to TICK_DIVISOR+2, 1L shl n5 to TICK_DIVISOR+3, 1L shl n4 to TICK_DIVISOR+3, 1L shl n3 to TICK_DIVISOR+4, 1L shl n4 to TICK_DIVISOR+4, - 1L shl n7 to TICK_DIVISOR+6, 1L shl n8 to TICK_DIVISOR+8, 1L shl n9 to TICK_DIVISOR+16, 1L shl n7 to TICK_DIVISOR+32) + 1L shl n7 to TICK_DIVISOR+6, 1L shl n8 to TICK_DIVISOR+8, 1L shl n9 to TICK_DIVISOR+12, 1L shl n7 to TICK_DIVISOR+24) } private fun end3(vararg ns: Int): List { @@ -145,8 +181,57 @@ class FixtureMechanicalTines : Electric { if (it % TICK_DIVISOR == 0) notes[it / TICK_DIVISOR] else 0 } - private fun toPianoRoll2(vararg notes: Long) = List(notes.size * TICK_DIVISOR) { - if (it % TICK_DIVISOR == 0) notes[it / TICK_DIVISOR] else 0 - }.let { it.subList(0, 1) + List(3) { 0L } + it.subList(1, it.size) } } -} \ No newline at end of file +} + +object ParticleMusicalNoteFactory { + + init { + CommonResourcePool.addToLoadingList("basegame-particles-musical_note") { + TextureRegionPack(ModMgr.getGdxFile("basegame", "particles/musical_note.tga"), 8, 8) + } + CommonResourcePool.loadAll() + } + + private val tex = CommonResourcePool.getAsTextureRegionPack("basegame-particles-musical_note") + private val rng = HQRNG() + + private const val HALF_PI = 1.5707963267948966 + + private const val ANGLE_LEFTMOST = -(HALF_PI - 1.0) + private const val ANGLE_RIGHTMOST = -(HALF_PI + 1.0) + + private val noteColours = (0..60).map { + val hue = it / 60f * 270f + val saturation = 100f + val lightness = 80f + val (r, g, b) = HUSLColorConverter.hsluvToRgb(floatArrayOf(hue, saturation, lightness)) + Color(r, g, b, 1f) + } + + private val angles = (0..60).map { + FastMath.interpolateLinear(it / 60.0, ANGLE_RIGHTMOST, ANGLE_LEFTMOST) + } + + fun makeRandomParticle(note: Int, pos: Vector2): ParticleVanishingTexture { + val it = object : ParticleVanishingTexture(tex.get(rng.nextInt(3), rng.nextInt(2)), pos.x, pos.y, false) { + override fun update(delta: Float) { + super.update(delta) + + drawColour.a = ((lifetimeMax - lifetimeCounter) / lifetimeMax).pow(1f / 2.2f).coerceIn(0f, 1f) + } + } + + // set flying velocity + val direction = angles[note] + val magnitude = rng.nextTriangularBal() * 0.2 + 1.0 + + it.velocity.set(Vector2.create(magnitude, direction)) + + // set particle colour + it.drawColour.set(noteColours[note]) + + + return it + } +}