Guillaume D
Guillaume D

Reputation: 185

Problem occurs during code execution of setInterval loop

I'm facing a weird issue developping a 2D game in Angular.

the function in my component call an async function to load the sprites, then execute 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 which define the game loop GameService.ts:

  startGame(): void {
    this.score = 0;
    /* launch the loop every 10 miliseconds */
    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 which call the clearInterval 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 of the call the checkCollision function 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 problem is when the clearInterval is reached and the loop finish the code execution doesn't go out of the startGame method and i can't reach the code part outside the subscription in the AfterViewInit inside the component.

Upvotes: 1

Views: 103

Answers (1)

ForestG
ForestG

Reputation: 18123

Here is my solution for your problem: updated stackblitz example

I have created an EventEmitter, to which you can subscribe, in order to get the final score.

in the game.service.ts:

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 put any kind of information in here",
        score: this.score
      })
...

and in the app.component.ts:

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);
      })

Hope this is something you wanted to.

Upvotes: 1

Related Questions