Arkiv för kategori ‘ActionScript’
ActionScript3 till HTML5 – Utopi eller lösning?
tisdag, 2 februari, 2010Det är mycket prat om ”kriget” mellan HTML5 och Flash. Apple har tagit sida, likaså Google och helt plötsligt ska alla som arbetar med flashutveckling börja se sig om efter ett nytt jobb. Någonstans på vägen har hela diskussionen blivit lika löjlig som vilket operativsystem som är bäst, vilken spelkonsol som är roligast och om hur vida iPad är något att ha eller inte. Många tycks se det som att två tekniker inte kan existera utan att slå ut den andra som om det skulle handla om någon form av teknisk Darwinism. Som ni förstår så tillhör jag varken ”Flash ska dö” eller ”HTML5 är skit”-lägret utan jag skulle helst se att de bästa delarna från båda sidorna kan användas.
Men jag tänkte inte skriva ännu ett ”varför HTML5 och Flash ska gå hand i hand”-inlägg utan en tanke slog mig när jag stod och lagade mat idag. Tänk om Adobe skulle kunna göra något liknande som de gjort för iPhone-utvecklingen. Koda dina applikationer med AS3, sedan tar kompilatorn över och gör om den exporterade SWF-filen till ett program som går att installera på en iPhone. Att de tillförde ännu ett val, exportera ett actionscript-projekt inte bara som en SWF utan också som en HTML5-sida. Som det ser ut idag med tanke på vilka experiment som gjorts till Google Chrome verkar man kunna göra ganska mycket med bland annat canvas-, video- och ljudtaggen samt en del JavaScript.
Mycket av det Flash kan göra idag skulle såklart vara svårt att åstadkomma men efter som vi redan sett riktigt bra exempel på till exempel fysikmotorer och liknande i JavaScript känns inte detta helt omöjligt. Men i ett rent fallbacksyfte tror jag att detta skulle lösa många av de problem som det pågående formatkriget verkar handla om. Och jag tror att både kunder och utvecklare är villiga att lägga både tid och pengar på att skapa HTML5-versioner av sina Flashsidor om det ”ändå görs automatiskt”.
Dynamic mask using ActionScript
fredag, 15 januari, 2010I was asked if is possible to use my inverted mask-class with a dynamic mask. The answer right now is ”not yet”. But it got me thinking and if you ask me again in a few days the answer might be ”of course, it always has”. So I Googled some stuff about dynamic masks and found that almost none suited what I wanted. I wanted the user to be able to double click somewhere inside the swf, add as many anchorpoints they want, be able to move them around and if they so choose, delete them.
Not as much Frankencode as I was affraid it would be but someone might find it useful so I thought I´d share it. The code is commented if you are new to AS3 and want to know what is going on.
And here is a demo of the little thing. Doubleclick inside the swf to add anchorpoints and doubleclick the handles to remove them.
package{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.Event;
public class Main extends Sprite{
//Setup a some stuff
public var maskBG:Sprite = new Sprite();
public var cord:Array = [];
public function Main():void{
// The image that will appear thru the mask
var lemmyImage:Sprite = new Sprite();
lemmyImage.addChild(new Lemmy());
addChild(lemmyImage);
// An invisible sprite that tracks where the user click
var clickMe:Sprite = new Sprite();
clickMe.graphics.beginFill(0xFF0000,0);
clickMe.graphics.drawRect(0,0,stage.stageWidth,stage.stageHeight);
clickMe.graphics.endFill();
addChild(clickMe);
// Some eventhandlers to see where the user click and to update the mask
clickMe.doubleClickEnabled = true;
clickMe.addEventListener(MouseEvent.DOUBLE_CLICK,addCord);
stage.addEventListener(Event.ENTER_FRAME,updateMask);
addChild(maskBG);
// Set the mask layer to cover the image
lemmyImage.mask = maskBG;
}
private function moveStart(e:MouseEvent):void{
e.currentTarget.startDrag();
e.currentTarget.addEventListener(MouseEvent.MOUSE_MOVE, moveUpdate);
}
private function moveStop(e:MouseEvent):void{
e.currentTarget.stopDrag();
e.currentTarget.removeEventListener(MouseEvent.MOUSE_MOVE, moveUpdate);
}
private function moveUpdate(e:MouseEvent):void{
// Get the location in the array for the handler
var id:int = getHandleId(e.currentTarget.name);
// Update the array with the new values
cord[id] = {id:e.currentTarget.name,x:e.currentTarget.parent.mouseX,y:e.currentTarget.parent.mouseY};
}
private function removeHandle(e:MouseEvent):void{
// Get the location in the array for the handler
var id:int = getHandleId(e.currentTarget.name);
// Remove the part of the array by splicing it.
// Save the splica in a temporaryarray so that it is possible
// to merge the stuff after out deletedpart with the array again.
var a:Array = cord.splice(id,cord.length);
for(var i:int = 1;i<a.length;++i){
cord.push(a[i]);
}
e.currentTarget.parent.removeChild(e.currentTarget);
}
private function updateMask(e:Event):void{
// Clear the masklayer
maskBG.graphics.clear();
maskBG.graphics.lineStyle(2,0xffffff);
maskBG.graphics.beginFill(0xFF0000,1);
// If the value of i is 0 then we want to move to the locatino.
// If we use lineTo it will draw a line from the top left corner.
for(var i:int=0;i<cord.length;++i){
if(i==0){
maskBG.graphics.moveTo(cord[i].x,cord[i].y);
}else{
maskBG.graphics.lineTo(cord[i].x,cord[i].y);
}
}
maskBG.graphics.endFill();
}
private function getHandleId(val:String):int{
// Hack to find the location of the coordinate in the array
for(var i:int=0;i<cord.length;++i){
if(cord[i].id == val){
var id:int = i;
}
}
return id;
}
private function addCord(e:MouseEvent):void{
//Add handle
var handle:Sprite = new Sprite();
handle.graphics.beginFill(0xff0000,1);
handle.graphics.drawRect(0,0,10,10);
handle.graphics.endFill();
handle.x = e.currentTarget.mouseX-5;
handle.y = e.currentTarget.mouseY-5;
// I use the datemethod just cause it easy to get a uniquevalue.
// It's not close to perfect so you should rewrite this part.
// It was late when I did this, sorry I guess =)
var now:Date = new Date();
handle.name = String(now.getUTCMinutes()+now.getMilliseconds()*Math.random());
// Set up the listeners for the handler
handle.doubleClickEnabled = true;
handle.addEventListener(MouseEvent.MOUSE_DOWN, moveStart);
handle.addEventListener(MouseEvent.MOUSE_DOWN, updateMask);
handle.addEventListener(MouseEvent.MOUSE_UP, moveStop);
handle.addEventListener(MouseEvent.DOUBLE_CLICK, removeHandle);
handle.addEventListener(Event.ADDED_TO_STAGE,updateMask);
addChild(handle);
// Push the coordinate into the array
cord.push({id:handle.name,x:e.currentTarget.mouseX,y:e.currentTarget.mouseY});
}
}
}
Brightcove plugin, custom mutebutton
torsdag, 17 december, 2009I think Brightcove is a great service. I’ve been building videoplayers using their API for the past months and I must say it’s super sweet. The API take a while to get your head around but once you do you can do a lot, even if you are just using their own markup-language BEML (Brightcove Experience Markup Language).
But this is’nt a post about how great Brightcove is. I know by experience that you can find a lot of stuff on the internet but not that many tutorials about Brightcoveplayers and that is a problem if you are just getting started and need a push in the right direction.
Before I start.
I do assume that you have used the Brightcove Studio, you know how to create playertemplates using BEML and know some basic ActionScript 3.
Some background.
The client I’ve done most of my Brightcoveprojects for wanted a chromeless player with nothing more than a mutebutton. They didn’t want to use the default controllers so I needed to write a custom plugin. Doing so is pretty straight forward but if you know a thing or two about the Player API you might understand how things work a little more.
It all began in… the template
The first thing you need to do is download the API SWC from Brightcove.
Then you need to create a playertemplate inside the Brightcove studio. The player on which I based this tutorial got no controls beside the ”play”-button that appear when you click on the moviearea.
A Brightcove plugins is nothing more than a SWF that you tell the template to import using the SWFLoader. So in the template we add a VideoPlayer-object and a SWFLoader-object. Since we use a VideoPlayer-object we can’t add a playlist to the player and therefore we don’t need to tell it which playlist or video to play since it will get that ID thru the embedcode. Moving on to the SWFLoader. The most important thing is the source, here you tell the template from where you want to load the plugin. Then set the X and Y-position of the plugin to what ever you want.
And that is pretty much all we have to do inside the Brightcove Studio. The last thing you need to do is to create the player itself and enable the ”Enable ActionScript/JavaScript APIs”-option otherwise you will bash your head bloody against the screen since nothing you do will work.
<Runtime> <Layout style="background-color:#000000" width="600" height="200"> <VideoDisplay id="videoPlayer"/> <SWFLoader depth="2" y="10" x="10" source="YOUR_DOMAIN_URL_HERE/swfname.swf"/> </Layout> </Runtime>
The plugin
When I code I use FlashDevelop or Flex Builder. As long as the IDE you use can import SWC-files your safe, if not i suggest you download the free IDE FlashDevelop and the Flex SDK.
Fire up your IDE and create a new project. The only thing that matters is that you use AS3. Now include the Player API SWC in the project and we can start to write some code. *jay* You can read more about SWCs here and how to include them into your FlashDevelop-project here.
When I write plugins I do it in two different ways. The first one is to hook the VideoPlayer-module yourself. That requires you to write a lot of extra code but saves you a few kb in the end and gives you more control. The other way is to let your mainclass extend the CostumeModule. The CostumModule-class will take care of all the API-stuff at the cost of a few extra kb but in the end it will save you some work. It’s all comes down to if you want to re-invent the wheel or not.
Since I wanted the mutebutton to have an on and off-state I created two MovieClips with the classname ”muteOn” and ”muteOff” in Flash, exported the graphics as a SWC and included it in my FlashDevelop-project.
We begin by importing everything we need. The Sprite and MouseEvent are standard AS3-stuff so nothing new there so we move on to the three Brightcove-classes. APIModules, CustomModule and VideoPlayerModule. If you want more in depth knowledge about what they do just follow the links. Now we create all the stuff we want to use. The only thing that might be new is the datatype for the _playerModule, VideoPlayerModule. This will allow us to use all the stuff the videoplayer can, like mute, but before we can do that we must link _playerModule and the actual videoplayer together. We do that by overriding the initialize-function in the CostumModule-class, or at least I think it’s in that class. But it works.
In the Main-function we set up the graphics and the mouseevent. The variable muted is just to keep track of whether the player is muted or not. You might be able to ask the videoplayer if it’s muted or not, it’s not pretty but for this plugin I think this solution does the job.
When the user click the button the MouseEvent will call the mute-function and set the visibility for both icons to false and then let the if-statement check whether the player is muted. If not, the visibility of ”muteOnGfx” is set to true and the mute-function within the videoplayer-object fires. When we call the mute-function we have to pass a booelan parameter, True if we want the sound off and false if we want it on. And that is it. Mute away now kids!
The code in one piece
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import com.brightcove.api.APIModules;
import com.brightcove.api.CustomModule;
import com.brightcove.api.modules.VideoPlayerModule;
public class Main extends CustomModule{
private var button:Sprite = new Sprite();
private var _playerModule:VideoPlayerModule;
private var muted:Boolean = false;
private var muteOnGfx:muteOn = new muteOn();
private var muteOffGfx:muteOff = new muteOff();
override protected function initialize():void {
_playerModule = player.getModule(APIModules.VIDEO_PLAYER) as VideoPlayerModule;
}
public function Main():void {
button.addChild(muteOnGfx);
button.addChild(muteOffGfx);
if (muted == false) {
muteOnGfx.visible = false;
}else {
muteOffGfx.visible = false;
}
button.buttonMode = true;
addChild(button);
button.addEventListener(MouseEvent.CLICK, mute);
}
private function mute(e:MouseEvent):void {
muteOnGfx.visible = false;
muteOffGfx.visible = false;
if (muted == false) {
_playerModule.mute(true);
muteOnGfx.visible = true;
muted = true;
}else {
_playerModule.mute(false);
muteOffGfx.visible = true;
muted = false;
}
}
}
}
Conclusion
This plugin could of course be modified to control almost everything like play-, pause-, stopbuttons etc. But this is a start and I plan to write some more tutorials about how to make the Brightcoveplayer do what you want. The first step is the hardest, right?
Pure ActionScript 3 inverted mask
onsdag, 21 oktober, 2009I love masks. I really do. I use them alot and I’m proud of it. But a lot of times I need to make something I think Adobe should put into Flash as a native alternative to the regular mask. And that is the inverted mask.
I know more people than me miss this feature and I for one would love to see something like DisplayObject.invertedMask = MaskObject; but its no where to be found unless you want to make your own AS3-solution, which I think is more or less a workaround for something that should have been there from the start.
I’ve seen some people using blendmodes to achive the same effect like the one from Rachel Diesel (http://dieselation.com/2009/04/11/inverting-a-mask-in-actionscript-3/) but most of the time they are not pure as3 so I modified her solution into a more reusable piece of code. And I also added the function moveMask() which allowes you to move the inverted mask after it has been added to the stage with out any hazzle.
It’s not perfect and I bet that a lot of improvements can be done but you can try out the demo here. And yes, that is a pink elephant in a fake Guccibag.
package com.mattiasnorell.bitmap
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* ...
* Original author: Rachel Diesel
* http://dieselation.com/2009/04/11/inverting-a-mask-in-actionscript-3/
*
* Pure AS3 code Mattias Norell
* http://blog.mattiasnorell.com/2009/10/21/pure-actionscript-3-inverted-mask/
*
*/
public class InvertedMask extends Sprite{
public function InvertedMask($parent:DisplayObject,$mask:DisplayObject,$maskPos:Object):void {
var inverted:Sprite = new Sprite();
inverted.x = $parent.x;
inverted.y = $parent.y;
var dup:BitmapData = new BitmapData($mask.width, $mask.height, true, 0xffffff);
dup.draw($mask);
var newAlpha:Bitmap = new Bitmap(dup, "auto", true);
newAlpha.x = $maskPos.x;
newAlpha.y = $maskPos.y;
newAlpha.blendMode = BlendMode.ERASE;
$mask.parent.removeChild($mask);
inverted.addChild($parent);
$parent.x=$parent.y = 0;
inverted.addChild(newAlpha);
inverted.blendMode = BlendMode.LAYER;
addChild(inverted);
}
public function moveMask($target:Object,$maskPos:Object):void {
$target.getChildAt(0).getChildAt(1).x = $maskPos.x;
$target.getChildAt(0).getChildAt(1).y = $maskPos.y;
}
}
}
To activate it you just copy/paste this into your project.
The first parameter is the object you want to mask, the second is the mask itself and in the third parameter you tell the mask where along the x and y-axis it should go.
var newMask:InvertedMask = new InvertedMask(OBJECT_TO_BE_MASKED, THE_MASK, { x:0, y:0 } );
addChild(newMask);
What about moving the mask?
If you add an eventListener to the InvertedMask-object and call the function below it will move your mask in anyway you want.
newMask.addEventListener(MouseEvent.MOUSE_MOVE, moveMask);
private function moveMask(e:MouseEvent):void {
e.currentTarget.moveMask(e.currentTarget, { x:mouseX-10, y:mouseY-10 } );
}
So, all credits for the solution goes to Rachel, I’ve just tweaked it a little to suit my needs and as I said, it’s not perfect but it’s a start.
Hur man bygger en diskbänk
fredag, 8 maj, 2009
Nu undrar ni säkert hur man får en så här snygg kaffekopp. Jo det får man genom att arbeta ihop med diskbänkstillverkaren Intra. De har nu lanserat sin applikation Intra Design Studio i vilken man kan designa sin egen diskbänk. Ett massivt as3-projekt som lämnade two-byggnaden för någon månad sedan. Mer om Intra-projektet finns att läsa här.