actionscript matrix rotate() and DisplayObject.rotation property - actionscript-3

It seems applying matrix rotate() to a display object is different from DisplayObject.rotation. What I want is using the matrix.rotate() to get the same result of using rect.rotation = 45. But the actual result is not the same.
Code example:
public class Demo extends Sprite {
public function Demo() {
testRotation();
}
private function testRotation():void {
var rect:Shape = new Shape();
rect.graphics.beginFill(0xff0000,1);
rect.graphics.beginFill(0xff0000, 1);
rect.graphics.drawRect(0,0,100,100);
rect.graphics.endFill();
rect.x = 100;
rect.y = 100;
addChild(rect);
var matrix:Matrix = new Matrix();
trace(matrix);
matrix.rotate(Math.PI*45/180);
rect.transform.matrix = matrix;
}
}

the reason is that rotate method rotates coordination around top-left corner(0,0) as the pic shows.
solution:
var matrix:Matrix = new Matrix();
matrix.translate(-50,-50)// Translate to center of square
matrix.rotate(Math*45/180); //rotate 45 degrees
matrix.translate(rect.x+150, rect.y+150)
rect.transform.matrix = matrix

Related

As3: Draw overlapping rectangles to a sprite and apply alpha

I need to draw independet rectangles to a sprite. But the overlapping areas will get visible if I apply alpha to my sprite (the sprite will be fade in and out):
var spBox:Sprite = new Sprite();
this.addChild(spBox);
spBox.graphics.beginFill(0x123456)
spBox.graphics.drawRect(100, 100, 50, 50);
spBox.graphics.endFill();
spBox.graphics.beginFill(0x123456)
spBox.graphics.drawRect(125, 125, 50, 50);
spBox.graphics.endFill();
Is there a way to compine/flatten/merge the rectangles of my sprite? I want a seamless aplha appearence.
I suspect that the graphics object does not support this kind of functionality for parts of its data.
If both boxes are individual DisplayObjects, you can set the .blendMode of the DisplayObjectContainer to BlendMode.LAYER, which gives the desired result. Here's some example code that refactors the drawing of a rectangle into a Box class:
var spBox:Sprite = new Sprite();
this.addChild(spBox);
var a:Box = new Box(50, 50, 0x123456);
a.x = a.y = 100;
spBox.addChild(a);
var b:Box = new Box(50, 50, 0x123456);
b.x = b.y = 125;
spBox.addChild(b);
spBox.alpha = .5;
spBox.blendMode = BlendMode.LAYER;
The relevant parts of the Box class look like this:
public class Box extends Shape
{
public function Box(width:Number = 100, height:Number = 100, color:uint = 0)
{
graphics.beginFill(color)
graphics.drawRect(0, 0, width, height);
graphics.endFill();
}
}

Drawing triangle shape background

I have three Points in the array. I want to draw a triangle using this Points.
For now, I achieve to draw a border of this triangle using MoveTo() and LineTo() functions.
The problem is, I also need to draw an inner background of an area that this lines creates.
Is there a way to achieve this?
You should use graphics.beginFill(color);:
public function astest()
{
var verticies:Vector.<Point> = Vector.<Point>([new Point(0, 100), new Point(100, 0), new Point(100, 100)]);
var sh:Shape = new Shape();
addChild(sh);
drawPolygon(sh.graphics, verticies, 0xFF0000);
}
protected function drawPolygon(graphics:Graphics, verticies:Vector.<Point>, color:uint):void
{
graphics.beginFill(color);
var p:Point = verticies.shift();
graphics.moveTo(p.x, p.y);
for(var i:int = 0; i < verticies.length; i++)
{
p = verticies[i];
graphics.lineTo(p.x, p.y);
}
graphics.endFill();
}

AS3 Bitmaps are too large and improperly placed

