How do I make object fall on impact in Matter.js? - javascript

I'm using Matter.js for some graphics and want this rectangle
let title = Bodies.rectangle(w / 2.4, height / 1.8, 300, 100, {
isStatic: true,
})
to get isStatic: false and fall when it's hit by some circles that are raining down on it. I've done some extensive Googling, but haven't really found anything else but this:
Events.on(engine, 'collisionStart', function (event) {
event.pairs.forEach(function (obj) {
console.log(
'BodyA is static: ' + obj.bodyA.isStatic + '. BodyB is static: ' + obj.bodyB.isStatic
)
})
})
This gives me all the collisions happening, but I haven't figured out how to set isStatic: false when something hits. Appreciate your help!

You can call Matter.Body.setStatic(body, false) on the body in question to make it active.
Here's an example:
const engine = Matter.Engine.create();
const render = Matter.Render.create({
element: document.body,
engine,
options: {width: 400, height: 400, wireframes: false},
});
const fallingBody = Matter.Bodies.rectangle(
200, 0, 20, 20, {
frictionAir: 0.1,
density: 0.8,
render: {fillStyle: "red"},
},
);
const wall = Matter.Bodies.rectangle(
200, 150, 400, 20, {
frictionAir: 0.05,
isStatic: true,
render: {fillStyle: "green"}
},
);
Matter.Composite.add(engine.world, [fallingBody, wall]);
Matter.Events.on(engine, "collisionStart", event => {
if (
wall.isStatic &&
event.pairs.some(e => Object.values(e).includes(wall))
) {
Matter.Body.setStatic(wall, false);
}
});
Matter.Render.run(render);
Matter.Runner.run(Matter.Runner.create(), engine);
<script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.18.0/matter.min.js"></script>

Related

Phaser 3 - Particles become more the more often I emit them?

I have particles that I emit when clicking and moving my mouse over a certain object. However I noticed that while the particles start out as little, they become more and more the more often I click and move my mouse,until the stream of particles is far too dense.
This only seems to happen when I click down multiple times (thus triggering the pointerdown event multiple times), not when I click once and keep moving.
How can I stop this?
function pet(start, scene, pointer = null)
{
if(start){
scene.input.on('pointermove', function(){
if (scene.input.activePointer.isDown && gameState.chara.getBounds().contains(scene.input.activePointer.x, scene.input.activePointer.y)){
gameState.sparkle.emitParticle(1,scene.input.activePointer.x, scene.input.activePointer.y); // !!!! Here is where I emit my particles
}
});
} else {
gameState.sparkle.stop(); // !!!! Here I stop my particles
}
}
const gameState = {
gameWidth: 800,
gameHeight: 800,
menu: {},
textStyle: {
fontFamily: "'Comic Sans MS'",
fill: "#fff",
align: "center",
boundsAlignH: "left",
boundsAlignV: "top"
},
};
function preload()
{
this.load.baseURL = 'assets/';
// Chara
this.load.atlas('chara', 'chara.png', 'chara.json');
// Particle
this.load.image('sparkle', 'sparkle.png'); // Here I load my particle image
}
function create()
{
// Scene
let scene = this;
// Chara
this.anims.create({
key: "wag",
frameRate: 12,
frames: this.anims.generateFrameNames("chara", {
prefix: 'idle_000',
start: 0,
end: 5}),
repeat: 0,
});
this.anims.create({
key: "happy",
frameRate: 12,
frames: this.anims.generateFrameNames("chara", {
prefix: 'happy_000',
start: 0,
end: 5}),
repeat: -1
});
gameState.chara = this.add.sprite(400, 400, "chara", "idle_0000");
gameState.chara.setInteractive({cursor: "pointer"});
// !!!! Here I set up my Particle Emitter !!!!
gameState.sparkle = this.add.particles('sparkle').createEmitter({
x: gameState.height/2,
y: gameState.width/2,
scale: { min: 0.1, max: 0.5 },
speed: { min: -100, max: 100 },
quantity: 0.1,
frequency: 1,
lifespan: 1000,
gravityY: 100,
on: false,
});
gameState.chara.on('pointerdown', function(){ pet(true, scene) });
gameState.chara.on('pointerout', function(){ pet(false, scene, 'default') });
gameState.chara.on('pointerup', function(){ pet(false, scene, 'pointer') });
}
function update()
{
}
// Configs
var config = {
backgroundColor: "0xf0f0f0",
scale: {
width: gameState.gameWidth,
height: gameState.gameHeight,
autoCenter: Phaser.Scale.CENTER_BOTH
},
scene: {
preload, create, update
}
};
var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
The problem is, that you are adding a new scene.input.on('pointermove',...) event-handler in the pet function, on each click.
I would only change the code abit (look below), this should prevent generating too many particles and too many event-handlers (too many event-handlers could harm performance, so be careful, when adding them).
Here is how I would modify the Code:
(I stripped out and added some stuff to make the demo, easier to understand and shorter. And also that the snippet can be executed, without errors/warnings)
The main changes are marked and explained in the code, with comments
function pet(start, scene, pointer = null)
{
if(start){
// Update: remove Event listener add click state
gameState.mouseDown = true
} else {
// Update: add click state
gameState.mouseDown = false;
gameState.sparkle.stop();
}
}
const gameState = {
gameWidth: 400,
gameHeight: 200,
// Update: add click state
mouseDown: false
};
function create()
{
// Scene
let scene = this;
// Just could for Demo START
var graphics = this.add.graphics();
graphics.fillStyle(0xff0000);
graphics.fillRect(2,2,10,10);
graphics.generateTexture('particle', 20, 20);
graphics.clear();
graphics.fillStyle(0xffffff);
graphics.fillRect(0,0,40,40);
graphics.generateTexture('player', 40, 40);
graphics.destroy();
// Just Code for Demo END
gameState.chara = this.add.sprite(200, 100, "player");
gameState.chara.setInteractive({cursor: "pointer"});
gameState.sparkle = this.add.particles('particle').createEmitter({
scale: { min: 0.1, max: 0.5 },
speed: { min: -100, max: 100 },
quantity: 0.1,
frequency: 1,
lifespan: 1000,
gravityY: 100,
on: false,
});
gameState.chara.on('pointerdown', function(){ pet(true, scene) });
gameState.chara.on('pointerout', function(){ pet(false, scene, 'default') });
gameState.chara.on('pointerup', function(){ pet(false, scene, 'pointer') });
// Update: add new single Event Listener
gameState.chara.on('pointermove', function(pointer){
if(gameState.mouseDown){
gameState.sparkle.emitParticle(1,pointer.x, pointer.y);
}
});
}
// Configs
var config = {
width: gameState.gameWidth,
height: gameState.gameHeight,
scene: { create }
};
var game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>

