Reputation: 733
I'm creating a game with Phaser 3, specifically with the Matter physics engine. I want an animation to play only while an object is colliding with another.
Code for the object (the variable bench
is declared before the create()
function)
//Place a bench
bench = this.matter.add.sprite(2000, 200, 'sheet', 'bench', {shapes: shapes.bench});
bench.setScale(2, 1);
bench.setPosition(2250 + bench.centerOfMass.x, 200 + bench.centerOfMass.y);
//Needed this again so that bench can detect collisions
bench.isSensor(true);
Current code
//Detect collision when we are on the bench, so we can play the grind animation
this.matter.world.on('collisionstart', function (grindNow, skater, bench) {
grind = true;
});
The problem is, the code above still logs true
to the console when the player is colliding with the ground and I only want to detect collisions with the bench
object here. I've tried just playing the animation inside the function, which doesn't work either. I've also tried
if (this) {
grind = true;
}
else {
grind = false;
}
and then tried to use that variable to decide when to play the grinding animation, but that didn't help either. Lastly, I've tried playing the animation inside the create function, which would always return undefined
even though the animation had been created.
I've tried setting a variable inside that function and only playing
Upvotes: 1
Views: 1373
Reputation: 6342
I have found a solution, although I don't know if you want to use it. I found this plugin that makes it easier to manage collisions with Phaser.
Follow these steps:
<script src="//cdn.jsdelivr.net/npm/phaser-matter-collision-plugin"></script>
in your game_index.html
file like so:<script src="//cdn.jsdelivr.net/npm/phaser-matter-collision-plugin"></script>
<script src= "skateboarding.js" ></script>
<script src = "archery.js"></script>
<script src = "soccer.js"></script>
If you want to install it in a different way, read the full installation guide.
config
object add this code snippet:plugins: {
scene: [
{
plugin: PhaserMatterCollisionPlugin, // The plugin class
key: "matterCollision", // Where to store in Scene.Systems, e.g. scene.sys.matterCollision
mapping: "matterCollision" // Where to store in the Scene, e.g. scene.matterCollision
}
]
},
Now, your config
object should look like this:
//Game configurations
var config = {
type: Phaser.AUTO,
width: 1500, //<-- this is the width of what we will see at one time
height: gameHeight,
physics: physicsConfig,
plugins: {
scene: [
{
plugin: PhaserMatterCollisionPlugin, // The plugin class
key: "matterCollision", // Where to store in Scene.Systems, e.g. scene.sys.matterCollision
mapping: "matterCollision" // Where to store in the Scene, e.g. scene.matterCollision
}
]
},
scene: {
preload: preload,
create: create,
update: update
}
}
Third, remove these code snippet:
//Detect the player's collision with the ground
this.matter.world.on('collisionstart', function (onGround, skater, ground) {
//If the player is touching the ground, set this value to true
skaterTouchingGround = true;
});
//Detect collision when we are on the bench, so we can play the grind animation
this.matter.world.on('collisionstart', function (grindNow, skater, bench) {
grind = true;
});
Fourth, on the same place where you removed the previous code snippets add these code blocks:
//Detect the player's collision with the ground
this.matterCollision.addOnCollideStart({
objectA: skater,
objectB: ground,
callback: () => skaterTouchingGround = true
});
//Detect collision when we are on the bench, so we can play the grind animation
this.matterCollision.addOnCollideStart({
objectA: skater,
objectB: bench,
callback: () => grind = true
});
Now, you should be able to get the grind
's value printed in the console
when touching the player
touches the bench
.
For your reference, here is the entire code:
//Define our start button for out index page
var startButton = document.querySelector("#startSkate").addEventListener("click", () => {
//Delay in ms to remove our button
let removeDelay = 1;
//Call function to start the game
this.startSkateGame();
//Call the setTimeout method and define a function
setTimeout(function () {
//Get elements and remove them to clear the page
document.getElementById('startArch').remove();
document.getElementById('startSkate').remove();
document.getElementById('startSoccer').remove();
document.getElementById('logo').remove();
//Pass the delay
}, removeDelay);
});
//Define the function that we call when our start button is clicked
startSkateGame = () => {
//Configurations for the physics engine
var physicsConfig = {
default: 'matter',
matter : {
gravity: {
x: 0,
y: 2.5, // <--This is the only way I could get the skater to roll up the ramp.s
},
debug: true //CHANGE THIS TO TRUE TO SEE LINES
}
}
//Variables for height and width
var gameHeight = 750;
var gameWidth = 5000;
//Game configurations
var config = {
type: Phaser.AUTO,
width: 1500, //<-- this is the width of what we will see at one time
height: gameHeight,
physics: physicsConfig,
plugins: {
scene: [
{
plugin: PhaserMatterCollisionPlugin, // The plugin class
key: "matterCollision", // Where to store in Scene.Systems, e.g. scene.sys.matterCollision
mapping: "matterCollision" // Where to store in the Scene, e.g. scene.matterCollision
}
]
},
scene: {
preload: preload,
create: create,
update: update
}
}
/* This variable will be used to make sure the skater
cannot ollie while he is already in the air */
var skaterTouchingGround;
var grind;
//Start the game
var game = new Phaser.Game(config);
//Declare variables so we can access them in all functions
var skater;
var ground;
var sky;
var bench;
//Score variables
let score = 0;
let scoreBoard;
function preload() {
//Images
this.load.image('sky', 'archery_assets/images/sky.png');
//Load sprites from TexturePacker
this.load.atlas('sheet', 'skate_assets/sprites.png', 'skate_assets/sprites.json');
//Load body shapes from PhysicsEditor
this.load.json('shapes', 'skate_assets/spritesPE.json');
}
function create() {
//Background
sky = this.add.image(2500, 325,'sky')
//Scale the image
sky.setDisplaySize(gameWidth, gameHeight);
//Get the hitboxes
var shapes = this.cache.json.get('shapes');
//Set world bounds
this.matter.world.setBounds(0, 0, gameWidth, gameHeight);
//Place ground object
ground = this.matter.add.sprite(0, 0, 'sheet', 'ground', {shape: shapes.ground});
//Ground is 600x600, so double the x pixels and we get screen width
ground.setScale(8.5, 1);
ground.setPosition(2500, 650);
//Let the ground detect collisions
ground.isSensor(true);
//Place the ramp
var ramp = this.matter.add.sprite(0, 0, 'sheet', 'ramp', {shape: shapes.ramp});
ramp.setPosition(550 + ramp.centerOfMass.x, 250 + ramp.centerOfMass.y);
//Place a bench
bench = this.matter.add.sprite(2000, 200, 'sheet', 'bench', {shapes: shapes.bench});
bench.setScale(2, 1);
bench.setPosition(2250 + bench.centerOfMass.x, 200 + bench.centerOfMass.y);
//Needed this again so that bench can detect collisions
bench.isSensor(true);
//Create the skater
skater = this.matter.add.sprite(0, 0, 'sheet', 'roll/0001', {shape: shapes.s0001});
skater.setPosition(100 + skater.centerOfMass.x, 200 + skater.centerOfMass.y);
//Collision filtering
var staticCategory = this.matter.world.nextCategory();
ramp.setCollisionCategory(staticCategory);
ground.setCollisionCategory(staticCategory);
bench.setCollisionCategory(staticCategory);
//Skater needs to be in a different category
var skaterCategory = this.matter.world.nextCategory();
skater.setCollisionCategory(skaterCategory);
//Roll animation
//Generate the frame names
var rollFrameNames = this.anims.generateFrameNames(
'sheet', {start: 1, end: 4, zeroPad: 4,
prefix: 'roll/'}
);
//Create the animation
this.anims.create({
key: 'roll', frames: rollFrameNames, frameRate: 16, repeat: -1
});
//Push animation
var pushFrameNames = this.anims.generateFrameNames(
'sheet', {start: 5, end: 8, zeroPad: 4,
prefix: 'push/'}
);
this.anims.create({
key: 'push', frames: pushFrameNames, frameRate: 16, repeat: 0
});
//Shuvit animation
var shuvFrameNames = this.anims.generateFrameNames(
'sheet', {start: 9, end: 12, zeroPad: 4,
prefix: 'shuv/'}
);
this.anims.create({
key: 'shuv', frames: shuvFrameNames, frameRate: 32, repeat: 0
});
//Ollie animation
var ollieFrameNames = this.anims.generateFrameNames(
'sheet', {start: 13, end: 20, zeroPad: 4,
prefix: 'ollie/'}
);
this.anims.create({
key: 'ollie', frames: ollieFrameNames, frameRate: 24, repeat: 0
});
//Kickflip animation
var kfFrameNames = this.anims.generateFrameNames(
'sheet', {start: 21, end: 33, zeroPad: 4,
prefix: 'kickflip/'}
);
this.anims.create({
key: 'kickflip', frames: kfFrameNames, frameRate: 24, repeat: 0
});
//Nosegrind animation
var ngFrameNames = this.anims.generateFrameNames(
'sheet', {start: 34, end: 37, zeroPad: 4,
prefix: 'nosegrind/'}
);
this.anims.create({
key: 'nosegrind', frames: ngFrameNames, frameRate: 24, repeat: 0
});
//This keeps the rolling animation going once the push animation is done
skater.on('animationcomplete', () => {
skater.anims.play('roll');
});
//Input for arrowkeys
this.arrowKeys = this.input.keyboard.addKeys({
up: 'up',
down: 'down',
left: 'left',
right: 'right'
});
//Input for WASD keys
this.WASDkeys = this.input.keyboard.addKeys({
W: 'W',
A: 'A',
S: 'S',
D: 'D'
});
//Spacebar
this.spacebar = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
//Camera to follow the skater
this.cameras.main.setBounds(0, 0, gameWidth, gameHeight);
this.cameras.main.startFollow(skater);
//Detect the player's collision with the ground
this.matterCollision.addOnCollideStart({
objectA: skater,
objectB: ground,
callback: () => skaterTouchingGround = true
});
//Detect collision when we are on the bench, so we can play the grind animation
this.matterCollision.addOnCollideStart({
objectA: skater,
objectB: bench,
callback: () => grind = true
});
//Create the scoreboard as a container
scoreBoard = this.add.container(10, 50);
//Add text to this container, displaying our score
scoreText = this.add.text(10, 50, "SCORE: 0", {fontSize: '56px', color: '#fff'});
//Add the text to the container which will be our scoreboard
scoreBoard.add(scoreText);
//Make the scoreboard follow the player
this.tweens.add({
targets: scoreBoard,
ease: 'Linear',
duration: 1,
delay: 1,
yoyo: false,
repeat: -1
});
}
function update() {
console.log(skaterTouchingGround);
//Set variable for player movement
var pushSpeed = 0;
var ollie = 0;
//Make sure the player isn't doing anything if he's upside down, or crashed
let skaterCrashed;
//Variable to check the angle of the skater
let angleOkay = skater.angle > -89 && skater.angle < 89;
//Determine if the player is crashed or not
if (angleOkay) {
skaterCrashed = false;
}
else {
skaterCrashed = true;
window.alert("You crashed!");
}
//Starting parameter, as we don't want to do anything if we are crashed
if (!skaterCrashed) {
//Pushing
if (Phaser.Input.Keyboard.JustDown(this.spacebar) && skaterTouchingGround) {
//Increase speed
pushSpeed = 15;
//Move player
skater.setVelocityX(pushSpeed);
//Play push animation
skater.anims.play('push');
}
//Ollie
if (Phaser.Input.Keyboard.JustDown(this.arrowKeys.up) && skaterTouchingGround) {
//Set this to false, because we are about to jump
skaterTouchingGround = false;
//Set ollie power
ollie = -15;
//Set skate velocity
skater.setVelocityY(ollie);
//Play the ollie animation
skater.anims.play('ollie');
//Scoring for ollie
score += 1;
}
//Shuvit
if (Phaser.Input.Keyboard.JustDown(this.arrowKeys.down)) {
//Play the shuvit animation
skater.anims.play('shuv');
//Scoring for shuv
score += 3;
}
//Kickflip
if (Phaser.Input.Keyboard.JustDown(this.WASDkeys.W) && skaterTouchingGround) {
//Reset variable since we are jumping
skaterTouchingGround = false
//Set jump height
ollie = -14
//Move the player
skater.setVelocityY(ollie);
//Play animation
skater.anims.play('kickflip');
//Scoring for kickflip
score += 10;
}
//Tilting backwards in the air
if (this.arrowKeys.left.isDown && !skaterTouchingGround) {
//Be able to turn backwards so you don't flip
skater.angle -= 3 ;
}
//Tilting forwards in the air
if (this.arrowKeys.right.isDown && !skaterTouchingGround) {
//Be able to turn forwards so you don't flip
skater.angle += 3 ;
}
}
//Move the scoreboard
scoreText.x = skater.body.position.x - 200;
scoreText.setText("SCORE : " + score);
}
}
Upvotes: 1