This has been really bugging me and I can't seem to ask the right question while searching for a solution! The problem is simple enough: Why can I not attach an event to a programmatically created MovieClip in Actionscript 3? This has got to be something basic I am missing, right?
package {
//imports
import flash.display.*;
import flash.events.*;
//document class
public class Document extends MovieClip {
//variables
public var utilities:Object;
public var test:MovieClip;
//constructor
public function Document()
{
//instantiate the utilities object - this will contain some
//simple functions for setting dimensions and background color of
//a display object.
this.utilities = new Object();
//utility function: set dimensions.
this.utilities.setDimensions = function(what:*, width:uint, height:uint)
{
what.graphics.drawRect(0, 0, width, height);
}
//utility function: set opaque background color.
this.utilities.setBgColor = function(what:DisplayObject, color:uint)
{
what.cacheAsBitmap = true;
what.opaqueBackground = color;
}
//create/add a test movie clip.
test = new MovieClip();
//set dimensions and background color of the test movie clip.
this.utilities.setDimensions(test, 100, 100);
this.utilities.setBgColor(test, 0xff0000);
//add test movie clip to document class.
this.addChild(test);
//add a click event to the test movie clip.
test.addEventListener(MouseEvent.CLICK, onClick);
}
//click event handler
private function onClick(evt:Event):void
{
trace('click');
}
}
}
//update based on Casey Yee's answer
//the set dimension function needs to contain a fill to be clickable
//a fill is added with alpha set to zero to maintain transparency.
//utility function: set dimensions
this.utilities.setDimensions = function(what:*, width:uint, height:uint)
{
what.graphics.beginFill(0x000000, 0);
what.graphics.drawRect(0, 0, width, height);
what.graphics.endFill();
}
test is still a empty movie clip, try adding drawing something into it:
test = new MovieClip();
test.graphics.beginFill(0xFF0000);
test.graphics.drawRect(0,0,100,100);
test.graphics.endFill();
Related
Hi i try to convert my Texture 2D in Image (and i cant use a Raw Image because the resolution dont match in phones) but the problem is that Image does not have the Texture element. how Convert UnityEngine.Texture2D in Image.Sprite.
//Image Profile
protected Texture2D pickedImage;
public Texture2D myTexture2D;
public RawImage getRawImageProfile;
public RawImage getRawImageArrayProfile;
public Image getRawImageProfile2;
public Image getRawImageArrayProfile2;
public void PickImageFromGallery(int maxSize = 256)
{
NativeGallery.GetImageFromGallery((path) =>
{
if( path != null )
{
byte[] imageBytes = File.ReadAllBytes(path);
pickedImage = null;
pickedImage = new Texture2D(2, 2);
pickedImage.LoadImage(imageBytes);
getRawImageProfile.texture = pickedImage;
getRawImageArrayProfile.texture = pickedImage;
getRawImageProfile2.sprite = pickedImage; //ERROR CONVERT SPRITE
//getRawImageArrayProfile2.texture = pickedImage;
}
}, maxSize: maxSize);
byte[] myBytes;
myBytes = pickedImage.EncodeToPNG();
enc = Convert.ToBase64String(myBytes);
}
Sprite.Create does exactly what you're looking for.
From the Unity docs on Sprite.Create:
Sprite.Create creates a new Sprite which can be used in game applications. A texture needs to be loaded and assigned to Create in order to control how the new Sprite will look.
In code:
public Texture2D myTexture2D; // The texture you want to convert to a sprite
Sprite mySprite; // The sprite you're gonna save to
Image myImage; // The image on which the sprite is gonna be displayed
public void FooBar()
{
mySprite = Sprite.Create(myTexture2D, new Rect(0.0f, 0.0f, myTexture2D.width, myTexture2D.height), new Vector2(0.5f, 0.5f), 100.0f);
myImage.sprite = mySprite; // apply the new sprite to the image
}
In the above example we take the image data from myTexture2D, and create a new Rect that is of the same size as the original texture2D, with its pivot point in the center, using 100 pixels per unit. We then apply the newly made sprite to the image.
I have a sprite that I can drag around on screen. I want to be able to drag this sprite into an area (box). As it stands now I can only drop the sprite into the box, but when I drag it directly inn, the program crashes.
I have debugged in FlashDevelop using the Adobe Flash debugger. When I place the sprite into the box the debugger points to this line of code in the DistanceJoint.hx file:
if(b1.space!=space||b2.space!=space)throw "Error: Constraints must have each body within the same space to which the constraint has been assigned";
I think I understand what I have to do, but I am having a hard time finding a way to make a proper exception in my Drag class.
My idea is to break the mouseJoint in the Drag class when the collideLightBox function in Playstate is used. But I do not know how to do that, or if it is the right idea. Please help.
Relevant code:
class Drag extends FlxGroup {
var mouseJoint:DistanceJoint;
public inline function registerPhysSprite(spr:FlxNapeSprite)
{
MouseEventManager.add(spr, createMouseJoint);
}
function createMouseJoint(spr:FlxSprite)
{
var body:Body = cast(spr, FlxNapeSprite).body;
mouseJoint = new DistanceJoint(FlxNapeState.space.world, body,
new Vec2(FlxG.mouse.x, FlxG.mouse.y),
body.worldPointToLocal(new Vec2(FlxG.mouse.x, FlxG.mouse.y)),
0, 0);
mouseJoint.space = FlxNapeState.space;
}
override public function update():Void
{
super.update();
if (mouseJoint != null)
{
mouseJoint.anchor1 = new Vec2(FlxG.mouse.x, FlxG.mouse.y);
if (FlxG.mouse.justReleased)
{
mouseJoint.space = null;
}
}
}
}
class PlayState extends FlxNapeState {
override public function create()
{
super.create();
bgColor = FlxColor.BLACK;
napeDebugEnabled = true;
var light = new Light(10, 10);
var box = new Box(100, 100);
var drag:Drag;
createWalls(1, 1, 1024, 768, 10, new Material(1, 1, 2, 1, 0.001));
add(light);
add(box);
drag = new Drag();
add(drag);
drag.registerPhysSprite(light);
light.body.velocity.y = 200;
FlxNapeState.space.listeners.add(new InteractionListener(
CbEvent.BEGIN,
InteractionType.COLLISION,
Light.CB_TYPE,
Box.CB_TYPE,
collideLightBox));
}
function collideLightBox(callback:InteractionCallback)
{
var light:Light = cast callback.int1.castBody.userData.sprite;
light.kill();
}
}
class Light extends FlxNapeSprite {
public static var CB_TYPE(default, null) = new CbType();
public function new(x:Float, y:Float)
{
super(x, y);
makeGraphic(10, 10, FlxColor.TRANSPARENT);
var radius = 5;
drawCircle(5, 5, radius, FlxColor.WHITE);
createCircularBody(radius);
body.cbTypes.add(CB_TYPE);
body.userData.sprite = this;
}
}
class Box extends FlxNapeSprite {
public static var CB_TYPE(default, null) = new CbType();
public function new(x:Float, y:Float)
{
super(x, y);
makeGraphic(100, 50, FlxColor.GREEN);
createRectangularBody(width, height);
body.cbTypes.add(CB_TYPE);
body.type = BodyType.STATIC;
}
}
Give Drag a function like "destroyConstraints()" and set mouseJoint.space = null inside that function. In collideLightBox, call drag.destroyConstraints().
I am just starting to learn actionscript, and to help get used to the syntax, I am challenging myself to make a simple game where you are a circle that shoots falling blocks.
For some reason every time I try to add a keyboard event listener the game doesn't run.
Here is my player file.
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
public class Player extends Sprite
{
//Variables
private var playerRadius:Number = 50;
private var playerX:Number = 5;
private var playerY:Number = 5;
private var speed:Number = 0;
private var xvel:Number = 0;
public function Player()
{
init();
//Drawing
drawPlayer();
//Event Listeners
this.addEventListener(Event.ENTER_FRAME, updatePlayer);
stage.addEventListener(KeyboardEvent.KEY_DOWN, controlPlayer);
}
//Update
public function updatePlayer(event:Event):void{
this.x ++;
}
//Draw
private function drawPlayer():void{
graphics.beginFill(0xFF0000);
graphics.drawCircle(10,10,50);
graphics.endFill();
}
//Control
public function controlPlayer(event:KeyboardEvent):void{
if (event.keyCode == Keyboard.RIGHT) {
speed = 5;
}
}
}
}
With this code I just get a white screen, but if I comment out
stage.addEventListener(KeyboardEvent.KEY_DOWN, controlPlayer);
it works, but I don't have control of the player.
I'd appreciate any and all help!
Using your code I was able to figure out your issue which ultimately turned out to be a couple problems with your code. I'm surprised you were not seeing the following error in the Flash 'Output' Panel when you tested the application:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Player()
at Player_fla::MainTimeline/frame1()
The first issue is that when you create an object of the type Player, it isn't yet added to the Stage, so it does not yet have access to the stage object.
Once the player object is added to the Stage, only then will you be able to add the listener for keyboard events to the stage; however, for this to happen, your Player class needs to be made aware of the fact that an instance of it was added to the stage so that it knows exactly when it should register the keyboard event listener.
Here is an updated version of your code that should resolve these issues:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
public class Player extends Sprite
{
//Variables
private var playerRadius:Number = 50;
private var playerX:Number = 5;
private var playerY:Number = 5;
private var speed:Number = 0;
private var xvel:Number = 0;
public function Player()
{
init();
//Drawing
drawPlayer();
//Event Listeners
this.addEventListener(Event.ENTER_FRAME, updatePlayer);
this.addEventListener(Event.ADDED_TO_STAGE, initKeyboardListener);
}
public function initKeyboardListener(event:Event) {
stage.addEventListener(KeyboardEvent.KEY_DOWN, controlPlayer);
}
//Update
public function updatePlayer(event:Event):void{
this.x++;
}
//Draw
private function drawPlayer():void{
graphics.beginFill(0xFF0000);
graphics.drawCircle(10,10,50);
graphics.endFill();
}
//Control
public function controlPlayer(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.RIGHT) {
this.speed = 5;
}
}
} // end class
} // end package
For all of this to work, don't forget to add the player object to the stage. I can only assume you have done this since you haven't shared any code showing where you use the Player class, but here is an example of what I am referring to:
import Player;
var player:Player = new Player();
stage.addChild(player);
Also, the keyboard listener simply alters the speed variable; however the speed variable hasn't been implemented anywhere else in your code, so you won't see the difference in the GUI until this is fixed. I verified that all the listeners were working as they should using trace statements.
Is there an easy way to add a simple border to an image?
I'm loading in image thumbs, and would like to add a border at runtime, instead of having to edit all the thumbs.
I'm using Spark Image.
Thanks!
EDIT:
I need to add a 1 px white border around these thumbs. I set the size of the tumbs to be 90x90, to make them fit if they are either horisontal or vertical, but the actual images in my example scales down to 90x51 (this is not fixed, only 90x90 as a maximum is fixed)
This is my code for adding thumbNails to a TileGroup (loading the gallery from an xml file):
private function loadPopUpThumbs():void{
if(curThumbImg <= totThumbImg){
var thumbImg:Image = new Image();
var _loader:Loader = new Loader();
var imageNr:int = curThumbImg;
var thumbContainer:BorderContainer = new BorderContainer();
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE,function(e:Event):void{
thumbImg.source = e.currentTarget.content;
popUpImgGroup.addElement(thumbImg);
thumbImg.width = 90;
thumbImg.height = 90;
thumbImg.scaleMode = "letterbox";
thumbImg.verticalAlign = "bottom";
thumbImg.smooth = true;
thumbImg.id = "thumbImg" + imageNr;
//thumbImg.drawRoundRect(0,0,thumbImg.width,thumbImg.height, null, 0xffffff);
thumbImg.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void{
popUpThumbClicked(imageNr.toString());
});
trace("Thumb added: " + popUpXMLList.(attribute('nr')==imageNr.toString()).#thumbURL);
curThumbImg++;
loadPopUpThumbs();
});
_loader.load(new URLRequest(encodeURI(popUpXMLList.(attribute('nr')==imageNr.toString()).#thumbURL)));
}else{
trace("DONE Adding thubs!!!");
}
}
Also: Would it be possible to add a linebreak in the items added to the TileGroup?
In my XML file I've defined a group attribute, so that I'm able to devide the images into groups. If I click a image from one group, I can skip next/prev within that group, but not to the next group. Is there any way for me to insert a linebreak to my TileGroup, so that I can listen for when the prevGroup != curGroup, and then add in some sort of spacing before continuing adding the next thumbs? All I need is a way to skip a line in the tileGroup :)
Thanks!
You can create new custom Image Class, extends spark Image. Very simple and clean. And set border size and color with css. See example:
package classes
{
import flash.display.CapsStyle;
import flash.display.JointStyle;
import flash.display.LineScaleMode;
import spark.components.Image;
public class ImageBorder extends Image
{
public function ImageBorder()
{
super();
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if (imageDisplay && imageDisplay.bitmapData)
{
var borderSize:Number = getStyle("borderSize") || 0;
var borderColor:Number = getStyle("borderColor") || 0xffffff;
var half:Number = borderSize/2;
imageDisplay.left = imageDisplay.top = imageDisplay.right = imageDisplay.bottom = borderSize;
graphics.clear();
graphics.lineStyle(borderSize, borderColor, 1, false, LineScaleMode.NONE, CapsStyle.NONE, JointStyle.MITER);
graphics.moveTo(0, half);
graphics.lineTo(unscaledWidth -half, half);
graphics.lineTo(unscaledWidth - half, unscaledHeight-half);
graphics.lineTo(half, unscaledHeight-half);
graphics.lineTo(half, half);
}
}
}
}
In application use with css:
<fx:Style>
#namespace s "library://ns.adobe.com/flex/spark";
#namespace mx "library://ns.adobe.com/flex/mx";
#namespace classes "classes.*";
classes|ImageBorder
{
borderSize : 10;
borderColor : "0xff00ff";
}
</fx:Style>
<classes:ImageBorder source=" your source url " />
Spark image is a SkinnableComponent.
You can create your custom skin that supports borders in any
convenient way, like styles or properties.
Or you can set that
skin if you want to see border or remove it if you don't want
Or you can put it inside BorderContainer, and set borderVisible to
true when you want to see the border.
I am loading images for a game before the game begin. So the main function sends links of images to an image loading object. This is what happen in my image loading object when I do image.load(link) in my main :
public function charge(str:String, img_x:int, img_y:int, layer:Sprite):void
{
trace("load");
urlRequest = new URLRequest(str);
loaderArray[cptDemande] = new Loader();
loaderArray[cptDemande].contentLoaderInfo.addEventListener(Event.COMPLETE, loading_done);
loaderArray[cptDemande].load(urlRequest);
posX[cptDemande] = img_x;
posY[cptDemande] = img_y;
layerArray[cptDemande] = layer;
cptDemande++;
}
The parameters img_x:int, img_y:int and layer:Sprite are related to displaying the images afterward. I am using arrays to be able to add the images to the stage when the loading is all done.
The event listener fire this function :
public function loading_done(evt:Event):void
{
cptLoaded++;
evt.currentTarget.contentLoaderInfo.removeEventListener(Event.COMPLETE, loading_done);
if((cptDemande == cptLoaded) && (isDone == true))
{
afficher();
}
}
what I want is to be able to target the good loader to remove the event listener. What I am currently using(evt.currentTarget) doesn't work and generate an error code :
1069 Property data not found on flash.display.LoaderInfo and there is no default value
Tracing evt.currentTarget shows that currentTarget is the LoaderInfo property. Try updating your code as follows:
public function loading_done(evt:Event):void
{
cptLoaded++;
// Current target IS the contentLoaderInfo
evt.currentTarget.removeEventListener(Event.COMPLETE, loading_done);
//evt.currentTarget.contentLoaderInfo.removeEventListener(Event.COMPLETE, loading_done);
if((cptDemande == cptLoaded) && (isDone == true))
{
afficher();
}
}
Just a wee tip for you while I'm at it, you could make life a lot easier for yourself by storing all the properties of your images on an Object and then pushing these onto a single Array, rather than managing a separate Array for each property.
Something like this:
private var loadedImages:Array = new Array();
public function charge(str:String, img_x:int, img_y:int, layer:Sprite):void
{
var urlRequest:URLRequest = new URLRequest(str);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loading_done);
loader.load(urlRequest);
var imageData:Object = { };
imageData.loader = loader;
imageData.posX = img_x;
imageData.posY = img_y;
imageData.layer = layer;
// Now we have a single Array with a separate element for
// each image representing all its properties
loadedImages.push(imageData);
cptDemande++;
}