Ionic service call on phaser page error second call (undefined)

Hey,
I wanted to add a flappy bird game in my Ionic APP. It worked perfectly but I have an error trying to use a service when you die or when you click a button in the APP.

The error is: Uncaught TypeError: Cannot read property ‘subscribe’ of undefined
But it only happens with the second call!

I wanted to reward the user after he die or he leaves the page, and the first time is working but the second the page can’t find the auth.service

This is a strange phaser code because it doesn’t have preload, create and that functions but it still loads and works, I’ve found it here:

As you can see in InitAPP (ionic-flappybird/app.component.ts at a237d0d64bb443016f07a4ba1d62dc2b5b2f86f0 · jbagaresgaray/ionic-flappybird · GitHub) all logical code is there.

I’ve added a function in my auth.service and added it to my constructor. I also added a click function in html side: <div id=“replay” (click)=“sumarprotogemas()”>replay
And i’ve declared a numeric variable to know how many points the user has done.

Then I added the “sumarprotogemas” function which calls the auth.service. It checks if the number is higher than 0 to reward the user.

sumarprotogemas(){

if(numProtogemas > 0){

  this.auth.protogemasFlappy(numProtogemas.toString()).subscribe(result => {

    if (result !== 'ERROR'){

      this.auth.actualitzarProtogemas();

      this.presentToast(result);

    }

  });

}

}

I don’t understand why is working the first time, and then it doesn’t found my auth.service. Is the page reloaded after I hit the reload button? It should reload the constructor service too, no?

I’ve also tried to add a exit button to the application, that goes to the home page and force destroy the flappy page, but when it loads again, I’ve the same problem.

I’m working in Ionic 6.12.3 version

I know it’s a strange problem but i would appreciate if someone has any ideas to solve this! Thank you!

This is my flappy.page.ts code (same as github with the description changes):

import { Component, OnInit, ViewEncapsulation } from ‘@angular/core’;

import { Keyboard } from “@ionic-native/keyboard/ngx”;

import { NavController, Platform, ToastController } from ‘@ionic/angular’;

import { AuthService } from ‘…/auth/auth.service’;

import { Router } from ‘@angular/router’;

let numProtogemas = 0;

declare let buzz: any;

declare let $: any;

declare var window: any;

let exitApretat = false;

//declare let numProtogemas: number;

@Component({

selector: ‘app-flappy’,

encapsulation: ViewEncapsulation.None,

templateUrl: ‘./flappy.page.html’,

styleUrls: [’./flappy.page.css’],

})

