I'm creating an Rpg in Phaser, and I'm trying to make a Flash effect happen over a Sprite -that means turning the Sprite all white for a moment and then returning to its original color-.
So my question is: what's the best way of achieving this effect?. I've tried two solutions so far, but i'm missing something:
Solution 1:
I tried tweening the tint parameter of the sprite, like this:
this.game.add.tween(enemy).to({
tint: 0xffffff,
}, 100, Phaser.Easing.Exponential.Out, true, 0, 0, true);
But it doesn't work since setting the tint to 0xffffff is the same as setting it to its default color.
Solution 2:
My second possible solution is adding a white square that has the same size of the sprite, and using the actual sprite as a mask for the square:
var flash = this.game.add.graphics(0, 0);
flash.beginFill(0xffffff);
flash.drawRect(enemy.x, enemy.y, enemy.width, enemy.height);
flash.endFill();
flash.mask = enemy // enemy is my Sprite
/* .. code for tweening the flash */
The problem with this solution is that the mask needs to be a PIXI.Graphics object; and I'm using a Sprite object.
So please, any guidance would be appreciated.
In the version of Pixi that Phaser 2.2.2 uses there is a 'tintCache' which basically rounds the tint value, then caches the result. This means you can't do subtle tint ramping like you're trying to do with a tween. We removed this in Phaser 2.3, so it will be available from then, but as of now it's still in dev.
Also you can tint to a 'near white' colour - only 0xffffff precisely resets the tint. But a value very close to that would still be set ok and probably have the desired result.
If you're using WebGL I would still use a tint with 'as near as white as possible' colour values and tween them. You could disable the tint cache for yourself by copying that part of the changed code from the Phaser dev branch.
In Canvas mode it's expensive though as it has to recalculate the pixels every single time you update it.
If you need to worry about Canvas performance then honestly I would create a new PNG that matches your sprite, colour it in all-white and display it over the top of your main sprite as needed and alpha it out. It's less than ideal because of the extra assets required, but it would be the fastest in canvas mode for sure. All depends on your game though is that's acceptable or not.
Edit: Also occurred to me that you could probably achieve what you need by using a blend mode too, such as lighten. You'd duplicate your main sprite, set the blend mode on it, display it over the top of your sprite and fade it out. This would work fine in Canvas at least.
You can use a ColorMatrixFilter on the Sprite. In Phaser, you may have to manually load in the PIXI script first:
game.load.script('filter', 'js/filters/ColorMatrixFilter.js');
Use this for white:
var filter = new PIXI.ColorMatrixFilter();
filter.matrix = [1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1];
this.game.filter = [filter];
You can also tween the matrix values if you want a smooth transition.
Related
I have been developing a program which includes some sort of genetic algorithm. For my program, let's say there is a population of 200 units, and each unit can be in 5 different states. Inititlly, they all start at state 0, and they can randomly jump to states 1 to 4, and influence other units to jump as well. This way, the more units are on state 2, the more units will jump to state 2 and so on. I have these units moving randomly inside my canvas, bouncing off the walls when they hit them.
The one thing I want to do now is visualize the evolution on a chart, and for that I would like to have the canvas with the units jumping states on one side and the chart next to it, dynamically representing the percentage of units in state 0, 1, 2... simultaneously. I will presumably have no problem in coding the chart, however I cannot find a way of displaying it outside the canvas or without altering it.
Just in case, I am programming in Atom and have mostly used p5 libraries.
Any ideas??
You have 2 options:
Make a second canvas (Like enhzflep said), but this might be complicated for you, becuase you will not have access to P5.js drawing tools on that second canvas, look at this:
(On your first canvas)
fill(255,0,0)
rect(50,50,50,50);
To make and draw to a second canvas:
const canvas = document.createElement('canvas');
document.body.appendChild(canvas);
//deal with positioning, scaling, and other stuff (comment if you need help with that)
...
const c = canvas.getContext('2d');
c.fillStyle = "rgb(255,0,0)";
c.fillRect(50,50,50,50);
(See, lots of effort)
Or, you can just use your first canvas, and partition a section off that is dedicated to the graph
createCanvas(600 + graphWidth, 600);
//Wherever your bouncing off walls code is
//for the right side of the screen
if(this.x > width - graphWidth){
bounce();
}
//that leaves you a graphWidth by 600 rectangle for you to draw you graph
The second option is much easier to read and will save you some headaches (I would use that).
Here is a solution that just replaces the entire texture with a solid color:
sprite.texture = PIXI.Texture.WHITE
Obviously this wont work with transparent sprites. Any transparency ends up solid as well. (Resulting in a solid rectangle)
How could I change the color of only non transparent pixels of the sprite?
(tint wont work either since all sprites would have to be white)
As far as I know, you can't do it with Pixi. According to one of Pixi maintainers here, you can use dark tint from pixi-heaven package (https://github.com/gameofbombs/pixi-heaven). This exact example is listed in its readme:
Make whole sprite of one color:
sprite.tint = 0xffaacc;
sprite.color.dark[0] = sprite.color.light[0];
sprite.color.dark[1] = sprite.color.light[1];
sprite.color.dark[2] = sprite.color.light[2];
//dont forget to invalidate, after you changed dark DIRECTLY
sprite.color.invalidate();
You could apply a custom filter to the sprite. "Filter" is PixiJS's term for a shader.
Start with this custom filter example.
Modify the file shader.frag with a shader that returns the desired color or transparent, depending on the current pixel.
Optional: The above will continuously calculate the solid sprite from the original sprite. If performance is a problem, I think there is a way to save the results and set that as the sprite's texture.
The fragment shader should be pretty simple. Here are two good fragment shader tutorials:
WebGL Fundamentals (Specifically, this part: WebGL Image Processing)
The Book of Shaders
It is possible in pure PIXI with ColorMatrixFilter:
let filter = new PIXI.filters.ColorMatrixFilter();
filter.matrix = [
10, 10, 10, 10,
10, 10, 10, 10,
10, 10, 10, 10,
-1, -1, -1, 1
];
sprite.filters = [filter];
AFAIK tint and alpha might stop working, but you can add additional filters after this one (e.g. AlphaFilter) to achieve a similar effect.
So, I'm trying to create a (very) simple progress bar in Phaser, (initially it's empty) and getting it to resize/scale to a specific size.
I'm not a fan of erasing and redrawing, since I assume this is more resource-heavy / not as efficient as simply tweening.
Whenever I scale its width, it insists on moving to the right - it is also updating its X coordinate as well.
I do know that we should change/set the anchor. I tried setting it to 0.5 (center), to 0 (left, top) and to 1.0 (bottom, right) as I saw in this question (and in the Phaser forums), but no matter the value that I set, the progress bar always moves (and always to the same place) as well.
Here is my code:
//Fill
var graphs = game.add.graphics(0, 0);
graphs.lineStyle(2, 0xFF0000, 1);
graphs.beginFill(0xFF0000, 1);
progressBar = graphs.drawRect(100, 50, 1, 20);
progressBar.anchor.setTo(0.5, 0.5);
//Outline
graphs = game.add.graphics(0, 0);
graphs.lineStyle(2, 0xFFFFFF, 1);
progressBarOutline = graphs.drawRect(100, 50, 100, 20);
progressBarOutline.anchor.setTo(0.5, 0.5);
//Resize it whenever the user presses the game area
game.input.onDown.add( resizeProgressBar, this );
And here is the code that I call to resize the (fill) bar (currently done through a tween):
function resizeProgressBar()
{
game.add.tween(loadingProgressBar.scale).to( { x: 2.5},
1000, Phaser.Easing.Quadratic.InOut, true);
}
Here is a fiddle that shows the issue (click on the canvas to update the bar).
This can't be that complicated. Am I forgetting something? Or am I supposed to calculate the new x position myself?
I'm using Phaser CE 2.11
I'm not sure why the height of the progressBar is growing, nor why it's moving, as I haven't done much with the raw graphics drawing capabilities in Phaser. However, there's a few things I do know which might help.
The difference between the questions you've linked to and your progress bar is that you're using raw graphics, instead of sprites.
If you switch to using a sprite-based progress bar you could either scale or set the width, depending upon what your progress graphic looks like.
Another option would be to do something similar to this tutorial for progress bars in Phaser 3. The relevant bits are defining the progress bar and then creating it:
var progressBar = this.add.graphics();
/// ...
this.load.on('progress', function (value) {
progressBar.clear();
progressBar.fillStyle(0xffffff, 1);
progressBar.fillRect(250, 280, 300 * value, 30);
});
You can change the last five lines as needed for your particular circumstances.
While this does clear and then redraw the rectangle, I personally haven't seen much of a performance hit doing this. At least with older versions of Phaser 2, using Sprites instead of Graphics seems to be the way to go. Of course, it also depends upon how often and how many of these progress bars you'll be displaying.
I have a series of dots with connected lines that I am animating in an easel.js canvas. The dots move around, and the lines stay connected to them as they move. As the dots move, I'm animating their color, so I want the lines to animate color as well.
I tried calling a color tween on the line, but it requires that I cache the line first.
For a circle, that's easy - I get the radius and, since its registration is in the center, its x and y coordinates and width and height are easy to calculate (for a circle with r=100 at 50,50, its cache would be cache(0,0,100,100). But for a line, I'm not sure how to reference the right coordinates for the cache statement, especially since the line start position, end position, and length are always changing.
Anyone have a way to do this?
I'm using greensock's timelinemax / tweenlite with the easeljs plugin to handle all the animations, if that's helpful.
If TweenLite handles color tweens, then you should just be able to update the "style" of your line any time:
var shape = new createjs.Shape();
var colorCommand = shape.graphics.beginStroke("#000000").command;
shape.graphics.moveTo(0,0).lineTo(100,100); // Draw the line
// Any time
colorCommand.style = "#ff0000";
// So in a tween:
TweenLite.to(colorCommand, 20, {style:"#00ffff"});
If you are using EaselJS, you can also use TweenJS, which has a ColorPlugin. Using similar code:
createjs.Tween.get(colorCommand).to({style:"#00fffff"}, 20000);
Here is a fiddle I made tweening the color of a line with TweenJS https://jsfiddle.net/lannymcnie/5zxpb944/
Cheers.
I am attempting to create a very simple beacon-like animation in Paper JS. The idea is that a circle starts off very small and totally opaque and then gets larger and more transparent until it disappears and the animation restarts.
I'm using scaling to make the image larger but resetting it to it's original size is becoming problematic and at the moment I have resorted to cloning a second circle to reset it rather than just working with a single shape, there has to be a simpler way of doing this.
I've create a jsFiddle to demonstrate my rough code so far, any help would be appreciated.
http://jsfiddle.net/colethecoder/Y3S9n/1
Paperjs does not store the original Path, nor does it remember any operations that have been applied to reach the current state, so it can be difficult to reset to a previous state. The easiest approach is to use the this.scale that your current code is calculating and when you want to reset do this.circle.scale(1/this.scale); Here is a jsfiddle that way.
FYI, here is the code path for scaling:
Item.scale()
Item.transform()
Item.apply()
Path._apply()
Segment._transformCoordinates()
So the end result is that _transformCoordinates() is called on each of the four segments in the circle, and it simply moves the point coordinates...nothing is remembered to "undo" the scaling later.
Alternatively to remembering the scale yourself, you can use the Path.fitBounds() function to shrink the circles to an arbitrary size...for instance you could save the bounding rectangle right after creating the Circle, and then fitBounds back to that size.
Set item.applyMatrix = false if you don't want to persist transformations alongside item.
For example, the following code linearly (i.e. "additively") animates item.scaling:
var item = new Path.Rectangle({
point: [75, 75],
size: [5, 5],
strokeColor: 'black',
applyMatrix: false
});
function onFrame(event) {
item.scaling += 0.1;
}
The way i approached this issue was attaching a new object called originalBounds to the paper.js shapes immediately after their instantiation. If i needed to play with its size, coming back its original one became fairly trivial.