0

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:

Android wallpaper

  • 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 and ShapeRenderer

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: enter image description here

As you can see, textures are confused. Top white circle shape is drawn by ShapeRenderer, other 3 images are textures.

P. Ilyin
  • 761
  • 10
  • 28
  • post the code..and highlight the area in the image "what is wrong?" – HarshitMadhav Apr 01 '18 at 06:19
  • @HarshitAgrawal I think it is obvious what area is wrong. Attached code for both images – P. Ilyin Apr 01 '18 at 08:24
  • Don't understand the question. You have code that produces a good image and code that produces bad. So just use the code that isn't buggy. By the way, using System time will give big time jumps whenever the wallpaper resumes. – Tenfour04 Apr 01 '18 at 13:33
  • @Tenfour04 both of the codes are right. They produces a good image. But both sometimes accidently may produce bad. There is no sequence to reach this behaviour. – P. Ilyin Apr 01 '18 at 16:03
  • The issue is in whatever class is drawing the deformed sprites (Presentation?) so we need to see that. – Tenfour04 Apr 01 '18 at 16:13
  • @Tenfour04 updated code – P. Ilyin Apr 01 '18 at 16:29
  • `CoreUtils.getDeviceBounds()` looks suspicious. Is it possible it's polling Gdx for the device screen size before the Application has been started up? Maybe you're instantiating some stuff in constructors rather than waiting for `create()`? – Tenfour04 Apr 04 '18 at 19:51
  • @Tenfour04 I am sure that there is no `CoreUtils.getDeviceBounds()` calls before `create`. All calls are invokes only in constructors of `Background`, `Stars` and `Presentation` classes. And thoose classes invokes their constructors only inside of `create()` – P. Ilyin Apr 06 '18 at 03:12

0 Answers0