scalascalafx

Unable to draw multiple instace of same Image with GraphicsContext


Hi guys this is my first question, so feel free to give constructive criticism. I am making a space shooter game with ScalaFX and I'm facing a problem where when I am drawing the bullet laser in my AnimationTimer loop, whenever the player shoots another bullet, the program only renders the newest bullet and the old bullet just disappears.

For the sake of brevity, I'm going to post the main AnimationTimer loop related to the bullet input and rendering only:

      //List of stuffs (Bullets, enemies etc)
      var laserListB : ListBuffer[Laser] = ListBuffer()

      val timer = AnimationTimer( currentNanoTime => {
      //Calculating time since last frame for frame independant rendering
      var elapsedTime : Double = (currentNanoTime - lastNanoTime) / 1000000000.0;
      lastNanoTime = currentNanoTime;

      //Input check
      //SKIPPED PLAYER MOVEMENT CODE
      if(shootPress){
        var now = System.nanoTime()
        //Checking for atkSpeed cooldwon
        if((lastShootNano <= 0L) || ((now - lastShootNano) >= player.atkSpeed)){
          laserListB += player.shoot()
        }
        lastShootNano = now
      }
      
      //Updating position
      for(laser <- laserListB){
        laser.sprite.velocityX = 0
        laser.sprite.velocityY = -400
        laser.sprite.update(elapsedTime)
      }

      //Rendering
      //Bullets
      for(laser <- laserListB){
        laser.sprite.render(gc)
      }
      
    })

And the following is my Sprite class:

import scalafx.scene.image.Image
import scalafx.scene.canvas.GraphicsContext
import scalafx.geometry.Rectangle2D

class Sprite(
    private var _image : Image,
    private var _positionX : Double,
    private var _positionY : Double,
    private var _velocityX : Double,
    private var _velocityY : Double,
    private var _width : Double,
    private var _height : Double){

    //Functions
    def render(gc : GraphicsContext){
        gc.drawImage(_image, _positionX, _positionY);
    }
}

And if you need, here's my player's shoot function:

    def shoot() = {
        //Setting up laser sprite
        val laser = new Laser(_atkSprite, damage, true)
        laser.sprite.velocityX = 0 
        laser.sprite.velocityY = -400 
        laser.sprite.positionX = _sprite.positionX + (_sprite.width / 2)       //Center laser horizontally on player sprite
        laser.sprite.positionY = _sprite.positionY - 10                   //Slight offset to be a bit higher than the player sprite
        laser
    }

Thank you for reading this far :D

Edit 1: Here's a video demonstrating the problem: https://youtu.be/DliNyBoa1DI


Solution

  • Ok I solved it, it wasn't a problem with GraphicsContext but rather due to the fact, Laser is instantiated with the same Sprite in player.shoot(), therefore all Lasers will have the same X and Y, and be overlapped, thus appearing as if it "disappeared".

    The new code instantiates a new Sprite everytime Laser is instantiated as follows:

        def shoot() = {
            //Laser sprites
            val atkImg = new Image(getClass.getResourceAsStream("/Images/small_laser_blue.png"))
            val atkSprite = new Sprite(atkImg, 0, 0, 0, 0, atkImg.getWidth(), atkImg.getHeight())
            val laser_ = new Laser(atkSprite, _damage, true)
            laser_.sprite.velocityX = 0 
            laser_.sprite.velocityY = -400 
            laser_.sprite.positionX = _sprite.positionX + (_sprite.width / 2)  //Center laser horizontally on player sprite
            laser_.sprite.positionY = _sprite.positionY - 10                   //Slight offset to be a bit higher than the player sprite
        }