1

So i'm making a html canvas game in angular that will have lots of script files and I want to make it with optimal readability and performance.

Here is my code so far:

import { Component, OnInit } from '@angular/core';
import { Player } from './scripts/entities';
declare let $: any;

@Component({
  selector: 'app-game-screen',
  templateUrl: './game-screen.component.html',
  styleUrls: ['./game-screen.component.scss']
})
export class GameScreenComponent implements OnInit {

  constructor() { }

  ngOnInit() {
    //Draw canvas
    let sw = $("#container").width(); // Screen width
    let sh = $("#container").height(); // Screen height

    //Player canvas
    let canvas: any = document.querySelector("#gameScreen");
    canvas.width = sw;
    canvas.height = sh;
    let ctx = canvas.getContext("2d");

    //Test canvas
    let testCanvas: any = document.querySelector("#testScreen");
    testCanvas.width = sw;
    testCanvas.height = sh;
    let test = testCanvas.getContext("2d");

    //function to clear canvas
    function clearCanvas(screen) {
      screen.clearRect(0, 0, canvas.width, canvas.height);
    }
    //!Draw canvas

    // Entities - player, enemies, bosses
    const player = new Player('Player', sw / 2, sh / 2, sw / 10, sh / 7, ctx);
    player.draw();

    const posMarker = new Player('Position indicator', sw / 2, sh / 2, 5, 5, test);
    posMarker.boxColor = 'red';
    posMarker.draw();

    // ! Entities - player, enemies, bosses

    //Controls
    document.addEventListener('keydown', keyDownHandler, false);
    document.addEventListener('keyup', keyUpHandler, false);

    let rightPressed = false;
    let leftPressed = false;
    let upPressed = false;
    let downPressed = false;

    function keyDownHandler(event) {
      if (event.keyCode == 39) {
        rightPressed = true;
      }
      else if (event.keyCode == 37) {
        leftPressed = true;
      }
      if (event.keyCode == 40) {
        downPressed = true;
      }
      else if (event.keyCode == 38) {
        upPressed = true;
      }
    }

    function keyUpHandler(event) {
      if (event.keyCode == 39) {
        rightPressed = false;
      }
      else if (event.keyCode == 37) {
        leftPressed = false;
      }
      if (event.keyCode == 40) {
        downPressed = false;
      }
      else if (event.keyCode == 38) {
        upPressed = false;
      }
    }

    function controlMove() {
      clearCanvas(ctx);
      if (rightPressed) {
        player.x += 10;
      }
      else if (leftPressed) {
        player.x -= player.speed;
      }
      if (downPressed) {
        player.y += player.speed;
      }
      else if (upPressed) {
        player.y -= player.speed;
      }
      //Border limitations
      if (player.x - player.w / 2 < 0) { player.x = player.w / 2 }
      if (player.x + player.w / 2 > sw) { player.x = sw - player.w / 2 }
      if (player.y - player.h / 2 < 0) { player.y = player.h / 2 }
      if (player.y + player.h / 2 > sh) { player.y = sh - player.h / 2 }
      //!Border limitations
      player.draw();
      requestAnimationFrame(controlMove);
    }
    controlMove();
    // ! Controls

  }

}

Let's say i want this whole part about controls in another external file. How would I go on about doing that?

    //Controls
    document.addEventListener('keydown', keyDownHandler, false);
    document.addEventListener('keyup', keyUpHandler, false);

    let rightPressed = false;
    let leftPressed = false;
    let upPressed = false;
    let downPressed = false;

    function keyDownHandler(event) {
      if (event.keyCode == 39) {
        rightPressed = true;
      }
      else if (event.keyCode == 37) {
        leftPressed = true;
      }
      if (event.keyCode == 40) {
        downPressed = true;
      }
      else if (event.keyCode == 38) {
        upPressed = true;
      }
    }

    function keyUpHandler(event) {
      if (event.keyCode == 39) {
        rightPressed = false;
      }
      else if (event.keyCode == 37) {
        leftPressed = false;
      }
      if (event.keyCode == 40) {
        downPressed = false;
      }
      else if (event.keyCode == 38) {
        upPressed = false;
      }
    }

    function controlMove() {
      clearCanvas(ctx);
      if (rightPressed) {
        player.x += 10;
      }
      else if (leftPressed) {
        player.x -= player.speed;
      }
      if (downPressed) {
        player.y += player.speed;
      }
      else if (upPressed) {
        player.y -= player.speed;
      }
      //Border limitations
      if (player.x - player.w / 2 < 0) { player.x = player.w / 2 }
      if (player.x + player.w / 2 > sw) { player.x = sw - player.w / 2 }
      if (player.y - player.h / 2 < 0) { player.y = player.h / 2 }
      if (player.y + player.h / 2 > sh) { player.y = sh - player.h / 2 }
      //!Border limitations
      player.draw();
      requestAnimationFrame(controlMove);
    }
    controlMove();
    // ! Controls

What do I do about my functions referencing variables like player.x and player.y (while trying to maintain performance)?

And is it possible to initialize these event listeners somehow other than in the main file, to reduce clutter.

document.addEventListener('keydown', keyDownHandler, false);
document.addEventListener('keyup', keyUpHandler, false);

1 Answer 1

1

1st of all, use the OnPush change detection strategy. Especially in a game in which you want to optimize performance.

@Component({
  selector: 'app-game-screen',
  templateUrl: './game-screen.component.html',
  styleUrls: ['./game-screen.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class GameScreenComponent implements OnInit {

This might require you to trigger change detection yourself on some occasions, so you better have a look at this article, which explains it.

https://blog.thoughtram.io/angular/2016/02/22/angular-2-change-detection-explained.html

If you want to separate the controls into a separate file, then you should probably just make a one singleton service (aka. GameStore) that holds your player.x and player.y and other app wide data and then another service, which accesses GameStore-s player values, detects or waits for notification of keystrokes and handles them (aka. GameController).

I usually use Observables in my Stores, aka.

export class GameStoreService {

    private _player: BehaviorSubject<PlayerModel> = new BehaviorSubject(null);

    setPlayer( _player: PlayerModel ) {
        this._player.next( _player );
    }

    get player() {
        return this._player.asObservable();
    }
}

Which anyone can subscribe to and push to.

Concerning the listeners in anything other than the main file

document.addEventListener('keydown', keyDownHandler, false);
document.addEventListener('keyup', keyUpHandler, false);

Do use HostListeners for these, but you cannot set them in any file, I think this SO thread had a good explanation of what's going on

Is it possible to use HostListener in a Service?

Sign up to request clarification or add additional context in comments.

3 Comments

Additional question: Should I drop angular and just use plain js and maybe jquery since now, that I think of it, I don't really know if i have any benefits using angular for making a game.
I haven't made any games on Angular, but I guess if you do not know angular, then the learning curve will be rather large, compared to jQuery and regular JS. So ask yourself, if you want to spend time learning angular and rewriting your app a few times, because you made an anti-angular-pattern mess of a project. Instead of writing your game. And this is not a negative thing, so to speak, but if you are just looking for an evening project, where you can focus on building the game, not handling the framework, then you might think twice about angular. - I am a professional Angular2 developer.
And off the records, it is a great framework. I definately endorse it!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.