Step 14 - Ground Graphics
Finally the ground graphics, feel free to use and remix.
We want the ground to tile and repeat horizontally we can take advantage of the ex.ImageWrapping.Repeat
to accomplish this
typescript
// resources.tsexport const Resources = {// Relative to /public in vite...GroundImage: new ex.ImageSource('./images/ground.png', {wrapping: ex.ImageWrapping.Repeat})} as const;
typescript
// resources.tsexport const Resources = {// Relative to /public in vite...GroundImage: new ex.ImageSource('./images/ground.png', {wrapping: ex.ImageWrapping.Repeat})} as const;
When the ex.ImageWrapping.Repeat
mode is set, specifying a bigger sourceView
than the original image has a tiling effect, the original image gets repeated over and over.
typescript
// ground.tsonInitialize(engine: ex.Engine): void {this.groundSprite.sourceView.width = engine.screen.drawWidth;this.groundSprite.destSize.width = engine.screen.drawWidth;this.graphics.use(this.groundSprite);}
typescript
// ground.tsonInitialize(engine: ex.Engine): void {this.groundSprite.sourceView.width = engine.screen.drawWidth;this.groundSprite.destSize.width = engine.screen.drawWidth;this.graphics.use(this.groundSprite);}
To make the ground appear scroll to the left, we can do a nifty trick to move the sourceView.x
by the speed of our Pipe
typescript
onPostUpdate(_engine: ex.Engine, elapsedMs: number): void {if (!this.moving) return;this.groundSprite.sourceView.x += Config.PipeSpeed * (elapsedMs / 1000);this.groundSprite.sourceView.x = this.groundSprite.sourceView.x % Resources.GroundImage.width;}
typescript
onPostUpdate(_engine: ex.Engine, elapsedMs: number): void {if (!this.moving) return;this.groundSprite.sourceView.x += Config.PipeSpeed * (elapsedMs / 1000);this.groundSprite.sourceView.x = this.groundSprite.sourceView.x % Resources.GroundImage.width;}
Putting it all together
typescript
// ground.tsexport class Ground extends ex.Actor {groundSprite = Resources.GroundImage.toSprite();moving = false;constructor(pos: ex.Vector) {super({pos,anchor: ex.vec(0, 0),height: 64,width: 400,z: 1})}onInitialize(engine: ex.Engine): void {this.groundSprite.sourceView.width = engine.screen.drawWidth;this.groundSprite.destSize.width = engine.screen.drawWidth;this.graphics.use(this.groundSprite);}onPostUpdate(_engine: ex.Engine, elapsedMs: number): void {if (!this.moving) return;this.groundSprite.sourceView.x += Config.PipeSpeed * (elapsedMs / 1000);this.groundSprite.sourceView.x = this.groundSprite.sourceView.x % Resources.GroundImage.width;}start() {this.moving = true;}stop() {this.moving = false;}}
typescript
// ground.tsexport class Ground extends ex.Actor {groundSprite = Resources.GroundImage.toSprite();moving = false;constructor(pos: ex.Vector) {super({pos,anchor: ex.vec(0, 0),height: 64,width: 400,z: 1})}onInitialize(engine: ex.Engine): void {this.groundSprite.sourceView.width = engine.screen.drawWidth;this.groundSprite.destSize.width = engine.screen.drawWidth;this.graphics.use(this.groundSprite);}onPostUpdate(_engine: ex.Engine, elapsedMs: number): void {if (!this.moving) return;this.groundSprite.sourceView.x += Config.PipeSpeed * (elapsedMs / 1000);this.groundSprite.sourceView.x = this.groundSprite.sourceView.x % Resources.GroundImage.width;}start() {this.moving = true;}stop() {this.moving = false;}}