Trying to detect if 2 specific bodies are colliding with matter.js in phaser 3 - phaser-framework

I'm trying to add enemies to my platformer game using the matter physics engine however using the this.matter.world.on collisionactive function only checks collision between the floor and enemy after the player jumps once. I'm currently using labels to check for collision. I have tried adding extra conditions but have only been able to allow the player to infinitely jump. i.e- it is checking the labels of what is colliding.
Collision checking code:
this.matter.world.on("collisionactive", (e,o1,o2) => {
if(o1.label == 'floor' && o2.label == 'player')
{
this.touchingGround = true;
console.log('touching')
}
});
Enemy creation function:
Right now the enemies are cubes that are created at the cursor when the player presses f
function createEnemy(scene,x,y)
{
enemy = scene.matter.add.image(x,y,'enemy').setScale(1.5)
enemy.body.label = 'enemy'
}

I don't completely understand the problem, but if you have an issue with checking/finding all current collisions, you can use the pairs property of the event-object-argument (link to the documentation), which is passed to the physics-callback function. This property should contain, the other collisions.
"...The event.pairs array may contain more colliding bodies. ..."
Here a short demo:
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 11 * 16,
height: 6 * 16,
zoom: 2,
pixelArt: true,
scene: {
preload: preload,
create: create
},
physics: {
default: 'matter',
matter: {
gravity: {
y:.3
},
debug:true
}
},
banner: false
};
function preload (){
this.load.image('mario-tiles', 'https://labs.phaser.io/assets/tilemaps/tiles/super-mario.png');
}
function create (){
var level = [
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split('').map( _ => 14),
];
var map = this.make.tilemap({ data: level, tileWidth: 16, tileHeight: 16 });
var tiles = map.addTilesetImage('mario-tiles');
var layer = map.createLayer(0, tiles, 0, 0);
this.add.text(4, 4, 'click to jump', {color:'#9EE6FF', fontSize:10})
.setOrigin(0);
var info = this.add.text(4, 14, 'waiting ...', {color:'#ffffff', fontSize:10})
.setOrigin(0);
let enemy1 = this.add.rectangle(60.25, 5, 8, 8, 0xfff000)
.setOrigin(0.5);
let player = this.add.rectangle(60, 20, 8, 8, 0xffffff);
layer.setCollision([14]);
this.matter.add.gameObject(enemy1);
this.matter.add.gameObject(player);
this.matter.world.convertTilemapLayer(layer, {label:'floor'});
player.body.label = 'player';
enemy1.body.label = 'enemy';
this.input.on('pointerup', _=> player.setVelocityY(-3))
player.setVelocityY(-1)
this.matter.world.on("collisionactive", (e, o1, o2) => {
let text = 'p: ';
if( e.pairs.some (pair => pair.bodyA.label == 'player' && pair.bodyB.label =='floor' )) {
text += 'touch floor ';
}
if( e.pairs.some (pair => pair.bodyA.label == 'enemy' && pair.bodyB.label =='player' )) {
text += 'touch enemy ';
}
if( e.pairs.some (pair => pair.bodyA.label == 'enemy' && pair.bodyB.label =='floor' )) {
text += '\ne: touch floor';
}
info.setText(text);
});
}
new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>

Related

How do I run every exported function