Can't limite bandwidth usage in RTCMulticonnection

I am using RTCMulticonnection in one of my projects. Where I want to limit video stream bandwidth to 500-600kbp. I gone through the documentation and set sdp constraints with bandwidth Handeller. and I reduced the width to 320p and height 180 using mediaConstrains. but still, 2-2.5 Mbps used in both sent and receive.
Here is the code what I am using
<script src="https://rtcmulticonnection.herokuapp.com/dist/RTCMultiConnection.min.js"></script>
<script src="https://rtcmulticonnection.herokuapp.com/socket.io/socket.io.js"></script>
<script>
var connection = new RTCMultiConnection();
// this line is VERY_important
connection.socketURL = 'https://rtcmulticonnection.herokuapp.com:443/';
// if you want audio+video conferencing
connection.session = {
audio: true,
video: true
};
connection.mediaConstraints = {
audio: true,
video: {
mandatory: {
minWidth: 360,
maxWidth: 360,
minHeight: 180,
maxHeight: 180,
minFrameRate: 15,
minAspectRatio: 1.77
}
}
};
if (DetectRTC.browser.name === 'Firefox') {
connection.mediaConstraints = {
audio: true,
video: {
width: 360,
height: 180,
frameRate: 15,
aspectRatio: 1.77
}
};
}
var BandwidthHandler = connection.BandwidthHandler;
connection.bandwidth = {
audio: 90,
video: 400,
screen: 360
};
connection.processSdp = function(sdp) {
sdp = BandwidthHandler.setApplicationSpecificBandwidth(sdp, connection.bandwidth, !!connection.session.screen);
sdp = BandwidthHandler.setVideoBitrates(sdp, {
min: connection.bandwidth.video,
max: connection.bandwidth.video
});
sdp = BandwidthHandler.setOpusAttributes(sdp);
sdp = BandwidthHandler.setOpusAttributes(sdp, {
'stereo': 1,
//'sprop-stereo': 1,
'maxaveragebitrate': connection.bandwidth.audio * 1000 * 8,
'maxplaybackrate': connection.bandwidth.audio * 1000 * 8,
//'cbr': 1,
//'useinbandfec': 1,
// 'usedtx': 1,
'maxptime': 3
});
return sdp;
};
connection.openOrJoin('your-room-id');
</script>
Is that anything am I doing wrong?
I have no experience about RTCMulticonnection.
So I just want to say about bandwidth option in SDP.
How about add value in sdp?
like 'b=AS:600'

React Cytoscape JS : All nodes are accumulated in one position

