Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/excaliburjs/Excalibur. 🎮 Your friendly TypeScript 2D game engine for the web 🗡️ excaliburjs.com
excalibur excaliburjs game-development game-engine game-framework gamedev games html5-canvas typescript
Something went wrong. Try again.
3.8 kB · 164 lines
MDX
at Graph
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165---title: Step 9 - Scoring Pointsslug: /step-9-scoring-pointssection: 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.tsexport 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.tsexport 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 }); } ...}
```