Phaser 3 如何在两个不涉及玩家的物体之间的碰撞中访问和影响玩家
Phaser 3 How to Access and Affect Player in Collision between 2 Objects Not Involving Player
我正在尝试在 Phaser 3 中创建抓钩。我可以成功地以向上的角度远离玩家发射抓钩。当抓钩到达目的地时,我需要让玩家向抓钩移动。问题是我无法访问 Spawner.ts
文件中的播放器对象来移动播放器对象。如果我可以访问玩家对象,我可以在抓钩和关卡发生碰撞时设置速度。
这是Spawner.ts
文件中的相关代码:
import { Actor } from "./Actor";
import { Level } from "./Level";
import { Layer } from "./shared";
import { Projectile } from "./Projectile/Projectile";
import { GameScene } from "../scenes/GameScene";
import { Player } from "./Player";
import { GrapplingHook } from "./GrapplingHook";
interface ActorConstructor {
new (scene: Phaser.Scene, x: number, y: number): Actor;
}
interface GrapplingHookContructor {
new (scene: GameScene, x: number, y: number): GrapplingHook;
}
export class Spawner {
private projectiles: Phaser.GameObjects.Group;
private actors: Phaser.GameObjects.Group;
private grapplinghooks: Phaser.GameObjects.Group;
constructor(private scene: GameScene, private level: Level) {
this.actors = this.scene.add.group();
this.setUpGrapplingHooks();
}
spawnDynamic<T extends ActorConstructor>(
layer: Layer,
type: T
): Phaser.GameObjects.Group {
const objects = this.level.getObjects(layer);
const instances = objects.map((e) => new type(this.scene, e.x, e.y));
const group = this.scene.add.group(instances);
this.level.addGroundCollision(group);
return group;
}
spawnPlayer(layer: Layer): Player {
const player = this.spawnDynamic(
layer,
Player
).getChildren()[0] as Player;
this.actors.add(player);
return player;
}
spawnGrapplingHook<T extends GrapplingHookContructor>(
type: T,
x: number,
y: number,
xVelocity = 0,
yVelocity = 0
): void {
const grapplinghook = new type(this.scene, x, y);
this.grapplinghooks.add(grapplinghook);
grapplinghook.body.setVelocity(xVelocity, yVelocity);
grapplinghook.body.setCollideWorldBounds(true, undefined, undefined, true);
}
destroyGrapplingHooks() {
this.grapplinghooks.getChildren().map(child => child.destroy());
}
private getObjectData(
object: Phaser.Types.Tilemaps.TiledObject
): Record<string, unknown> {
const props = object.properties as unknown;
const data: Record<string, unknown> = {};
if (props instanceof Array) {
props.forEach((p: { name: string; value: unknown }) => {
data[p.name] = p.value;
});
}
return data;
}
private setUpGrapplingHooks() {
this.grapplinghooks = this.scene.add.group();
this.grapplinghooks.runChildUpdate = true;
this.level.addGroundCollision(this.grapplinghooks, (grapplinghook) =>
(grapplinghook as GrapplingHook).onLevelCollide()
);
this.scene.physics.add.collider(
this.grapplinghooks,
this.level.getLayer(Layer.Bricks),
(grapplinghook) => (grapplinghook as Projectile).onLevelCollide()
);
this.scene.physics.add.collider(
this.grapplinghooks,
this.actors,
(grapplinghook, entity) => {
(grapplinghook as Projectile).onCollide(entity as Actor);
}
);
}
}
这是Player.ts
文件中的相关代码:
import { TILE_WIDTH } from "./shared";
import type { GameScene } from "../scenes/GameScene";
import { Actor } from "./Actor";
import { Assets } from "./shared";
import { GrapplingHook } from "./GrapplingHook";
interface Controls {
Left: Phaser.Input.Keyboard.Key;
Right: Phaser.Input.Keyboard.Key;
Jump: Phaser.Input.Keyboard.Key;
ThrowGrapplingHook: Phaser.Input.Keyboard.Key;
}
export class Player extends Actor {
protected readonly totalHitPoints = 3;
protected readonly immunityAfterDamageTime: number = 1000;
private controls: Controls;
constructor(scene: GameScene, x: number, y: number) {
super(scene, x, y, Assets[Assets.Player], 1);
// controls
this.controls = {
Left: scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A),
Right: scene.input.keyboard.addKey(
Phaser.Input.Keyboard.KeyCodes.D
),
Jump: scene.input.keyboard.addKey(
Phaser.Input.Keyboard.KeyCodes.SPACE
),
ThrowGrapplingHook: scene.input.keyboard.addKey(
Phaser.Input.Keyboard.KeyCodes.H
)
};
}
/**
* Throws a projectile at a given angle and force
* @param time The current game time
* @param angle The angle to throw the projectile; Should be a value between -90 (straight down) and 90 (straight up)
* @param force What velocity to throw the projectile at
*/
protected throwGrapplingHook(time: number, angle: number, force: number) {
if (angle > 90 || angle < -90) {
throw `throwProjectile(angle) must be between -90 and 90; current value: ${angle}`;
}
this.lastProjectileThrowTime = time;
let x = this.body.x;
if (this.flipX) {
x = x + TILE_WIDTH;
}
// calculate the x and y force based on angle and total force
// angle: 0 -> x velocity at 100%, y at 0%
// angle: 90 -> x velocity at 0%, y at 100%
const percentYForce = angle / 90;
const yVelocity = force * percentYForce * -1;
let xVelocity = force - Math.abs(yVelocity);
if (this.body.velocity.x < 0) {
xVelocity *= -1;
}
this.scene.spawner.spawnGrapplingHook(
GrapplingHook,
x,
this.body.y,
xVelocity,
yVelocity
);
}
protected onUpdate(): void {
if (!this.active) {
return;
}
}
}
这是 GrapplingHook.ts
文件中的相关代码:
import type { Actor } from "./Actor";
import { Assets } from "./shared";
export class GrapplingHook extends Phaser.Physics.Arcade.Sprite {
declare body: Phaser.Physics.Arcade.Body;
constructor(scene: Phaser.Scene, x: number, y: number) {
super(scene, x, y, Assets[Assets.Projectiles], 1);
scene.add.existing(this);
scene.physics.add.existing(this);
this.body.setAllowGravity(false);
this.body
.setSize(this.body.width, this.body.height - 20, true)
.updateCenter()
}
onCollide(target: Actor): void {
this.destroy();
}
onLevelCollide(): void {
this.setVelocity(0,0);
}
update(): void {
this.flipX = this.body.velocity.x >= 0
}
}
就像现在一样,代码成功地抛出了抓钩,但在它与关卡碰撞后我实际上无法移动玩家。我什至没有研究如何将玩家 移向 实际碰撞的抓钩,作为概念证明我只想轻推碰撞发生时玩家向前。
我的直觉是将 GrapplingHook.ts
中的 onLevelCollide
函数更改为:
onLevelCollide(player: Player): void {
player.setVelocityX(100);
this.setVelocity(0,0);
}
然后在 Spawner.ts
中调用播放器对象时将其添加到 onLevelCollide()
中,但我似乎无法访问 Spawner.ts
中的播放器。我如何将播放器对象传递到 onLevelCollide 或可能以其他方式解决此问题?
我再次尝试在抓钩与关卡发生碰撞时移动玩家。如果您需要我 post 更多代码或澄清,请告诉我。
重构 GrapplingHook
构造函数以接受播放器
在Spawner.ts
interface GrapplingHookContructor {
// refactor the constructor to accept a player as well
new (scene: GameScene, player: Player, x: number, y: number): GrapplingHook;
}
在GrapplingHook.ts
中做同样的事情,添加一个播放器属性并从构造函数参数
中分配播放器给它
export class GrapplingHook extends Phaser.Physics.Arcade.Sprite {
declare body: Phaser.Physics.Arcade.Body;
private player: Player; // add this
// refactor the constructor to accept a player as well
constructor(scene: Phaser.Scene, player: Player, x: number, y: number) {
super(scene, x, y, Assets[Assets.Projectiles], 1);
this.player = player; // add this
重构 spawnGrapplingHook
调用以接受播放器并将播放器传递给 GrapplingHook
构造函数
spawnGrapplingHook<T extends GrapplingHookContructor>(
type: T,
player: Player, // add this
x: number,
y: number,
xVelocity = 0,
yVelocity = 0
): void {
// pass the player as a parameter
const grapplinghook = new type(this.scene, player, x, y);
// ...
}
在GrapplingHook.ts
onLevelCollide(): void {
// do the math here to move the player
this.player.setVelocityX(100);
this.setVelocity(0,0);
}
另一个可能对您有用的选项是在 Spawner.ts
中保留对播放器的引用,在调用 spawnPlayer(layer: Layer): Player
时设置它。然后使用 this.scene.spawner.player
在您需要的任何地方访问它?
只是因为我对自己如何解决这个问题感兴趣,所以我改编了 (我去掉了大部分内容,这不是真正需要的) 这个移相器示例(First Game) 完成抓钩机制。
我只是分享它,因为它是一个涵盖关键任务的小型工作示例:
- 上钩
- 管理速度,在 hook-action
之前/期间/之后
- 将玩家拉向钩子
是的,只有javascript没有类(和...),但它仍然很好地说明了要点(我认为)。
Controls:
- left mouse button: shoot "hook"
- left / Right : move/walk player (animation was removed)
- SHIFT retract grappling hook
var config = {
type: Phaser.AUTO,
width: 400,
height: 300,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 150 }
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var player;
var platforms;
var cursors;
// basic Hook Object
var hook = {
isPulling: false,
isAttached: false,
speed: 500,
set display(value){
this.gameObject.visible = value;
this.ropeGameObject.visible = value;
}
}
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('ground', 'https://labs.phaser.io/src/games/firstgame/assets/platform.png');
this.load.image('star', 'https://labs.phaser.io/src/games/firstgame/assets/star.png');
this.load.spritesheet('dude', 'https://labs.phaser.io/src/games/firstgame/assets/dude.png', { frameWidth: 32, frameHeight: 48 });
}
function create ()
{
let txt = this.add.text(0, 20, '> click mouse to shoot hook\n\t>> press "shift" to pull');
platforms = this.physics.add.staticGroup();
platforms.create(200, 310, 'ground');
platforms.create(200, -10, 'ground');
platforms.create(400, 100, 'ground').setScale(.5).refreshBody();
platforms.create(50, 175, 'ground').setScale(.5).refreshBody();
// Setup Hook Rope
hook.ropeGameObject = this.add.line(0,0, 0,0, 10,10, 0xff0000).setOrigin(0);
// Setup Hook
hook.gameObject = this.physics.add.sprite(100, 450, 'star').setScale(.3);
hook.gameObject.body.allowGravity = false;
// Hide Hook
hook.display = false;
// Setup Hook Collision
this.physics.add.collider(hook.gameObject, platforms, grab);
player = this.physics.add.sprite(100, 450, 'dude',4).setScale(.75);
player.setCollideWorldBounds(true);
player.setBounce(0.2);
this.physics.add.collider(player, platforms);
// Setup User Controls
cursors = this.input.keyboard.createCursorKeys();
this.input.on('pointerdown', shootHook, this);
}
function grab(hk, platform){
hook.gameObject.setVelocity(0);
hook.isAttached = true;
}
function shootHook(pointer){
if(!hook.isPulling){
let velocity = new Phaser.Math.Vector2(pointer.x - player.x, pointer.y - player.y)
.normalize()
.scale(hook.speed);
hook.gameObject.x = player.x;
hook.gameObject.y = player.y;
hook.display = true;
hook.isAttached = false;
hook.gameObject.setVelocity(velocity.x, velocity.y);
}
}
function updateHookRope(){
hook.ropeGameObject.setTo(player.x, player.y,hook.gameObject.x,hook.gameObject.y);
}
function update ()
{
updateHookRope();
if(hook.isAttached && cursors.shift.isDown){
hook.isPulling = true;
let pullVelocity = new Phaser.Math.Vector2( hook.gameObject.x - player.x, hook.gameObject.y - player.y)
.normalize()
.scale(hook.speed / 1.5);
player.setVelocity(pullVelocity.x, pullVelocity.y);
} else if(hook.isPulling) { // Hook was released so remove it
if(hook.isAttached){
hook.isAttached = false;
hook.display = false;
}
hook.isPulling = !player.body.touching.down;
}
if(hook.isPulling){
return;
}
if (cursors.left.isDown) {
player.setVelocityX(-160);
}
else if (cursors.right.isDown) {
player.setVelocityX(160);
}
else {
player.setVelocityX(0);
}
}
<script src="//cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.min.js"></script>
我正在尝试在 Phaser 3 中创建抓钩。我可以成功地以向上的角度远离玩家发射抓钩。当抓钩到达目的地时,我需要让玩家向抓钩移动。问题是我无法访问 Spawner.ts
文件中的播放器对象来移动播放器对象。如果我可以访问玩家对象,我可以在抓钩和关卡发生碰撞时设置速度。
这是Spawner.ts
文件中的相关代码:
import { Actor } from "./Actor";
import { Level } from "./Level";
import { Layer } from "./shared";
import { Projectile } from "./Projectile/Projectile";
import { GameScene } from "../scenes/GameScene";
import { Player } from "./Player";
import { GrapplingHook } from "./GrapplingHook";
interface ActorConstructor {
new (scene: Phaser.Scene, x: number, y: number): Actor;
}
interface GrapplingHookContructor {
new (scene: GameScene, x: number, y: number): GrapplingHook;
}
export class Spawner {
private projectiles: Phaser.GameObjects.Group;
private actors: Phaser.GameObjects.Group;
private grapplinghooks: Phaser.GameObjects.Group;
constructor(private scene: GameScene, private level: Level) {
this.actors = this.scene.add.group();
this.setUpGrapplingHooks();
}
spawnDynamic<T extends ActorConstructor>(
layer: Layer,
type: T
): Phaser.GameObjects.Group {
const objects = this.level.getObjects(layer);
const instances = objects.map((e) => new type(this.scene, e.x, e.y));
const group = this.scene.add.group(instances);
this.level.addGroundCollision(group);
return group;
}
spawnPlayer(layer: Layer): Player {
const player = this.spawnDynamic(
layer,
Player
).getChildren()[0] as Player;
this.actors.add(player);
return player;
}
spawnGrapplingHook<T extends GrapplingHookContructor>(
type: T,
x: number,
y: number,
xVelocity = 0,
yVelocity = 0
): void {
const grapplinghook = new type(this.scene, x, y);
this.grapplinghooks.add(grapplinghook);
grapplinghook.body.setVelocity(xVelocity, yVelocity);
grapplinghook.body.setCollideWorldBounds(true, undefined, undefined, true);
}
destroyGrapplingHooks() {
this.grapplinghooks.getChildren().map(child => child.destroy());
}
private getObjectData(
object: Phaser.Types.Tilemaps.TiledObject
): Record<string, unknown> {
const props = object.properties as unknown;
const data: Record<string, unknown> = {};
if (props instanceof Array) {
props.forEach((p: { name: string; value: unknown }) => {
data[p.name] = p.value;
});
}
return data;
}
private setUpGrapplingHooks() {
this.grapplinghooks = this.scene.add.group();
this.grapplinghooks.runChildUpdate = true;
this.level.addGroundCollision(this.grapplinghooks, (grapplinghook) =>
(grapplinghook as GrapplingHook).onLevelCollide()
);
this.scene.physics.add.collider(
this.grapplinghooks,
this.level.getLayer(Layer.Bricks),
(grapplinghook) => (grapplinghook as Projectile).onLevelCollide()
);
this.scene.physics.add.collider(
this.grapplinghooks,
this.actors,
(grapplinghook, entity) => {
(grapplinghook as Projectile).onCollide(entity as Actor);
}
);
}
}
这是Player.ts
文件中的相关代码:
import { TILE_WIDTH } from "./shared";
import type { GameScene } from "../scenes/GameScene";
import { Actor } from "./Actor";
import { Assets } from "./shared";
import { GrapplingHook } from "./GrapplingHook";
interface Controls {
Left: Phaser.Input.Keyboard.Key;
Right: Phaser.Input.Keyboard.Key;
Jump: Phaser.Input.Keyboard.Key;
ThrowGrapplingHook: Phaser.Input.Keyboard.Key;
}
export class Player extends Actor {
protected readonly totalHitPoints = 3;
protected readonly immunityAfterDamageTime: number = 1000;
private controls: Controls;
constructor(scene: GameScene, x: number, y: number) {
super(scene, x, y, Assets[Assets.Player], 1);
// controls
this.controls = {
Left: scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.A),
Right: scene.input.keyboard.addKey(
Phaser.Input.Keyboard.KeyCodes.D
),
Jump: scene.input.keyboard.addKey(
Phaser.Input.Keyboard.KeyCodes.SPACE
),
ThrowGrapplingHook: scene.input.keyboard.addKey(
Phaser.Input.Keyboard.KeyCodes.H
)
};
}
/**
* Throws a projectile at a given angle and force
* @param time The current game time
* @param angle The angle to throw the projectile; Should be a value between -90 (straight down) and 90 (straight up)
* @param force What velocity to throw the projectile at
*/
protected throwGrapplingHook(time: number, angle: number, force: number) {
if (angle > 90 || angle < -90) {
throw `throwProjectile(angle) must be between -90 and 90; current value: ${angle}`;
}
this.lastProjectileThrowTime = time;
let x = this.body.x;
if (this.flipX) {
x = x + TILE_WIDTH;
}
// calculate the x and y force based on angle and total force
// angle: 0 -> x velocity at 100%, y at 0%
// angle: 90 -> x velocity at 0%, y at 100%
const percentYForce = angle / 90;
const yVelocity = force * percentYForce * -1;
let xVelocity = force - Math.abs(yVelocity);
if (this.body.velocity.x < 0) {
xVelocity *= -1;
}
this.scene.spawner.spawnGrapplingHook(
GrapplingHook,
x,
this.body.y,
xVelocity,
yVelocity
);
}
protected onUpdate(): void {
if (!this.active) {
return;
}
}
}
这是 GrapplingHook.ts
文件中的相关代码:
import type { Actor } from "./Actor";
import { Assets } from "./shared";
export class GrapplingHook extends Phaser.Physics.Arcade.Sprite {
declare body: Phaser.Physics.Arcade.Body;
constructor(scene: Phaser.Scene, x: number, y: number) {
super(scene, x, y, Assets[Assets.Projectiles], 1);
scene.add.existing(this);
scene.physics.add.existing(this);
this.body.setAllowGravity(false);
this.body
.setSize(this.body.width, this.body.height - 20, true)
.updateCenter()
}
onCollide(target: Actor): void {
this.destroy();
}
onLevelCollide(): void {
this.setVelocity(0,0);
}
update(): void {
this.flipX = this.body.velocity.x >= 0
}
}
就像现在一样,代码成功地抛出了抓钩,但在它与关卡碰撞后我实际上无法移动玩家。我什至没有研究如何将玩家 移向 实际碰撞的抓钩,作为概念证明我只想轻推碰撞发生时玩家向前。
我的直觉是将 GrapplingHook.ts
中的 onLevelCollide
函数更改为:
onLevelCollide(player: Player): void {
player.setVelocityX(100);
this.setVelocity(0,0);
}
然后在 Spawner.ts
中调用播放器对象时将其添加到 onLevelCollide()
中,但我似乎无法访问 Spawner.ts
中的播放器。我如何将播放器对象传递到 onLevelCollide 或可能以其他方式解决此问题?
我再次尝试在抓钩与关卡发生碰撞时移动玩家。如果您需要我 post 更多代码或澄清,请告诉我。
重构 GrapplingHook
构造函数以接受播放器
在Spawner.ts
interface GrapplingHookContructor {
// refactor the constructor to accept a player as well
new (scene: GameScene, player: Player, x: number, y: number): GrapplingHook;
}
在GrapplingHook.ts
中做同样的事情,添加一个播放器属性并从构造函数参数
export class GrapplingHook extends Phaser.Physics.Arcade.Sprite {
declare body: Phaser.Physics.Arcade.Body;
private player: Player; // add this
// refactor the constructor to accept a player as well
constructor(scene: Phaser.Scene, player: Player, x: number, y: number) {
super(scene, x, y, Assets[Assets.Projectiles], 1);
this.player = player; // add this
重构 spawnGrapplingHook
调用以接受播放器并将播放器传递给 GrapplingHook
构造函数
spawnGrapplingHook<T extends GrapplingHookContructor>(
type: T,
player: Player, // add this
x: number,
y: number,
xVelocity = 0,
yVelocity = 0
): void {
// pass the player as a parameter
const grapplinghook = new type(this.scene, player, x, y);
// ...
}
在GrapplingHook.ts
onLevelCollide(): void {
// do the math here to move the player
this.player.setVelocityX(100);
this.setVelocity(0,0);
}
另一个可能对您有用的选项是在 Spawner.ts
中保留对播放器的引用,在调用 spawnPlayer(layer: Layer): Player
时设置它。然后使用 this.scene.spawner.player
在您需要的任何地方访问它?
只是因为我对自己如何解决这个问题感兴趣,所以我改编了 (我去掉了大部分内容,这不是真正需要的) 这个移相器示例(First Game) 完成抓钩机制。
我只是分享它,因为它是一个涵盖关键任务的小型工作示例:
- 上钩
- 管理速度,在 hook-action 之前/期间/之后
- 将玩家拉向钩子
是的,只有javascript没有类(和...),但它仍然很好地说明了要点(我认为)。
Controls:
- left mouse button: shoot "hook"
- left / Right : move/walk player (animation was removed)
- SHIFT retract grappling hook
var config = {
type: Phaser.AUTO,
width: 400,
height: 300,
physics: {
default: 'arcade',
arcade: {
gravity: { y: 150 }
}
},
scene: {
preload: preload,
create: create,
update: update
}
};
var player;
var platforms;
var cursors;
// basic Hook Object
var hook = {
isPulling: false,
isAttached: false,
speed: 500,
set display(value){
this.gameObject.visible = value;
this.ropeGameObject.visible = value;
}
}
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('ground', 'https://labs.phaser.io/src/games/firstgame/assets/platform.png');
this.load.image('star', 'https://labs.phaser.io/src/games/firstgame/assets/star.png');
this.load.spritesheet('dude', 'https://labs.phaser.io/src/games/firstgame/assets/dude.png', { frameWidth: 32, frameHeight: 48 });
}
function create ()
{
let txt = this.add.text(0, 20, '> click mouse to shoot hook\n\t>> press "shift" to pull');
platforms = this.physics.add.staticGroup();
platforms.create(200, 310, 'ground');
platforms.create(200, -10, 'ground');
platforms.create(400, 100, 'ground').setScale(.5).refreshBody();
platforms.create(50, 175, 'ground').setScale(.5).refreshBody();
// Setup Hook Rope
hook.ropeGameObject = this.add.line(0,0, 0,0, 10,10, 0xff0000).setOrigin(0);
// Setup Hook
hook.gameObject = this.physics.add.sprite(100, 450, 'star').setScale(.3);
hook.gameObject.body.allowGravity = false;
// Hide Hook
hook.display = false;
// Setup Hook Collision
this.physics.add.collider(hook.gameObject, platforms, grab);
player = this.physics.add.sprite(100, 450, 'dude',4).setScale(.75);
player.setCollideWorldBounds(true);
player.setBounce(0.2);
this.physics.add.collider(player, platforms);
// Setup User Controls
cursors = this.input.keyboard.createCursorKeys();
this.input.on('pointerdown', shootHook, this);
}
function grab(hk, platform){
hook.gameObject.setVelocity(0);
hook.isAttached = true;
}
function shootHook(pointer){
if(!hook.isPulling){
let velocity = new Phaser.Math.Vector2(pointer.x - player.x, pointer.y - player.y)
.normalize()
.scale(hook.speed);
hook.gameObject.x = player.x;
hook.gameObject.y = player.y;
hook.display = true;
hook.isAttached = false;
hook.gameObject.setVelocity(velocity.x, velocity.y);
}
}
function updateHookRope(){
hook.ropeGameObject.setTo(player.x, player.y,hook.gameObject.x,hook.gameObject.y);
}
function update ()
{
updateHookRope();
if(hook.isAttached && cursors.shift.isDown){
hook.isPulling = true;
let pullVelocity = new Phaser.Math.Vector2( hook.gameObject.x - player.x, hook.gameObject.y - player.y)
.normalize()
.scale(hook.speed / 1.5);
player.setVelocity(pullVelocity.x, pullVelocity.y);
} else if(hook.isPulling) { // Hook was released so remove it
if(hook.isAttached){
hook.isAttached = false;
hook.display = false;
}
hook.isPulling = !player.body.touching.down;
}
if(hook.isPulling){
return;
}
if (cursors.left.isDown) {
player.setVelocityX(-160);
}
else if (cursors.right.isDown) {
player.setVelocityX(160);
}
else {
player.setVelocityX(0);
}
}
<script src="//cdn.jsdelivr.net/npm/phaser@3.55.2/dist/phaser.min.js"></script>