Draw Text on a generated Sprite object as3 - actionscript-3

Everyone, I'm just a beginner and I have question. The idea of my program is that when the user clicks a button a circle is generated and it should be counting for each additional circle it should look something like this :
The number should be in center and I should be able to move the object with the number together this is my code:
add_s.addEventListener(MouseEvent.CLICK,new_sond);
function new_sond(event:MouseEvent):void
{
var btn:Sprite = new Sprite();
btn.graphics.beginFill(0x00FF00, 1);
btn.graphics.drawCircle(400, 300, 25);
btn.graphics.endFill();
this.addChild(btn);
}
//----------------------------Drag And Drop----------------------
this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownH);
this.addEventListener(MouseEvent.MOUSE_UP, mouseUpH);
function mouseDownH(evt:MouseEvent):void {
var object = evt.target;
object.startDrag();
}
function mouseUpH(evt:MouseEvent):void {
var obj = evt.target;
obj.stopDrag();
}
I will be very thankful if someone can help me.
How do i make the text to apear on the center of the circles and i still will be able to move them with the text

This is what Vesper should have posted as an answer :)
Add a TextField object to your Sprite. Since the TextField is a child of the Sprite, it will move w/the Sprite. All you need to do is position the text in the middle of the circle:
function new_sond(event:MouseEvent):void
{
var btn:Sprite = new Sprite();
btn.graphics.beginFill(0x00FF00, 1);
btn.graphics.drawCircle(400, 300, 25);
btn.graphics.endFill();
var textField = new TextField();
textField.text = "1";
textField.width = textField.textWidth; // default width is 100
textField.height = textField.textHeight;
textField.x = (25 - textField.textWidth)/2; // center it horizontally
textField.y = (25 - textField.textHeight)/2; // center it vertically
btn.addChild(textField);
this.addChild(btn);
}
Note, as suggested by #Joeson Hwang, you could use a Shape object instead of a Sprite to draw the circles. The Shape is more lightweight than a Sprite. However, since Shape does not extend DisplayObjectContainer, you cannot add child objects to a Shape like you can with a Sprite.
#Joeson Hwang's answer suggests to add the Shape and the text to a Sprite. But that won't be saving you anything, so just draw the graphics directly to the Sprite as you are doing now.

use btn:Shape (saves a lot of system resources). and then put the Shape and your text into a Sprite. You could also add a Sprite into another Sprite.

You can use also flash.text.engine package:
function new_sond(event:MouseEvent):void
{
var btn:Sprite = new Sprite();
btn.graphics.beginFill(0x00FF00, 1);
btn.graphics.drawCircle(cx, cy, cr);
btn.graphics.endFill();
// Font format
var fontDescription:FontDescription = new FontDescription("Arial");
var format:ElementFormat = new ElementFormat(fontDescription, 16, 0x000088);
// Display text
var textElement:TextElement = new TextElement('1', format);
var textBlock:TextBlock = new TextBlock();
textBlock.content = textElement;
// New display object containing text
var textLine:TextLine = textBlock.createTextLine(null, 500);
// Centers the text inside the circle
textLine.x = cx + (cr - textLine.width) / 2;
textLine.y = cy + (cr - textLine.height) / 2;
// Add text into button
btn.addChild(textLine);
this.addChild(btn);
}
More info about creating text: Creating and displaying text in ActionScript 3.0 Developer’s Guide

Related

AS3 : How do I clear graphics in a specific pixel/area

