ChetD90

How do I get a character to enter a building?

Recommended Posts

I am making a top down RPG styled game using Tiled and Phaser 3. I have already made a map in Tiled for the city and store. Also, I have already set the objects for the location of the store where the player is suppose to go in order to enter the store and the location where the player is supposed to appear. The thing I am having trouble figuring out the code I am suppose to use in order to facilitate this action, as well as going back to city map. One more thing, If there are any other ideas on how to go about this I am all ears.

Share this post


Link to post
Share on other sites

I have yet to do that myself. 

 

An idea would be to have one scene for the outside world, and another for the inside world. When entering the tile for a transition to the inside of a building, launch that scene so that it may load the new map.

Of course it is more complicated than this, but its a start.

 

I recommend going over the tile map in the API if you haven't.   

https://photonstorm.github.io/phaser3-docs/Phaser.Tilemaps.Tilemap.html

Share this post


Link to post
Share on other sites

Yeah, I've always approached this in a similar way.

Your map structure needs to handle certain events when a tile is stepped on.

So, the tile in the doorway 'teleports' you to a new map, which is the building interior.

Alternatively, if you had roof graphics, then that tile removes them when entering the interior or adds them when exiting.

Either way, you need to handle certain 'onStep' style events. This is quite a nice pattern as you can scale it up to do way more things too as your game grows.

Share this post


Link to post
Share on other sites

Thank you for the responses, right I am trying to get my character to "teleport" to a different map using a object that appears in the map. The character is supposed to walk into that object and go into the building and appear in a store that is on a different map. In order to facilitate this  do I need to use the setCollisionByProperty or collider function in order to detect to player walking into it. Also, I need to make a const variable of the "store" object. Therefore, I guess I am trying to build the code that will make this happen.

function preload() {
  this.load.image("tiles", "../assets/tilesets/RunItUpCity.png");
  this.load.tilemapTiledJSON("map", "../assets/tilemaps/GetawayCity.json");
  this.load.image("tiles2", "../assets/tilesets/modern-day-shop-add-on-right.png");
  this.load.tilemapTiledJSON("map2", "../assets/tilemaps/store.json");

  // An atlas is a way to pack multiple images together into one texture. I'm using it to load all
  // the player animations (walking left, walking right, etc.) in one image. For more info see:
  //  https://labs.phaser.io/view.html?src=src/animation/texture%20atlas%20animation.js
  // If you don't use an atlas, you can do the same thing with a spritesheet, see:
  //  https://labs.phaser.io/view.html?src=src/animation/single%20sprite%20sheet.js
  this.load.atlas("atlas", "../assets/atlas/atlas.png", "../assets/atlas/atlas.json");
}

