Error happens while running the setInterval loop in the code execution

I encountered a peculiar issue while developing a 2D game in Angular.

The function in my component calls an async function to load the sprites, then executes the game loop in the callback GameComponent.ts:

  constructor(private loader: AppService, private game: GameService, private 
              score: ScoreService) {}

  ngAfterViewInit(): void {
    this.loader.createGameEnvironment(this.canvas.nativeElement);
    this.subscribed = this.loader.getAssetsLoadedEmitter().subscribe(() => {
      this.game.startGame();
      this.lastScore = this.game.score;
      console.log(this.userScore._id);
    });
    console.log(this.userScore._id);
    if (this.userScore._id !== undefined) {
      this.userScore.score = this.lastScore;
      this.score.updateScore(this.userScore).subscribe( () => {
        console.log('score updated successfully: ' + this.userScore.score);
      });
    } else {
      this.showModal = true;
    }
  }

The function in my game service class defines the game loop GameService.ts:

  startGame(): void {
    this.score = 0;
    /* Launch the loop every 10 milliseconds */
    this.gameLoop = setInterval(() => {
      this.suffleProperties();
      this.cleanCanvas();
      this.renderBackground();
      this.createObstacles();
      this.moveObstacles();
      this.createPlayer();
      this.updateScore();
      console.log(this.score);
    }, 10);
    // window.location.reload();
  }

The function that calls the clearInterval is in GameService.ts:

  checkCollision(obstacle: Obstacles): void {
    if (((this.player.x + CONFIG.playerCar.width > obstacle.x) && (this.player.y < obstacle.y + obstacle.height)) &&
        ((this.player.x < obstacle.x + obstacle.width) && (this.player.y < obstacle.y + obstacle.height)) &&
        ((this.player.x + CONFIG.playerCar.width > obstacle.x) && (this.player.y + CONFIG.playerCar.height > obstacle.y)) &&
        ((this.player.x < obstacle.x + obstacle.width) && (this.player.y + CONFIG.playerCar.height > obstacle.y))) {
      clearInterval(this.gameLoop);
      alert('Game Over');
    }
  }

The entry point where we call the checkCollision function in GameService.ts:

  moveObstacles(): void {
    this.obstacles.forEach((element: Obstacles, index: number) => {
      element.y += 3;
      element.update();
      this.checkCollision(element);
      if (element.y > this.height) {
        this.obstacles.splice(index, 1);
      }
    });
  }

Definition of the EventEmitter where we load the game in the callback in the component:

export class AppService {

isAssetsLoaded: EventEmitter<number> = new EventEmitter();

  constructor(private game: GameService) { }

  createGameEnvironment(canvasElement): void {
    this.game.loadSpritesAssets(canvasElement).then( () => {
      this.isAssetsLoaded.emit();
    });
  }

  getAssetsLoadedEmitter(): EventEmitter<number> {
    return this.isAssetsLoaded;
  }

The issue arises when the clearInterval is reached and the loop finishes, the code execution does not exit the startGame method, and I cannot reach the code part outside the subscription in the AfterViewInit inside the component.

Answer №1

Here's a solution I've come up with for your issue: check out the updated example

I've implemented an EventEmitter that you can subscribe to in order to receive the final score.

Within the game.service.ts file:

export interface IGameEndData{
  message: string;
  score: number;
}

@Injectable()
export class GameService {
 gameEndEvent = new EventEmitter<IGameEndData>();

