How do I set configuration for a group in Phaser 3? - javascript

In my Phaser 3 game I have a group called OBS that stores all the obstacles sprites.
OBS = this.physics.add.group
I want to set the velocity of every child created from this group to a particular value say
setVelocityY=40
So every object that is in group OBS will move at velocity 40. How do I set a configuration for the group such that every object that I add to it moves at the given velocity and shares other common properties?

There are multiple ways to do that.
using config -
You can pass PhysicsGroupConfig while creating group, and set velocityY in that config that will set velocityY of every children of that group. You can set many properties in config. Check out the docs.
using group's methods like setVelocity or setVelocityY - if you want to set velocity after creating group you can use group's methods like setvelocityY or setVelocity.

You can use a for-loop to add properties to all the child elements.
Eg. if you have 3 child elements, you can do it like this:
var OBSPositions = [
{ x: 50, y: 80 },
{ x: 50, y: 480 },
{ x: 300, y: 480 }
];
OBS = this.physics.add.group;
for (var i = 0; i < OBSPositions.length; i++) {
var OBSchild = OBS.create(
OBSPositions[i].x,
OBSPositions[i].y,
'OBSsprite'
).setScale(0.13, 0.13);
OBSchild.setVelocityY = 40;
}

Related

Phaser 3 - Check group collision with world bounds

In my scenario, i create a ship according to player's preferences. The ship consists of the flag and the hull.
An example view
PROBLEM-1
Ship is an Arcade.Group and i want to prevent this group from going outside the borders of the world.
create(){
// Create a group for ship
this.shipGroup = this.physics.add.group()
// Add hull to shipGroup
this.shipGroup.create(400, 500, "1021")
// Add flag to shipGroup
const mainFlag = this.shipGroup.create(400, 500, "FA1")
mainFlag.setOrigin(0.5, 0.8)
// Set collision property to true of every object in shipGroup
this.shipGroup.children.each((item: any) =>
item.setCollideWorldBounds(true)
)
}
update(t: number, dt: number){
if (this.cursor.up.isDown) {
this.shipGroup.setVelocity(...)
}
else {
this.shipGroup.setVelocity(0, 0)
}
}
With this approach every object in group calculated seperately. After hitting the world boundary, the position of the objects is distorted.
PROBLEM-2
To avoid this i tried another approach. I add bounding box to group. Instead of check collision for every object, i will only check collision for bounding box.
create(){
// Create a group for ship
this.shipGroup = this.physics.add.group()
// Add bounding box for shipGroup
this.shipBox = this.shipGroup.create(400, 500, "bbox")
this.shipBox.setCollideWorldBounds(true)
this.shipBox.body.onWorldBounds = true
// Add hull to shipGroup
this.shipGroup.create(400, 500, "1021")
// Add flag to shipGroup
const mainFlag = this.shipGroup.create(400, 500, "FA1")
mainFlag.setOrigin(0.5, 0.8)
/*this.shipGroup.children.each((item: any) =>
item.setCollideWorldBounds(true)
)*/
}
update(t: number, dt: number){
if (this.cursor.up.isDown && !this.shipBox.body.checkWorldBounds()) {
this.shipGroup.setVelocity(...)
}
else {
this.shipGroup.setVelocity(0, 0)
}
}
The problem is checkWorldBounds() returns false even if shipBox hits world boundaries. But collision for shipBox is work.
checkWorldBounds()
Description: Checks for collisions between this Body and the world
boundary and separates them.
Returns: True if this Body is colliding with the world boundary.
How can i implement collision for group and world boundary?
P.S. : phaser version is 3.55.2
There are a few ways to solve/work around this issue, I personally would just use only one image why one physics-body (hull and flag combined) and just move that single image/texture, and switch the image, when needed.
That said, if you need to use the separate images, the easy way is to use a phaser container. (link to the documentation)
create a container
add the images to the container
set the size for the container (default size is width=0 height=0)
create a physics body for the container
done
A short demo:
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536,
height: 183,
physics: {
default: 'arcade',
arcade: {
gravity:{ y: 0 },
debug: true
}
},
scene: {
create
},
banner: false
};
function create () {
this.add.text(10,10, 'Ship with physics')
.setScale(1.5)
.setOrigin(0)
.setStyle({fontStyle: 'bold', fontFamily: 'Arial'});
let graphics = this.make.graphics();
graphics.fillStyle(0xffffff);
graphics.fillRect(0, 0, 10, 40);
graphics.generateTexture('ship', 10, 40);
graphics.fillStyle(0xff0000);
graphics.fillRect(0, 0, 30, 10);
graphics.generateTexture('flag', 30, 10);
graphics.generateTexture('flag2', 20, 6);
let hull = this.add.image(0, 0, 'ship')
let flag = this.add.image(0, -5, 'flag')
let flag2 = this.add.image(0, 10, 'flag2')
this.ship = this.add.container(100, 80, [ hull, flag, flag2]);
this.ship.setAngle(-90)
this.ship.setSize(40, 30)
this.physics.world.enable(this.ship);
this.ship.body.setVelocity(100, 0).setBounce(1, 1).setCollideWorldBounds(true);
}
new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
Info: this demo is based partly from this official example

