AS3 | Move graphics points at runtime? - actionscript-3

how to get the graphics points and change the values of its x&y at runtime?
for example:
var moveToX:Array = [50, 200];
var moveToY:Array = [0, 0];
var lineToX:Array = [100, 0, 50, 250, 150, 200];
var lineToY:Array = [100, 100, 0, 100, 100, 0];
var _points:Array = [];
var linesIndex:int = 0;
var myShape:Shape = new Shape();
myShape.graphics.lineStyle(3, 0x000000, .2);
myShape.graphics.beginFill(0x666666, .1);
for (var i:uint = 0; i< moveToX.length; i++)
{
var _point:Point = new Point(moveToX[i], moveToY[i]);
_points.push(_point);
}
for (var p:uint = 0; p< _points.length; p++)
{
myShape.graphics.moveTo(_points[p].x, _points[p].y);
myShape.graphics.lineTo(lineToX[linesIndex], lineToY[linesIndex]);
myShape.graphics.lineTo(lineToX[linesIndex+1], lineToY[linesIndex+1]);
myShape.graphics.lineTo(lineToX[linesIndex+2], lineToY[linesIndex+2]);
linesIndex +=3;
}
myShape.x = 0;
myShape.y = 0;
addChild(myShape);
Now I want to change the points values and update the shape at runtime, but what I am looking for is NOT to clear and redraw it again.. I am trying to apply the changes directly to the same shape because it has a lot of points and lines as the update will be every 20 milliseconds..
So can you help please? Thnaks.

You can't just simply move graphic geometry and see it moves on the screen.
There is no magic and when you want to see graphic in different position on the screen you need to redraw it. When you move MovieClip by changing x or y properties the whole its graphics is redrawing still.
If you want to translate all points by the same value the best way to do this is just change position properties of your Shape object.

Related

Manipulate pixels before drawing on the canvas

I'm using the following code to draw a base64 image on the canvas. I get the base64 string from a query in PHP. With globalAlpha i can set the alpha of the whole image to 0. I need to manipulate the alpha of random pixels with a form. So when I submit 7 with the form, 7 random pixels need to be set from alpha 0 to 255.
Is it possible to manipulate the alpha of this image and after that, draw it to the canvas? It's very important that the original image remains secret.
var complex = "<?php echo str_replace("\n", "", $DBimage); ?>";
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var image = new Image();
image.src = "data:image/png;base64," + complex;
image.onload= function(){
ctx.drawImage(image, 0, 0);
}
<canvas id="rectangle" width="300" height="300" style="border:solid black 1px; </canvas>
​
the javascript
var canvas = document.getElementById('rectangle');
//replace this rectangle drawing by your image
if (canvas.getContext) {
var context = canvas.getContext('2d');
context.fillStyle = "rgb(150,29,28)";
context.fillRect(10, 10, 280, 280);
}
var imgd = context.getImageData(0, 0, canvas.width, canvas.height);
var numberOfAlphaPix = 10000; //this is the number of pixel for which you want to change the alpha channel, I let you do the job to retrieve this number as you wish
//fill an array with numbers that we'll pop to get unique random values
var rand = [];
// Loop over each pixel with step of 4 to store only alpha channel in array ( R=0 ,G=1 , B=2, A=3 )
for (var i = 3; i < imgd.data.length; i += 4) {
rand.push(i);
}
//shuffle the array
for (var i = rand.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = rand[i];
rand[i] = rand[j];
rand[j] = tmp;
}
for (var i = 0; i < numberOfAlphaPix; i++) {
imgd.data[rand.pop()] = 255; //set alpha channel to 255
}
// Draw the ImageData object at the given (x,y) coordinates.
context.putImageData(imgd, 0, 0);​
Try it here http://jsfiddle.net/LuEzG/5/
I'm not sure what you mean "stay secret", but I think you mean:
show only a few pixels at a time
Make it impossible for people to view source and discover the image (with a bit of JavaScript)
If those are the only requirements (And if they are requirements) then you'll have to:
decode the image on the server
Pick a few random pixels on the server and send the data for those pixels (RGB values) to the client
Use canvas to show those few pixels that were received
The nice thing about this approach is that you don't need to use ImageData at all. You can just fillRect with a fillStyle of the RGB values for each pixel recieved.
The not-so-nice thing about this approach is that it means you have to do a lot more work on the server, but if you want the image to be completely hidden from the client, it's the only way.

