diff --git a/package-lock.json b/package-lock.json index 329b8fd..d3a7dda 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7135,9 +7135,9 @@ } }, "websocket-extensions": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, "which": { diff --git a/src/app/brawlers/colt.ts b/src/app/brawlers/colt.ts index 47c3cc8..1717b1b 100644 --- a/src/app/brawlers/colt.ts +++ b/src/app/brawlers/colt.ts @@ -7,20 +7,20 @@ export class Colt extends Phaser.GameObjects.Container { let rightArmImage: Phaser.GameObjects.Image = this.scene.add.image( 0, 0, - "armColtImage" + "armColt" ); this.add(rightArmImage); let leftArmImage: Phaser.GameObjects.Image = this.scene.add.image( 0, 0, - "armColtImage" + "armColt" ); leftArmImage.flipX = true; this.add(leftArmImage); let headArmImage: Phaser.GameObjects.Image = this.scene.add.image( 0, 0, - "bodyColtImage" + "bodyColt" ); this.add(headArmImage); diff --git a/src/app/game.ts b/src/app/game.ts index 171753e..3f29718 100644 --- a/src/app/game.ts +++ b/src/app/game.ts @@ -1,9 +1,10 @@ import * as Phaser from "phaser"; import { MainScene } from "./scenes/mainScene"; +import { UiScene } from "./scenes/uiScene"; export const run = (): void => { - const scenes: Array = [MainScene]; + const scenes: Array = [MainScene, UiScene]; const config: Phaser.Types.Core.GameConfig = { type: Phaser.AUTO, diff --git a/src/app/joystick.ts b/src/app/joystick.ts new file mode 100644 index 0000000..f58fb31 --- /dev/null +++ b/src/app/joystick.ts @@ -0,0 +1,148 @@ +import * as Phaser from "phaser"; + +/** + * The Joystick class emulate a virtual joystick. The joystick is composed by a + * head and a base. It is given a maximum length (distance between head and + * base). It takes the pointer's screen position as input to update the position + * the head of the joystick. Then if the base is too far away from the head + * (head-base distance above the maximum length), the base is moved closer to + * the head until their distance is equal to the maximum length. The Joystick is + * a Phaser Container always positionned at the origin and the head and base + * positionned relatively to the Container. Since its position is (0;0), it + * simplifies the formulas. + */ +export class Joystick extends Phaser.GameObjects.Container { + // This object belongs to the UiScene + public scene: Phaser.Scene; + + // Maximum length between the base and the head of the joystick + private maxLengthJoystick: number; + // The joystick head's position + private joystickHeadPos: Phaser.Math.Vector2; + // The joystick base's position + private joystickBasePos: Phaser.Math.Vector2; + // The joystick's head game object Image + private joystickHeadImage: Phaser.GameObjects.Image; + // The joystick's base game object Image + private joystickBaseImage: Phaser.GameObjects.Image; + + /** + * Creates the Joystick object. + * @param {Scene} scene - The Scene this Joystick belongs to + * (should be UiScene) + * @param {number} maxLengthJoystick - The maximum distance between the head + * and the base of the joystick + */ + public constructor(scene: Phaser.Scene, maxLengthJoystick: number) { + super(scene, 0, 0); + + this.joystickBasePos = new Phaser.Math.Vector2(50, 50); + this.joystickHeadPos = new Phaser.Math.Vector2(50, 50); + + this.maxLengthJoystick = maxLengthJoystick; + + this.joystickBaseImage = this.scene.add.image(0, 0, "joystickBase"); + this.joystickBaseImage.name = "joystickBase"; + this.add(this.joystickBaseImage); + + this.joystickHeadImage = this.scene.add.image(0, 0, "joystickHead"); + this.joystickHeadImage.name = "joystickHead"; + this.add(this.joystickHeadImage); + + // this.hide(); + } + + /** + * Updates the position of the head of the joystick by giving the pointer's + * world position. Moves the base too if it gets too far from the head. + * @param pointerScreenPos - The position of the pointer in screen coordinates + */ + public updatePosition(pointerScreenPos: Phaser.Math.Vector2): void { + this.joystickHeadPos = pointerScreenPos; + + // Distance between joystick's base and head + // const currentLengthJoystick: number = Utils.distance( + // this.joystickHeadPos, + // this.joystickBasePos + // ); + const currentLengthJoystick: number = this.joystickHeadPos.distance( + this.joystickBasePos + ); + + /** + * If the head (pointer) is too far from the base of the joystick, then + * moves the base towards the head until the distance reaches the + * maxLengthJoystick + */ + if (currentLengthJoystick > this.maxLengthJoystick) { + this.joystickBasePos = new Phaser.Math.Vector2(this.joystickBasePos) + .subtract(this.joystickHeadPos) + .scale(this.maxLengthJoystick / currentLengthJoystick) + .add(this.joystickHeadPos); + // this.joystickBasePos = Utils.add( + // this.joystickHeadPos, + // Utils.scale( + // Utils.subtract(this.joystickBasePos, this.joystickHeadPos), + // this.maxLengthJoystick / currentLengthJoystick + // ) + // ); + } + + // Updates the position of the joystick's head and base + this.joystickBaseImage.setPosition( + this.joystickBasePos.x, + this.joystickBasePos.y + ); + this.joystickHeadImage.setPosition( + this.joystickHeadPos.x, + this.joystickHeadPos.y + ); + } + + /** + * Returns a Vector2 which goes from the base to the head of the Joystick + * @returns {Vector2} - The Vector2 going from the base to the head of the + * Joystick + */ + // public getMove(): Vector2 { + // return Utils.subtract(this.joystickHeadPos, this.joystickBasePos); + // } + + /** + * Returns the ratio between the current length of the joystick (base to head) + * to its maximum length. Gives a number between 0 and 1 representing how much + * the joystick is moved. + */ + // public getRatio(): number { + // const currentLengthJoystick: number = Utils.distance( + // this.joystickHeadPos, + // this.joystickBasePos + // ); + // return Utils.clamp(currentLengthJoystick / this.maxLengthJoystick, 0, 1); + // } + + /** + * Resets base and head's position to the same reset position. + * @param pointerScreenPos - The reset position + */ + public resetTo(resetPos: Phaser.Math.Vector2): void { + this.joystickHeadPos = resetPos; + this.joystickBasePos = resetPos; + } + + /** + * Hides the Joystick. + */ + public hide(): void { + this.joystickBaseImage.visible = false; + this.joystickHeadImage.visible = false; + } + + /** + * Shows the Joystick. + */ + public show(): void { + this.joystickBaseImage.visible = true; + this.joystickHeadImage.visible = true; + } +} diff --git a/src/app/scenes/mainScene.ts b/src/app/scenes/mainScene.ts index 9bac954..19f239f 100644 --- a/src/app/scenes/mainScene.ts +++ b/src/app/scenes/mainScene.ts @@ -2,19 +2,23 @@ import * as Phaser from "phaser"; import * as armColtImage from "../../assets/armColt.png"; import * as bodyColtImage from "../../assets/bodyColt.png"; +import * as joystickHeadImage from "../../assets/joystickHead.png"; +import * as joystickBaseImage from "../../assets/joystickBase.png"; import { Colt } from "../brawlers/colt"; export class MainScene extends Phaser.Scene { public constructor() { super({ - key: "WorldScene", + key: "MainScene", }); } public preload(): void { - this.load.image("armColtImage", armColtImage.default); - this.load.image("bodyColtImage", bodyColtImage.default); + this.load.image("armColt", armColtImage.default); + this.load.image("bodyColt", bodyColtImage.default); + this.load.image("joystickHead", joystickHeadImage.default); + this.load.image("joystickBase", joystickBaseImage.default); } public create(): void { @@ -30,6 +34,8 @@ export class MainScene extends Phaser.Scene { this.cameras.main.centerOn(0, 0); this.add.existing(new Colt(this, 0, 0)); + + this.scene.launch("UiScene"); } /** diff --git a/src/app/scenes/uiScene.ts b/src/app/scenes/uiScene.ts new file mode 100644 index 0000000..3bd029d --- /dev/null +++ b/src/app/scenes/uiScene.ts @@ -0,0 +1,37 @@ +import * as Phaser from "phaser"; + +import { Joystick } from "../joystick"; + +export class UiScene extends Phaser.Scene { + private joystick: Joystick; + + public constructor() { + super({ + key: "UiScene", + }); + } + + public preload(): void {} + + public create(): void { + this.joystick = new Joystick(this, 30); + this.add.existing(this.joystick); + console.log(100); + } + + /** + * This method is called once per game step while the scene is running. + * Handles the realtime updates. + * @param {number} time - The current time + * @param {number} delta - The delta time in ms since the last frame. This is + * a smoothed and capped value based on the FPS rate. + */ + public update(time: number, delta: number): void { + const pointerScreenPos: Phaser.Math.Vector2 = new Phaser.Math.Vector2( + this.input.activePointer.x, + this.input.activePointer.y + ); + + this.joystick.updatePosition(pointerScreenPos); + } +} diff --git a/src/assets/joystickBase.png b/src/assets/joystickBase.png new file mode 100644 index 0000000..e8e2de6 Binary files /dev/null and b/src/assets/joystickBase.png differ diff --git a/src/assets/joystickHead.png b/src/assets/joystickHead.png new file mode 100644 index 0000000..3c689b6 Binary files /dev/null and b/src/assets/joystickHead.png differ