Intro
Hi. This will be a very short intro for the very basic tutorial in angular. We will develop a very simple idle game, that shows how we can use Angular with NGRX and RXJS, but it will touch a few different aspects of the app as well.
Plan
The goal is to create a game with basic idle/click game functionality: gain by click, gain by time, gain by idle, bonuses, perks, improvements, etc. Only necessary text and a lot of code, with repo as a source. Everything based in angular 10 and bootstrap 4 CSS to not reinvent the wheel for basic components.
Because of recent presidential elections in Poland, I'm a bit disappointed, this game will be about a politician that wants to be a president. We will incrementally improve the complexity of the game, but we will start very simple.
Preparation
Initialize the app
First, install Angular CLI if you don't have it yet
npm i -g @angular/cli
Then just start the project and follow instructions
ng new idle
a value and then it
Then, add bootstrap to our project.
npm i bootstrap
...and include it in angular.json
so the CSS classes will be accessible inside your IDE. We need new entry in projects\[project-name]\architect\build\options\scripts
so the angular.json
will look like this:
{
...
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/idle",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": true,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"./node_modules/bootstrap/scss/bootstrap.scss",
"src/styles.scss"
],
"scripts": []
},
...
}
Finally, let's add bootstrap CDN to the <head>
element in the index.html
file
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
Icons
For icons, we will use font-awesome@4
since it's free. However, you can use whatever you want.
npm i font-awesome@4
Then we need to add it to angular.json
in the same way as bootstrap.scss
Basic template
We will use mainly app.component.html
and child components for now. So let's create it quickly:
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="#"><i class="fa fa-gamepad" aria-hidden="true"></i> Idle</a>
</div>
</nav>
<div class="container">
container
</div>
Let's go!
Finally, the meat.
Value display component
We will need a simple component that will display the value of some resources (cash, influence, popularity etc). We assume that there will be a few of them to illustrate the data, so we want to specify a color and icon for each. So let's create it first with the CLI
command:
ng generate component components/value-display --skip-tests
We won't write tests for that app, although it could be interesting, I want to focus on a different aspect of the angular app.
And let's fill it out:
// value-display.component.html
import { Component, OnInit, Input } from '@angular/core';
import { Color as COLOR } from '../../types';
@Component({
selector: 'app-value-display',
templateUrl: './value-display.component.html',
styleUrls: ['./value-display.component.scss']
})
export class ValueDisplayComponent implements OnInit {
@Input() title: string;
@Input() color: COLOR = COLOR.primary;
@Input() icon: string;
@Input() value: number;
constructor() { }
ngOnInit(): void {
}
getTitle() {
return this.icon ? `<i class="fa fa-${this.icon}></i> ${this.title}` : this.title;
}
getText() {
return this.value;
}
}
<!-- value-display.component.html -->
<div class="card my-3" [ngClass]="'bg-' + color" >
<div class="card-header">
<i *ngIf="icon" class="fa" [ngClass]="'fa-' + icon"></i> {{ title }}
</div>
<div class="card-body">
<p class="card-title" [innerHTML]="getText()"></p>
<p class="card-text small"><ng-content></ng-content></p>
</div>
</div>
Engine
We will need to control the time for a few purposes. So for now, we will create an engine.service.ts
that will take care of that.
ng g s engine --no-spec
import { Injectable } from '@angular/core';
import { interval, Subscription, Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class EngineService {
time$: Observable<number> = interval(1000);
constructor() { }
}
We also need to add it to app.module
into providers
array.
Then we can update our app.component
export class AppComponent implements OnDestroy {
time = 0;
subscriptions: Subscription[] = [];
constructor(private engine: EngineService) {
this.subscriptions.push(this.engine.time$.subscribe(time => {
this.time = time;
}));
}
ngOnDestroy(): void {
this.subscriptions.map(subscription => subscription.unsubscribe());
}
}
And then update the app.component
markup:
...
<app-value-display class="col-4" [icon]="'clock-o'" [title]="'time'" [value]="time" [color]="'warning'">
time goes by
</app-value-display>
...
And voila!
Summary
You can get the codebase from github. If you have any ideas on how the game could look like, or any other question, please let me know in the comments!
Discussion