When creating a path using dagre, the whole nodes accumulate in one position. How can we set default positions for nodes ( Cytoscape js without react works fine) instead of setting position separately using position attribute for nodes.
const layout = {
name: "dagre",
rankDir: "LR"
}
pageData = < CytoscapeComponent
elements = {
CytoscapeComponent.normalizeElements({
nodes: nodess,
edges: edgess,
layout: layout,
})
}
pan = {
{
x: 200,
y: 200
}
}
autounselectify = {
true
}
userZoomingEnabled = {
false
}
boxSelectionEnabled = {
false
}
style = {
{
width: "1200px",
height: "1000px"
}
}
/>
return (
< div
{
pageData
}
< /div>
);
Expected result:
Current result:
There is a way to force the calculation of node positions as they are added. This is also useful when the elements of the graph change dynamically with the state of the component and the graph has to be rendered again with updated node positions.
<CytoscapeComponent
cy={(cy) => {
this.cy = cy
cy.on('add', 'node', _evt => {
cy.layout(this.state.layout).run()
cy.fit()
})
}}
/>
Here is what worked for me:
cytoscape.use(fcose)
//..then in my render...
<CytoscapeComponent
elements={elements1}
layout={{
animate: true,
animationDuration: undefined,
animationEasing: undefined,
boundingBox: undefined,
componentSpacing: 40,
coolingFactor: 0.99,
fit: true,
gravity: 1,
initialTemp: 1000,
minTemp: 1.0,
name: 'fcose',
nestingFactor: 1.2,
nodeDimensionsIncludeLabels: false,
nodeOverlap: 4,
numIter: 1000,
padding: 30,
position(node) {
return { row: node.data('row'), col: node.data('col') }
},
randomize: true,
refresh: 20,
}}
style={{ width: '600px', height: '300px' }}
/>
You may try "Euler" layout instead of "Dagre" layout

Rex UI Scrollable Panel: Unable to understand how it works

I'm working on a game in Phaser 3 and I need to use some sort of scrollable panel, so I chose to use Rex UI (if you know any alternatives, please tell me. At first I wanted to use phaser-list-view from npm but it's only in phaser 2). It seems like these plugins do not have much documentation. The docs are on this site: Notes of Phaser 3.
So I have my game configuration and I'm loading like this (oversimplified):
import UIPlugin from '../plugins/ui-plugin.js';
const config = {
// ...
plugins: {
scene: [{
key: 'rexUI',
plugin: UIPlugin,
mapping: 'rexUI'
}]
}
// ...
};
const game = new Phaser.Game(config);
And in a scene I try to use it:
export default class MyScene extends Phaser.Scene {
create() {
this.rexUI.add.scrollablePanel({
x: 0, y: 0,
width: innerWidth,
height: innerHeight/2,
scrollMode: 'horizontal',
panel: {
child: this.add.container().setSize(2 * innerWidth, innerHeight/2)
.add(this.itemImage(1))
.add(this.itemImage(2))
// ...
// (I'm actually using for-loop and save this container in a
// separate variable, but I'm over simplifying this snippet)
mask: false
},
slider: {
track: this.add.graphics({x: 0, y: innerHeight/2 + 10})
.fillRect(0, 0, innerWidth, 30).fillStyle(SOME_LIGHT_COLOR)
.setInteractive(
new Phaser.Geom.Rectangle(0, 0, innerWidth, 30),
Phaser.Geom.Rectangle.Contains
),
thumb: this.add.graphics({x: 0, y: innerWidth/2 + 10})
.fillRect(0, 0, 50, 30).fillStyle(SOME_DARK_COLOR)
.setInteractive(
new Phaser.Geom.Rectangle(0, 0, 50, 30),
Phaser.Geom.Rectangle.Contains
)
}
}).layout()
}
itemImage(n) {
return this.add.image((innerHeight/2 + 30) * (n-1), 0, 'item' + n)
.setDisplaySize(innerHeight/2, innerHeight/2)
}
}
There are many problems. Firstly with the above code I get the error:
Uncaught TypeError: this.child.getAllChildren is not a function
at e.Xo [as resetChildPosition] (<anonymous>:1:205731)
at e.layout (<anonymous>:1:206243)
at e.layout (<anonymous>:1:126859)
at e.layout (<anonymous>:1:126859)
at e.value (<anonymous>:1:172299)
at MyScene.create (MyScene.js:117)
at initialize.create (phaser.min.js:1)
at initialize.loadComplete (phaser.min.js:1)
at initialize.h.emit (phaser.min.js:1)
at initialize.loadComplete (phaser.min.js:1)
The error goes away if I just remove .layout(). But however, the thumb on the scroller is not anywhere in the scene and I can't even scroll the container.
The docs don't say what exacly should go in panel.child, scrolller.track and scroller.thumb
Can someone help me out of this?
try this, just call createTable():
me.createTable({
x: 390,
y: 410,
width: 350,
height: 220,
rank: [{"score":1520,"userID":1,"userName":"Augustus Nico"},{"score":360,"userID":"_2hzxb91byxw","userName":"lipão"},{"score":250,"userID":3,"userName":"Sarão"},{"score":200,"userID":5,"userName":"Bruna Santini"},{"score":160,"userID":4,"userName":"Paulo Junior"},{"score":100,"userID":2,"userName":"Vilasboas"}]
});
const COLOR_PRIMARY = 0x4e342e;
const COLOR_LIGHT = 0x7b5e57;
const COLOR_DARK = 0x260e04;
const COLOR_WHITE = 0xffffff;
export const createTable = ({ x, y, width, height, rank }) => {
var scrollablePanel = this.rexUI.add
.scrollablePanel({
x: x,
y: y,
width: width,
height: height,
scrollMode: 0,
background: this.rexUI.add.roundRectangle(0, 0, 2, 2, 10, COLOR_WHITE),
panel: {
child: createGrid(this, rank),
mask: {
mask: true,
padding: 1
}
},
slider: {
track: this.rexUI.add.roundRectangle(0, 0, 20, 10, 10, COLOR_LIGHT),
thumb: this.rexUI.add.roundRectangle(0, 0, 0, 0, 13, COLOR_DARK)
},
space: {
left: 10,
right: 10,
top: 10,
bottom: 10,
panel: 10,
header: 10,
footer: 10
}
})
.layout();
};
const createGrid = (scene, rank) => {
var sizer = scene.rexUI.add.gridSizer({
column: 2,
row: rank.length,
columnProportions: 1
});
rank.forEach((player, index) => {
sizer.add(
scene.createItem(scene, 0, index, player.userName), // child
0, // columnIndex
index, // rowIndex
"center", // align
0, // paddingConfig
true // expand
);
sizer.add(
scene.createItem(scene, 1, index, player.score), // child
1, // columnIndex
index, // rowIndex
"center", // align
0, // paddingConfig
true // expand
);
});
return sizer;
};
const createItem = (scene, colIdx, rowIdx, text) => {
var item = scene.rexUI.add
.label({
background: scene.rexUI.add
.roundRectangle(0, 0, 0, 0, 0, undefined)
.setStrokeStyle(2, COLOR_DARK, 1),
text: scene.add.text(0, 0, text, {
fontSize: 18,
fill: "#000"
}),
space: {
left: 10,
right: 10,
top: 10,
bottom: 10,
icon: 10
}
})
.setDepth(3);
var press = scene.rexUI.add.press(item).on("pressstart", function() {
console.log(`press ${text}`);
});
return item;
};

