1
votes

I have been following this tutorial, https://learn.yorkcs.com/2019/02/07/build-a-space-shooter-with-phaser-3-3/ , to make games with Phaser 3 but since I want to deploy them online I'm converting the code to use with TypeScript as I am preparing it via an Ionic 5 app. In the tutorial, I'm supposed to set a player sprite's velocity. For clarity, there are two classes I must create, Entities.js (which I created as entities.ts) and Player.js (which I made into player.ts). The entities are supposed to be an extension of Phaser.GameObjects.Sprite, and the player is supposed to be an entity, extending the entities class. So far, I get everything working except when reaching the part about setting the player's velocity.

This is my entities.ts:

class Entity extends Phaser.GameObjects.Sprite {
  constructor(scene, x, y, key, type) {
    super(scene, x, y, key);

    this.scene = scene;
    this.scene.add.existing(this);
    this.scene.physics.world.enableBody(this, 0);
    this.setData('type', type);
    this.setData('isDead', false);
  }
}

And this is my player.ts:

class Player extends Entity {
  constructor(scene, x, y, key) {
    super(scene, x, y, key, 'Player');

    this.setData('speed', 200);
    this.play('sprPlayer');
  }

  moveUp() {
    this.body.velocity.y = -this.getData('speed');
  }

  moveDown() {
    this.body.velocity.y = this.getData('speed');
  }

  moveLeft() {
    this.body.velocity.x = -this.getData('speed');
  }

  moveRight() {
    this.body.velocity.x = this.getData('speed');
  }

  update() {
    this.body.setVelocity(0, 0);
  }
}

Once I write the line, this.body.setVelocity(0, 0), I get an error: Property 'setVelocity' does not exist on type 'Body | StaticBody | BodyType'. Property 'setVelocity' does not exist on type 'StaticBody'. Apparently the body of a sprite can be used for either a Body, StaticBody, or BodyType object. Checking on the documentation, the Body class https://photonstorm.github.io/phaser3-docs/Phaser.Physics.Arcade.Body.html allows for the setVelocity function to happen, whereas the StaticBody one https://photonstorm.github.io/phaser3-docs/Phaser.Physics.Arcade.StaticBody.html doesn't.

Is it that TypeScript expects for each of the possible types to support the function to be used? If so, is there a way for me to specify what type of body I'm using? I tried parsing to no avail.

Now, I think there may be a way to specify Ionic I wish to develop in plain JavaScript https://uptoskill.com/ionic-react-javascript/ , but without resorting to that, is there a way to specify which type from the union I wish to use in my function calls? Please let me know, and thanks for the help.

2
Please consider modifying the code here to constitute a self-contained minimal reproducible example suitable for dropping into a standalone IDE like The TypeScript Playground, and/or a link to a web IDE that demonstrates the issue. Right now someone either has to spend time/effort getting this set up in their own environment or else give you an answer they haven't tested themselves. Good luck! - jcalz
I'll try to reproduce this and will comment back with a github repo link - gfcf14
A GitHub repo isn’t a web IDE, unfortunately. Consider something like codesandbox, the TS Playground, stackblitz, etc. The idea is to reduce the effort needed for someone to reproduce your issue. Also note that you should make the example minimal; pull out everything unrelated to the problem you’re having. Good luck! - jcalz
I mean that’d be nice, and I could look that up. But if I can’t find an online tool that runs in the way you describe but for Ionic, then it’ll have to be a repo. - gfcf14
Sure, and maybe someone will be able to use that to help you, but I for one could not commit to installing a repo in my own environment to answer a SO question. Your question is tagged with ionic-framework so maybe someone already has this environment set up and has insight about it. Still, I suspect this has less to do with ionic and more to do with discriminating union types in TypeScript... and that you could reproduce your issue with toy versions of the classes/types in question, without requiring anything other than pure TypeScript. - jcalz

2 Answers

3
votes

The error message indicates that your player body is one of these types 'Body | StaticBody | BodyType' but StaticBody does not have a setVelocity method. Typescript has the concept of typeguards to handle this situtation, where you work with union types that have different members.

The solution here, is to check if the this.body has a setVolicity function.

update() {
    // when true typescript know it is not a StaticBody
    if ("setVelocity" in this.body)
    this.body.setVelocity(0, 0);
  }

You could also define a custom typeguard function and use it inside the if statement like this:

//custom typeguard function with the return type 'body is Body'    
function isBody(body: Body | StaticBody): body is Body {
  return (body as Body).setVelocity !== undefined;
}

if (isBody(this.body)) {
  this.body.setVelocity(5); 
}
0
votes

As explained by jcalz, the answer was to test if the object in question is an instance of the class that contains the function to call. In other words, to ensure that we wish to use Body and not StaticBody. This could have been done by simply checking if the function exists in the object:

if('setVelocity' in this.body) {
  this.body.setVelocity(0, 0);
}

More specifically, we could check if the object is an instance of the object expected, via:

if(this.body instanceof Phaser.Physics.Arcade.Body) {
  this.body.setVelocity(0, 0);
}