A Flash Developer Resource Site

Results 1 to 20 of 20

Thread: [RESOLVED] Bitmap / copyPixels problem

  1. #1
    Member
    Join Date
    Jun 2005
    Posts
    56

    resolved [RESOLVED] Bitmap / copyPixels problem

    I'm working on a tile-based game, which uses copyPixels to put the tiles in the right place.

    The problem I'm having is, the screen flashes the initial bitmap with all the tiles in the correct place then goes straight to a blank bitmap screen where it stays

    If I comment out the world_bmpData = ... line then the image stays there, but when changing the start column/row variables (which changes which tiles are copied), the image does not update at all (though I have checked startColumn and startRow are changing correctly.)

    What am I doing wrong?

    Here is my code at the moment:

    Code:
    private function refreshScreen():void {
    	world_bmpData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0x000000);
    	for (var k:int = startColumn; k < (startColumn+20); k++) {
    		for (var j:int = startRow; j < (startRow+15); j++) {
    			world_bmpData.copyPixels(tile_bmpData, tileType[(Number(aLevelMap[k][j]))], new Point(myX, myY));
    			myY += 40;
    		}
    		myX += 40;
    		myY = 0;
    	}
    	
    	worldBitmap = new Bitmap(world_bmpData);
    	// add the main bitmap
    	addChild(worldBitmap);
    	
    }
    Thanks in advance for any help given!
    Last edited by sixblade; 02-12-2008 at 01:28 PM.

  2. #2
    Palindrome emordnilaP Diniden's Avatar
    Join Date
    Feb 2008
    Posts
    230
    All I can say on this one is try not to redeclare world_bmpData as a whole new instance everytime. Does the BitmapData function have a type of clear method within itself? If so, it'd be better to handle the resetting of the bitmap data using it's internal methods rather than redeclaring the instance.

  3. #3
    Member
    Join Date
    Jun 2005
    Posts
    56
    I was hoping it did but unfortunately not!

    It seems that the copyPixels command for whatever reason is NEVER running again after the first time. I've tried calling it in different ways, and running traces before and after the for loops, and each time it seems that it should be working!

    It makes no sense to me and I've got no idea how to continue

  4. #4
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Although BitmapData does not have a clear method, it does have fillRect, which you can use the same way:
    Code:
    bd.fillRect(bd.rect, 0x00000000);
    If you get rid of the unnecessary object creation, you don't even need to explicitly update worldBitmap, as it will get the changes from world_bmpData.

    You may want to lock and unlock the bmp while processing it though.

  5. #5
    Member
    Join Date
    Jun 2005
    Posts
    56
    where would i put the lock and unlock bits in my code? I think that may fix it (I'm hoping tried so many things now!)

  6. #6
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    It won't fix the problem you're having with the copyPixels command not running. That seems like something is altering the values of your startColumn and startRow values in code elsewhere.

    But, to answer:
    Code:
    bd.lock();
    //code which changes bitmapdata - like copyPixels
    bd.unlock();
    This is strictly a performance optimization. All it does is keep things from trying to redraw themselves as you change the bitmapdata they depend on.

  7. #7
    Member
    Join Date
    Jun 2005
    Posts
    56
    Would you mind taking a look at it please? I've even asked my lecturers at university and still couldn't figure out what the problem is!

    I've zipped up the flp/fla/as/xml files here:

    Game.zip


    If you, or anyone have the time to help it would be greatly appreciated!

    I've commented quite a lot of the code so hopefully it should be easy to understand what I'm trying to do with most of it, if you do have any questions, please let me know so I can explain

  8. #8
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I don't even have the flash IDE, so I can't look at the fla. I don't even know what an flp is. But sure, I'll take a look.

  9. #9
    Member
    Join Date
    Jun 2005
    Posts
    56
    oh sorry an flp is just a flash project file it just keeps note of which files you're using in a project, but its mostly pointless really!

    The flash file is simple anyway - it has a tilesheet png graphic which is exported to actionscript with the class "tileSheet" and the document class for the fla file is Incarnate (so auto runs the incarnate function in the actionscript code when the movie is loaded )

    I really appreciate your helping out, thanks a lot!

  10. #10
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    You responded while I was writing again.

    Okay, so if tileSheet is just a png graphic, I can fake that. Unless you want to post that too?

  11. #11
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Okie doke. You had some problems with adding/removing stuff unneccessarily. I've fixed those. main added gameloop as an enterframe listener, gameloop called main, ...

    The problem you had with the bitmaps was that myX and myY were class level variables, and you never reset myX. They didn't need to be class level at all, so I made them local to the refreshScreen method.

    You were also missing quite a few variable type declarations.

    The control code is still not working, but I don't want to do your entire project for you.

    Oh, and change your tileSheet back to the way it was. That embed syntax is for the flex compiler.
    Attached Files Attached Files

  12. #12
    Palindrome emordnilaP Diniden's Avatar
    Join Date
    Feb 2008
    Posts
    230
    I checked out your file and developed some of my own questions if you got time :3

    Why did you place the call on your key listeners within the game enterFrame listener? If they are listeners can't they listen arbitrarily outside the frame handler?

  13. #13
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I did not really look at or alter the key listeners from the way sixblade had it. As I said above, it was not working for me, but I wanted to concentrate on the problems he was having with the bitmap.

  14. #14
    Palindrome emordnilaP Diniden's Avatar
    Join Date
    Feb 2008
    Posts
    230
    Oh heh...I didn't check on your file ^^' I looked at his to see if I could find the problem myself :P, but I had the same conclusion of non-conclusiveness...

    One interesting thing I noticed from the file is that the fla itself hadn't a lick of as to it T_T, I didn't realize you could start up and fire off all AS from the .as files :x

  15. #15
    Member
    Join Date
    Jun 2005
    Posts
    56
    5TonsOfFlax - PM me with your paypal email so I can send you $5 to buy a pint for helping me here - apparently it was something unbelievably simple (I can't believe it was that! I spent so long trying other things! lol) but I really appreciate your help because I probably would have spent the rest of the day trying to get it to work!

    By the way the key listeners should work but the game uses z, x, / and ' instead of the arrow keys - its proper old school keys but they are so much easier to use! Don't understand why people made a move to the cramped arrow keys!

  16. #16
    Member
    Join Date
    Jun 2005
    Posts
    56
    Deleted
    Last edited by sixblade; 02-13-2008 at 08:09 AM.

  17. #17
    Member
    Join Date
    Jun 2005
    Posts
    56
    I noticed you removed my code that was trying to stop it multiplying by zero - which shouldn't be mathematically possible - does flash allow this?
    Last edited by sixblade; 02-13-2008 at 08:09 AM.

  18. #18
    Member
    Join Date
    Jun 2005
    Posts
    56
    Woooooooooooooo it works!

    But only when moving to the right. wonder why the rest isn't working - next thing for me to figure out

    Edit: * Slaps Actionscript 3 around a bit with a large trout. * Disable keyboard shortcuts.. oh, it works. stupid thing
    Last edited by sixblade; 02-13-2008 at 07:36 AM.

  19. #19
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    Multiplying by zero is perfectly mathematically possible. The result is 0. It's dividing where you run into problems.

  20. #20
    Member
    Join Date
    Jun 2005
    Posts
    56
    Thanks

    If anyone wants to see how this works, I've put it online now -->

    Link

    The code at this stage is:

    Code:
    package {
    	
    	import flash.display.Sprite;
    	import flash.display.Bitmap;
    	import flash.display.BitmapData;
    	import flash.display.Loader;
    	import flash.geom.Point;
    	import flash.geom.Rectangle;
    	import flash.net.*;
    	import flash.events.*;
    	import flash.text.*;
    	
    	public class Incarnate extends Sprite {
    
    		// Create a bitmapData object which will hold the bitmap data for the currently displayed world
    		private var world_bmpData:BitmapData = new BitmapData((stage.stageWidth + 40),(stage.stageHeight + 40));
    		private var offset_bmpData:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight);
    		// Create a bitmap display object to hold the bitmapData object! [Otherwise we can't display it on screen!]
    		private var worldBitmap:Bitmap = new Bitmap(offset_bmpData);
    		// This is used to load the XML level data.
    		private var xmlLoader:URLLoader;
    		//This variable is used for storing XML level data.
    		private var tileData:XML;
    		// This array holds the locations/types of all tiles in the world map.
    		private var aLevelMap:Array=new Array();
    		// This variable brings in and holds the Bitmap Data from our library tilesheet image.
    		// The arguments are width, height.
    		private var tile_bmpData:BitmapData = new tileSheet(160,80);
    		
    		//private var tile_bmp:Bitmap = new tileSheet(); // 160, 80);
    		//private var tile_bmpData:BitmapData = tile_bmp.bitmapData;
    		// This rectangle is used to select the tiles for copying pixels to the world bitmap
    		private var tileType:Array=new Array();
    		// Variables for setting the point for copyPixel use
    		private var worldX:Number = 0;
    		private var worldY:Number = 0;
    		private var worldXMax:Number = 99999999999999999999999999999999;
    		private var worldYMax:Number = 99999999999999999999999999999999;
    		private var xOffset:Number = 0;
    		private var yOffset:Number = 0;
    		
    		private var moveUp:Boolean = false;
    		private var moveDown:Boolean = false;
    		private var moveLeft:Boolean = false;
    		private var moveRight:Boolean = false;
    		private var screenFlip:Boolean = false;
    		private var totalColumns:int;
    		private var totalRows:int;
    		private var nextWorldX:int =0;
    		private var nextWorldY:int =0;
    		private var yIncrement:int =0;
    		private var xIncrement:int =0;
    		private var charSpeed:int = 2;
    		
    		private var startColumn:int = 0;
    		private var startRow:int = 0;
    		
    		private var rectStart:int = 0;
    		
    		// These variables set which keys to use for controlling the character via the keyboard.
    		public static const UP:int = 192; // The ' key
    		public static const DOWN:int = 191; // The / key
    		public static const LEFT:int = 90; // The z key
    		public static const RIGHT:int = 88; // The x key
    		public static const FLIP:int = 13; // The Enter key
    
    		public function Incarnate():void {
    					
    			// Load the XML file and call the loadComplete function to create a 2-dimensional array of tile locations.
    			xmlLoader = new URLLoader();
    			xmlLoader.addEventListener(Event.COMPLETE,loadComplete);
    			xmlLoader.load(new URLRequest("level1.xml"));			
    		}
    
    		private function loadComplete(evt:Event):void {
    			tileData = new XML(xmlLoader.data);
    			//For every column in the XML file
    			for each (var vCount:XML in tileData.tilecol) {
    				// Grab the values of the rows, convert the list to an XML string, and split them into an array, 
    				// then append this array to the end of aLevelMap array, making a 2-dimensional array.
    				// This means Tiles can be accessed by their x,y coordinates by calling aLevelMap[x][y]
    				aLevelMap.push( vCount.tilerow.text().toXMLString().split("\n") );
    			}
    			// Create array of rectangles for each tile number so we can grab tiles easily with copyPixels
    			//******************************************************************************************
    			// This needs to be changed to grab all tiles dynamically from tilesheets of differing sizes
    			//******************************************************************************************
    			for (var i:int = 0; i < 4; i++) {
    				if (i == 0) {
    					rectStart = 0;
    				} else {
    					rectStart = i*40;
    				}
    				tileType[i] = new Rectangle (rectStart,0,40,40);
    			}
    			for (i = 4; i < 8; i++) {
    				if (i == 4) {
    					rectStart = 0;
    				} else {
    					rectStart = (i-4)*40;
    				}
    				tileType[i] = new Rectangle (rectStart,40,40,40);
    			}
    			totalColumns = aLevelMap.length;
    			totalRows = aLevelMap[1].length;
    			addChild(worldBitmap);
    			refreshScreen();
    			main();
    			
    		}
    		
    		private function main():void {
    			addEventListener(Event.ENTER_FRAME, gameLoop);
    			stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownListener);
    			stage.addEventListener(KeyboardEvent.KEY_UP,keyUpListener);
    		}
    		
    		private function gameLoop(evt:Event):void {
    			captureControls();
    			moveTest();
    			moveWorld();
    		}
    				
    		private function keyDownListener(evt:KeyboardEvent):void {
    			switch (evt.keyCode) {
    				case UP:
    				moveUp = true;
    				break;
    				case DOWN:
    				moveDown = true;
    				break;
    				case LEFT:
    				moveLeft = true;				
    				break;
    				case RIGHT:
    				moveRight = true;
    				break;
    				case FLIP:
    				screenFlip = true;
    				break;
    			}
    			
    		}
    		
    		private function keyUpListener(evt:KeyboardEvent):void {
    			switch (evt.keyCode) {
    				case UP:
    				moveUp = false;
    				break;
    				case DOWN:
    				moveDown = false;
    				break;
    				case LEFT:
    				moveLeft = false;
    				break;
    				case RIGHT:
    				moveRight = false;
    				break;
    				case FLIP:
    				screenFlip = false;
    				break;
    			}
    		}
    		
    		private function captureControls():void {
    			yIncrement = 0;
    			xIncrement = 0;
    			if (moveUp) {
    				yIncrement -= charSpeed;
    			}
    			if (moveDown) {
    				yIncrement += charSpeed;
    			}
    			if (moveLeft) {
    				xIncrement -= charSpeed;
    			}
    			if (moveRight) {
    				xIncrement += charSpeed;
    			}
    			if (screenFlip) {
    				//code to handle screen flip here
    			}
    		}
    		
    		private function moveTest():void {
    			nextWorldX = worldX + xIncrement;
    			nextWorldY = worldY + yIncrement;
    			// create next bitmap data for use
    			// hit test if character can move there - if not, implement physics to determine
    			// where his actual next move is.
    			// If character has moved from worldX, worldY, refresh background if needed
    			// Also call character animation function here (which will likely be part of physics)
    		}
    		
    		private function refreshScreen():void {
    			// This function will soon need to be edited to use nextScreen (a bitmapdata created in moveTest)
    			// and the x/yOffset variables to update the one we copy to the displayed bitmap instead of current use.
    			
    			world_bmpData.lock();
    			world_bmpData.fillRect(world_bmpData.rect, 0xff000000);
    			var myX:int = 0;
    			var myY:int = 0;
    			var finalColumn:int = 0;
    			var finalRow:int = 0;
    			finalColumn = startColumn + 21;
    			if (finalColumn > totalColumns) {
    				finalColumn = totalColumns;
    			}
    			finalRow = startRow + 16;
    			if (finalRow > totalRows) {
    				finalRow = totalRows;
    			}
    			
    			for (var k:int = startColumn; k < finalColumn; k++) {
    				for (var j:int = startRow; j < finalRow; j++) {
    					world_bmpData.copyPixels(tile_bmpData, tileType[aLevelMap[k][j]], new Point(myX, myY));
    					myY += 40;
    				}
    				myX += 40;
    				myY = 0;
    			}
    			world_bmpData.unlock();
    			offset_bmpData.lock();
    			offset_bmpData.copyPixels(world_bmpData,new Rectangle(xOffset,yOffset,800,600),new Point(0,0));
    			offset_bmpData.unlock();
    			
    		}
    		
    		private function moveWorld():void {
    
    			worldXMax = (totalColumns - 20)*40;
    			worldYMax = (totalRows - 15)*40;
    			worldX = nextWorldX;
    			if (worldX < 0) {
    				worldX = 0;
    			} else if (worldX > worldXMax) {
    				worldX = worldXMax;
    			}
    			worldY = nextWorldY;
    			if (worldY < 0) {
    				worldY = 0;
    			} else if (worldY > worldYMax) {
    				worldY = worldYMax;
    			}
    			trace(worldX);
    trace(worldY);
    			
    			startColumn = Math.floor(worldX/40);
    			xOffset = worldX - (startColumn*40);
    			if (startColumn > (totalColumns - 20)) {
    				startColumn = totalColumns - 20;
    				xOffset = 0;
    			} else if (startColumn < 0) {
    				startColumn = 0;
    				xOffset = 0;
    			}
    			trace(totalRows);
    			startRow = Math.floor(worldY/40);
    			yOffset = worldY - (startRow*40);
    			if (startRow > (totalRows - 15)) {
    				startRow = totalRows - 15;
    				yOffset = 0;
    			} else if (startRow < 0) {
    				startRow = 0;
    				yOffset = 0;
    			}
    			
    			refreshScreen();
    
    		}
    	}
    }
    This is saved as Incarnate.as in the same directory as the below files

    Other bits in this example are:

    A single tilesheet bitmap (160px by 80px) with 8 tiles 40x40px saved as png

    A flash file with the document class Incarnate which has the tilesheet bitmap added to the library. Then in the library the bitmap is exported to actionscript with the class "tileSheet" : Link

    An xml file called level1.xml in which the tile numbers are organised by column then row using <tilecol> and <tilerow> tags: Link

    The XML file was created using mappy and an export lua script I modified from a version made by a guy on 8bitrocket.com (his exported by row then column, which imo is much slower for a side-scrolling platform game! the luascript is here: Link

    Hopefully this will help anyone else who wants to make a tile-based scrolling platform game in the future.
    Last edited by sixblade; 02-13-2008 at 01:04 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center