Created
November 14, 2021 22:54
-
-
Save FoamyGuy/f4a57c6fd1752abe4b109b53aa5007ff to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Author: Michael Hadley, mikewesthad.com | |
* Asset Credits: | |
* - Tuxemon, https://github.com/Tuxemon/Tuxemon | |
*/ | |
const config = { | |
type: Phaser.AUTO, | |
width: 800, | |
height: 600, | |
parent: "game-container", | |
pixelArt: true, | |
physics: { | |
default: "arcade", | |
arcade: { | |
gravity: {y: 0} | |
} | |
}, | |
scene: { | |
preload: preload, | |
create: create, | |
update: update | |
} | |
}; | |
const game = new Phaser.Game(config); | |
let cursors; | |
let player; | |
let showDebug = false; | |
let keyA; | |
let keyS; | |
let keyD; | |
let keyW; | |
const AREA_OUTSIDE = "Outside"; | |
const AREA_BUILDING_0 = "Building0"; | |
let CUR_AREA = AREA_OUTSIDE; | |
let tileset; | |
let aboveLayer; | |
let worldLayer; | |
let belowLayer; | |
let doorLayer; | |
let belowCollider; | |
let worldCollider; | |
let doorOverlaps = []; | |
let doorGroup; | |
let debugGraphic; | |
let map; | |
function getPropertyValue(object, property_name) { | |
if (object.hasOwnProperty("properties")) { | |
for (let i = 0; i < object.properties.length; i++) { | |
if (object.properties[i].name === property_name) { | |
return object.properties[i].value; | |
} | |
} | |
} | |
return undefined; | |
} | |
function showArea(game, area_name, spawn_obj_name) { | |
console.log(map.getTileLayerNames()); | |
if (aboveLayer !== undefined) { | |
console.log("Need to destroy:"); | |
console.log(CUR_AREA); | |
belowLayer.destroy(); | |
aboveLayer.destroy(); | |
worldLayer.destroy(); | |
//map.destroyLayer(CUR_AREA + "/Below Player"); | |
//map.destroyLayer(CUR_AREA + "/World"); | |
//map.destroyLayer(CUR_AREA + "/Above Player"); | |
console.log(map.getTileLayerNames()); | |
//game.physics.remove(doorGroup); | |
doorGroup.clear(true, true); | |
game.physics.world.removeCollider(belowCollider); | |
game.physics.world.removeCollider(worldCollider); | |
for (let i = 0; i < doorOverlaps.length; i++){ | |
doorOverlaps[i].destroy() | |
} | |
doorOverlaps = []; | |
//debugGraphic.destroy(); | |
} | |
CUR_AREA = area_name | |
if (spawn_obj_name === undefined) { | |
spawn_obj_name = "Spawn Point"; | |
} | |
console.log("area: " + CUR_AREA); | |
console.log(map.getTileLayerNames()); | |
// Parameters: layer name (or index) from Tiled, tileset, x, y | |
belowLayer = map.createLayer(CUR_AREA + "/Below Player", tileset, 0, 0); | |
worldLayer = map.createLayer(CUR_AREA + "/World", tileset, 0, 0); | |
aboveLayer = map.createLayer(CUR_AREA + "/Above Player", tileset, 0, 0); | |
doorLayer = map.getObjectLayer(CUR_AREA + "/Doors")['objects']; | |
console.log("world layer"); | |
console.log(worldLayer); | |
worldLayer.setCollisionByProperty({collides: true}); | |
belowLayer.setCollisionByProperty({collides: true}); | |
console.log("layer depth:"); | |
console.log(belowLayer.depth); | |
// 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. | |
aboveLayer.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(CUR_AREA + "/Objects", obj => obj.name === spawn_obj_name); | |
player.x = spawnPoint.x; | |
player.y = spawnPoint.y; | |
// Watch the player and worldLayer for collisions, for the duration of the scene: | |
worldCollider = game.physics.add.collider(player, worldLayer); | |
belowCollider = game.physics.add.collider(player, belowLayer); | |
doorLayer.forEach(door => { | |
console.log("door: "); | |
console.log(door); | |
// TODO: why is hardcoding +16 needed here? | |
let door_body = doorGroup.create(door.x + 16, door.y + 16, "door"); | |
door_body.body.width = door.width; | |
door_body.body.height = door.height; | |
door_body.visible = false; | |
//console.log(door_body.height) | |
//console.log(door_body.body.height) | |
doorOverlaps.push(game.physics.add.overlap(player, door_body, function (args) { | |
//console.log(args) | |
//console.log("player touching door_0"); | |
console.log(getPropertyValue(door, "change_map")); | |
showArea(game, getPropertyValue(door, "change_map")); | |
})); | |
}); | |
debugGraphic = game.physics.world.createDebugGraphic(); | |
// Create worldLayer collision graphic above the player, but below the help text | |
const graphics = game.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 | |
}); | |
} | |
function preload() { | |
this.load.image("tiles", "img/tilemap_packed.png"); | |
this.load.tilemapTiledJSON("map", "maps/map_0.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", "https://mikewesthad.github.io/phaser-3-tilemap-blog-posts/post-1/assets/atlas/atlas.png", "https://mikewesthad.github.io/phaser-3-tilemap-blog-posts/post-1/assets/atlas/atlas.json"); | |
this.load.atlas("atlas", "img/char_0.png", "img/char_0.json"); | |
} | |
function create() { | |
map = this.make.tilemap({key: "map"}); | |
console.log(map.getTileLayerNames()); | |
// 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) | |
tileset = map.addTilesetImage("tilemap_packed", "tiles"); | |
//console.log(door_0_obj); | |
// 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(0, 0, "atlas", "misa-front") | |
.setSize(16, 16) | |
.setOffset(0, 0); | |
player.setDepth(1); | |
console.log("depth: "); | |
console.log(player.depth); | |
doorGroup = this.physics.add.staticGroup(); | |
showArea(this, AREA_BUILDING_0); | |
/*const door_0_obj = map.findObject("Doors", obj => obj.name === "door_0"); | |
door_0_group = this.physics.add.staticGroup(); | |
door_0_body = door_0_group.create(door_0_obj.x+16, door_0_obj.y+16, "door_0"); | |
//door_0_body.setScale(door_0_obj.polygon[1][0]/16, door_0_obj.polygon[2][1]/16); | |
door_0_body.body.width = door_0_obj.width; | |
door_0_body.body.height = door_0_obj.height; | |
door_0_body.setOrigin(0); | |
//door_0_body.body.setOrigin(0) | |
door_0_body.visible = false;*/ | |
/*this.physics.add.overlap(player, door_0_body, function (args) { | |
//console.log(args) | |
//console.log("player touching door_0"); | |
console.log(getPropertyValue(door_0_obj, "change_map")); | |
});*/ | |
// 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; | |
console.log(anims.generateFrameNames("atlas", {prefix: "char_0/char_0_back_walk/", start: 1, end: 3, zeroPad: 4})); | |
anims.create({ | |
key: "misa-left-walk", | |
frames: anims.generateFrameNames("atlas", {prefix: "char_0/char_0_left_walk/", start: 1, end: 3, zeroPad: 4}), | |
frameRate: 10, | |
repeat: -1 | |
}); | |
anims.create({ | |
key: "misa-right-walk", | |
frames: anims.generateFrameNames("atlas", {prefix: "char_0/char_0_right_walk/", start: 1, end: 3, zeroPad: 4}), | |
frameRate: 10, | |
repeat: -1 | |
}); | |
anims.create({ | |
key: "misa-front-walk", | |
frames: anims.generateFrameNames("atlas", {prefix: "char_0/char_0_front_walk/", start: 1, end: 3, zeroPad: 4}), | |
frameRate: 10, | |
repeat: -1 | |
}); | |
anims.create({ | |
key: "misa-back-walk", | |
frames: anims.generateFrameNames("atlas", {prefix: "char_0/char_0_back_walk/", start: 1, end: 3, zeroPad: 4}), | |
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(); | |
keyA = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A); | |
keyS = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.S); | |
keyD = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.D); | |
keyW = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.W); | |
camera.zoom = 2 | |
console.log(camera.zoom) | |
// 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 | |
}); | |
});*/ | |
} | |
function 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 (keyA.isDown) { | |
player.body.setVelocityX(-speed); | |
} else if (keyD.isDown) { | |
player.body.setVelocityX(speed); | |
} | |
// Vertical movement | |
if (keyW.isDown) { | |
player.body.setVelocityY(-speed); | |
} else if (keyS.isDown) { | |
player.body.setVelocityY(speed); | |
} | |
// Normalize and scale the velocity so that player can't move faster along a diagonal | |
player.body.velocity.normalize().scale(speed); | |
// Update the animation last and give left/right animations precedence over up/down animations | |
if (keyA.isDown) { | |
player.anims.play("misa-left-walk", true); | |
} else if (keyD.isDown) { | |
player.anims.play("misa-right-walk", true); | |
} else if (keyW.isDown) { | |
player.anims.play("misa-back-walk", true); | |
} else if (keyS.isDown) { | |
player.anims.play("misa-front-walk", true); | |
} else { | |
player.anims.stop(); | |
// If we were moving, pick and idle frame to use | |
if (prevVelocity.x < 0) player.setTexture("atlas", "char_0/char_0_left_walk/0001"); | |
else if (prevVelocity.x > 0) player.setTexture("atlas", "char_0/char_0_right_walk/0001"); | |
else if (prevVelocity.y < 0) player.setTexture("atlas", "char_0/char_0_back_walk/0001"); | |
else if (prevVelocity.y > 0) player.setTexture("atlas", "char_0/char_0_front_walk/0001"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment