Adding a new SelectCharacterScene

Taking what was done in the LoginScene regarding character selection and putting it in its own scene.
Also, making character selection possible via the keyboard.
This commit is contained in:
David Négrier 2020-05-25 23:26:27 +02:00
parent a0ce57e582
commit da0d9fed87
3 changed files with 221 additions and 17 deletions

View File

@ -3,25 +3,25 @@ import {SpeechBubble} from "./SpeechBubble";
import BitmapText = Phaser.GameObjects.BitmapText;
export const PLAYER_RESOURCES: Array<any> = [
{name: "male1", img: "resources/characters/pipoya/Male 01-1.png", x: 32, y: 32},
{name: "male2", img: "resources/characters/pipoya/Male 02-2.png", x: 64, y: 32},
{name: "male3", img: "resources/characters/pipoya/Male 03-4.png", x: 96, y: 32},
{name: "male4", img: "resources/characters/pipoya/Male 09-1.png", x: 128, y: 32},
{name: "male1", img: "resources/characters/pipoya/Male 01-1.png" /*, x: 32, y: 32*/},
{name: "male2", img: "resources/characters/pipoya/Male 02-2.png"/*, x: 64, y: 32*/},
{name: "male3", img: "resources/characters/pipoya/Male 03-4.png"/*, x: 96, y: 32*/},
{name: "male4", img: "resources/characters/pipoya/Male 09-1.png"/*, x: 128, y: 32*/},
{name: "male5", img: "resources/characters/pipoya/Male 10-3.png", x: 32, y: 64},
{name: "male6", img: "resources/characters/pipoya/Male 17-2.png", x: 64, y: 64},
{name: "male7", img: "resources/characters/pipoya/Male 18-1.png", x: 96, y: 64},
{name: "male8", img: "resources/characters/pipoya/Male 16-4.png", x: 128, y: 64},
{name: "male5", img: "resources/characters/pipoya/Male 10-3.png"/*, x: 32, y: 64*/},
{name: "male6", img: "resources/characters/pipoya/Male 17-2.png"/*, x: 64, y: 64*/},
{name: "male7", img: "resources/characters/pipoya/Male 18-1.png"/*, x: 96, y: 64*/},
{name: "male8", img: "resources/characters/pipoya/Male 16-4.png"/*, x: 128, y: 64*/},
{name: "Female1", img: "resources/characters/pipoya/Female 01-1.png", x: 32, y: 96},
{name: "Female2", img: "resources/characters/pipoya/Female 02-2.png", x: 64, y: 96},
{name: "Female3", img: "resources/characters/pipoya/Female 03-4.png", x: 96, y: 96},
{name: "Female4", img: "resources/characters/pipoya/Female 09-1.png", x: 128, y: 96},
{name: "Female1", img: "resources/characters/pipoya/Female 01-1.png"/*, x: 32, y: 96*/},
{name: "Female2", img: "resources/characters/pipoya/Female 02-2.png"/*, x: 64, y: 96*/},
{name: "Female3", img: "resources/characters/pipoya/Female 03-4.png"/*, x: 96, y: 96*/},
{name: "Female4", img: "resources/characters/pipoya/Female 09-1.png"/*, x: 128, y: 96*/},
{name: "Female5", img: "resources/characters/pipoya/Female 10-3.png", x: 32, y: 128},
{name: "Female6", img: "resources/characters/pipoya/Female 17-2.png", x: 64, y: 128},
{name: "Female7", img: "resources/characters/pipoya/Female 18-1.png", x: 96, y: 128},
{name: "Female8", img: "resources/characters/pipoya/Female 16-4.png", x: 128, y: 128}
{name: "Female5", img: "resources/characters/pipoya/Female 10-3.png"/*, x: 32, y: 128*/},
{name: "Female6", img: "resources/characters/pipoya/Female 17-2.png"/*, x: 64, y: 128*/},
{name: "Female7", img: "resources/characters/pipoya/Female 18-1.png"/*, x: 96, y: 128*/},
{name: "Female8", img: "resources/characters/pipoya/Female 16-4.png"/*, x: 128, y: 128*/}
];
export class PlayableCaracter extends Phaser.Physics.Arcade.Sprite {

View File

@ -0,0 +1,203 @@
import {gameManager} from "../Game/GameManager";
import {TextField} from "../Components/TextField";
import {ClickButton} from "../Components/ClickButton";
import Image = Phaser.GameObjects.Image;
import Rectangle = Phaser.GameObjects.Rectangle;
import {PLAYER_RESOURCES} from "../Entity/PlayableCaracter";
//todo: put this constants in a dedicated file
export const SelectCharacterSceneName = "SelectCharacterScene";
enum LoginTextures {
playButton = "play_button",
icon = "icon",
mainFont = "main_font"
}
interface InitDataInterface {
name: string
}
export class SelectCharacterScene extends Phaser.Scene {
private readonly nbCharactersPerRow = 4;
private textField: TextField;
private pressReturnField: TextField;
private logo: Image;
private loginName: string;
private selectedRectangle: Rectangle;
private selectedRectangleXPos = 0; // Number of the character selected in the rows
private selectedRectangleYPos = 0; // Number of the character selected in the columns
private selectedPlayer: Phaser.Physics.Arcade.Sprite;
private players: Array<Phaser.Physics.Arcade.Sprite> = new Array<Phaser.Physics.Arcade.Sprite>();
constructor() {
super({
key: SelectCharacterSceneName
});
}
init({ name }: InitDataInterface) {
this.loginName = name;
}
preload() {
this.load.image(LoginTextures.playButton, "resources/objects/play_button.png");
this.load.image(LoginTextures.icon, "resources/logos/tcm_full.png");
// Note: arcade.png from the Phaser 3 examples at: https://github.com/photonstorm/phaser3-examples/tree/master/public/assets/fonts/bitmap
this.load.bitmapFont(LoginTextures.mainFont, 'resources/fonts/arcade.png', 'resources/fonts/arcade.xml');
//add player png
PLAYER_RESOURCES.forEach((playerResource: any) => {
this.load.spritesheet(
playerResource.name,
playerResource.img,
{frameWidth: 32, frameHeight: 32}
);
});
}
create() {
this.textField = new TextField(this, this.game.renderer.width / 2, 50, 'Select your character');
this.textField.setOrigin(0.5).setCenterAlign()
this.pressReturnField = new TextField(this, this.game.renderer.width / 2, 230, 'Press enter to start');
this.pressReturnField.setOrigin(0.5).setCenterAlign()
let rectangleXStart = this.game.renderer.width / 2 - (this.nbCharactersPerRow / 2) * 32 + 16;
this.selectedRectangle = this.add.rectangle(rectangleXStart, 90, 32, 32).setStrokeStyle(2, 0xFFFFFF);
this.logo = new Image(this, this.game.renderer.width - 30, this.game.renderer.height - 20, LoginTextures.icon);
this.add.existing(this.logo);
this.input.keyboard.on('keyup-ENTER', () => {
return this.login(this.loginName);
});
this.input.keyboard.on('keydown-RIGHT', () => {
if (this.selectedRectangleXPos < this.nbCharactersPerRow - 1) {
this.selectedRectangleXPos++;
}
this.updateSelectedPlayer();
});
this.input.keyboard.on('keydown-LEFT', () => {
if (this.selectedRectangleXPos > 0) {
this.selectedRectangleXPos--;
}
this.updateSelectedPlayer();
});
this.input.keyboard.on('keydown-DOWN', () => {
if (this.selectedRectangleYPos < Math.ceil(PLAYER_RESOURCES.length / this.nbCharactersPerRow) - 1) {
this.selectedRectangleYPos++;
}
this.updateSelectedPlayer();
});
this.input.keyboard.on('keydown-UP', () => {
if (this.selectedRectangleYPos > 0) {
this.selectedRectangleYPos--;
}
this.updateSelectedPlayer();
});
/*create user*/
this.createCurrentPlayer();
}
update(time: number, delta: number): void {
this.pressReturnField.setVisible(!!(Math.floor(time / 500) % 2));
}
private async login(name: string) {
return gameManager.connect(name, this.selectedPlayer.texture.key).then(() => {
// Do we have a start URL in the address bar? If so, let's redirect to this address
let instanceAndMapUrl = this.findMapUrl();
if (instanceAndMapUrl !== null) {
let [mapUrl, instance] = instanceAndMapUrl;
let key = gameManager.loadMap(mapUrl, this.scene, instance);
this.scene.start(key);
return mapUrl;
} else {
// If we do not have a map address in the URL, let's ask the server for a start map.
return gameManager.loadStartMap().then((scene : any) => {
if (!scene) {
return;
}
let key = gameManager.loadMap(window.location.protocol + "//" + scene.mapUrlStart, this.scene, scene.startInstance);
this.scene.start(key);
return scene;
}).catch((err) => {
console.error(err);
throw err;
});
}
}).catch((err) => {
console.error(err);
throw err;
});
}
/**
* Returns the map URL and the instance from the current URL
*/
private findMapUrl(): [string, string]|null {
let path = window.location.pathname;
if (!path.startsWith('/_/')) {
return null;
}
let instanceAndMap = path.substr(3);
let firstSlash = instanceAndMap.indexOf('/');
if (firstSlash === -1) {
return null;
}
let instance = instanceAndMap.substr(0, firstSlash);
return [window.location.protocol+'//'+instanceAndMap.substr(firstSlash+1), instance];
}
createCurrentPlayer(): void {
for (let i = 0; i <PLAYER_RESOURCES.length; i++) {
let playerResource = PLAYER_RESOURCES[i];
let [x, y] = this.getCharacterPosition(i % this.nbCharactersPerRow, Math.floor(i / this.nbCharactersPerRow));
let player = this.physics.add.sprite(x, y, playerResource.name, playerResource.name);
player.setBounce(0.2);
player.setCollideWorldBounds(true);
this.anims.create({
key: playerResource.name,
frames: this.anims.generateFrameNumbers(playerResource.name, {start: 0, end: 2,}),
frameRate: 10,
repeat: -1
});
player.setInteractive().on("pointerdown", () => {
this.selectedPlayer.anims.pause();
this.selectedRectangle.setY(player.y);
this.selectedRectangle.setX(player.x);
player.play(playerResource.name);
this.selectedPlayer = player;
});
this.players.push(player);
}
this.selectedPlayer = this.players[0];
this.selectedPlayer.play(PLAYER_RESOURCES[0].name);
}
/**
* Returns pixel position by on column and row number
*/
private getCharacterPosition(x: number, y: number): [number, number] {
return [
this.game.renderer.width / 2 + 16 + (x - this.nbCharactersPerRow / 2) * 32,
y * 32 + 90
];
}
private updateSelectedPlayer(): void {
this.selectedPlayer.anims.pause();
let [x, y] = this.getCharacterPosition(this.selectedRectangleXPos, this.selectedRectangleYPos);
this.selectedRectangle.setX(x);
this.selectedRectangle.setY(y);
let playerNumber = this.selectedRectangleXPos + this.selectedRectangleYPos * this.nbCharactersPerRow;
let player = this.players[playerNumber];
player.play(PLAYER_RESOURCES[playerNumber].name);
this.selectedPlayer = player;
}
}

View File

@ -5,13 +5,14 @@ import {cypressAsserter} from "./Cypress/CypressAsserter";
import {LoginScene} from "./Phaser/Login/LoginScene";
import {ReconnectingScene} from "./Phaser/Reconnecting/ReconnectingScene";
import {gameManager} from "./Phaser/Game/GameManager";
import {SelectCharacterScene} from "./Phaser/Login/SelectCharacterScene";
const config: GameConfig = {
title: "Office game",
width: window.innerWidth / RESOLUTION,
height: window.innerHeight / RESOLUTION,
parent: "game",
scene: [LoginScene, ReconnectingScene],
scene: [SelectCharacterScene, LoginScene, ReconnectingScene],
zoom: RESOLUTION,
physics: {
default: "arcade",