So i have this mess of a js file
cardPool = []
class Card {
constructor(name = "", portrait = "", bloodCost = 0, boneCost = 0, power = 0, health = 1, sigilList = ["No sigil"]) {
this.name = name
this.portrait = portrait;
this.bloodCost = bloodCost;
this.boneCost = boneCost;
this.power = power;
this.health = health;
this.sigilList = sigilList;
cardPool.push(this)
}
Damage(dmg = 1) {
this.health -= dmg
}
}
blank = new Card("blank", "🔳");
income = new Card("income", "⬇️");
module.exports = {
Card,
blank,
income,
bear: function () { new Card("Grizzly", "🐻", 3, 0, 4, 6) },
wolf: function () { new Card("Wolf", "🐺", 2, 0, 3, 2) },
cardPool,
};
All I want to do is on start up it run all of the function being exported. There more function that I export but here only a few so stack overflow won't scream at me. This is for a game that I'm making to be able to handle multiple instance of the same card. You can read about why I make new card using function here: How to change a local class varible node js . And I need a card pool so that I can do stuff in another file here my other question: How can i put an object inside a list on Initialization. Now I need on startup put all the card that I make in the module.export in the cardPool.
The best way to do this would be placing the functions in some kind of container (for example an array or a map) (in case you later want to export other functions from the file that don't create cards). Here's the simplest way with an array:
// Note the return statements! The functions will not return anything without them!
function bear () { return new Card("Grizzly", "🐻", 3, 0, 4, 6) }
function wolf () { return new Card("Wolf", "🐺", 2, 0, 3, 2) }
module.exports = {
// ...
cardCreatorFunctions: [bear, wolf, /* and maybe others */],
}
Then, you can iterate through the array and push created cards into cardPool one-by-one:
for (let fun of cardLib.cardCreatorFunctions) {
cardLib.cardPool.push(fun())
}
Or you can do it in one statement:
cardLib.cardPool = cardLib.cardCreatorFunctions.map(fun => fun())

Phaser 3: How to detect if there's a group member at location

Okay I have a little game going on Phaser with a slider which the player can move up or down:
As you can see, the slider is on a track which one would assume restricts where the slider can go. At the moment, this isn't the case and the slider can run right off the rail.
How can I detect if there's a slider track in the target location before moving the slider?
Here's where I'm creating the static groups for slider and slider track.
sliders = this.physics.add.staticGroup();
slider_tracks = this.physics.add.staticGroup();
Here's where the objects themselves are being added to the game:
add_slider: function (x, y, data) {
map.add_slider_track(x, y, data);
var slider = sliders.create(x, y, data.direction + '_slider');
for (var key in data) {
slider[key] = data[key];
}
},
add_slider_track: function (x, y, data) {
slider_tracks.create(x, y, data.direction + '_track');
},
And here's the functions which move it:
hitSlider: function (player, slider) {
if (slider.direction == 'vertical') {
if (player.body.onFloor() && player.slamming) {
interaction.moveSliderDown(slider)
} else if (player.body.onCeiling()) {
interaction.moveSliderUp(slider);
}
}
player.slamming = false;
},
moveSliderUp: function (slider) {
slider.setY(slider.y - block_size);
slider.body.position.y = (slider.y - (block_size / 2));
player.setVelocityY(100);
},
moveSliderDown: function (slider) {
slider.setY(slider.y + block_size);
slider.body.position.y = (slider.y - (block_size / 2));
}
I've tried using slider_track.getFirst (https://rexrainbow.github.io/phaser3-rex-notes/docs/site/group/) but it seems to change the location of a given piece of track, not just detect if there's one there.
Just to don't let this question without answer as we normally start a chat, effectively I see in the js/slider_actions.js the solution but I can just say you can use velocity but seriously my level of coding even if I am for a long time in the Phaser community is lower than yours ;)
sliderTrackRight: function (slider) {
track = slider_tracks.children.entries.find(
function (track) {
return (
track.body.y == slider.body.y &&
track.body.x == (slider.body.x + block_size) &&
track.direction == 'horizontal'
)
}
);
return (typeof track != 'undefined');
},

How to load multiple sliders with values and tooltips with noUISlider?

I'm trying to load multiple sliders using noUISlider and it's not working. When using the first slider, the values changes for the second and third. How do I go about refactoring the code for one slider so I can easily add additional sliders with different options?
Here's a fiddle and below is my code.
// noUISlider
var actSlider = document.getElementById('act-slider');
noUiSlider.create(actSlider, {
start: [0, 50],
connect: false,
step: 1,
range: {
'min': 0,
'max': 50
},
format: {
to: function (value) {
return value + '';
},
from: function (value) {
return value.replace('', '');
}
}
});
// Connect bar
var connectBar = document.createElement('div'),
connectBase = actSlider.getElementsByClassName('noUi-base')[0],
connectHandles = actSlider.getElementsByClassName('noUi-origin');
// Give the bar a class for styling and add it to the slider.
connectBar.className += 'connect';
connectBase.appendChild(connectBar);
actSlider.noUiSlider.on('update', function (values, handle) {
// Pick left for the first handle, right for the second.
var side = handle ? 'right' : 'left',
// Get the handle position and trim the '%' sign.
offset = (connectHandles[handle].style.left).slice(0, -1);
// Right offset is 100% - left offset
if (handle === 1) {
offset = 100 - offset;
}
connectBar.style[side] = offset + '%';
});
// Value tooltips
var tipHandles = actSlider.getElementsByClassName('noUi-handle'),
tooltips = [];
// Add divs to the slider handles.
for (var i = 0; i < tipHandles.length; i++) {
tooltips[i] = document.createElement('div');
tooltips[i].className += 'value-tooltip';
tipHandles[i].appendChild(tooltips[i]);
}
// When the slider changes, write the value to the tooltips.
actSlider.noUiSlider.on('update', function (values, handle) {
tooltips[handle].innerHTML = values[handle];
});
You can wrap your slider creation in a function, and call it for all elements where you want a slider created.
noUiSlider also supports tooltips (from version 8.1.0) and connect options, so you don't have to implement those yourself if you don't want to make very specific changes.
As for different options for every slider, there are several ways to do this. I've added an example using data attributes for the step option.
The following code initializes a slider on all elements with a .slider class.
function data ( element, key ) {
return element.getAttribute('data-' + key);
}
function createSlider ( slider ) {
noUiSlider.create(slider, {
start: [0, 50],
connect: false,
step: Number(data(slider, 'step')) || 1,
range: {
'min': 0,
'max': 50
},
tooltips: true,
connect: true,
format: {
to: function (value) {
return value + '';
},
from: function (value) {
return value.replace('', '');
}
}
});
}
Array.prototype.forEach.call(document.querySelectorAll('.slider'), createSlider);
Here's a jsFiddle demonstrating this code.

how to : specify colors for multiple axes chart?

My chart shows up well but the two lines are of the same color. How do I specify different colors for the two lines? Here is my code (fragment) so far:
config.pointIndex = null;
config.areaPoints = new Array();
config.areaPoints[0] = pointsopens;
config.areaPoints[1] = pointsclicks;
var plotLinesopen = createPlotlines(pointsopens);
var plotLinesclick = createPlotlines(pointsclicks);
var options = {
chart : { renderTo : 'areaChart' },
colors: [
'#4572A7',
'#AA4643'
],
xAxis: {
plotLines1: plotLinesopen,
plotLines2: plotLinesclick
},
series : [ data.pointsopens, data.pointsclicks ]
};
if (length > 100) {
options.plotOptions = {
area : {
lineWidth: 1,
marker : { radius : 1 }
}
};
}
options = jQuery.extend(true, {}, areaChartDefault, options);
charts.area = new Highcharts.Chart(options);
Thank you.
PS, my code is now:
config.pointIndex = null;
config.areaPoints = new Array();
config.areaPoints[0] = pointsopens;
config.areaPoints[1] = pointsclicks;
var plotLinesopen = createPlotlines(pointsopens, '#AAAAAA');
var plotLinesclick = createPlotlines(pointsclicks, '#DDDDDD');
var options = {
chart : { renderTo : 'areaChart' },
xAxis: {
plotLines: [plotLinesopen, plotLinesclick]
},
series : [ data.pointsopens, data.pointsclicks ]
};
if (length > 100) {
options.plotOptions = {
area : {
lineWidth: 1,
marker : { radius : 1 }
}
};
}
options = jQuery.extend(true, {}, areaChartDefault, options);
charts.area = new Highcharts.Chart(options);
but it still gives me two dark blue plotlines. The createPlotlines function looks like so:
function createPlotlines(points, colour) {
// Create plotlines from point data
colour = typeof colour !== 'undefined' ? colour : '#CCCCCC';
alert ('colour=='+colour);
var plotLines = [];
var middleYval = 0;
for (var i in points) {
middleYval = Math.max(middleYval, points[i].y);
if (points[i].l) { // l property is true if label should be on for this point
plotLines.push({
color: colour,
id: 'plotline'+i,
value: points[i].x,
width: 1,
});
}
}
return plotLines;
}
Do you mean different colors for the xAxis and yAxis? I only see that this would make one of each. You can definitely set the colors of the axis lines independently.
See this: example, ref
EDIT:
For plotLines you can use this:
demo
If you take a look the reference you'll see that there's no attr named colors.
Other problem is that there's no attr plotLines1 and plotLines2 as you can see here
Solution: If you want to change a plot line color your have to pass your plotlines thrue an array, like the following and set theire color:
var options = {
chart : { renderTo : 'areaChart' },
xAxis: {
plotLines: [{
color: '#4572A7', //
width: 2,
value: 5.5,
id: 'plotline-1'
}, {
color: '#AA4643',
width: 2,
value: 8.5,
id: 'plotline-2'
}]
},
series : [ data.pointsopens, data.pointsclicks ]
};
Live example
Update1:
You're returning an array of objects in this function createPlotlines and then you put this array inside other array. That's the problem.
Replace your function to the following:
function createPlotlines(points, colour) {
// Create plotlines from point data
colour = colour || '#CCCCCC';
var middleYval = 0;
for (var i in points) {
middleYval = Math.max(middleYval, points[i].y);
if (points[i].l) { // l property is true if label should be on for this point
return {
color: colour,
id: 'plotline'+i,
value: points[i].x,
width: 1,
};
}
}
}
ok, here is what I needed, lineColor:
$data = array(
"name" => $name,
"color" => '#00FFFF',
"lineColor"=> '#00FFFF',
"data" => $rows
);
that code goes in a local function called compileChartData in my php.
Thanks for the effort and sorry for the mixup.
you can change plotLines to target single line.
Or else you can change the whole Yaxis or Xaxis
xAxis: {
type: 'datetime',
gridLineColor: '#EEEEEE'
},
yAxis: {
title: {
text: 'Calls'
},
gridLineColor: '#EEEEEE'
}

YUI3 scrollView and mousewheel

I'm starting to work only with YUI3. I include component scrollView, but it did not work mousewheel event, in the options I have not found how to turn on it. I would appreciate any help.
var scrollView = new Y.ScrollView({
id: "scrollview",
srcNode: '.scrollview-item',
height: 375,
flick: {
minDistance: 10,
minVelocity: 0.3,
axis: "y"
}
});
scrollView.render();
I stumbled upon this as well, after some trial and error, I managed to get that working(note, that it is just plain scrolling, without an easing).
var DOM_MOUSE_SCROLL = 'DOMMouseScroll',
fixArgs = function(args) {
var a = Y.Array(args, 0, true), target;
if (Y.UA.gecko) {
a[0] = DOM_MOUSE_SCROLL;
// target = Y.config.win;
} else {
// target = Y.config.doc;
}
if (a.length < 3) {
// a[2] = target;
} else {
// a.splice(2, 0, target);
}
return a;
};
Y.Env.evt.plugins.mousewheel = {
on: function() {
return Y.Event._attach(fixArgs(arguments));
},
detach: function() {
return Y.Event.detach.apply(Y.Event, fixArgs(arguments));
}
};
This is the YUI mousewheel event, but it's changed a bit. The biggest issue was, that originally, either the window or document elements, which makes no sense(for example when you mousewheel over the #myelement you want that to be the returned target..)
Bellow is the code used to initialize the ScrollView and the function that handles the mousewheel event:
// ScrollView
var scrollView = new Y.ScrollView({
id: "scrollview",
srcNode: '#mycontainer',
height: 490,
flick: {
minDistance:10,
minVelocity:0.3,
axis: "y"
}
});
scrollView.render();
var content = scrollView.get("contentBox");
var scroll_modifier = 10; // 10px per Delta
var current_scroll_y, scroll_to;
content.on("mousewheel", function(e) {
// check whether this is the scrollview container
if ( e.currentTarget.hasClass('container') ) {
current_scroll_y = scrollView.get('scrollY');
scroll_to = current_scroll_y - ( scroll_modifier * e.wheelDelta );
// trying to scroll above top of the container - scroll to start
if ( scroll_to <= scrollView._minScrollY ) {
// in my case, this made the scrollbars plugin to move, but I'm quite sure it's important for other stuff as well :)
scrollView._uiDimensionsChange();
scrollView.scrollTo(0, scrollView._minScrollY);
} else if ( scroll_to >= scrollView._maxScrollY ) { // trying to scroll beneath the end of the container - scroll to end
scrollView._uiDimensionsChange();
scrollView.scrollTo(0, scrollView._maxScrollY);
} else { // otherwise just scroll to the calculated Y
scrollView._uiDimensionsChange();
scrollView.scrollTo(0, scroll_to);
};
// if we have scrollbars plugin, flash the scrollbar
if ( scrollView.scrollbars ) {
scrollView.scrollbars.flash();
};
// prevent browser default behavior on mouse scroll
e.preventDefault();
};
});
So basically that's how I managed to that, but my next challenge is to get the scrollbar work like regular scrollbar(when you drag it, the container should move correspondingly...)
Hope this helps anyone :)

Resources