首页 > 解决方案 > 在 setInterval 循环的代码执行期间出现问题

问题描述

我在 Angular 中开发 2D 游戏时遇到了一个奇怪的问题。

我的组件中的函数调用异步函数来加载精灵,然后在回调 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;
    }
  }

我的游戏服务类中定义游戏循环 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();
  }

调用 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');

    }
  }

调用checkCollision函数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);
      }
    });
  }

我们在组件的回调中加载游戏的 EventEmitter 的定义:

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

问题是当达到 clearInterval 并且循环完成时,代码执行不会超出 startGame 方法,并且我无法到达组件内 AfterViewInit 中订阅之外的代码部分。

标签: angulartypescript

解决方案


这是我对您的问题的解决方案:更新的 stackblitz 示例

我创建了一个 EventEmitter,您可以订阅它,以获得最终分数。

在 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
      })
...

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

希望这是你想要的。


推荐阅读