Switching to AS3

Discussion in 'Game Development (Technical)' started by hippocoder, Dec 21, 2008.

  1. hippocoder

    Indie Author

    Joined:
    Mar 18, 2008
    Messages:
    591
    Likes Received:
    0
    Hi all,

    I've switched from using Blitzmax to Flash / AS3. The reason for the switch is deployment and market reach. Flash clearly will allow me to reach more platforms and more customers than Blitzmax will. Interestingly, both languages are quite similar so my migration is eased considerably. However where they differ is in the wealth of misconceptions.

    With Blitz, you have a very defined way you make games with: Drawimage.
    With AS3, you have a vast number of different ways to get something on the screen.

    Here are some of my findings/research which I have come up with so far:

    1. The best way to make games for speed is using copypixels() much like we do with SDL. Blending and Transformations are possible (but I haven't got far into this yet).

    2. A simple stack or Single Linked List is the best way to keep track of all the game data: aliens, bullets, whatever.

    3. If you're using objects in your Linked List, you should use a pool, because allocation and destruction is very slow comparitively, in AS3.


    Therefore to build my skeleton game app, from which to work from I need to build a set of libraries mostly devoted to game rendering, as this will be the biggest bottleneck.

    Do you have any resources or contributions to help with? I am very grateful for and advice or assistence in this matter. There is so much to learn every day, and so little time to do it.

    Thanks in advance!
     
  2. andrew

    andrew New Member

    Joined:
    Jan 14, 2007
    Messages:
    487
    Likes Received:
    0
    With AS3 you have exactly two ways to put something on the screen. Either you attach it to a Sprite and let Flash's display list manage/move/update it, or you draw it yourself via bitmap functions (copypixels, etc). The first is easy, the second is a bit more involved. Depends on what kind of game you're making.

    As for lists, etc, it depends on how complicated your objects are. Allocation isn't *that* slow, however it is a garbage-collected language which you'll have to keep in mind. In general you write the same way you would if the game was in C++ or Java.
     
  3. esrix

    Original Member

    Joined:
    Aug 11, 2005
    Messages:
    143
    Likes Received:
    0
    One thing I was taught was not to use fixed movement with the enter frame event in AS3. That is, it's not a good idea to say mySprite.x += 5 on every enter frame event.. If Flash runs slow on a person's computer, it makes your game appear to run slow as well.

    Instead, a good idea is to move the objects based on the amount of time that has passed since the last frame was rendered. This can be done using Flash's getTimer function in the flash.utils package. So something like:

    mySprite.x = 300 * ( ( getTimer() - lastFrameTime ) / 1000 )

    will make your game appear to run at the same speed on most computers.

    The drawback to this is that you may have to cap the movement increments if you are using collision detection. If the frame updates too late, it is possible to have an object move completely move through another object and not detect that it collided with it at all.
     
  4. hippocoder

    Indie Author

    Joined:
    Mar 18, 2008
    Messages:
    591
    Likes Received:
    0
    Thank you for the excellent replies. I've been looking into this sorta thing:

    A couple of functions, logic called 30 times a second, and drawing which is called "whenever it can". By doing this it should remain a fixed framerate.

    I've started getting into Copypixels, but I can't find an example which actually works - can someone post a little snippet, something simple ie to make the backbuffer, draw a blob and display it?

    Thanks a lot :)
     
  5. Backov

    Original Member

    Joined:
    Oct 23, 2005
    Messages:
    812
    Likes Received:
    0
    It's super simple really. Here's a small piece from the class that holds my sprite strips..

    Code:
    		private function handleLoadComplete(evt:Event):void
    		{
    			loaded = true;
    			
    			bitmapdata = (ldr.content as Bitmap).bitmapData;
    			
    			ldr = null;
    			
    			srcRect.y = 0;
    			srcRect.width = bitmapdata.width/frameCount;
    			srcRect.height = bitmapdata.height;
    			
    			dispatchEvent(new Event(LOAD_COMPLETE));
    			
    			// Fire an event
    		}
    
    
    		public function copyFrameTo(frame:int,bmp:BitmapData,pt:Point):void
    		{
    			if (frame>-1 && frame<frameCount)
    			{
    				srcRect.x = frame*srcRect.width; 
    				bmp.copyPixels(bitmapdata,srcRect,pt);
    			}
    		}
    
    
    That's the load handler which gets called when Loader finishes loading the file (from a URL) and the copyFrameTo() which the sprites call to get the frame data into their own local bitmapdata storage.
     
  6. hippocoder

    Indie Author

    Joined:
    Mar 18, 2008
    Messages:
    591
    Likes Received:
    0
    Thanks for the excellent reply.

    If its no problem can you point out how to get hold of the BitmapData of an image I have imported, or allow me to load raw BitmapData?

    So far I tried 2 methods:

    1. attempted to load through embed, that failed
    2. used the Import feature of CS3 to import the .png file

    However I cannot use either of them with CopyPixels - it seems unable to find those bitmaps.

    What am I doing wrong? In particular, am I even doing it right? In Blitzmax you would go:

    myimage = LoadImage("blub.png")

    And there you had it, and myimage would be the image I wanted. I feel as I am using CS3 it might be a good idea to just use the import feature (File->Import) to add png files via the UI. If this isn't efficient, loading bitmap data would be great?
     
  7. oNyx

    Original Member

    Joined:
    Jul 26, 2004
    Messages:
    1,212
    Likes Received:
    0
    Code:
    [Embed(source = '../images/rect.png')]
    private var SelRectClass:Class;
    private var selRectBitmap:Bitmap = new SelRectClass();
    [...]
    buffer.copyPixels(selRectBitmap.bitmapData, <Rectangle for dimensions>, <Point for position>);
     
  8. Backov

    Original Member

    Joined:
    Oct 23, 2005
    Messages:
    812
    Likes Received:
    0
    You could also use the Loader class if you didn't want to embed. With that you can either load it from another SWF, a url (local or remote), etc..

    If you're doing web-based games, everything you embed will get loaded with the game, but it will be longer before you're showing something.

    Note: that link isn't responding, but that should be it. The Adobe site is flakey as hell, I've just downloaded all the Flex docs.
     
  9. hippocoder

    Indie Author

    Joined:
    Mar 18, 2008
    Messages:
    591
    Likes Received:
    0
    thanks for the reply. My clumsy attempt is failing though:

    Any idea why? it fails on the last line with 1061: Call to a possibly undefined method BitmapData through a reference with static type flash.display:Bitmap.
     
  10. Backov

    Original Member

    Joined:
    Oct 23, 2005
    Messages:
    812
    Likes Received:
    0
    The property name is case sensitive. :)
     
  11. Backov

    Original Member

    Joined:
    Oct 23, 2005
    Messages:
    812
    Likes Received:
    0
    Oh, and if you want my advice: Do yourself a favor and get Flex Builder. You can still use Flash for components and such (it's great for that) - but do the game in Flex. You wouldn't have been stuck on an error like that in Flex, the code completion would have shown you what you were doing wrong.
     
  12. hippocoder

    Indie Author

    Joined:
    Mar 18, 2008
    Messages:
    591
    Likes Received:
    0
    Thanks guys.

    Here's my first attempt finished. I've managed to get to grips in AS3 since the start of this topic - only took a couple of days to get this demo up and running:

    - linked lists
    - blitted display
    - inputs etc

    http://hippocoder.net84.net/penguintest.swf

    Let me know what you think. It isn't a game I'm making but I tend to make shootemups to get to grips with a new language, so a fun shooter called "Flight of the Penguin" will do :D
     
    #12 hippocoder, Dec 23, 2008
    Last edited: Dec 23, 2008
  13. JGOware

    Indie Author

    Joined:
    Aug 22, 2007
    Messages:
    1,578
    Likes Received:
    0
    hey...that's an interesting demo. Could you post the entire code to that here? That would be a GREAT learning experience for someone like me considering the transition to Flex in 2009. Thanks for your consideration in sharing the demo code. ;)

    Also, what's the native res of the demo? It runs in a scaleable window so it's hard to know?

    Thanks.
     
  14. Alistair Hutton

    Alistair Hutton New Member

    Joined:
    Jun 13, 2007
    Messages:
    60
    Likes Received:
    0
    What resolution are you displaying at? On my machine with the window sized at 800x600 I'm getting around 20 frames-per-second on your .swf. My game with a similar amount of stuff being drawn maxes out at whatever frame rate the Flash player is set too (ie it's breaking 200 fps).
     
  15. hippocoder

    Indie Author

    Joined:
    Mar 18, 2008
    Messages:
    591
    Likes Received:
    0
    JGOWare: Sure, here is the code for it. You will find that it is all a discovery process for me at the moment I'm afraid, and I reference external import libraries (you can look them up on google for linked lists and such), but as the next poster pointed out - my code is in fact very slow!

    Code:
    //----------------------------------------------------------------------------
    //Main app
    //----------------------------------------------------------------------------
    package
    {
    	
    	//----------------------------------------------------------------------------
    	//basic flash import
    	//----------------------------------------------------------------------------
    	import flash.display.MovieClip;
    	import flash.events.Event;
    	import flash.events.TimerEvent;
    	import flash.utils.Timer;
    	import flash.geom.*;
    	import flash.events.*;
    	import flash.utils.getTimer;
    	import flash.display.Bitmap;
    	import flash.display.BitmapData;
    	import flash.display.Sprite;
    	
    	//----------------------------------------------------------------------------
    	//custom imports
    	//----------------------------------------------------------------------------
    	import FPSCounter;
    	import de.polygonal.ds.DLinkedList;
    	import de.polygonal.ds.DListIterator;
    	import de.polygonal.ds.DListNode;
    
    	//----------------------------------------------------------------------------
    	//game imports
    	//----------------------------------------------------------------------------
    	import cShip
    	
    	//----------------------------------------------------------------------------
    	//main code
    	//----------------------------------------------------------------------------
    	public class Main extends MovieClip
    	{
    		//----------------------------------------------------------------------------
    		//load from library
    		//----------------------------------------------------------------------------
    		var testship:testshipClass = new testshipClass(0,0);
    		var clouds:cloudsClass = new cloudsClass(0,0);
    				
    		//----------------------------------------------------------------------------
    		//variables
    		//----------------------------------------------------------------------------
    		var backBufferData:BitmapData; //the backbuffer bitmap data we draw on
    		var backBuffer:Bitmap; //the bitmap object
    		var point:Point; //generic coordinate
    		var rect:Rectangle; //generic rect
    		var i:int; //for loops
    		
    		//vars for scrolling
    		var scrollX:Number = 0; //init with 0 or Number freaks out like a spastic
    		
    		//linked lists
    		var lShip:DLinkedList ; //a linked list for cShip class - use dll.append(item) to add an item to the end
     		//----------------------------------------------------------------------------
    		//the main code of the class
    		//----------------------------------------------------------------------------
    		public function Main()
    		{
    			
    			
    			//set up the linked list
    			lShip = new DLinkedList();
    
    			//add some random ships
    			for (i=0; i<50; i++)
    			{
    				var ship:cShip = new cShip();
    				ship.x = (Math.random()*640)-32;
    				ship.y = (Math.random()*480)-32;
    				ship.speed = (Math.random()*5)+1;
    				ship.image = testship;
    				lShip.append(ship);
    			}
    		
    			//set up the backbuffer for drawing on
    			backBufferData = new BitmapData(640,480 , false , 0x666666); //data storage of the backbuffer
    			backBuffer = new Bitmap(backBufferData); // "canvas" of the backbuffer
    			addChild(backBuffer); //add the backBuffer canvas object to the displaylist of the stage			
    			
    			//set up a little fps counter
    			addChild(new FPSCounter(0,0 , 0xFFFFFF , true ));
    			
    			//begin the mainloop
    			addEventListener(Event.ENTER_FRAME, Mainloop);
    
    		}
    		//----------------------------------------------------------------------------
    		//mainloop
    		//----------------------------------------------------------------------------
    		public function Mainloop(e:Event)
    		{
    			Update();
    			Render();
    		}
    		
    		//----------------------------------------------------------------------------	
    		//update
    		//----------------------------------------------------------------------------
    		function Update():void
    		{
    			//update scrolling
    			scrollX -= 0.5;
    			if (scrollX < -640)
    			{
    				scrollX += 640;
    			}
    			
    			//update ships
    			var item:DListNode = lShip.head; //item is used to step through a linked list
    			while(item)
    			{
    				//logic
    				item.data.x += item.data.speed;
    				if (item.data.x > 640)
    				{
    					item.data.x =-64;
    					item.data.y = (Math.random()*480)-32;
    					item.data.speed = (Math.random()*5)+1;
    					//lShip.remove(new DListIterator(lShip, item)); //delete an item
    				}
    
    				//step through (required)
        			item = item.next; //step through list
    			}
    		}
    
    		//----------------------------------------------------------------------------
    		//render
    		//----------------------------------------------------------------------------
    		function Render():void
    		{
    			//lock backbuffer
    			backBufferData.lock();
    			
    			//draw background
    			DrawImage( clouds , scrollX , 0 , 0 , 0 , 640 , 480 );
    			DrawImage( clouds , scrollX+640 , 0 , 0 , 0 , 640 , 480 );
    
    			
    			//draw ships
    			var item:DListNode = lShip.head; //item is used to step through a linked list
    			while (item)
    			{
    				//render ships
    				 DrawImage( testship , item.data.x , item.data.y , 0 , 0 , 64 , 64);
    
    				//step through (required)
        			item = item.next; //step through list
    			}
    			
    			//unlock backbuffer 
    			backBufferData.unlock();
    		}
    		
    		//----------------------------------------------------------------------------
    		//drawimage
    		//----------------------------------------------------------------------------
    		function DrawImage( image:BitmapData , x:Number , y:Number , sx:int , sy:int , w:int , h:int ):void
    		{
    			point = new Point(x,y);
    			rect = new Rectangle(sx,sy,w,h);
    			backBufferData.copyPixels( image , rect , point )//, null , null , false);
    		}
    
    	}//main
    }//package
    Alistair, you pointed out my code is very slow. I'm very anxious about this to discover just why. I hope you can identify the problem for me. The resolution is 640x480.

    Loading is done by loading pngs into the library, and then setting the class in the link properties. Then in code I go:

    var testship:testshipClass = new testshipClass(0,0);
    (seems to return valid bitmapdata)


    For drawing to the back buffer (bitmapdata) I use:

    point = new Point(x,y);
    rect = new Rectangle(sx,sy,w,h);
    backBufferData.copyPixels( image , rect , point )

    Just why could it be this slow? it is all blitting by the way.
     
  16. Backov

    Original Member

    Joined:
    Oct 23, 2005
    Messages:
    812
    Likes Received:
    0
    Two quick tips:

    Code:
    
    point = new Point(x,y);
    rect = new Rectangle(sx,sy,w,h);
    
    
    Don't do that. Those have to be garbage collected, and that's a bad thing. What I did was have my objects keep their source rects and dest rects. You can get the point from destRect.topLeft.

    Also, why are you using a linked list? The AS3 containers aren't great, but they're not bad either. I don't really see a reason to use anything external.
     
  17. hippocoder

    Indie Author

    Joined:
    Mar 18, 2008
    Messages:
    591
    Likes Received:
    0
    What do you mean keep their source and dest rects? you mean define the Rect outside the loop ie precalculate all rects?

    As for linked lists, the code runs the same speed ish without them, so its not the bottleneck as far as I can see. I haven't yet learned container classes. Can I add and remove classes at will and iteriate through?
     
  18. Backov

    Original Member

    Joined:
    Oct 23, 2005
    Messages:
    812
    Likes Received:
    0
    Of course. You can either use an Array or an ArrayCollection.. There's Dictionary as well, but you'll need an ordered list. As I said, containers are weak but they're not THAT weak. :)

    As for what I meant, I simply mean that instead of creating two new objects for every object every frame, have each object hold its own source and destination rects and update them instead of an x and y value.

    So something like:

    newSprite.srcRect = new Rectangle(0,0,64,64);
    newSprite.bounds = new Rectangle(x,y,srcRect.width,srcRect.height);

    Then in your update, you update bounds.topLeft instead of x/y.
     
  19. oNyx

    Original Member

    Joined:
    Jul 26, 2004
    Messages:
    1,212
    Likes Received:
    0
    Set the framerate to 67fps if you also want to get 60ish fps in IE. (65fps are actually enough, but 67 makes more sense from a mathematical Pov [~15msec per frame].)
     
  20. Jack Norton

    Indie Author

    Joined:
    Jul 28, 2004
    Messages:
    5,130
    Likes Received:
    0
    On my pc the demo runs at 57fps.
    BTW does anyone has a link to a AS3 very basic wrapper/template for a game? I know that everyone keep saying that AS3 is dead easy etc.
    But basically I don't know all the hidden tricks (like copypixel) and what I would like is just a set of ready-made libraries that I can import, and then just do something like:
    test=loadImage("test.png");
    blitImage(test,100,150);

    and so on? possible that nobody ever made a sort of wrapper for making AS3 flash games (display,audio,input)?
     

Share This Page

  • About Indie Gamer

    When the original Dexterity Forums closed in 2004, Indie Gamer was born and a diverse community has grown out of a passion for creating great games. Here you will find over 10 years of in-depth discussion on game design, the business of game development, and marketing/sales. Indie Gamer also provides a friendly place to meet up with other Developers, Artists, Composers and Writers.
  • Buy us a beer!

    Indie Gamer is delicately held together by a single poor bastard who thankfully gets help from various community volunteers. If you frequent this site or have found value in something you've learned here, help keep the site running by donating a few dollars (for beer of course)!

    Sure, I'll Buy You a Beer