How do I keep object location from being increased exponentially after each call to draw function?

Simple animation that creates a firework-like effect on the canvas with each click. The issue is the animation is made with a setInterval(draw) and every time the canvas is redrawn the location of each particle is += particle.speed. But with each click the particles move faster and faster as it seems the speed of each particle is not reset.
As you can see with a couple clicks on the working example here: , with the first click the particles move very (correctly) slowly, but with each subsequent click the speed is increased.
JS used is pasted below as well, any help is greatly appreciated!
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
canvas.addEventListener("click", startdraw, false);
//Lets resize the canvas to occupy the full page
var W = window.innerWidth;
var H = window.innerHeight;
canvas.width = W;
canvas.height = H;
ctx.fillStyle = "black";
ctx.fillRect(0, 0, W, H);
//global variables
var radius;
radius = 10;
balls_amt = 20;
balls = [];
var locX = Math.round(Math.random()*W);
var locY = Math.round(Math.random()*H);
//ball constructor
function ball(positionx,positiony,speedX,speedY)
{
this.r = Math.round(Math.random()*255);
this.g = Math.round(Math.random()*255);
this.b = Math.round(Math.random()*255);
this.a = Math.random();
this.location = {
x: positionx,
y:positiony
}
this.speed = {
x: -2+Math.random()*4,
y: -2+Math.random()*4
};
}
function draw(){
ctx.globalCompositeOperation = "source-over";
//Lets reduce the opacity of the BG paint to give the final touch
ctx.fillStyle = "rgba(0, 0, 0, 0.1)";
ctx.fillRect(0, 0, W, H);
//Lets blend the particle with the BG
//ctx.globalCompositeOperation = "lighter";
for(var i = 0; i < balls.length; i++)
{
var p = balls[i];
ctx.beginPath();
ctx.arc(p.location.x, p.location.y, radius, Math.PI*2, false);
ctx.fillStyle = "rgba("+p.r+","+p.g+","+p.b+", "+p.a+")";
ctx.fill();
var consolelogX = p.location.x;
var consolelogY = p.location.y;
p.location.x += p.speed.x;
p.location.y += p.speed.y;
}
}
function startdraw(e){
var posX = e.pageX; //find the x position of the mouse
var posY = e.pageY; //find the y position of the mouse
for(i=0;i<balls_amt;i++){
balls.push(new ball(posX,posY));
}
setInterval(draw,20);
//ball[1].speed.x;
}
After each click startdraw is called, which starts every time a new periodical call (setInterval) for the draw method. So after the 2nd click you have 2 parallel intervals, after the 3rd you have 3 parallel intervals.
It is not exponentially, only linearly increasing :)
A possible dirty fix:
Introduce an interval global variable, and replace this row:
setInterval(draw,20);
with this one:
if (!interval) interval = setInterval(draw,20);
Or a nicer solution is to start the interval at the onLoad event.
setInterval will repeat its call every 20th ms, and returns an ID.
You can stop the repetition by calling clearInterval(ID).
var id = setInterval("alert('yo!');", 500);
clearInterval(id);

dynamically draw circle preloader error 1061 when in document class