Different Depth In 3D BarChart in Highcharts

I know that I can set depth of all bars in Highcharts using depth property in column property of plotOptions likes the following code:
plotOptions: {
column : {
depth: 30
}
}
Or
# in R
hc_plotOptions(column = list(
depth = 30
)
The questions is how can I set different depth for each bar group in a bar chart (not one depth for all)? Solution can be in R (Highcharter) or in JS?
In core code the depth property is always taken from the series object options. Every group consists of the points with the same x values.
These 2 solutions came to my mind:
1. Modify the core code so that depth values are taken from points' configuration instead:
(function(H) {
(...)
H.seriesTypes.column.prototype.translate3dShapes = function() {
(...)
point.shapeType = 'cuboid';
shapeArgs.z = z;
shapeArgs.depth = point.options.depth; // changed from: shapeArgs.depth = depth;
shapeArgs.insidePlotArea = true;
(...)
};
})(Highcharts);
Series options:
series: [{
data: [{y: 5, depth: 50}, {y: 2, depth: 100}]
}, {
data: [{y: 13, depth: 50}, {y: 1, depth: 100}]
}]
Live demo: http://jsfiddle.net/kkulig/3pkon2Lp/
Docs page about overwriting core functions: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
2. Create a separate series for every point.
depth property can be applied to a series so the modification of the core wouldn't be necessary. Every series is shown in legend by default so series will have to be properly connected using linkedTo property (so that the user doesn't see as many series as points).
Points can be modified before passing them to the chart constructor or dynamically handled in chart.events.load.
Live demo: http://jsfiddle.net/kkulig/37sot3am/
load: function() {
var chart = this,
newSeries = [],
merge = Highcharts.merge,
depths = [10, 100]; // depth values for subsequent x values
for (var i = chart.series.length - 1; i >= 0; i--) {
var s = chart.series[i];
s.data.forEach(function(p, i) {
// merge point options
var pointOptions = [merge(p.options, {
// x value doesn't have to appear in options so it needs to be added manually
x: p.x
})];
// merge series options
var options = merge(s.options, {
data: pointOptions,
depth: depths[i]
});
// mimic original series structure in the legend
if (i) {
options.linkedTo = ":previous"
}
newSeries.push(options);
});
s.remove(true);
}
newSeries.forEach((s) => chart.addSeries(s));
}
API reference:
https://api.highcharts.com/highcharts/plotOptions.series.linkedTo

javascript - draw image with layers