Alright I'm programming in actionscript 3, using flex as a compiler. I have an 16x16 large PNG file that is basically a square outline like this:
http://wiki.urbandead.com/images/1/1c/Square.gif
But in more noticeable colors.
I want to draw an 11x11 grid of these squares, so I use these for loops:
for (i1 = 0; i1 < 11; i1 ++)
{
for (i2 = 0; i2 < 11; i2 ++)
{
new OBJECT_tile().CREATE(CONTAINER,32 + 16*i1,32 + 16*i2);
}
}
Where the CREATE() function makes a new tile object with the container CONTAINER with the given x and y coordinates.
public class OBJECT_tile extends Sprite
{
public var X:Number; public var Y:Number;
public var DEPTH:int = 10 ;
public var SPRITE:Sprite = new Sprite();
public var BITMAP:Bitmap;
public var CONTAINER:Sprite = new Sprite();
[Embed(source = 'TILE.png')]
private var CLASS_IMAGE:Class;
private var IMAGE:Bitmap = new CLASS_IMAGE();
public function CREATE(CONTAINER:Sprite,X:Number,Y:Number):void
{
var DATA:BitmapData = new BitmapData(16,16,true,0);
DATA.draw(IMAGE);
BITMAP = new Bitmap(DATA);
BITMAP.smoothing = false;
addChild(BITMAP);
this.CONTAINER = CONTAINER;
(CONTAINER as MAIN).INSTANCE_LIST[(CONTAINER as MAIN).INSTANCE_LIST.length] = this;
this.X = X; BITMAP.x = this.X;
this.Y = Y; BITMAP.y = this.Y;
DRAW();
}}
However for some reason the tiles are drawn to twice their size (32x32 instead of 16x16) and tend to bunch up or spread out depending on how many tabs I have open in my browser. The bunching up isn't consistent either, for instance the tiles might for a 3x3 group that's perfectly fine but then there will just be a line of messed up tiles next to that group (really hard to describe). Why is this happening?
Okay I figured it out. It turns out as3 will try to scale things behind your back, I'm guessing this is some kind of holdout from Adobe's ide (I detest the thing and program in notepad++). Anyways if you stick this:
stage.scaleMode = StageScaleMode.NO_SCALE;
In your main function it will stop it from scaling unless you say otherwise.

ActionScript 3 - Tweening rotateAroundExternalPoint

i'm unsuccessfully trying to rotate a rectangle around an external point while tweening. i'm trying to lock the top of the red rectangle to the line while it tweens from left to right and rotates from 0º to 90º.
alt text http://www.freeimagehosting.net/uploads/0b937c92e6.png
the image above shows 3 states of the tween. state 1 shows the red rectangle at the start of the line with no angle. state 2 shows the red rectangle has tweened half way along the line with an angle of 45º that is also half the total angle of 90º. state 3 shows the final position of the tween where the red rectangle has an angle of 90º and is placed at the edge of the line.
it seems the problem i'm experiencing is that while tweening, the rotation causes the top of the red rectangle to lose sync with the black line.
here is my code that doesn't work, but hopefully will give you a clearer picture of what i'm attempting.
var angle:Number = 90;
var previousAngle:Number = 0;
var distanceObject:Object = new Object();
distanceObject.distance = line.width;
distanceTween = new Tween(distanceObject, "distance", None.easeNone, 0, distanceObject.distance, 5, true);
distanceTween.addEventListener(TweenEvent.MOTION_CHANGE, tweenHandler);
function tweenHandler(evt:TweenEvent):void
{
var angleShift:Number = (angle / distance) * distanceObject.distance;
//1:tween RedBox position
redBox.x = line.x + line.width * distanceObject.distance;
//2:tween RedBox angle
var externalPointMatrix:Matrix = redBox.transform.matrix;
MatrixTransformer.rotateAroundExternalPoint(externalPointMatrix, 0 + redBox.width * distanceObject.distance, 0, angleShift - previousAngle);
redBox.transform.matrix = externalPointMatrix;
previousAngle = angleShift;
}
I don't think you have specified the problem well enough for a generic solution. There are 3 things changing here: x, y and rotation. Each of these is calculated as a result of a point on the rectangle (the blue "x" in your diagram) that changes over time. That means the thing you need to focus on first is the point on the rectangle that changes over time. Next you need to know that the x and y can be calculated using that point along with the rotation.
So break it down into steps.
find the location of the "x" point on the line
rotate the object
find the location of the "x" point wrt to the rectangle
based on the angle of rotation and the known location of the "x" point calculate the x and y position of the rectangle (SOHCAHTOA)
Here is some code to illustrate:
package
{
import com.greensock.TweenNano;
import flash.display.Sprite;
import flash.events.Event;
[SWF(width='500', height='300', backgroundColor='#ffffff', frameRate='30')]
public class BoxAnim extends Sprite
{
private static const LINE_WIDTH:int = 350;
private static const RECT_WIDTH:int = 150;
private static const RECT_HEIGHT:int = 100;
private static const FINAL_ROTATION:Number = Math.PI/2;
public var point:Number;
private var line:Sprite;
private var rect:Sprite;
private var cross:Sprite;
public function BoxAnim()
{
addEventListener(Event.ADDED_TO_STAGE, addedToStage);
}
private function addedToStage(event:Event):void
{
line = new Sprite();
addChild(line);
line.graphics.lineStyle(10, 0x0);
line.graphics.lineTo(LINE_WIDTH, 0);
line.x = 50;
line.y = 175;
rect = new Sprite();
addChild(rect);
rect.graphics.lineStyle(4, 0xFF0000);
rect.graphics.beginFill(0xFF0000, 0.5);
rect.graphics.drawRect(0, 0, RECT_WIDTH, RECT_HEIGHT);
rect.x = 50;
rect.y = 175;
cross = new Sprite();
addChild(cross);
cross.graphics.lineStyle(5, 0x41a9f4);
cross.graphics.moveTo(-5, -5);
cross.graphics.lineTo(5, 5);
cross.graphics.moveTo(5, -5);
cross.graphics.lineTo(-5, 5);
cross.x = 50;
cross.y = 175;
point = 0;
TweenNano.to(this, 3, {point: 1, onUpdate: tick});
}
private function tick():void
{
// first calculate where the point should be on the line
cross.x = (point * LINE_WIDTH) + line.x;
// calculate the angle of rotation
var rotationRadians:Number = (point * FINAL_ROTATION);
rect.rotation = rotationRadians*180/Math.PI;
// calculate where on the rectangle the point would be
var rectCrossX:Number = (point * RECT_WIDTH);
// use trig to find the x & y points
rect.x = cross.x - Math.cos(rotationRadians)*rectCrossX;
rect.y = cross.y - Math.sin(rotationRadians)*rectCrossX;
}
}
}
I'm just using the variable point as a percentage that goes from 0 to 1. I then scale it to find the position of the "x" point on the line. Scale it again to figure out the rotation. Scale it again to find where it lies along the top of the rectangle. Then trig solves the location of the corner of the rectangle wrt the point.

