angular - 在 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 中订阅之外的代码部分。
解决方案
这是我对您的问题的解决方案:更新的 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);
})
希望这是你想要的。
推荐阅读
- python - How To Edit ManyToManyField In Django Admin list Display Page?
- roku - Use LabelList or MarkupList to render two labels for each content node?
- python - Pandas groupby find common strings
- c# - How to get ApplicationDbContext instance in AccountController for ASP .NET Core 2.0 With Individual Authentication?
- selenium - how to execute Cucumber Step defination with TestNG annotation
- opencv - 当我尝试使用 opencv 一起显示 2 个图像时
- axis2 - AxisFault at org.apache.axis2.AxisFault.makeFault
- gtk - What's the difference between functions starting with G_ and GTK_?
- java - Java Jersey:在主对象和 Web 服务之间共享数据的最佳方式是什么
- android - ContentCatcher:无法通知 WebView