I know that you use graphics.clear to clear all the graphics but that clears the graphics from the stage, I would like to clear graphics in a specific pixel(s) or between x-y value how do I do that?
There's no way to do that with graphics. I just tried, drawing transparent shapes does not create holes, alas.
You should convert the graphics you have into Bitmap instance and work with pixels:
package
{
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.DisplayObject;
public class Holey extends Sprite
{
public function Holey()
{
super();
// Lets create some example graphics.
graphics.beginFill(0x990000);
graphics.drawCircle(200, 200, 100);
graphics.endFill();
// Convert into raster and make 1 pixel transparent.
var aBit:Bitmap = rasterize(this);
aBit.bitmapData.setPixel32(50, 50, 0x00000000);
graphics.clear();
addChild(aBit);
}
private function rasterize(source:DisplayObject):Bitmap
{
// Obtain bounds of the graphics.
var aBounds:Rectangle = source.getBounds(source);
// Create raster of appropriate size.
var aRaster:BitmapData = new BitmapData(aBounds.width, aBounds.height, true, 0x00000000);
// Make an offset to capture all the graphics.
var aMatrix:Matrix = new Matrix;
aMatrix.translate(-aBounds.left, -aBounds.top);
aRaster.draw(source, aMatrix);
return new Bitmap(aRaster);
}
}
}
The way to do this would be with a mask. Using an alpha mask (both mask and maskee use cacheAsBitmap=true) you can draw transparent pixels onto the mask to erase parts. The basic approach would be:
Put all your graphics that you want to be effected by the mask in a common container (if you mean for everything to be cut, then they are already in a common container: the stage or root timeline.)
Draw a bitmap data object that has a transparent "hole" in the area you want to erase. For example:
// fill the stage with a solid rectangle
var maskBitmapData:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0xff000000);
// erase part of it by drawing transparent pixels
maskBitmapData.fillRect(new Rectangle(20, 20, 200, 100), 0);
// create the mask object
var maskBitmap:Bitmap = new Bitmap(maskBitmapData);
maskBitmap.cacheAsBitmap = true; // this makes the mask an alpha mask
addChild(maskBitmap);
Set the container's .mask property. For example, to mask the entire main timeline:
root.cacheAsBitmap = true; // this makes the mask an alpha mask
root.mask = maskBitmap;
Open stack overflow to answer some questions, think for next hour about how holes are placed in cheese... :)
You could also set blendMode property of your hole object to BlendMode.ERASE in combination with cacheAsBitmap. This works similar to masks except you would be actually drawing the wholes and not the area outside them.
Here is an example:
//make cheese
var cheese:Sprite = new Sprite();
cheese.cacheAsBitmap = true;
stage.addChild(cheese);
cheese.x = cheese.y = 10;
//define holes
var holes:Shape = new Shape();
holes.blendMode = BlendMode.ERASE;
cheese.addChild(holes);
//draw cheese
var g = cheese.graphics;
g.beginFill(0xFFCC00);
g.drawRect(0,0,200,150);
//**Attack chees with mices.
g = holes.graphics;
for (var i:int = 0; i < 10; i++){
g.beginFill(0xFF00FF);
var hx = Math.random()*(cheese.width-7)+7;
var hy = Math.random()*(cheese.height-7)+7;
var s = Math.random()*15;
g.drawCircle(hx, hy, s);
g.endFill();
}
Result would be something like that:
edit:
Turns out that you don't need to use cacheAsBitmap if you set blend mode of parent object to LAYER (doc says it should be set automatically...)
So you can use cheese.blendMode = BlendMode.LAYER; instead of cheese.cacheAsBitmap = true;. And if I remember correctly, masks also don't require cahceAsBitmap, even with NORMAL blending mode.

as3 getting object coordinates