function create() {
  const map = this.make.tilemap({ key: "map" });

  // Parameters are the name you gave the tileset in Tiled and then the key of the tileset image in
  // Phaser's cache (i.e. the name you used in preload)
  const tileset = map.addTilesetImage("RunitUpCity", "tiles");

  // Parameters: layer name (or index) from Tiled, tileset, x, y
  const belowLayer = map.createStaticLayer("Bottom Layer", tileset, 0, 0);
  const worldLayer = map.createStaticLayer("Top Layer", tileset, 0, 0);
  const aboveLayer = map.createStaticLayer("Collision Layer", tileset, 0, 0);

  worldLayer.setCollisionByProperty({ collides: true });

  // By default, everything gets depth sorted on the screen in the order we created things. Here, we
  // want the "Above Player" layer to sit on top of the player, so we explicitly give it a depth.
  // Higher depths will sit on top of lower depth objects.
  worldLayer.setDepth(10);

  // Object layers in Tiled let you embed extra info into a map - like a spawn point or custom
  // collision shapes. In the tmx file, there's an object layer with a point named "Spawn Point"
  const spawnPoint = map.findObject("Objects", obj => obj.name === "Spawn Point");
  const Store = map.findObject("Objects", obj => obj.name === "store");

 

Share this post


Link to post
Share on other sites

Update: I got the character to load on the map with the function I already have but problem is that I can’t move my character.

Here is the function I have so far:

// When the player walks into the store.
  player.onCollide = new Phaser.signal();
  Store.onCollide.add(enterstore,this);

  function enterstore(player){
 	const map2 = this.make.tilemap({ key: "map2" });
  	const tileset2 = map.addTilesetImage("store", "tiles2");

  	const storeLayer = map.createStaticLayer("Tile Layer 1", tileset, 0, 0);

  	storeLayer.setCollisionByProperty({ collides: true });

  	this.physics.add.collider(player, storeLayer);

  	storeLayer.setDepth(10);

  	const SpawnPoint = map.findObject("Objects", obj => obj.name === "Spawn Point");
  	const Store = map.findObject("Objects", obj => obj.name === "store");

  	player = this.physics.add
    .sprite(SpawnPoint.x, SpawnPoint.y, "atlas", "misa-front")
    .setSize(30, 40)
    .setOffset(282, 202);

 };
 Run code snippet

 

Share this post


Link to post
Share on other sites

Ok, here is an update. I am trying to use a sprite instead of an object in order to facilitate a collision that will change the scene of the game to the store. Here is the code I have right now. 

// Create a sprite with physics enabled via the physics system. The image used for the sprite has
  // a bit of whitespace, so I'm using setSize & setOffset to control the size of the player's body.
  player = this.physics.add
    .sprite(spawnPoint.x, spawnPoint.y, "atlas", "misa-front")
    .setSize(30, 40)
    .setOffset(0, 24);

  entrance = this.physics.add
    .sprite(enterstore.x, enterstore.y, "store")
    .setSize(41, 39)
    .setOffset(409, 1163);



  // Watch the player and worldLayer for collisions, for the duration of the scene:
  this.physics.add.collider(player, worldLayer);
  this.physics.add.collider(player, entrance, enterstore, null, this);
  
enterstore(player, entrance)
    {
    	this.scene.start('sceneB');
    }

The problem I am having is that my map still loads up but my character won't load and the camera goes to the 0,0 position. here is the error I got from inspecting it:

Uncaught TypeError: Cannot read property 'x' of null
    at SceneA.create (index.js:67)
    at SceneManager.create (phaser.js:45999)
    at SceneManager.loadComplete (phaser.js:45893)
    at LoaderPlugin.emit (phaser.js:2007)
    at LoaderPlugin.loadComplete (phaser.js:88695)
    at LoaderPlugin.fileProcessComplete (phaser.js:88654)
    at ImageFile.onProcessComplete (phaser.js:4033)
    at Image.data.onload (phaser.js:6634)

Here is a link to the acutal files of the project:

https://drive.google.com/file/d/1hAVbznPVmudmORioaJTlA61mLNDlJNBW/view?usp=sharing

Share this post


Link to post
Share on other sites

Update: I changed the condition for switching scenes to something simple as pushing a button and I was to resolve a bunch of problems with the store map. However, when I do try to change scenes the whole game freezing and when I go to inspect it I get this error message: 

Uncaught TypeError: Cannot read property 'velocity' of undefined
    at SceneA.update (index.js:145)
    at Systems.step (phaser.js:26785)
    at SceneManager.update (phaser.js:45932)
    at Game.step (phaser.js:109993)
    at TimeStep.step (phaser.js:106785)
    at step (phaser.js:66250)

Also, get these warning messages: 

phaser.js:51943 Invalid Animation Key, or Key already in use: misa-left-walk
create @ phaser.js:51943
phaser.js:51943 Invalid Animation Key, or Key already in use: misa-right-walk
create @ phaser.js:51943
phaser.js:51943 Invalid Animation Key, or Key already in use: misa-front-walk
create @ phaser.js:51943
phaser.js:51943 Invalid Animation Key, or Key already in use: misa-back-walk

What do you all think should be done? Also, here is a code snippet of what is it referring to:

const spawnPoint = map.findObject("Objects", obj => obj.name === "Spawn Point");
  const entrance = map.findObject("Objects", obj => obj.name === "store");

  // Create a sprite with physics enabled via the physics system. The image used for the sprite has
  // a bit of whitespace, so I'm using setSize & setOffset to control the size of the player's body.
  player = this.physics.add
    .sprite(spawnPoint.x, spawnPoint.y, "atlas", "misa-front")
    .setSize(30, 40)
    .setOffset(0, 24);

  


  // Watch the player and worldLayer for collisions, for the duration of the scene:
  this.physics.add.collider(player, worldLayer);
 
  
  
  // Create the player's walking animations from the texture atlas. These are stored in the global
  // animation manager so any sprite can access them.
  const anims = this.anims;
  anims.create({
    key: "misa-left-walk",
    frames: anims.generateFrameNames("atlas", { prefix: "misa-left-walk.", start: 0, end: 3, zeroPad: 3 }),
    frameRate: 10,
    repeat: -1
  });
  anims.create({
    key: "misa-right-walk",
    frames: anims.generateFrameNames("atlas", { prefix: "misa-right-walk.", start: 0, end: 3, zeroPad: 3 }),
    frameRate: 10,
    repeat: -1
  });
  anims.create({
    key: "misa-front-walk",
    frames: anims.generateFrameNames("atlas", { prefix: "misa-front-walk.", start: 0, end: 3, zeroPad: 3 }),
    frameRate: 10,
    repeat: -1
  });
  anims.create({
    key: "misa-back-walk",
    frames: anims.generateFrameNames("atlas", { prefix: "misa-back-walk.", start: 0, end: 3, zeroPad: 3 }),
    frameRate: 10,
    repeat: -1
  });

  const camera = this.cameras.main;
  camera.startFollow(player);
  camera.setBounds(0, 0, map.widthInPixels, map.heightInPixels);

  cursors = this.input.keyboard.createCursorKeys();

  // Help text that has a "fixed" position on the screen
  this.add
    .text(16, 16, 'Arrow keys to move\nPress "D" to show hitboxes', {
      font: "18px monospace",
      fill: "#000000",
      padding: { x: 20, y: 10 },
      backgroundColor: "#ffffff"
    })
    .setScrollFactor(0)
    .setDepth(30);

  // Debug graphics
   this.input.keyboard.once("keydown_D", event => {
    // Turn on physics debugging to show player's hitbox
    this.physics.world.createDebugGraphic();

    // Create worldLayer collision graphic above the player, but below the help text
    const graphics = this.add
      .graphics()
      .setAlpha(0.75)
      .setDepth(20);
    worldLayer.renderDebug(graphics, {
      tileColor: null, // Color of non-colliding tiles
      collidingTileColor: new Phaser.Display.Color(243, 134, 48, 255), // Color of colliding tiles
      faceColor: new Phaser.Display.Color(40, 39, 37, 255) // Color of colliding face edges
    });
  });

        this.input.keyboard.once("keydown_S", event => {

            this.scene.start('sceneB');

        },this);
}

 update(time, delta) {
  const speed = 175;
  const prevVelocity = player.body.velocity.clone();

  // Stop any previous movement from the last frame
  player.body.setVelocity(0);

  // Horizontal movement
  if (cursors.left.isDown) {
    player.body.setVelocityX(-speed);
  } else if (cursors.right.isDown) {
    player.body.setVelocityX(speed);
  }

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.