I have a wallpaper application, written in libgdx.
I use SpriteBatch
and ShapeRenderer
to render my stuff.
All goes well, but sometimes some artifacts happen like this:
grey background has its own
ShapeRenderer
stars over background have their own
ShapeRenderer
all planets (there may be more than 1) have a shared
SpriteBatch
andShapeRenderer
What might be wrong?
There is code of ApplicationListener
which in charge on drawing right image
private lateinit var stars: Stars
private lateinit var bg: GameBackground
private lateinit var presentation: Presentation
private lateinit var sr: ShapeRenderer
private lateinit var sb: SpriteBatch
override fun render() {
val time = System.currentTimeMillis()
val delta = time - prev
if (delta > FRAME_DURATION) {
frame(delta)
draw()
prev = time
}
}
override fun create() {
sr = ShapeRenderer().apply { setAutoShapeType(true) }
sb = SpriteBatch()
bg = GameBackground(sr)
stars = Stars(sr)
presentation = Presentation(sr, sb)
}
private fun frame(timeElapsed: Long) {
bg.frame(timeElapsed)
stars.frame(timeElapsed)
presentation.frame(timeElapsed)
}
private fun draw() {
bg.draw()
stars.draw()
presentation.draw()
}
override fun pause() {
}
override fun resume() {
}
override fun dispose() {
sr.dispose()
sb.dispose()
}
And there is code of image left:
private lateinit var stars: Stars
private lateinit var bg: GameBackground
private lateinit var presentation: Presentation
private var prevTime: Long = System.currentTimeMillis()
private lateinit var sr: ShapeRenderer
private lateinit var sb: SpriteBatch
override fun create() {
super.create()
sr = ShapeRenderer().apply { setAutoShapeType(true) }
sb = SpriteBatch()
bg = GameBackground(sr)
stars = Stars(sr)
presentation = Presentation(sr, sb)
}
override fun render() {
val now = System.currentTimeMillis()
val elapsedTime = now - prevTime
if (elapsedTime > FRAME_DURATION) {
prevTime = now
bg.frame(FRAME_DURATION)
stars.frame(FRAME_DURATION)
presentation.frame(FRAME_DURATION)
}
bg.draw()
stars.draw()
presentation.draw()
}
override fun dispose() {
sr.dispose()
sb.dispose()
}
companion object {
private const val FRAMES_PER_SECOND = 60
private const val FRAME_DURATION = DateUtils.SECOND_IN_MILLIS / FRAMES_PER_SECOND
}
Right image is wrong.
There is my Presentation
class
class Presentation constructor(private val sr: ShapeRenderer, private val sb: SpriteBatch) : DrawingObject {
private var planetPresentations = mutableListOf<PlanetPresentation>()
override fun draw() {
planetPresentations
.forEach {
sb.begin()
it.drawGlowing(sb)
sb.end()
sr.begin(ShapeRenderer.ShapeType.Filled)
it.drawAtmosphere(sr)
sr.end()
sb.begin()
it.drawBody(sb)
it.drawRing(sb)
sb.end()
}
}
override fun frame(frameDuration: Long) {
planetPresentations
.forEach { it.frame(frameDuration) }
}
}
And PlanetPresentation
class PlanetPresentation constructor(val model: PlanetModel) {
private val texturer = PlanetV(model)
private val bounds = CoreUtils.getDeviceBounds()
private val minScreenSize = Math.min(bounds.x, bounds.y).toFloat() / 2
private var scale = 1f
private val diameter
get() = minScreenSize * model.diameter * scale
private val body = texturer.getPlanetTexture(1024f)
private val glow = Texture("glow.png")
private val ring = texturer.getRingTexture(1024f)
val x: Float
get() = model.x * bounds.x
val y: Float
get() = model.y * bounds.y
private var live = 0L
fun drawAtmosphere(sr: ShapeRenderer) {
val x = model.x * bounds.x
val y = model.y * bounds.y
sr.color = Color(1f, 1f, 1f, 0.4f)
sr.circle(x, y, diameter / 2 * 1.05f)
}
fun drawBody(sb: SpriteBatch) {
val x = model.x * bounds.x
val y = model.y * bounds.y
sb.draw(TextureRegion(body), x - diameter / 2, y - diameter / 2, diameter / 2, diameter / 2, diameter, diameter, 1f, 1f, model.rotation)
}
fun drawRing(sb: SpriteBatch) {
val x = model.x * bounds.x
val y = model.y * bounds.y
ring?.let {
sb.draw(TextureRegion(it), x - diameter, y - diameter / 2 / 2, diameter, diameter / 2 / 2, diameter * 2, diameter / 2, 1f, 1f, model.rotation)
}
}
fun drawGlowing(sb: SpriteBatch) {
val x = model.x * bounds.x
val y = model.y * bounds.y
val increasing = live / GLOW_PULSE_DURATION % 2 == 0L
val pulseDuration = live % GLOW_PULSE_DURATION
val pulseProgress = pulseDuration.toFloat() / GLOW_PULSE_DURATION
val totalPulseProgress = if (increasing) pulseProgress else 1 - pulseProgress
val curGlowSize = diameter * 1.2f + diameter * totalPulseProgress / 6f
sb.draw(TextureRegion(glow), x - curGlowSize / 2, y - curGlowSize / 2, curGlowSize, curGlowSize)
}
fun frame(frameDuration: Long) {
live += frameDuration
}
companion object {
private const val GLOW_PULSE_DURATION = 3000L
}
}
There is another screenshot to clarify what actualy happend:
As you can see, textures are confused. Top white circle shape is drawn by ShapeRenderer
, other 3 images are textures.