Hello everyone so i have a piece of code witch creates some circles, and after i move them with another function i want to get their center coordinates so i can draw lines from center to center of circles, but i don`t have any idea how to do it ... if you can suggest me 1 , here is the code witch creates the circle :
function new_sond(event:MouseEvent):void
{
if (i<9)
{
i++;
q=i;
var btn:Sprite = new Sprite();
btn.graphics.beginFill(0x0099FF, 1);
btn.graphics.drawCircle(400, 300, 15);
btn.graphics.endFill();
var s:String = String(q);
btn.name=s;
var textField = new TextField();
textField.mouseEnabled=false;
textField.text = i;
textField.width = 10;
textField.height = 17;
textField.x = 395; // center it horizontally
textField.y = 292; // center it vertically
btn.addChild(textField);
this.addChild(btn);
}
}
the code with is mooving them is :
this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownH);
this.addEventListener(MouseEvent.MOUSE_UP, mouseUpH);
function mouseDownH(evt:MouseEvent):void {
var object = evt.target;
object.startDrag();
}
function mouseUpH(evt:MouseEvent):void {
var obj = evt.target;
obj.stopDrag();
}
And the code where i draw the lines between them :
function click1(e:MouseEvent):void{
e.currentTarget.removeEventListener(MouseEvent.CLICK, click1);
var i:int;
i=1;
if (e.target.name!=null){
trace(e.target.name);
sx=mouseX;
sy=mouseY;
stage.addEventListener(MouseEvent.CLICK,click2);
}
}
function click2(e:MouseEvent):void{
e.currentTarget.removeEventListener(MouseEvent.CLICK, click2);
fx=mouseX;
fy=mouseY;
var i:int;
i=2;
trace(e.target.name);
var line:Shape = new Shape();
line.graphics.lineStyle(1,0x0066FF,1);
line.graphics.moveTo(sx,sy);
line.graphics.lineTo(fx,fy);
this.addChild(line);
var inputField:TextField = new TextField();
inputField.border = true;
inputField.type = TextFieldType.INPUT;
str=inputField.text;
trace(str);
inputField.width = 23;
inputField.height = 18;
inputField.x = (sx+fx)/2;
inputField.y = (sy+fy)/2;
addChild(inputField);
}
The thing is i want to draw the line from center to center, but i get the mouseX and mouseY coordinates to draw, because i don`t know how to take the center coordinates of an object.... what i get is : http://gyazo.com/6003630d549209ec5e16ccfffe0ee689
But i want the lines to be drawn from center, if someone has any suggestions please help
Sorry for the long post, i just don`t know where i need to put the piece with will center them so i wanted to give the hole code where it can be placed.... I will appreciate very much any idea .
Well, if you drew the circle at 0,0 and moved the btn object .x and .y to 400,300 like this:
btn.graphics.drawCircle(0,0,15);
btn.x = 400;
btn.y = 300;
Then as you drag btn around the screen, btn.x , btn.x (or in the click handler, e.target.x and e.target.y) would always be the center of the circle.
Alternately, if you can't or don't want to do it that way, you can get the bounds of btn (with respect to this coordinate system, since that's where line is being drawn), and since it's a circle, then center of the bounds will be the center of the circle:
var btn:Sprite = e.target;
var bounds:Rectangle = btn.getBounds(this);
var center_x:Number = bounds.x + bounds.width/2;
var center_y:Number = bounds.y + bounds.height/2;

Drawing a bitmap based on a transformed movieclip

I'm drawing bitmaps of movieclips which I then feed into my hittest function to test for collisions. However, I'm not quite sure how i would add to the code below to take into account and draw bitmaps for movieclips which have been scaled and/or rotated. The below code obviously only works for non-transformed movieclips. I've included in comments code which i've already tried but to no success.
When adding the drawn bitmap to the stage, no matter whether the movieclip in question is transformed or not, the drawn bitmap is "cut off" and incorrectly drawn - it appears to only draw a section of it. However, this does not particularly affect the collision testing for the non-transformed movieclips, but has an adverse effect on transformed movieclips.
All of the movieclips I want to be drawn have been created through the graphics property.
//for example:
var mymc:MovieClip = new MovieClip();
var g:Graphics = mymc.graphics;
g.moveTo(0,0);
g.lineTo(17.5,0);
g.lineTo(8.75,17.5);
g.lineTo(-8.75,17.5);
g.lineTo(0,0);
main code:
for each(var mc:MovieClip in impassable) {
//var bMatrix:Matrix = new Matrix();
//bMatrix.scale(mc.scaleX, mc.scaleY);
//bMatrix.rotate(mc.rotation * (Math.PI/180));
var bData:BitmapData = new BitmapData(mc.width, mc.height, true, 0);
//bData.draw(mc, bMatrix);
bData.draw(mc);
var bitmap:Bitmap = new Bitmap(bData);
bitmap.x = mc.x;
bitmap.y = mc.y;
var HitTest:Number = newCollision(bitmap, centerX, centerY, 13.7);
Any thoughts? thanks
This function will create a BitmapData clone of a DisplayObject, taking into account its transform matrix, though it doesn't take into account bitmap filters. (Based on this answer.)
function createBitmapClone(target:DisplayObject):BitmapData {
var targetTransform:Matrix = target.transform.concatenatedMatrix;
var targetGlobalBounds:Rectangle = target.getBounds(target.stage);
var targetGlobalPos:Point = target.localToGlobal(new Point());
// Calculate difference between target origin and top left.
var targetOriginOffset:Point = new Point(targetGlobalPos.x - targetGlobalBounds.left, targetGlobalPos.y - targetGlobalBounds.top);
// Move transform matrix so that top left of target will be at (0, 0).
targetTransform.tx = targetOriginOffset.x;
targetTransform.ty = targetOriginOffset.y;
var cloneData:BitmapData = new BitmapData(targetGlobalBounds.width, targetGlobalBounds.height, true, 0x00000000);
cloneData.draw(target, targetTransform);
return cloneData;
}
When you call successive transforms on a Matrix, the ordering is very important and can really mess things up.
Luckily there is a helper method that allows you to specify translation, rotation and scaling in one go and avoid those issues - createBox
For your case, something like this:
var matrix:Matrix = new Matrix();
matrix.createBox(mc.scaleX, mc.scaleY, mc.rotation*Math.PI/180, 0, 0);
(the two zeros are for x and y translation)

over drawn the circle when input angle in actionscript?

var theTextField:TextField = new TextField();
var theText:TextField = new TextField();
theTextField.type = TextFieldType.INPUT;
theTextField.border = true;
theTextField.x = 50;
theTextField.y = 10;
theTextField.height = 20;
theTextField.multiline = true;
theTextField.wordWrap = true;
theText.border = false;
theText.x = 10;
theText.y = 10;
theText.text = "Angle";
addChild(theText);
addChild(theTextField);
submit.addEventListener(MouseEvent.CLICK, click_handler);
function click_handler(event:MouseEvent):void
{
var txt:String = theTextField.text;
ang = Number(txt);
if (ang<0)
{
angle = - ang;
}
else
{
angle = 360 - ang;
}
var circleSlider:CircleSlider=new CircleSlider(120,angle); //draw Circle According to the angle i think here is problem becoz every time clicked it creates new circle and draw over the old circle.
circleSlider.x = stage.stageWidth / 2;
circleSlider.y = stage.stageHeight / 2;
circleSlider.addEventListener(CircleSliderEvent.CHANGE, circleSliderEventHandler);
addChild(circleSlider);
}
Can someone help me.
var circleSlider:CircleSlider=new CircleSlider(120,angle);//draw Circle According to the angle i think here is problem becoz every time clicked it creates new circle and draw over the old circle.
this code is the problem. CircleSlider is a separate class.I tried like this
circleSlider.CircleSlider(120,angle);
but it gives an error "" Call to a possibly undefined method CircleSlider through a reference with static type CircleSlider.""
when i run the program and input value as 90.
then i enter another value as 180 then it becomes
how can i overcome this error
Every time your click handler is executed you're creating a new instance of your circle class and adding it to the stage without removing the old instance. I think the best way to resolve it would be to move the logic you have in the constructor of your CircleSlider class into a separate public method, say draw and call that in the click handler.
Your code would look something like this:
// Set up the circle once
var circleSlider = new CircleSlider();
circleSlider.x = stage.stageWidth / 2;
circleSlider.y = stage.stageHeight / 2;
circleSlider.addEventListener(CircleSliderEvent.CHANGE, circleSliderEventHandler);
// and add it to the stage once
addChild(circleSlider);
function click_handler(event:MouseEvent):void
{
var txt:String = theTextField.text;
ang = Number(txt);
if (ang<0)
{
angle = - ang;
}
else
{
angle = 360 - ang;
}
// Now simply redraw in the same circle instance
circleSlider.draw(120,angle); //draw Circle According to the angle i think here is problem becoz every time clicked it creates new circle and draw over the old circle.
}
Assuming you're using the drawing API to draw the graphic, you could draw the circle (which seems to be constant) in the constructor (once) and the line illustrating the angle in the draw method (repeatedly). You'll need to clear the old line each time like this:
// Assumes you're drawing in the graphics property of the class
this.graphics.clear();

ActionScript - Drawing BitmapData While Maintaining Center Registration of Display Object

maintaining the center registration point of a circle shape, or any other display object with center registration, while being converted to a bitmap object is proving to be difficult.
the following code converts a circle shape into a bitmap object and positions it in the center of the stage and subsequently removes its center registration poin.
the x and y origin of a new bitmapData object (top left) is the same as the x and y origin of the circle (center), but it's not possible to translate the x and y position of the bitmapData.draw() - its parameters only accept width, height, transparency and fill color.
var myCircle:Shape = new Shape();
myCircle.graphics.beginFill(0xFF0000, 1.0);
myCircle.graphics.drawCircie(0, 0, 100);
myCircle.graphics.endFill();
var matrix:Matrix = new Matrix();
matrix.tx = myCircle.width / 2;
matrix.ty = myCircle.height / 2;
var myCircleBitmapData:BitmapData = new BitmapData(myCircle.width, myCircle.height, true, 0x00FFFFFF);
myCircleBitmapData.draw(myCircle, matrix);
var result:Bitmap = new Bitmap(myCircleBitmapData, PixelSnapping.AUTO, true);
result.x = stage.stageWidth / 2 - matrix.tx;
result.y = stage.stageHeight / 2 - matrix.ty;
addChild(result);
with the help of a matrix translation, the new bitmap object will appear centered in the stage, but applying a regular or 3D rotation, etc., will clearly demonstrate that the registration point is now the top left corner instead of the center.
how can i convert a center registered display object into a bitmap while maintaining its center registration?
it appears the most common approach is to simply add the bitmap as a child of a sprite container and rotate the sprite container rather than the bitmap itself.
var myCircle:Shape = new Shape();
myCircle.graphics.beginFill(0xFF0000, 1.0);
myCircle.graphics.drawCircie(0, 0, 100);
myCircle.graphics.endFill();
var matrix:Matrix = new Matrix();
matrix.tx = myCircle.width / 2;
matrix.ty = myCircle.height / 2;
var myCircleBitmapData:BitmapData = new BitmapData(myCircle.width, myCircle.height, true, 0x00FFFFFF);
myCircleBitmapData.draw(myCircle, matrix);
var myCircleBitmap:Bitmap = new Bitmap(myCircleBitmapData, PixelSnapping.AUTO, true);
myCircleBitmap.x -= matrix.tx;
myCircleBitmap.y -= matrix.ty;
var circleContainer:Sprite = new Sprite();
circleContainer.addChild(myCircleBitmap);
alternatively, for those using Flash Professional IDE, there is the option to employ fl.motion.MatrixTransformer.rotateAroundInternalPoint instead of using a container sprite.
The following tutorial looks like what you're trying to do.
http://www.8bitrocket.com/2007/10/30/Actionscript-3-Tutorial-BitmapData-rotation-with-a-matrix/