export class FlappyPage implements OnInit {

constructor(private keyboard: Keyboard, private platform: Platform, private auth: AuthService, private router:Router, private toastController:ToastController, private navCtrl: NavController) {

console.log('constructor cridat');

}

ngOnInit() {

console.log('init app');



this.initializeApp();

}

ngOnDestroy(){

// console.log('pagina destruida');

// if(numProtogemas > 0){

//   this.auth.protogemasFlappy(numProtogemas.toString()).subscribe(result => {

//     if (result !== 'ERROR'){

//       this.auth.actualitzarProtogemas();

//       this.presentToast(result);

//     }

//   });

// }

}

ionViewWillEnter(){

// if(exitApretat){

//   this.initApp();

// }

}

initializeApp() {

this.platform.ready().then(() => {

  if (window.cordova) {

    this.keyboard.hideFormAccessoryBar(true);

  }

  this.initApp();

});

}

async presentToast(message: string) {

const toast = await this.toastController.create({

  message: message,

  duration: 5000,

  position: 'middle'

});

toast.present();

}

sumarprotogemas(){

if(numProtogemas > 0){

  this.auth.protogemasFlappy(numProtogemas.toString()).subscribe(result => {

    if (result !== 'ERROR'){

      this.auth.actualitzarProtogemas();

      this.presentToast(result);

    }

  });

}

}

sumarprotogemasExit(){

console.log('Num protogemas: '+numProtogemas);

//console.log('entrant protogemas exit');

if(numProtogemas > 0){

  this.auth.protogemasFlappy(numProtogemas.toString()).subscribe(result => {

    if (result !== 'ERROR'){

      this.auth.actualitzarProtogemas();

      this.presentToast(result);

      //this.presentToast(result);

    }

  });

}

//this.navCtrl.navigateRoot('/play');

this.router.navigate(['/play']);

}

initApp() {

//console.log("initApp");

let debugmode = true;

numProtogemas = 0;



const states = Object.freeze({

  SplashScreen: 0,

  GameScreen: 1,

  ScoreScreen: 2

});

let currentstate;

let gravity = 0.25;

let velocity = 0;

let position = 180;

let rotation = 0;

let jump = -4.6;

let flyArea = $("#flyarea").height();

let score = 0;

let highscore = 0;

let scoreFinal = 0;

let pipeheight = 90;

let pipewidth = 52;

let pipes = new Array();

let replayclickable = false;

let exitclicable = false;

// sounds

let volume = 30;

let soundJump = new buzz.sound("../../assets/sounds/sfx_wing.ogg");

let soundScore = new buzz.sound("../../assets/sounds/sfx_point.ogg");

let soundHit = new buzz.sound("../../assets/sounds/sfx_hit.ogg");

let soundDie = new buzz.sound("../../assets/sounds/sfx_die.ogg");

let soundSwoosh = new buzz.sound("../../assets/sounds/sfx_swooshing.ogg");

buzz.all().setVolume(volume);

// loops

let loopGameloop;

let loopPipeloop;

$(document).ready(function () {

  if (window.location.search === "?debug") {

    debugmode = false;

  }

  if (window.location.search === "?easy") {

    pipeheight = 200;

  }

  //pipeheight = 200;

  // get the highscore

  const savedscore = getCookie("highscore");

  if (savedscore !== "") {

    highscore = parseInt(savedscore);

  }

  // start with the splash screen

  showSplash();

});

// Handle space bar

$(document).keydown(function (e) {

  // space bar!

  if (e.keyCode === 32) {

    // in ScoreScreen, hitting space should click the "replay" button. else it's just a regular spacebar hit

    if (currentstate === states.ScoreScreen) {

      $("#replay").click();

    } else {

      screenClick();

    }

  }

});

// Handle mouse down OR touch start

if ("ontouchstart" in window) {

  $(document).on("touchstart", screenClick);

} else {

  $(document).on("mousedown", screenClick);

}

$("#replay").click(function () {

  

  // make sure we can only click once

  if (!replayclickable) {

    return;

  } else {

    replayclickable = false;

  }

  // SWOOSH!

  soundSwoosh.stop();

  soundSwoosh.play();

  // fade out the scoreboard

  $("#scoreboard").transition(

    { y: "-40px", opacity: 0 },

    1000,

    "ease",

    function () {

      // when that's done, display us back to nothing

      $("#scoreboard").css("display", "none");

      // start the game over!

      showSplash();

    }

  );

});

$("#exit").click(function () {

  

  // make sure we can only click once

  if (!exitclicable) {

    return;

  } else {

    exitclicable = false;

  }

});

const isIncompatible = {

  Android: function () {

    return navigator.userAgent.match(/Android/i);

  },

  BlackBerry: function () {

    return navigator.userAgent.match(/BlackBerry/i);

  },

  iOS: function () {

    return navigator.userAgent.match(/iPhone|iPad|iPod/i);

  },

  Opera: function () {

    return navigator.userAgent.match(/Opera Mini/i);

  },

  Safari: function () {

    return (

      navigator.userAgent.match(/OS X.*Safari/) &&

      !navigator.userAgent.match(/Chrome/)

    );

  },

  Windows: function () {

    return navigator.userAgent.match(/IEMobile/i);

  },

  any: function () {

    return (

      isIncompatible.Android() ||

      isIncompatible.BlackBerry() ||

      isIncompatible.iOS() ||

      isIncompatible.Opera() ||

      isIncompatible.Safari() ||

      isIncompatible.Windows()

    );

  }

};

function getCookie(cname) {

  const name = cname + "=";

  const ca = document.cookie.split(";");

  for (const row of ca) {

    const c = row.trim();

    if (c.indexOf(name) === 0) {

      return c.substring(name.length, c.length);

    }

  }

  return "";

}

function setCookie(cname, cvalue, exdays) {

  const d = new Date();

  d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);

  const expires = "expires=" + d["toGMTString"]();

  document.cookie = cname + "=" + cvalue + "; " + expires;

}

function showSplash() {

  

  currentstate = states.SplashScreen;

  // set the defaults (again)

  velocity = 0;

  position = 180;

  rotation = 0;

  score = 0;

  // update the player in preparation for the next game

  $("#player").css({ y: 0, x: 0 });

  updatePlayer($("#player"));

  soundSwoosh.stop();

  soundSwoosh.play();

  // clear out all the pipes if there are any

  $(".pipe").remove();

  pipes = new Array();

  // make everything animated again

  $(".animated").css("animation-play-state", "running");

  $(".animated").css("-webkit-animation-play-state", "running");

  // fade in the splash

  $("#splash").transition({ opacity: 1 }, 2000, "ease");

}

function startGame() {

  currentstate = states.GameScreen;

  // fade out the splash

  $("#splash").stop();

  $("#splash").transition({ opacity: 0 }, 500, "ease");

  // update the big score

  setBigScore();

  // debug mode?

  if (debugmode) {

    // show the bounding boxes

    $(".boundingbox").show();

  }

  // start up our loops

  const updaterate = 1000.0 / 60.0; // 60 times a second

  loopGameloop = setInterval(gameloop, updaterate);

  loopPipeloop = setInterval(updatePipes, 1400);

  // jump from the start!

  playerJump();

}

function updatePlayer(player) {

  // rotation

  rotation = Math.min((velocity / 10) * 90, 90);

  // apply rotation and position

  $(player).css({ rotate: rotation, top: position });

}

function gameloop() {

  var player = $("#player");

  //update the player speed/position

  velocity += gravity;

  position += velocity;

  //update the player

  updatePlayer(player);

  //create the bounding box

  var box = document.getElementById("player").getBoundingClientRect();

  var origwidth = 34.0;

  var origheight = 24.0;

  var boxwidth = origwidth - Math.sin(Math.abs(rotation) / 90) * 8;

  var boxheight = (origheight + box.height) / 2;

  var boxleft = (box.width - boxwidth) / 2 + box.left;

  var boxtop = (box.height - boxheight) / 2 + box.top;

  var boxright = boxleft + boxwidth;

  var boxbottom = boxtop + boxheight;

  //if we're in debug mode, draw the bounding box

  if (debugmode) {

    var boundingbox = $("#playerbox");

    boundingbox.css("left", boxleft);

    boundingbox.css("top", boxtop);

    boundingbox.css("height", boxheight);

    boundingbox.css("width", boxwidth);

  }

  //did we hit the ground?

  if (box.bottom >= $("#land").offset().top) {

    playerDead();

    return;

  }

  //have they tried to escape through the ceiling? :o

  var ceiling = $("#ceiling");

  if (boxtop <= ceiling.offset().top + ceiling.height()) position = 0;

  //we can't go any further without a pipe

  if (pipes[0] == null) return;

  //determine the bounding box of the next pipes inner area

  var nextpipe = pipes[0];

  var nextpipeupper = nextpipe.children(".pipe_upper");

  var pipetop = nextpipeupper.offset().top + nextpipeupper.height();

  var pipeleft = nextpipeupper.offset().left - 2; // for some reason it starts at the inner pipes offset, not the outer pipes.

  var piperight = pipeleft + pipewidth;

  var pipebottom = pipetop + pipeheight;

  if (debugmode) {

    var boundingbox = $("#pipebox");

    boundingbox.css("left", pipeleft);

    boundingbox.css("top", pipetop);

    boundingbox.css("height", pipeheight);

    boundingbox.css("width", pipewidth);

  }

  //have we gotten inside the pipe yet?

  if (boxright > pipeleft) {

    //we're within the pipe, have we passed between upper and lower pipes?

    if (boxtop > pipetop && boxbottom < pipebottom) {

      //yeah! we're within bounds

    } else {

      //no! we touched the pipe

      playerDead();

      return;

    }

  }

  //have we passed the imminent danger?

  if (boxleft > piperight) {

    //yes, remove it

    pipes.splice(0, 1);

    //and score a point

    playerScore();

  }

}

function screenClick() {

  

  if (currentstate === states.GameScreen) {

    playerJump();

  } else if (currentstate === states.SplashScreen) {

    startGame();

  }

}

function playerJump() {

  velocity = jump;

  // play jump sound

  soundJump.stop();

  soundJump.play();

}

function setBigScore(erase?) {

  const elemscore = $("#bigscore");

  elemscore.empty();

  if (erase) {

    return;

  }

  const digits = score.toString().split("");

  for (const row of digits) {

    elemscore.append(

      "<img src='../../assets/font_big_" + row + ".png' alt='" + row + "'>"

    );

  }

}

function setSmallScore() {

  const elemscore = $("#currentscore");

  elemscore.empty();

  const digits = score.toString().split("");

  for (const row of digits) {

    elemscore.append(

      "<img src='../../assets/font_small_" + row + ".png' alt='" + row + "'>"

    );

  }

}

function setHighScore() {

  const elemscore = $("#highscore");

  elemscore.empty();

  const digits = highscore.toString().split("");

  for (const row of digits) {

    elemscore.append(

      "<img src='../../assets/font_small_" + row + ".png' alt='" + row + "'>"

    );

  }

}

function setMedal() {

  const elemmedal = $("#medal");

  let medal;

  elemmedal.empty();

  if (score < 10) {

    // signal that no medal has been won

    return false;

  }

  if (score >= 10) {

    medal = "bronze";

  }

  if (score >= 20) {

    medal = "silver";

  }

  if (score >= 30) {

    medal = "gold";

  }

  if (score >= 40) {

    medal = "platinum";

  }

  elemmedal.append(

    "<img src='../../assets/medal_" + medal + ".png' alt='" + medal + "'>"

  );

  // signal that a medal has been won

  return true;

}

function playerDead() {

  numProtogemas = score * 10;

  //console.log('Número de protogemas a guanyar: '+numProtogemas);

  //this.sumarprotogemas((score * 10).toString());

  //scoreFinal = score * 10;

  // stop animating everything!

  $(".animated").css("animation-play-state", "paused");

  $(".animated").css("-webkit-animation-play-state", "paused");

  // drop the bird to the floor

  const playerbottom = $("#player").position().top + $("#player").width(); // we use width because he'll be rotated 90 deg

  const floor = flyArea;

  const movey = Math.max(0, floor - playerbottom);

  $("#player").transition(

    { y: movey + "px", rotate: 90 },

    1000,

    "easeInOutCubic"

  );

  // it's time to change states. as of now we're considered ScoreScreen to disable left click/flying

  currentstate = states.ScoreScreen;

  // destroy our gameloops

  clearInterval(loopGameloop);

  clearInterval(loopPipeloop);

  loopGameloop = null;

  loopPipeloop = null;

  // mobile browsers don't support buzz bindOnce event

  if (isIncompatible.any()) {

    // skip right to showing score

    showScore();

  } else {

    // play the hit sound (then the dead sound) and then show score

    soundHit.play().bindOnce("ended", function () {

      soundDie.play().bindOnce("ended", function () {

        showScore();

      });

    });

  }

  

}

function showScore() {

  // unhide us

  $("#scoreboard").css("display", "block");

  // remove the big score

  setBigScore(true);

  // have they beaten their high score?

  if (score > highscore) {

    // yeah!

    highscore = score;

    // save it!

    setCookie("highscore", highscore, 999);

  }

  // update the scoreboard

  setSmallScore();

  setHighScore();

  const wonmedal = setMedal();

  // SWOOSH!

  soundSwoosh.stop();

  soundSwoosh.play();

  // show the scoreboard

  $("#scoreboard").css({ y: "40px", opacity: 0 }); // move it down so we can slide it up

  $("#replay").css({ y: "40px", opacity: 0 });

  $("#exit").css({ y: "200px", opacity: 0 });

  $("#scoreboard").transition(

    { y: "0px", opacity: 1 },

    600,

    "ease",

    function () {

      // When the animation is done, animate in the replay button and SWOOSH!

      soundSwoosh.stop();

      soundSwoosh.play();

      $("#replay").transition({ y: "0px", opacity: 1 }, 600, "ease");

      $("#exit").transition({ y: "0px", opacity: 1 }, 600, "ease");

      // also animate in the MEDAL! WOO!

      if (wonmedal) {

        $("#medal").css({ scale: 2, opacity: 0 });

        $("#medal").transition({ opacity: 1, scale: 1 }, 1200, "ease");

      }

    }

  );

  // make the replay button clickable

  replayclickable = true;

  exitclicable = true;

  exitApretat = false;

}

function playerScore() {

  score += 1;

  // play score sound

  soundScore.stop();

  soundScore.play();

  setBigScore();

}

function updatePipes() {

  //console.log('entrant update pipes');

  // Do any pipes need removal?

  $(".pipe")

    .filter(function () {

      return $(this).position().left <= -100;

    })

    .remove();

  // add a new pipe (top height + bottom height  + pipeheight == flyArea) and put it in our tracker

  const padding = 80;

  const constraint = flyArea - pipeheight - padding * 2; // double padding (for top and bottom)

  const topheight = Math.floor(Math.random() * constraint + padding); // add lower padding

  const bottomheight = flyArea - pipeheight - topheight;

  const newpipe = $(

    "<div class='pipe animated'><div class='pipe_upper' style='height: " +

    topheight +

    "px;'></div><div class='pipe_lower' style='height: " +

    bottomheight +

    "px;'></div></div>"

  );

  //console.log('fly area: '+flyArea +' top height: ' + topheight + ' bottom height: '+ bottomheight);

  $("#flyarea").append(newpipe);

  //console.log('abans pipes push');

  pipes.push(newpipe);

  //console.log('despres pipes push');

}

}

}