How to disable a function to relaunch on hover

I'm trying to make a bouncy ball which move on hover by the user. I got a problem on how to disable the function to relaunch if the ball cross again the mouse. It cause some freeze/bugs sometimes. I'm not exactly sure on how to proceed to avoid that. Do you guys have any tips ?
https://codepen.io/kombolo/pen/YvzPvm
Thanks !
window.onmousemove = logMouseMove;
function logMouseMove(e) {
e = e || window.event;
mousePos = e.clientX;
el = document.querySelector('.circle');
const elPos = getOffset(el);
if(mousePos < (elPos -20) || mousePos > (elPos + 20)) {
triggerAnimation();
};
}
function getOffset(el) {
el = el.getBoundingClientRect();
return el.left + window.scrollX + 50;
}
function triggerAnimation() {
xValues = [100, 0, 400];
yValues = [0, 50, 200];
const xVal = xValues[Math.floor(Math.random()*xValues.length)];
const yVal = yValues[Math.floor(Math.random()*yValues.length)];
var duration = anime({
targets: '#duration .el',
translateX: [
{ value: xVal, duration: 1000, delay: 500, elasticity: 0 },
{ value: xVal, duration: 1000, delay: 500, elasticity: 0 }
],
scaleX: [
{ value: 2, duration: 100, delay: 500, easing: 'easeOutExpo' },
{ value: 1, duration: 900, elasticity: 300 },
{ value: 2, duration: 100, delay: 500, easing: 'easeOutExpo' },
{ value: 1, duration: 900, elasticity: 300 }
],
translateY: [
{ value: yVal, duration: 1000, delay: 500, elasticity: 0 },
{ value: yVal, duration: 1000, delay: 500, elasticity: 0 }
],
});
}
Mouse hover is an extensive event. You are doing too much on hover.
what I would suggest is - set window.onmousemove = undefined in
triggerAnimation function and then turn it on in the last. This helped a little.
function triggerAnimation() {
window.onmousemove = void 0;
xValues = [100, 0, 400];
.....
....
//loop: true
});
window.onmousemove = logMouseMove;
}

Categories