Draw a Sine Wave Between Two Arbitrary Points in Actionscript 3

Drawing "flat" waves is easy, but I want to draw the wave between two points x1,y1 x2,y2
Here is the "flat" code:
package display
{
import flash.display.Sprite;
import flash.events.Event;
public class SineWave extends Sprite
{
private var angle:Number = 0;
private var centerY:Number = 200;
private var range:Number = 50;
private var xspeed:Number = 2;
private var yspeed:Number = .1;
private var xpos:Number
private var ypos:Number
public function SineWave()
{
init()
}
protected function init():void
{
var sinWavePosition = 100;
var cosWavePosition = 200;
var sinWaveColor:uint = 0xFF0000;
var cosWaveColor:uint = 0x00FF00;
var waveMultiplier:Number = 10;
var waveStretcher:Number = 5;
var i:uint;
for(i = 1; i < 500; i++)
{
var sinPosY:Number = Math.sin(i / waveStretcher) * waveMultiplier;
var cosPosY:Number = Math.cos(i / waveStretcher) * waveMultiplier;
graphics.beginFill(sinWaveColor);
graphics.drawRect(i, sinWavePosition + sinPosY, 2, 2);
graphics.beginFill(cosWaveColor);
graphics.drawRect(i, cosWavePosition + cosPosY, 2, 2);
}
}
}
}
What about a bezier curve? This isn't a sine wave per se. But the effect is similar. With proper control points you should be able to make it look just like a sine wave.
Well quick cheat would be to get the distance between the points, draw the graphic onto a separate sprite, then just work out the angle between the two points and rotate the graphic to that angle.
Not the most 'perfect' solution, but should do the trick, otherwise I can imagine, working out the angle between the two points and then adding this as an increment to the existing values.
Hope this hack helps.
I believe this will work, it's basically a rotationmatrix that is applied to every point on the line.
There might be some errors with the order and signs of the multiplications and the parameters to atan2 but otherwhise i think this will work.
float v = Atan2(y2-y1, x2-x1);
for(blabla)
{
calculate sinPosY from i
newSinPosY = i*Cos(v) + sinPosY*Sin(v);
sinPosX = i*-Sin(v) + sinPosY*Cos(v));
add offset
render
}