Pixi.js - How to animate a line - pixi.js

I've been looking everywhere but I can't find a way to animate a line in Pixi.js.
Given this code:
var line = new PIXI.Graphics();
line.lineStyle(1, 0xff0000);
line.moveTo(0,window.innerHeight/2);
line.lineTo(window.innerWidth/2, 0);
line.lineTo(window.innerWidth, window.innerHeight/2);
app.stage.addChild(line);
which draws this magnificient jsfiddle
I'd like to achieve this very simple line animation:
Step 1
Step 2
Of course I'm guessing this should not be complicated, but I've no idea what I'm missing...
Any help will be appreciated!

Drawing inside a graphics object is very similar in API terms to drawing to a Canvas without Pixi.
A render loop is needed where the canvas is cleared and redrawn on every loop.
Pixi provides a useful Ticker that can be used to run functions on a loop.
Here's an example (in this case an infinite animation) and a jsfiddle sample:
var line = new PIXI.Graphics(),
centerY = 0,
increment = 2;
app.stage.addChild(line);
app.ticker.add(() => {
// clear the graphics object ('wipe the blackboard')
line.clear();
// redraw a new line
drawLine(centerY);
// calculate the next position
centerY = (centerY < window.innerHeight) ? centerY = centerY + increment : 0;
});
function drawLine(centerY) {
line.lineStyle(1, 0xff0000);
line.moveTo(0,window.innerHeight/2);
line.lineTo(window.innerWidth/2, centerY);
line.lineTo(window.innerWidth, window.innerHeight/2);
}

Related

libgdx draw text via project draws twice?

