Reputation: 733
I'm creating a game in JavaScript using the Phaser 3 framework. I'm using the Matter physics engine, and I only want the player to be able to jump (or ollie, as it is in the game) if they are touching the ground. I'm trying to use the collision detection within Matter physics, but I can't seem to get anything to work.
The error in this current code is "Uncaught TypeError: this.matter.world is not a function
", although I have tried other ways of implementing the collision detection used here.
I expect the player to only be able to jump when the up arrow key is hit AND they are touching the ground.
//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.
},
debug: false //CHANGE THIS TO TRUE TO SEE LINES
}
}
//Variables for height and width
var gameHeight = 750;
var gameWidth = 3000;
/* Declare variable to decide whether the player can ollie or not
Player should be touching the ground or a ramp to be able to ollie */
var canOllie;
//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,
scene: {
preload: preload,
create: create,
update: update
}
}
//Start the game
var game = new Phaser.Game(config);
//Declare variables so we can access them in all functions
var skater;
var ground;
//Declare variable for the sky background
var sky;
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(1500, 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(5, 1);
ground.setPosition(1500, 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);
//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);
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
});
//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, 3000, gameHeight);
this.cameras.main.startFollow(skater);
//Detect collision with ground
this.matter.world('collisionactive', (skater, ground) => {
if (this) {
canOllie = true;
}
else {
canOllie = false;
}
});
}
function update() {
//Set variable for player movement
var pushSpeed = 0;
var ollie = 0;
//Push
if (this.spacebar.isDown && skater.angle > -60 && skater.angle < 60) {
//Increase speed
pushSpeed = 10;
//Move player
skater.setVelocityX(pushSpeed);
//Play push animation
skater.anims.play('push');
}
//Ollie
if (Phaser.Input.Keyboard.JustDown(this.arrowKeys.up) && canOllie == true) {
//Set ollie power
ollie = -12;
//Set skate velocity
skater.setVelocityY(ollie);
//Play the ollie animation
skater.anims.play('ollie');
}
//Shuvit
if (this.arrowKeys.down.isDown) {
//Play the shuvit animation
skater.anims.play('shuv');
}
//Kickflip
if (this.WASDkeys.W.isDown) {
//Set jump height
ollie = -8
//Move the player
skater.setVelocityY(ollie);
//Play animation
skater.anims.play('kickflip');
}
//Tilting backwards in the air
if (this.arrowKeys.left.isDown && skater.y < 470) {
//Be able to turn backwards so you don't flip
skater.angle -= 3 ;
}
//Tilting forwards in the air
if (this.arrowKeys.right.isDown && skater.y < 470) {
//Be able to turn forwards so you don't flip
skater.angle += 3 ;
}
}
Upvotes: 1
Views: 2175
Reputation: 135
Manuel Abascal's answer is missing a few thing. If you make skaterTouchingGround true, then you also need to make it false. What's more, you also need to check which objects are being collided. So,
this.matter.world.on("collisionactive", (e,o1, o2) => {
skaterTouchingGround = true;
});
this.matter.world.on("collisionend", (e,o1, o2) => {
skaterTouchingGround = false;
})
Where e is the event, o1 is the object 1(player) and o2 is the object 2(platform). To check which items they are, you need to label them. After you create your player, add the lines:
player.body.label = 'myLabel'
Then, in your platforms the same thing:
platform.body.label = 'myPlatform'
After that, in your collisionactive function, check the labels like so:
this.matter.world.on("collisionactive", (e,o1, o2) => {
if(o1.label == 'myLabel' && o2.label == 'myPlatform'){
skaterTouchingGround = true;
}
});
this.matter.world.on("collisionend", (e,o1, o2) => {
if(o1.label == 'myLabel' && o2.label == 'myPlatform'){
skaterTouchingGround = false;
}
})
Then:
if(skaterTouchingGround){
jump
}
The code given above works as of phaser 3, if you added your labels correctly. Do remember to change the variable names to those that you have used.
NOTE: Even if the objects are being grouped in a phaser group( this.add.group()
), when you create your sprite, you should add the label before adding it to the group using group.add()
Upvotes: 0
Reputation: 6342
I have finally found the solution for this issue:
skaterTouchingGround
right after the config
object like so: let skaterTouchingGround;
create()
function add the collision detector event & set the variable skaterTouchingGround
to true
like so://Detect collision with ground
this.matter.world.on("collisionactive", (skater, ground) => {
skaterTouchingGround = true;
});
update()
function & if
statement, add the skaterTouchingGround
variable as condition to trigger the jump & once the jump is done set the variable skaterTouchingGround
to false
like so://Ollie
if (Phaser.Input.Keyboard.JustDown(this.arrowKeys.up) && skaterTouchingGround) {
skaterTouchingGround = false;
//Set ollie power
ollie = -12;
//Set skate velocity
skater.setVelocityY(ollie);
//Play the ollie animation
skater.anims.play('ollie');
}
If you follow these steps, the skater won't be able to jump midair.
EDIT:
Finally, for your reference, here is the final full working code sample:
//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.
},
debug: false //CHANGE THIS TO TRUE TO SEE LINES
}
}
//Variables for height and width
var gameHeight = 750;
var gameWidth = 3000;
/* Declare variable to decide whether the player can ollie or not
Player should be touching the ground or a ramp to be able to ollie */
var canOllie;
//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,
scene: {
preload: preload,
create: create,
update: update
}
}
//Start the game
var game = new Phaser.Game(config);
//Declare variables so we can access them in all functions
var skater;
let skaterTouchingGround;
var ground;
//Declare variable for the sky background
var sky;
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(1500, 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(5, 1);
ground.setPosition(1500, 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);
//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);
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
});
//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, 3000, gameHeight);
this.cameras.main.startFollow(skater);
//Detect collision with ground
this.matter.world.on("collisionactive", (skater, ground) => {
skaterTouchingGround = true;
});
}
function update() {
//Set variable for player movement
var pushSpeed = 0;
var ollie = 0;
//Push
if (this.spacebar.isDown && skater.angle > -60 && skater.angle < 60) {
//Increase speed
pushSpeed = 10;
//Move player
skater.setVelocityX(pushSpeed);
//Play push animation
skater.anims.play('push');
}
//Ollie
if (Phaser.Input.Keyboard.JustDown(this.arrowKeys.up) && skaterTouchingGround) {
skaterTouchingGround = false;
//Set ollie power
ollie = -12;
//Set skate velocity
skater.setVelocityY(ollie);
//Play the ollie animation
skater.anims.play('ollie');
}
//Shuvit
if (this.arrowKeys.down.isDown) {
//Play the shuvit animation
skater.anims.play('shuv');
}
//Kickflip
if (this.WASDkeys.W.isDown) {
//Set jump height
ollie = -8
//Move the player
skater.setVelocityY(ollie);
//Play animation
skater.anims.play('kickflip');
}
//Tilting backwards in the air
if (this.arrowKeys.left.isDown && skater.y < 470) {
//Be able to turn backwards so you don't flip
skater.angle -= 3 ;
}
//Tilting forwards in the air
if (this.arrowKeys.right.isDown && skater.y < 470) {
//Be able to turn forwards so you don't flip
skater.angle += 3 ;
}
}
Upvotes: 2