I found a tutorial on how to make a dynamic unfilled and filled circle. that will take input from a slider to dertermine how much of the circle is drawn. I wanted to use this for a preloader. Unlike the author I would like to use it inside of a document class. I am getting
1061: Call to a possibly undefined method createEmptyMovieClip through a reference with static type document. and 1120: Access of undefined property circ1. The second is caused from the first. How would I get this to work in my document class? Thanks in advance!
//original code
// x: circles center x, y: circles center y
// a1: first angle, a2: angle to draw to, r: radius
// dir: direction; 1 for clockwise -1 for counter clockwise
MovieClip.prototype.CircleSegmentTo = function(x, y, a1, a2, r, dir) {
var diff = Math.abs(a2-a1);
var divs = Math.floor(diff/(Math.PI/4))+1;
var span = dir * diff/(2*divs);
var rc = r/Math.cos(span);
this.moveTo(x+Math.cos(a1)*r, y+Math.sin(a1)*r);
for (var i=0; i<divs; ++i) {
a2 = a1+span; a1 = a2+span;
this.curveTo(
x+Math.cos(a2)*rc,
y+Math.sin(a2)*rc,
x+Math.cos(a1)*r,
y+Math.sin(a1)*r
);
};
return this;
};
// empty
this.createEmptyMovieClip("circ1",1);
circ1._x = 100;
circ1._y = 150;
circ1.radius = 35;
circ1.onEnterFrame = function(){
this.clear();
var endAngle = 2*Math.PI*percentLoaded;
var startAngle = 0;
if (endAngle != startAngle){
this.lineStyle(2,0,100);
this.CircleSegmentTo(0, 0, startAngle, endAngle, this.radius, -1);
}
}
//filled
this.createEmptyMovieClip("circ2",2);
circ2._x = 220;
circ2._y = 150;
circ2.radius = 35;
/* code in tutorial i left out since its for a second filled in circle
circ2.onEnterFrame = function(){
this.clear();
var endAngle = 2*Math.PI*slider.value/100;
var startAngle = 0;
if (endAngle != startAngle){
this.lineStyle(2,0,100);
this.beginFill(0xFF9999,100);
this.lineTo(this.radius,0);
this.CircleSegmentTo(0, 0, startAngle, endAngle, this.radius, -1);
this.lineTo(0,0);
this.endFill();
}
}
*/
That code you got was made using Actionscript 2, and you're building it for Actionscript 3, so you have to either recode it to Actionscript 3 or compile it for AS2.

nested array does not work

I have the following problem: I have this multi-level array (nested array) which contains two rows of bitmapData. Row 1:360 rotated bitmapData objects; row 2: 360 rotated and colored bitmapData objects.
I try to access row 2 but that doesn't work. There are some mysterious error messages coming up ("TypeError: Error #1034: Type Coercion failed: cannot convert []#36d7e9e9 to flash.display.BitmapData. at BasicBlitArrayObject/updateFrame()").
Please can someone help me out with this problem? Thank you very much.
this function rotates and colors bitmapData; the rotated bitmapData is thrown into an array and the colored bitmapData is thrown into another array; a third array is used as a level array for nesting the other two arrays inside of it
public function createColoredRotationBlitArrayFromBD(sourceBitmapData:BitmapData, inc:int, offset:int = 0, color:Number = 1, $alpha:Number = 1):Array
{
tileList = [];
tileListSec = [];
levelArray = [tileList, tileListSec];
var rotation:int = offset;
while (rotation < (360 + offset))
{
var angleInRadians:Number = Math.PI * 2 * (rotation / 360);
var rotationMatrix:Matrix = new Matrix();
rotationMatrix.translate(-sourceBitmapData.width * .5, -sourceBitmapData.height * .5);
rotationMatrix.rotate(angleInRadians);
rotationMatrix.translate(sourceBitmapData.width * .5, sourceBitmapData.height * .5);
var matrixImage:BitmapData = new BitmapData(sourceBitmapData.width, sourceBitmapData.height,
true, 0x00000000);
matrixImage.draw(sourceBitmapData, rotationMatrix);
tileList.push(matrixImage.clone());
bitmapData = new BitmapData(matrixImage.width, matrixImage.height, true, 0x00000000);
bitmapData = matrixImage;
var colorMatrix:ColorMatrixFilter = new ColorMatrixFilter (
[color, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, $alpha, 0]);
matrixImage.applyFilter(bitmapData, bitmapData.rect, point0, colorMatrix);
tileListSec.push(matrixImage.clone());
rotation += inc;
matrixImage.dispose();
matrixImage = null;
rotationMatrix = null;
bitmapData.dispose();
bitmapData = null;
colorMatrix = null;
}
return(levelArray);
}
creating my rotated and colored bitmapData
animationFrames = tempBlitArrayAsset.createRotationBlitArrayFromBD($bitmapData, 1, 270);
here I try to access the first row of my level array (that doesn't work; I can't access it)
tempEnemy.animationList = animationFrames;
tempEnemy.bitmapData = tempEnemy.animationList[1][tempEnemy.frame];
This function is for updating the frames
public function updateFrame(inc:int, row:int = 0):void
{
frame += inc;
if (frame > animationList.length - 1){
frame = 0;
}
bitmapData = animationList[row][frame];
}
}
this is a line showing how the updateFrame-function is used in my game (trueRotation is 0)
tempEnemy.updateFrame(tempEnemy.trueRotation);
I can't find anything wrong with createColoredRotationBlitArrayFromBD
var $bitmapData:BitmapData = new BitmapData(40,40,false, 0x7f7f7f);
var animationFrames:Array = createColoredRotationBlitArrayFromBD($bitmapData, 1, 270);
trace(animationFrames.length); // 2
trace(animationFrames[0].length); // 360
trace(animationFrames[1].length); // 360
var bitmap:Bitmap = new Bitmap();
this.addChild(bitmap);
bitmap.bitmapData = animationFrames[1][0]; // works..
That seems correct. Right? I get a red tinted bitmap.
The only 'bug' I see in the code you listed is in updateFrame
if (frame > animationList.length - 1){
frame = 0;
}
should probably be:
if (frame > animationList[row].length - 1){
frame = 0;
}
because animationList.length == 2
But everything else looks okay in the code you've provided, so without more code, i'm not sure there is anything to help.

