Jump to content

Cannot read property 'length' of null [Phaser Virtual Joystick]


Doyban
 Share

Recommended Posts

Trying to implement Phaser Virtual Joystick (https://phaser.io/shop/plugins/virtualjoystick), however once player will die the game crashes with the following error

Uncaught TypeError: Cannot read property 'length' of null
at Phaser.VirtualJoystick.Stick.get (phaser-virtual-joystick.js:1042)
at Phaser.VirtualJoystick.Stick.get (phaser-virtual-joystick.js:1063)
at YellowSidd.Player.update (Player.js:90)

It happens when joystick will be used at least once, while joystick is just added to the game, not used, the game works fine, on dead game is reseting. However, if I'll use at least single movement using joystick it throws an error on player dead.

Player.js:90 and related code, line 90 is exactly on second if, more precisely "if (this.stick.forceX => 0)", while I'll remove it there is later on forceX, which has exactly the same behaviour.

if (this.stick.isDown) {
    // console.log(this.stick.forceX);

    if (this.stick.forceX >= 0) {
      // Move right.
      this.body.velocity.x = this.walking_speed;
      this.direction = "RIGHT";
      this.scale.setTo(1, 1);
    }
    else if (this.stick.forceX < 0) {
      // Move left.
      this.body.velocity.x = -this.walking_speed;
      this.direction = "LEFT";
      this.scale.setTo(-1, 1);
    }
...

 

Any ideas? Tried to write [email protected], but no answer unfortunately, although it was send around 20 hours ago, hope so will got it finally ;)

During that time, maybe anyone here played with the joystick?

 

The following game is on Phaser 2.6.2, tried 2.3.1 (default in joystick doc) and it's the same.

Link to comment
Share on other sites

I did, the following snippet is in my die method.

// Destroy VirtualJoystick elements.
this.stick.destroy();
this.buttonFireball.destroy();

When destroy is commented this error doesn't occurs, however obviously the stick is multiplied every new initialisation of new game.

Link to comment
Share on other sites

Is the stick destroyed before the player is? Because if the player update is still running, and the stick is dead, it'll throw that error. But if the player has been properly destroyed first, then its update should never run.

Basically, there's not enough code shown above to nail the cause, but it sounds like a problem with the sequence of events to me.

Link to comment
Share on other sites

I tried to destroy it in many places, I see a hope that you know what can be wrong, I'm gonna to send you a bit longer code.

 

Player.js

YellowSidd.Player = function (game_state, name, position, properties) {
...
  this.pad = this.game.plugins.add(Phaser.VirtualJoystick); // Initialize VirtualJoystick Plugin.
  this.stick = this.pad.addStick(60, 340, 45, 'generic'); // Add stick for Virtual Joystick.
};

YellowSidd.Player.prototype.update = function () {
"use strict";
  // Check player collision.
  this.game_state.game.physics.arcade.collide(this, this.game_state.layers.collision); // Layers collisions.
  this.game_state.game.physics.arcade.collide(this, this.game_state.groups.enemies, this.hit_enemy, null, this); // Enemies collisions.

  // The player automatically dies if in contact with invincible enemies or enemy fireballs.
  this.game_state.game.physics.arcade.overlap(this, this.game_state.groups.invincible_enemies, this.die, null, this);
  this.game_state.game.physics.arcade.overlap(this, this.game_state.groups.enemy_fireballs, this.die, null, this);

  if (this.stick.isDown) {
    // console.log(this.stick.forceX);

    if (this.stick.forceX >= 0) { // TODO: HERE IS THE ERROR
      // Move right.
      this.body.velocity.x = this.walking_speed;
      this.direction = "RIGHT";
      this.scale.setTo(1, 1);
    }
    else if (this.stick.forceX < 0) { // TODO: HERE IS THE ERROR
      // Move left.
      this.body.velocity.x = -this.walking_speed;
      this.direction = "LEFT";
      this.scale.setTo(-1, 1);
    }

    this.animations.play('walking'); // Play walking animation.

    // Play sound only if player button sound is as "on" mode.
    if (PLAY_SOUND) {
      this.walking_sound.play(); // Play walking sound.
    }

    if (this.body.blocked.down) {
      this.body.velocity.y = this.stick.forceY * this.jumping_speed; // TODO: HERE IS THE ERROR AS WELL

      // Play sound only if player left button sound as on mode.
      if (PLAY_SOUND && this.stick.angleFull > 210 && this.stick.angleFull < 330) {
        this.jump_sound.play(); // Play jump sound.
      }
    }
  }
  else {
    // Stop.
    this.body.velocity.x = 0;
    this.animations.stop();
    this.frame = 3;
  }

  // Dies if touches the end of the screen.
  if (this.bottom >= this.game_state.game.world.height) {
    this.die();
  }
}

YellowSidd.Player.prototype.die = function () {
  "use strict";
  this.lives -= 1;
  this.shooting = false;

  // Destroy VirtualJoystick elements.
  this.stick.destroy();
  this.buttonFireball.destroy();

  // Play sound only if player left button sound as on mode.
  if (PLAY_SOUND) {
    this.lost_heart_sound.play(); // Play lost heart sound.
  }

  if (this.lives > 0) {
    this.game_state.restart_level(); // Player lost 1 life, but still have more then 0, so restart level eventually checkpoint.
  } else {
    this.game_state.game_over(); // Player lost all lives then game over.
  }
};

TiledState.js (for restart_level and game_over methods)
 

YellowSidd.TiledState.prototype.restart_level = function () {
  "use strict";
  // Restart the game only if the checkpoint was not reached.
  if (this.prefabs.checkpoint.checkpoint_reached) {
    // Respawn the player in the last reached checkpoint.
    this.prefabs.player.x = this.prefabs.checkpoint.x;
    this.prefabs.player.y = this.prefabs.checkpoint.y;
  } else {
    localStorage.removeItem('heart_plus_one_once'); // Remove heart_plus_one_once from localStorage.
    localStorage.removeItem('jump_plus_one_once'); // Remove jump_plus_one_once from localStorage.
    localStorage.removeItem('speed_plus_one_once'); // Remove speed_plus_one_once from localStorage.

    this.game.state.restart(true, false, this.level_data); // Restart TiledState state.
  }
};

YellowSidd.TiledState.prototype.game_over = function () {
  "use strict";
  localStorage.removeItem('heart_plus_one_once'); // Remove heart_plus_one_once from localStorage.
  localStorage.removeItem('jump_plus_one_once'); // Remove jump_plus_one_once from localStorage.
  localStorage.removeItem('speed_plus_one_once'); // Remove speed_plus_one_once from localStorage.

  this.game.state.start('BootState', true, false, 'assets/levels/game_over.json', 'GameOverState'); // Start MenuState.

  // Play sound only if player left button sound as on mode.
  if (PLAY_SOUND) {
    this.game_over_sound.play(); // Play game over sound.
  }
};

 

I'd say that this game went through many tests, has been deployed to itch.io and Facebook, so more or less it should be fine, just the stick causes problem, which I can't figure out...

Link to comment
Share on other sites

Found temporary solution, the problem is actually I won't destroy the player in most cases, as once the player dies the most often times the gameplay (not whole game) is restarting, only after reaching some point in the game there is classical "Game Over" with possible back to menu, it took me too many hours already, I think will stay with that solution, at least it works.

For others, if you'd have similar issues, maybe just in my case architecture is hard-coded already, and would need to change too much, including idea.
 

// WORKING
this.stick.visible = 0;
this.buttonFireball.visible = 0;

// OLD, THROWING AN ERROR
// this.stick.destroy();
// this.buttonFireball.destroy();

 

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...