 checkCount(): void {
    if (this.count === 10) {
      clearInterval(this.gameLoop);
      console.log('Game Over');
      this.gameEndEvent.emit({
        message: "You can add any relevant information here",
        score: this.score
      })
...

and in the app.component.ts file:

ngAfterViewInit(): void {
    this.loader.createGameEnvironment(this.canvas.nativeElement);
    this.subscribed = this.loader.getAssetsLoadedEmitter().subscribe(() => {
      this.game.startGame();

      this.game.gameEndEvent.subscribe((endData:IGameEndData)=>{
        console.log("endData: ", endData);
        console.log("setting the current score as last score:");
        this.lastScore.score = endData.score;
        console.log("last score object:", this.lastScore);
      })

I hope this meets your requirements.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What could be the reason behind Cors preventing my API request?

Currently, I am in the process of developing a project that requires me to access an API that I have created. const endpoint = 'localhost:3000/api/v1/'; const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'appl ...

Methods for invoking a JavaScript function from TypeScript within an Angular2 application

Hey there! I'm looking to execute a regular JavaScript function from a TypeScript file. Let's say I have a JavaScript file called test.js and it's been imported into the index.html of my application. Now, I want to invoke the test() functi ...

Using RxJS with Angular to intercept the valueChanges of a FormControl prior to subscribing

I decided to create a new observable using the values emitted by the FormControls.valueChanges observable. This creation of the observable takes place within the ngOnInit method in the following manner: ngOnInit(): void { this.myObservable$ = combine ...

In Angular 4, I encountered an issue where adjusting the height of the navigation bar caused the toggle button to no longer expand the menu in Bootstrap

In the process of developing an angular application, I encountered a situation where I needed to adjust the height of the nav bar using style properties. After making the necessary changes, everything was working fine. However, a problem arose when I mini ...

Encapsulate the module function and modify its output

I am currently utilizing the node-i18n-iso-countries package and I need to customize the getNames function in order to accommodate a new country name that I wish to include. At the moment, I am achieving this by using an if-else statement like so: let cou ...

Tips to successfully save and retrieve a state from storage

I've encountered a challenge while working on my Angular 14 and Ionic 6 app. I want to implement a "Welcome" screen that only appears the first time a user opens the app, and never again after that. I'm struggling to figure out how to save the s ...

"Exploring the method to navigate through a nested Firebase collection linked to its parent collection

I have a forum application in development where users can ask questions and receive answers, each answer having its own 'like' feature. I am trying to access the 'likes' subcollection when viewing an answer, but I am unsure of how to do ...

How can I convert duplicate code into a function in JavaScript?

I have successfully bound values to a view in my code, but I am concerned about the duplicate nested forEach loops that are currently present. I anticipate that Sonarcube will flag this as redundant code. Can anyone advise me on how to refactor this to avo ...

Restrict the keys to only properties that have an array data type

Is there a way to limit the keyof operator to only accept keys of a specified type in TypeScript? interface Data { items: string[]; name: string; } // I want to restrict the keyof operator to only allow keys where the value is of type `F` type Key&l ...

The element did not match the Angular Routing selector "app-home"

How can I prevent my initial component from being loaded twice in Angular? I am trying to implement a default/empty component to avoid the AppComponent being loaded within itself. The empty component would serve as the starting point for loading other comp ...

Using ngModel to Enhance Ionic Forms

I've encountered an issue with mapping a form to a model object. Once I include [[ngModel]] in the ion-input, the page fails to load without any errors. html <ion-input type="text" [(ngModel)]="personModel.username" formControlName="username" id= ...

"Encountered a problem when trying to access properties within a

Struggling to access properties of a nested object in TypeScript while using Angular, I encountered the following error: Object is possibly 'undefined'. Here is the code snippet: export interface Address{ city?: string; neighborhood?: string; } ...

Delete one item from a group of objects[]

In my TypeScript code, I have a declared object like this: public profileDataSource: { Value: string, Key: number }[]; This results in an object structure that looks similar to the following: 0: Object {Value: "<Select Profile>", Key: null} ...

Can you explain what exactly zone turns refer to?

I recently came across an error message in my Angular 2 application that read: WARNING: your application is taking longer than 2000 Zone turns. This got me thinking, what exactly are 'zone turns' and why does the warning trigger when it exceed ...

Tips for reusing a Jest mock for react-router's useHistory

When testing my code, I set up a mock for the useHistory hook from react-router-dom like this: jest.mock("react-router-dom", () => ({ useHistory: () => ({ length: 13, push: jest.fn(), block: jest.fn(), createHref: jest.fn(), go ...

Is it necessary to list all potential strings for accessibilityRole?

When working with accessibilityRole in React Native, I am wondering if there is a way to import all the possible strings instead of typing them out manually. createAccessibilityRole(parent: Element): string { if(isLink) return 'link' return ...

Encountering a Typescript error when attempting to access the 'submitter' property on type 'Event' in order to retrieve a value in a |REACT| application

I am facing an issue with my React form that contains two submit buttons which need to hit different endpoints using Axios. When I attempt to retrieve the value of the form submitter (to determine which endpoint to target), I encounter an error while work ...

Accessing the value of an object nested within another object in Angular

I have encountered numerous similar topics, but after going through all of them, I still cannot pinpoint what I am doing incorrectly. The data I retrieve is from DEXIE (indexedDB) where my record is stored in the following format: async addRequestToLocalD ...

Combining Rollup, Typescript, and converting images to base64 during the loading process

Having trouble preloading an image with Rollup. None of the solutions that should work seem to be effective, and I can't figure out why. Has anyone successfully managed to make this work? Here is my configuration in rollup.config.js: import image fr ...

Anticipated that 'styles' would comprise an array of strings in Angular2

Whenever I encounter this issue Uncaught Error: Expected 'styles' to be an array of strings. Below is my code example styleUrls:[ "../../styles/login.component.styles.scss" ], Interestingly, when I declare them in a similar manner but ...