I try to draw 2D texts for my 3D world objects with libgdx's camera.project function but have a weird problem.
See the pics below:
As you can see in the pictures, all is well in picture 1 but when I turn around 180 degrees the ball's name (codename 1) is be drawing the blank space also (picture 2). I couldn't get what the problem is and after hours of thinking decided to ask here.
Please help me.
My code is:
public static void drawNames(){
TheGame.spriteBatch.begin();
for(int i = 0; i < TheGame.playerMap.size; i++){
Player ply = TheGame.playerMap.getValueAt(i);
if(!ply.isAlive)
continue;
TheGame.tmpVec.set(ply.getPos().x, ply.getPos().y, ply.getPos().z);
TheGame.cam.project(TheGame.tmpVec);
TheGame.fontArialM.draw(TheGame.spriteBatch, ply.name, TheGame.tmpVec.x, TheGame.tmpVec.y, 0, Align.center, false);
}
TheGame.spriteBatch.end();
}
This is because if you project something that is behind the camera it still gets valid screen coordinates from the project method.
Consider the following that prints the screen coordinates of two world coordinates
PerspectiveCamera camera = new PerspectiveCamera(60, 800, 600);
camera.position.set(0, 0, -10);
camera.lookAt(0, 0, 0);
camera.update();
Vector3 temp = new Vector3();
Vector3 p1 = new Vector3(1, 0, 10); // This is in front of the camera, slightly to the right
Vector3 p2 = new Vector3(0, 0, -100); // This is behind of the camera
camera.project(temp.set(p1));
System.out.println("p1 is at screen " + temp);
if (camera.frustum.pointInFrustum(p1))
System.out.println("p1 is visible to the camera");
else
System.out.println("p1 is not visible to the camera");
camera.project(temp.set(p2));
System.out.println("p2 is at screen " + temp);
if (camera.frustum.pointInFrustum(p2))
System.out.println("p2 is visible to the camera");
else
System.out.println("p2 is not visible to the camera");
In your code, before rendering the text you need to check if the ply.getPos() vector is visible to the camera, and only render the text if it is.
if (TheGame.cam.frustum.pointInFrustum(ply.getPos()) {
TheGame.tmpVec.set(ply.getPos().x, ply.getPos().y, ply.getPos().z);
TheGame.cam.project(TheGame.tmpVec);
TheGame.fontArialM.draw(TheGame.spriteBatch, ply.name, TheGame.tmpVec.x, TheGame.tmpVec.y, 0, Align.center, false);
}
Note that there are other ways to cull things behind the camera that might be more efficient for you.

Why does the alpha value change when I have given it a constant value?

I am using the p5.js Web Editor
var sketch = function (p) {
with(p) {
p.setup = function() {
createCanvas(400, 400);
secCanvas = createGraphics(400, 400);
secCanvas.clear();
trans = 0;
drop_size = 10;
sun_size = 50;
radius = 10;
};
p.draw = function() {
background(3, 182, 252, 1);
image(secCanvas, 0, 0)
secCanvas.fill(255, 162, 0, 1)
secCanvas.ellipse(width/2, 0 + sun_size, sun_size)
fill(40, trans)
trans = random(255);
ellipse(random(mouseX + radius, mouseX - radius), random(mouseY + radius, mouseY - radius), drop_size)
drop_size = random(50)
};
}
};
let node = document.createElement('div');
window.document.getElementById('p5-container').appendChild(node);
new p5(sketch, node);
body {
background-color:#efefef;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<div id="p5-container"></div>
When I set a discrete value of alpha in secCanvas.fill(). The value appears to be gradually increase(and stops soon), while I gave no such instruction. Why is this happening? This only happens when I put background(3, 182, 252, 1); in the draw function but not when I put it in the setup function.
Each frame is drawn on top of all previous frames, so when you draw a semi-transparent background, you can still see the previous frames underneath it.
Think of it as adding a very thin coat of paint over top what you've already painted. Because the color you're adding is semi-transparent, you can still see what's underneath it. Then during the next frame, you add another layer of paint, and the previous frames get just a little more faint.
They stop becoming more faint because of the way the computer calculates the new color, based on the previous frames and the new semi-transparent background color. Long story short, the color you're drawing is almost 100% transparent, so it's not strong enough to completely hide previous frames.

Moving one end of a Phaser.Graphics line

For a project I'm trying to draw a moving line in Phaser. I initially drew it using game.debug.geom(line), but that is not really the right way to do it, since it doesn't allow for styling, and because the debugger takes a toll in performance.
Reading the docs, it seems to me that the way to do it would be with a Phaser.Graphics object, but I haven't been able to get it to work. As an example, I tried making a line move as the hand of a clock, with one end fixed and the other moving around it.
I thought it would be fine to create the Graphics object in the middle and then in update use reset to clear it and bring it back to the center, and then lineTo to make the rest of the line. But instead what I get is a line coming outwards from the centre, and then a ring.
Picture for sadness:
I made a pen with my attempts. The code is repeated below. What I would like to have is a line (lines?) coming from the center of the circle to the points in the circumference.
Is a Graphics object the best way to do that? How do I do it?
Demo.prototype = {
create: function() {
this.graphics = game.add.graphics(
game.world.centerX,
game.world.centerY
);
this.graphics.lineStyle(2, 0xffd900);
this.counter = 0;
this.step = Math.PI * 2 / 360;
this.radius = 80;
},
update: function() {
this.graphics.reset(
this.game.world.centerX,
this.game.world.centerY
);
var y = this.radius * Math.sin(this.counter);
var x = this.radius * Math.cos(this.counter);
this.graphics.lineTo(x, y);
this.counter += this.step;
}
};
You may want to check out this Phaser game called Cut It (not my game btw, found it here).
It also draws a variable length dotted line by cleverly using the Phaser.TileSprite, and then changing its width.
TileSprite draws a repeating pattern, and you can use this to draw a line by drawing one bitmap of a linepart segment, use that as background of the TileSprite and make the height of the TileSprite the same as the height of the bitmap.
You can take a look at the game's source code, it's compressed and minified but still somewhat readable. You can look for the variable called cut_line.
I finally understood that the coordinates taken by the Phaser.Graphics object are local, respective to the object's internal coordinate system. Using moveTo(0, 0) has the desired result of moving the object's drawing pointer back to its origin (and not, as I initially thought, to the origin of the game world). Using reset(0, 0), on the other hand, would have the effect of moving the object's origin to the world's origin.
As for deleting the previous lines, the only method I've found is to manually clear the object's graphicsData Array (short of calling destroy() and creating an entirely new object, which is probably not a very good idea).
Replacing the code in the original question with this does the trick:
Demo.prototype = {
create: function() {
this.graphics = game.add.graphics(
game.world.centerX,
game.world.centerY
);
this.graphics.lineStyle(2, 0xffd900);
this.counter = 0;
this.step = Math.PI * 2 / 360;
this.radius = 80;
},
update: function(){
// Erases the previous lines
this.graphics.graphicsData = [];
// Move back to the object's origin
// Coordinates are local!
this.graphics.moveTo( 0, 0 );
var y = this.radius * Math.sin(this.counter);
var x = this.radius * Math.cos(this.counter);
this.graphics.lineTo(x, y);
this.counter += this.step;
}
};

How to animate rectangle to fixed width in steps with createjs?

I'm trying to create loading bar for my game. I create basic rectangle and added to the stage and caluclated size acording to the number of files so I get fixed width. Everything works, but for every step (frame) it creates another rectangle, how do I get only one object?
this is my code:
function test(file) {
r_width = 500;
r_height = 20;
ratio = r_width / manifest.length;
if (file == 1) {
new_r_width = 0
// Draw
r = new createjs.Shape();
r_x = (width / 2) - (r_width / 2);
r_y = (height / 2) - (r_height / 2);
new_r_width += ratio;
r.graphics.beginFill("#222").drawRect(r_x, r_y, new_r_width, r_height);
stage.addChild(r);
} else {
stage.clear();
new_r_width += ratio;
r.graphics.beginFill("#" + file * 100).drawRect(r_x, r_y + file * 20, new_r_width, r_height);
stage.addChild(r);
}
stage.update();
}
https://space-clicker-c9-zoranf.c9.io/loading/
If you want to redraw the rectangle, you will have to clear the graphics first, and then ensure the stage is updated. In your code it looks like you are clearing the stage, which is automatically handled by the stage.update() unless you manually turn off updateOnTick.
There are some other approaches too. If you just use a rectangle, you can set the scaleX of the shape. Draw your rectangle at 100% of the size you want it at, and then scale it based on the progress (0-1).
r.scaleX = 0.5; // 50%
A new way that is supported (only in the NEXT version of EaselJS, newer than 0.7.1 in GitHub), you can save off the drawRect command, and modify it.
var r = new createjs.Shape();
r.graphics.beginFill("red");
var rectCommand = r.graphics.drawRect(0,0,100,10).command; // returns the command
// Later
rectCommand.w = 50; // Modify the width of the rectangle
Hope that helps!

resize SVG Element: best practice with multiple items

What is the best practice for resizing say an Ellipse or Rectangle on another SVG element?
If I check for the onMouseMove event on the ellipse when I am out of it, the resizing stops. I was thinking to implement the listener on the svg element as well and pass the information to the ellipse I started the resizing on. This means having a generic Resize() method on the svg element that passes to the Resize() of the selected ellipse.
Isn't there an easier way?
I'm currently doing it with Dart, but it should be the same with javascript.
An example is an <svg> element with a <g> containing <rect> and an <ellipse>. If I start to resize the rectangle on a rectangle.onMouseMove, the moment I'm outside it, it stops resizing. To avoid this, I have to use the svg.onMouseMove, and use a resize method that resizes the rectangle. To know that it's the rectangle to be resized, I check for onMouseDown and again check the target (MouseEvent.target on Dart. Not sure how to detect what I'm touching without doing a cumbersome check on id maybe). Note that what I am trying to accomplish is to use the rectangle to resize the ellipse. I'm showing the rectangle only when resizing.
The following code will create a circle and resize when you start dragging.
It also works when the mouse gets outside the circle.
Maybe you can modify this to your liking.
Oh, and my Dart-code might not be the best, as I just recently started learning Dart.
Any improvements are welcome.
import 'dart:html';
import 'dart:svg';
import 'dart:math' as math;
void main() {
// add new svg
var svg = new SvgSvgElement();
svg.style.width = '400px';
svg.style.height = '400px';
svg.style.border = '1px solid black';
var body = document.querySelector('body');
body.append(svg);
// add group
var g = new SvgElement.tag('g');
svg.append(g);
// center of circle
var center = new math.Point(200, 200);
var startR = 70;
var newR = 70;
// add circle
var circle = new CircleElement();
circle.setAttribute('cx', center.x.toString());
circle.setAttribute('cy', center.y.toString());
circle.setAttribute('r', startR.toString());
circle.setAttribute('fill', 'green');
g.append(circle);
circle.onMouseDown.listen((MouseEvent E) {
var startOffset = E.offset;
var startDistance = startOffset.distanceTo(center);
math.Point offset = E.offset;
// now start listening for document movements so we don't need to stay on the circle
var move = document.onMouseMove.listen((MouseEvent E) {
// calculate new position
var movement = E.movement;
offset = new math.Point(
// multiply with 0.5 to make the mouse move faster than the circle grows
// that way we show that the mouse movement also works outside the circle element
offset.x + movement.x * 0.5,
offset.y + movement.y * 0.5
);
// calculate new distance from center
var distance = offset.distanceTo(center);
// calculate new radius for circle
newR = distance / startDistance * startR;
// resize circle
circle.setAttribute('r', newR.toString());
});
// and stop all listening on mouseup
var up = document.onMouseUp.listen(null);
up.onData((MouseEvent E) {
move.cancel();
up.cancel();
startR = newR;
});
});
}
Hope this helps,
Kind regards,
Hendrik Jan

Resources