--- title: Step 9 - Scoring Points slug: /step-9-scoring-points section: Tutorial --- # Step 9 - Scoring Points! Any good game needs points, so let's add some! First we'll add a score label and best score to our `Level` to keep track of the current score for us. Additionally we'll add an `incrementScore()` to up the value. We can use the browser's `localStorage` feature to keep track of our best score. ```typescript // level.ts export class Level extends ex.Scene { ... score: number = 0; best: number = 0; scoreLabel = new ex.Label({ text: 'Score: 0', x: 0, y: 0, z: 1, font: new ex.Font({ size: 20, color: ex.Color.White }) }); bestLabel = new ex.Label({ text: 'Best: 0', x: 400, y: 0, z: 1, font: new ex.Font({ size: 20, color: ex.Color.White, textAlign: ex.TextAlign.End }) }); onInitialize(engine: ex.Engine): void { ... this.add(this.scoreLabel); this.add(this.bestLabel); const bestScore = localStorage.getItem('bestScore'); if (bestScore) { this.best = +bestScore; this.setBestScore(this.best); } else { this.setBestScore(0); } } incrementScore() { this.scoreLabel.text = `Score: ${++this.score}`; this.setBestScore(this.score); } setBestScore(score: number) { if (score > this.best) { localStorage.setItem('bestScore', this.score.toString()); this.best = score; } this.bestLabel.text = `Best: ${this.best}`; } } ``` When our `Bird` flies between two pipes we want to increment the score. To do this will create a new file `score-trigger.ts` to detect this. ```typescript // score-trigger.ts export class ScoreTrigger extends ex.Actor { constructor(pos: ex.Vector, private level: Level) { super({ pos, width: 32, height: Config.PipeGap, anchor: ex.vec(0, 0), vel: ex.vec(-Config.PipeSpeed, 0) }) this.on('exitviewport', () => { this.kill(); }); } override onCollisionStart(): void { this.level.incrementScore(); } } ``` Now in our pipe factory we put these triggers in between our pipes, and add `ScoreTrigger` to our `reset()` and `stop()` routines ```typescript // pipe-factory.ts export class PipeFactory { ... spawnPipes() { ... const scoreTrigger = new ScoreTrigger( ex.vec( this.level.engine.screen.drawWidth, randomPipePosition), this.level ); this.level.add(scoreTrigger); } ... reset() { for (const actor of this.level.actors) { if (actor instanceof Pipe || actor instanceof ScoreTrigger ) { actor.kill(); } } } stop() { this.timer.stop(); for (const actor of this.level.actors) { if (actor instanceof Pipe || actor instanceof ScoreTrigger ) { actor.vel = ex.vec(0, 0); } } } } ``` You might notice that sometimes the score double counts sometimes! Well this is because the bird is using a box collider and is rotating into the score trigger! This is an easy fix, we'll switch to a circle collider in the bird. ```typescript // bird.ts export class Bird extends ex.Actor { ... constructor() { super({ pos: Config.BirdStartPos, // width: 16, // height: 16, radius: 8, color: ex.Color.Yellow }); } ... } ```