Home > Enterprise >  There's no Gameloop in my P5js with Angular
There's no Gameloop in my P5js with Angular

Time:10-14

I am currently evaluating a Framework / Possibility to create a Game inside of an Angular Application. I have tried Canvas, now I want to use P5.

The Problem is, that it runs the whole draw function just once.


ngOnInit(): void {
    this.scrWidth = window.innerWidth;
    this.scrHeight = window.innerHeight;

    this.createCanvas();
  }

  private createCanvas() {
    const sketch = (s: p5) => {
      s.preload = () => {};

      s.setup = () => {
        s.frameRate(30);
        s.createCanvas(this.scrWidth, this.scrHeight - 10);
        s.background(50);

        this.objLayer = new ObjectLayer();

        this.player = new Player(
          this.scrHeight / 20, // Width (Using the screen height to scale the player)
          (this.scrHeight / 20) * 1.5, // Height (Using the screen height to scale the player)
          30, // X Starting Position
          30 // Y Starting Position
        );
        this.objLayer.children.push(this.player);
      };

      s.draw = () => {
        this.update(); //Updating states, coordinates, ..
        this.render(); // Drawing Objects to the sketch
      };
    };

    this.p5 = new p5(sketch.bind(this), this.container.nativeElement);
  }

I don't know if Angular is blocking the loop in someway, or if I just made a mistake. unfortunately, there's almost no help on the internet for using P5.js with Angular/Typescript.

I am very thankful for any ideas.

CodePudding user response:

I cannot reproduce your problem. You haven't provided enough of your code to constitute a minimal reproducible example. Here's the complete code of a working Angular 12 component:

import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';
import p5 from 'p5';

class Ball {
  public x: number;
  public y: number;
  public velocity: p5.Vector;
  public radius: number;

  constructor(x: number, y: number, velocity: p5.Vector, radius: number = 20) {
    this.x = x;
    this.y = y;
    this.velocity = velocity;
    this.radius = radius;
  }

  public render(p: p5) {
    p.circle(this.x, this.y, this.radius);
  }

  public update(p: p5) {
    // update position
    this.x  = this.velocity.x * (p.deltaTime / 1000);
    this.y  = this.velocity.y * (p.deltaTime / 1000)
    
    // check for collisions
    if (this.x < this.radius) {
      // Collision with the left hand edge of the "room" reverses the horizontal component of the velocity
      this.velocity.x *= -1;
      this.x = this.radius   (this.radius - this.x);
    } else if (this.x > p.width - this.radius) {
      this.velocity.x *= -1;
      this.x = p.width - this.radius - (this.x - (p.width - this.radius));
    }
    if (this.y < this.radius) {
      this.velocity.y *= -1;
      this.y = this.radius   (this.radius - this.y);
    } else if (this.y > p.height - this.radius) {
      this.velocity.y *= -1;
      this.y = p.height - this.radius - (this.y - (p.height - this.radius));
    }
  }
}

@Component({
  selector: 'app-p5js-sample',
  templateUrl: './p5js-sample.component.html',
  styleUrls: ['./p5js-sample.component.css']
})
export class P5jsSampleComponent {
  public instance?: p5;
  public ball?: Ball;

  @ViewChild('container')
  public container?: ElementRef<HTMLDivElement>;

  constructor() { }

  // Switched to ngAfterViewInit instead of ngOnInit just to support
  // the parent element for the sketch (not strictly necessary)
  ngAfterViewInit(): void {
    this.createSketch();
  }

  private createSketch() {
    const sketch = (p: p5) => {
      p.setup = () => {
        p.createCanvas(p.windowWidth - 20, p.windowHeight - 50);
        p.ellipseMode(p.RADIUS);
        p.fill('green');

        this.ball = new Ball(
          p.random(20, p.width - 20),
          p.random(20, p.height - 20),
          p.createVector(100, 0).rotate(p.random(0, p.TWO_PI))
        );
      };

      p.draw = () => {
        p.background(0);
        if (this.ball) {
          this.ball.update(p);
          this.ball.render(p);
        }
      };
    };
    
    this.instance = new p5(
      // this bind is not necessary
      sketch.bind(this),
      // Specifying a parent element is good practice, but is also
      // not strictly necessary
      this.container?.nativeElement
    );
  }
}

The complete, runnable example can be found here: https://replit.com/@KumuPaul/Angular-P5js-Sample

CodePudding user response:

I found a solution myself. It was my fault and yes I provided to less code. I actually was sure, that the mistake is not on my side, because there where no errors and it seemed like I did everything wrong.

In my class for the player, I created a draw function. This draw function was written wrong, because I recalled the draw function from P5js. Because of that my Player was rendered but the loop broke.

That's how it was:

  public draw(p: p5) {
    s.draw = () => {
      p.fill(255);
      p.rect(this.x, this.y, this.width, this.height);
    }
  }

That's how it works:

  public draw(p: p5) {
    p.fill(255);
    p.rect(this.x, this.y, this.width, this.height);
  }
  • Related