Have I possibility to draw image in canvas, with layers? Particularly using fabric.js or literallycanvas.js ? Will be appreciate for any information or examples, ty
Layers are software abstractions. They define groups of items that are processed in a specific order (layered).
Anything can be layered, so drawing on the canvas it is easy to make layers.Group all the objects to be drawn in each layer together. Then render all objects in each layer together in the order defined by the layers.
A very simple layer example
var layers = []; // holds layers
function addLayer(order){ /// creates and adds a layer
var l;
layers.push(l = {
order : order,
items : [],
render : function(){
this.items.forEach(function(img){
ctx.drawImage(img.bitmap,img.x,img.y);
});
});
return l;
}
// some items for the layers
var img1 = {
bitmap : new Image("URL"),
x : 100,
y : 200,
}
var img2 = {
bitmap : new Image("URL"),
x : 300,
y : 200,
}
// create a layer order 1
var lay1 = AddLayer(1);
// add some items to lay1
lay1.items.push(img1);
lay1.items.push(img2);
// add a second layer order 0
var lay2 = AddLayer(0);
lay1.items.push(img3);
lay1.items.push(img4);
// sort layers by order
layers.sort(function(a,b){return a.order-b.order;});
// process each layer in the sorted order
layers.forEach(function(layer){
layer.render();
});

Need a solid way to set relational indices for object polygons drawn in a canvas element

Okay this is going to be hard to explain. So bear with me.
Im having less of a problem with the programming, and more a problem with the idea behind what Im trying to do.
I have a grid of triangles. Ref: http://i.imgur.com/08BPHiD.png [1]
Each triangle is it's own polygon on a canvas element that I have set as an object within the code. The only difference between the objects is the coordinates that I pass through as parameters of a function like so:
var triCoordX = [1, 2, 3, ...];
var triCoordY = [1, 2, 3, ...];
var triCoordFlipX = [1, 2, 3, ...];
var triCoordFlipY = [1, 2, 3, ...];
var createTri = function(x, y, z) {
return {
x: x,
y: y,
sides: 3,
radius: 15,
rotation: z,
fillRed: 17,
fillGreen: 17,
fillBlue: 17,
closed: true,
shadowColor: '#5febff',
shadowBlur: 5,
shadowOpacity: 0.18
}
};
for (i = 0; i < triCoordX.length; i++){
var tri = new Kinetic.RegularPolygon(createTri(triCoordX[i], triCoordY[i], 0));
}
for (i = 0; i < triCoordFlipX.length; i++){
var triFlip = new Kinetic.RegularPolygon(createTri(triCoordFlipX[i], triCoordFlipY[i], 180));
}
Now what Im trying to do exactly is have each object polygon be able to 'recognise' its neighbors for various graphical effects.
How I propose to do this is pass a 4th parameter into the function that I push from another array using the for loop that sets a kind of "index" for each polygon. Also in the for loop I will define a function that points to the index 'neighbors' of the object polygon.
So for instance, if I want to select a random triangle from the grid and make it glow, and on completion of a tween want to make one of it's neighbors glow I will have the original triangle use it's object function to identify a 'neighbor' index and pick at random one of its 3 'neighbors'.
The problem is with this model, Im not entirely sure how to do it without large amounts of bloat in my programming, or when I set the function for the loop, to set a way for the loop to intuitively pick the correct index numbers for what are actually the triangle's neighbors.
If all of that made sense, Im looking for any and all suggestions.
Think of your triangles as being laid out in a grid with the triangle in the top left corner being col==0, row==0.
Then you can find the row/col coordinates of the 3 neighbors of any triangle with the following function.
Ignore any neighbors with the following coordinates because the neighbors would be off the grid.
col<0
row<0
col>ColumnCount-1
row>RowCount-1
Example code (warning...untested code--you may have to tweak it):
function findNeighbors(t){
// determine if this triangle's row/col are even or odd
var evenRow=(t.col%2==0);
var evenCol=(t.row%2==0;
// left neighbor is always the same
n1={ col:t.col-1, row:t.row };
// right neighbor is always the same
n2={ col:t.col+1, row:t.row };
// third neighbor depends on row/col being even or odd
if(evenRow && evenCol){
n3={ col:t.col, row:t.row+1 };
}
if(evenRow && !evenCol){
n3={ col:t.col, row:t.row-1 };
}
if(!evenRow && evenCol){
n3={ col:t.col, row:t.row-1 };
}
if(!evenRow && !evenCol){
n3={ col:t.col, row:t.row+1 };
}
// return an array with the 3 neighbors
return([n1,n2,n3]);
}

Working with Objects in Javascript

I am Currently Trying to work with JavaScript in a cleaner object orientated way, So Please excuse me if I'm doing this entirely incorrectly I am using this previous questions answer as a general reference, but Here's my 'test' code:
//Create some sample objects to play with.
var testJSON = {
"rectangle": [
{ "id":3 , "x":5, "y":10, "width":10, "height":50
}
]
};
//Create Rectangle Constructor
var rectangle = {
init: function( i, x, y, width, height ) {
this.id = i,
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.fields = []
},
move: function( x, y ) {
this.x += x;
this.y += y;
}
};
//Create test array to hold all the objects
var test = [];
//Create a new rectangle object
var myRectangle = Object.create( rectangle );
myRectangle.init( 1, 0, 0, 2, 4 );
myRectangle.move( 3, 5 );
//put rectangle object in array associated with id
test[myRectangle.id] = myRectangle;
//Create a new rectangle object with the same variable name as it will all be in an array anyway.
var myRectangle = Object.create( rectangle );
myRectangle.init( 2, 0, 0, 2, 4 );
myRectangle.move( 0, 0 );
//put rectangle object in array associated with id
test[myRectangle.id] = myRectangle;
//put JSON result in
test[testJSON.rectangle[0].id] = testJSON.rectangle[0];
//No Longer need this variable, is it worth getting rid of.. i dont know
myRectangle =null;
//Try and use methods created in the constructor.
test[2].move(4,8);
console.log(test);
Okay, Now the actual questions, The Application I am trying to create, has both json data and it will have users that create data, so for example: the application will generate a bunch of 'rectangles' and then the user can also create rectangles.
So the first question would be, 'Is this the correct approach' and then secondly how would i get the json data to also have the method defined in the rectangle constructor (move)?
Any Help Greatly Appreciated.
This an extension of what #Marc B and #Ray Toal mentioned...
You have created javascript functions - which is not at all that bad - but not JSON. To create graphics, you could use the canvas tag as, in effect, a "drawing div" and use the object's x and y positions to constantly update them - if you were considering doing 2d animation. If so, I would recommend CreateJs as a starting block before hard-coding JAVASCRIPT animations. Again, you're code is just fine, but having users create this data - if you were considering a server application would involve using real JSON or perhaps Node.js - but for now I'd focus on single player aspect and setting up you're objects on a graphical 'interface' like <canvas>

Categories