Change pixel color with ActionScript 3

Say I have drawn a triangle with:
import flash.geom.Matrix;
function drawTriangle(sideLength:uint):void {
var triangleHeight:uint = Math.sqrt(Math.pow(sideLength,2) - Math.pow(sideLength / 2,2));
var triangleShape:Shape = new Shape();
triangleShape.graphics.beginFill(0x2147AB);
triangleShape.graphics.lineStyle(1,0xff00ff00);
triangleShape.graphics.moveTo(sideLength/2, 0);
triangleShape.graphics.lineTo(sideLength, triangleHeight);
triangleShape.graphics.lineTo(0, triangleHeight);
triangleShape.graphics.lineTo(sideLength/2, 0);
addChild(triangleShape);
var matrix:Matrix = new Matrix;
matrix.translate(50, 50);
transform.matrix = matrix;
}
drawTriangle(400);
How can I achieve the following:
When the user clicks a point inside the triangle, we will get the x and y coordinates, do some calculation with those values and get some (lots) of pixel coordiantes accordingly (all of those calculated points will be within the triangle). And finally, change the color of those points (something different than triangleShape fill color).
Here's a solution using a triangle drawn to some BitmapData, added to a Bitmap, and then contained in a Sprite.
var box:Sprite = new Sprite();
box.graphics.beginFill(0x000000, 1);
box.graphics.lineStyle(1, 0x000000, 1);
box.graphics.moveTo(100, 50);
box.graphics.lineTo(50, 100);
box.graphics.lineTo(150, 100);
box.graphics.lineTo(100, 50);
box.graphics.endFill();
addChild(box);
var boxCopied:BitmapData = new BitmapData(box.width, box.height, true, 0x00000000);
var matr:Matrix = new Matrix();
matr.tx = -50;
matr.ty = -50;
boxCopied.draw(box, matr);
box.graphics.clear();
var boxCopy:Bitmap = new Bitmap(boxCopied);
box.addChild(boxCopy);
box.addEventListener(MouseEvent.CLICK, clicked, false, 0, true);
function clicked(evt:MouseEvent):void
{
for(var i=0;i<50;i++)
{
var pixel = new Point(Math.floor(Math.random() * boxCopy.width), Math.floor(Math.random() * boxCopy.height));
if(boxCopied.hitTest(new Point(boxCopy.x, boxCopy.y), 1, pixel))
{
boxCopied.setPixel32(pixel.x, pixel.y, Math.random() * 0xFFFFFFFF);
}
}
}
http://www.swfupload.com/view/162170.htm
Note I'm using setPixel32 to send a 32-bit integer (essentially an ARBG instead of RGB) to manipulate alpha as well.
50 random pixels are being generated. If they're inside of the triangle, they're kept.