Why can't I load this previously serialized object? - actionscript-3

This class is serializable:
package com.things {
public class MySerializableObject {
public var intVals:Array;
public var numVals:Array;
public var stringVals:Array
public function MySerializableObject() {
}
public function init(ints:Vector.<int>, nums:Vector.<Number>, strings:Vector.<String>) {
intVals = new Array();
for each (var i:int in ints) {
intVals.push(i);
}
numVals = new Array();
for each (var n:Number in nums) {
numVals.push(n);
}
stringVals = new Array();
for each (var s:String in strings) {
stringVals.push(s);
}
}
}
}
We can do this:
registerClassAlias("com.things.MySerializableObject", MySerializableObject);
And then do this:
var sharedObject:SharedObject = SharedObject.getLocal(SAVE_NAME); //SAVE_NAME is a string constant
var mso:MySerializableObject = getInitializedMSO();
sharedObject.data.mso = mso;
sharedObject.flush();
var newMSO:MySerializableObject = sharedObject.data.mso as MySerializableObject;
trace(newMSO); //outputs "[Object MySerializableObject]"
However, if we restart the application and do this:
var sharedObject:SharedObject = SharedObject.getLocal(SAVE_NAME);
registerClassAlias("com.things.MySerializableObject", MySerializableObject);
var previouslySavedMSO:MySerializableObject = sharedObject.data.mso as MySerializableObject;
trace(previouslySavedMSO); //outputs "null"
Flash apparently fails to read the saved object as a MySerializableObject after we close and re-open the application. We can see, by inspecting the SO in a debugger, that the data is still there, but Flash can't typecast it back into its original data type anymore. Is this the expected behavior? If not, what is the problem and how can we fix it?

You have to register your class aliases before you read from your LSO (or byte stream, etc..) otherwise you will end up with an anonymous object. Since you are than casting via an as the result will be null.
Returns null on second run:
var sharedObject:SharedObject = SharedObject.getLocal(SAVE_NAME);
registerClassAlias("com.things.MySerializableObject", MySerializableObject);
if (sharedObject.size > 0) {
var newMSO:MySerializableObject = sharedObject.data.mso as MySerializableObject;
trace(newMSO);
} else {
sharedObject.data.mso = getInitializedMSO();
sharedObject.flush();
trace(sharedObject.data.mso);
}
Returns MySerializableObject on the second run:
registerClassAlias("com.things.MySerializableObject", MySerializableObject);
var sharedObject:SharedObject = SharedObject.getLocal(SAVE_NAME);
if (sharedObject.size > 0) {
var newMSO:MySerializableObject = sharedObject.data.mso as MySerializableObject;
trace(newMSO);
} else {
sharedObject.data.mso = getInitializedMSO();
sharedObject.flush();
trace(sharedObject.data.mso);
}
Cut/Paste Example:
package {
import flash.display.Sprite;
import flash.net.SharedObject;
import flash.net.registerClassAlias;
public class Main extends Sprite {
private const SAVE_NAME:String = "foobar";
public function Main() {
registerClassAlias("com.things.MySerializableObject", MySerializableObject);
var sharedObject:SharedObject = SharedObject.getLocal(SAVE_NAME);
if (sharedObject.size > 0) {
var newMSO:MySerializableObject = sharedObject.data.mso as MySerializableObject;
trace(newMSO);
} else {
sharedObject.data.mso = getInitializedMSO();
sharedObject.flush();
trace(sharedObject.data.mso);
}
}
public function getInitializedMSO():MySerializableObject {
return new MySerializableObject();
}
}
}
class MySerializableObject {
public var intVals:Array;
public var numVals:Array;
public var stringVals:Array
public function MySerializableObject() {
}
public function init(ints:Vector.<int>, nums:Vector.<Number>, strings:Vector.<String>) {
intVals = new Array();
for each (var i:int in ints) {
intVals.push(i);
}
numVals = new Array();
for each (var n:Number in nums) {
numVals.push(n);
}
stringVals = new Array();
for each (var s:String in strings) {
stringVals.push(s);
}
}
}

Related

Why does my proprietary file format fail to unarchive?

I've got a proprietary file format that works as an archive. It takes a folder full of files and packs them into a single file with no compression - the first X bytes of the files are dedicated to the "Table of contents" - the file paths, their size in bytes and their location (byte index) in the archive file. the remaining bytes are for the actual data of each file.
This format works and has been working for several years except in a few cases I am trying to debug. There are some cases where the files fail to unarchive properly In my experience this is typically on laptops which I presume have 5400 rpm hard drives. But sometimes it fail on SSD hard drives (like a Surface Book) Also the failure is not consistent. If I were to unarchive the same file 10 times on a "problem" machine it might only fail 1 or 2 times or not at all in some cases.
In the language that I am unarchiving this format (as3), the file stream reader has property 'readAhead' - which as the docs indicate is 'The minimum amount of data to read from disk when reading files asynchronously' . Could this value be affecting my unarchiving? My initial value for this was '8192' which I have now changed to 8192/4 to test on some new machines. Anyone have any thoughts on this? Is the readAhead value irrelevant?
I realize this is vague. I'm not looking for a specific solution just want to get some feedback from people who have more experience on how I could better diagnose and resolve this issue.
Here is the class in question. I've tried to remove anything unrelated to what I'm asking about:
/**
* ...
* #author Phil
*/
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.filesystem.File;
import flash.filesystem.FileMode;
import flash.filesystem.FileStream;
import flash.utils.ByteArray;
import flash.utils.Endian;
public class Archive extends EventDispatcher
{
public static const UNARCHIVING_COMPLETE:String = "unarchivingComplete";
public static const UNARCHIVING_PROGRESS:String = "unarchivingProgress";
public static const UNARCHIVE_CANCEL:String = "unarchiveCancel";
public static const ENDIAN:String = Endian.LITTLE_ENDIAN;
private var _inputFile:File;
private var _outputFile:File;
private var _inputStream:FileStream;
private var _outputStream:FileStream;
private var _files:Vector.<ArchiveItem>;
private var _readAheadValue:uint = 8192 / 4;
private var _maxTableSize:uint = 40960 * 30;
private var _tableData:ByteArray;
private var _curArchiveItem:ArchiveItem;
private var _currentArchiveItemBytesWritten:uint;
private var _pointerPosition:uint = 0;
private var _tableSize:uint = 0;
private var _totalSize:uint = 0;
private var _totalFiles:uint = 0;
public function Archive()
{
}
public function readArchive(archive:File, dest:File):void
{
_inputFile = archive;
_outputFile = dest;
createReadStream();
createTableData();
_inputStream.openAsync( _inputFile, FileMode.READ );
}
public function destroy():void
{
killStreams();
_inputFile = null;
_outputFile = null;
}
public function cancel():void
{
killStreams();
}
private function killStreams():void
{
killInStream();
killOutStream();
}
private function killInStream():void
{
if (!_inputStream) return;
_inputStream.removeEventListener(Event.COMPLETE, onFileReadComplete);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onFileReadProgress);
_inputStream.removeEventListener(Event.COMPLETE, onArhiveReadComplete);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onTableReadProgress);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onArchiveReadProgress);
_inputStream.removeEventListener(Event.CLOSE, onInputClosed);
_inputStream.removeEventListener(IOErrorEvent.IO_ERROR, onErrorReadingArchive);
_inputStream.close();
_inputStream = null;
}
private function killOutStream():void
{
if (!_outputStream) return;
_outputStream.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
_outputStream.removeEventListener(Event.CLOSE, onOutPutClosed);
_outputStream.close();
_outputStream = null;
}
private function createTableData():void
{
_files = new Vector.<ArchiveItem>();
_tableData = new ByteArray();
_tableData.endian = ENDIAN;
}
private function createReadStream():void
{
_inputStream = new FileStream();
_inputStream.endian = ENDIAN;
_inputStream.readAhead = _readAheadValue;
_inputStream.addEventListener(Event.CLOSE, onInputClosed);
_inputStream.addEventListener(Event.COMPLETE, onArhiveReadComplete);
_inputStream.addEventListener(ProgressEvent.PROGRESS, onTableReadProgress);
_inputStream.addEventListener(IOErrorEvent.IO_ERROR, onErrorReadingArchive);
}
private function onErrorReadingArchive(e:IOErrorEvent):void
{
dispatchEvent( new Event(Event.CANCEL) );
}
private function onArhiveReadComplete(e:Event):void
{
if (_tableData.length < _maxTableSize)
{
onTableReadProgress( null, true);
}
}
private function onTableReadProgress(e:ProgressEvent, force:Boolean = false):void
{
if (_tableData.length < _maxTableSize && force == false)
{
_inputStream.readBytes( _tableData,_tableData.length );
}else {
_inputStream.removeEventListener(Event.COMPLETE, onArhiveReadComplete);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onTableReadProgress);
populateTable( _tableData );
}
return;
if (_inputStream.bytesAvailable < _maxTableSize && force == false)
{
return;
}else {
_inputStream.removeEventListener(Event.COMPLETE, onArhiveReadComplete);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onTableReadProgress);
var ba:ByteArray = new ByteArray();
ba.endian = ENDIAN;
_inputStream.readBytes(ba);
populateTable( ba );
}
}
private function populateTable(tableData:ByteArray):void
{
var a:ArchiveItem;
var offset:uint = 0;
var size:uint = 0;
var fileName:String;
if (tableData is ByteArray)
{
tableData.position = 0;
}
for (;;)
{
offset = tableData.readUnsignedInt();
size = tableData.readUnsignedInt();
fileName = tableData.readUTF();
if (fileName == "endTable")
{
_tableSize = tableData.position;
_totalFiles = _files.length;
_totalSize = _inputFile.size;
completeTableRead();
break;
}
a = new ArchiveItem();
a.filename = fileName;
a.offset = offset;
a.size = size;
_files.push(a);
}
}
private function completeTableRead():void
{
createFileOutputStream();
_inputStream.readAhead = _readAheadValue;
_inputStream.removeEventListener(Event.COMPLETE, onArhiveReadComplete);
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onTableReadProgress);
_inputStream.addEventListener(ProgressEvent.PROGRESS, onArchiveReadProgress);
_inputStream.addEventListener(Event.COMPLETE, onArchiveReadProgress);
writeNextArchiveItemToFile();
}
private function onInputClosed(e:Event):void
{
completeUnarchiving();
}
private function completeUnarchiving():void
{
killStreams();
dispatchEvent( new Event(UNARCHIVING_COMPLETE) );
}
private function createFileOutputStream():void
{
_outputStream = new FileStream();
_outputStream.endian = ENDIAN;
_outputStream.addEventListener(Event.CLOSE, onOutPutClosed);
_outputStream.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
}
private function onOutPutClosed(e:Event):void
{
completeUnarchiving();
}
private function onIOError(e:IOErrorEvent):void
{
dispatchEvent( new Event(Event.CANCEL) );
}
private function writeNextArchiveItemToFile():void
{
if (_files.length == 0)
{
endWriting();
return;
}
_curArchiveItem = _files.shift();
_currentArchiveItemBytesWritten = 0;
var dest:File = new File();
dest.nativePath = _outputFile.nativePath + File.separator + _curArchiveItem.filename;
_outputStream.open(dest, FileMode.WRITE);
movePointer();
}
private function endWriting():void
{
_inputStream.removeEventListener(ProgressEvent.PROGRESS, onArchiveReadProgress);
_inputStream.removeEventListener(Event.COMPLETE, onArchiveReadProgress);
_outputStream.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
_outputStream.close();
_inputStream.close();
}
private function onOutputStreamCloseOnCompelte(e:Event):void
{
dispatchEvent( new Event(UNARCHIVING_COMPLETE) );
}
private function movePointer():void
{
_inputStream.position = _tableSize + _curArchiveItem.offset;
_pointerPosition = _inputStream.position;
if (_curArchiveItem.size == 0)
{
writeNextArchiveItemToFile();
}
}
private function onArchiveReadProgress(e:Event):void
{
if (_currentArchiveItemBytesWritten >= _curArchiveItem.size)
{
writeNextArchiveItemToFile();
return;
}
writeBytesToDisk();
}
private function writeBytesToDisk():void
{
var bytes:ByteArray = new ByteArray();
var bytesRemaining:uint = _curArchiveItem.size - _currentArchiveItemBytesWritten;
var bytesToWrite:uint = _inputStream.bytesAvailable;
if (bytesToWrite > bytesRemaining)
{
bytesToWrite = bytesRemaining;
}
_inputStream.readBytes(bytes, 0, bytesToWrite);
try {
_outputStream.writeBytes(bytes, 0, bytes.length); //This throws an error on large files.
}catch (e:Error)
{
dispatchEvent( new Event(Event.CANCEL) );
return;
}
_currentArchiveItemBytesWritten += bytes.length;
_pointerPosition = _inputStream.position;
dispatchEvent( new Event(UNARCHIVING_PROGRESS) );
if (_currentArchiveItemBytesWritten >= _curArchiveItem.size)
{
writeNextArchiveItemToFile();
}
}
}
}
class ArchiveItem
{
public var offset:uint;
public var size:uint;
public var filename:String;
public function ArchiveItem()
{
}
}
This was too long for comments..
Just my personal opinion but I think you've over-cooked a simple task. Your usage of .readAhead is confusing. For un-archive part why not have..
(1) On startup your app creates & fills an Object with entries parsed from table of contents (myself I'd just make & update 3 arrays noting file Names, Sizes and also the Indices within the archive file).
(2) For extracting say the 5th file in archive you just check dest_Name = fileNames[4]; for expected output name String, then also note expected dest_Size = size[4]; integer (length to extract).
(3) Now just read the archive file (on disk) and get that 5th file saved.
Archive_Stream.openAsync( URL_Archive_File, FileMode.READ );
Archive_Stream.position = dest_indexInArchive[4]; //starting index
The above would read bytes into a temp_BA which can then be saved (when READ is complete, the handler function does a WRITE to disk of that single extracted file). Now you can use temp_BA.clear(); to reset and clear it for a different file (or just reclaim memory used).

How do I access a method of ClassA from classB?

I didn't really know what exactly to ask in the question. So I am going to explain everything here:
I am working on a Desktop AIR Database Application I have a Class named "Database Screen" which is linked to a movie clip:
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.InteractiveObject;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.filesystem.FileMode;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.text.TextField;
public class DatabaseScreen extends MovieClip {
private var allButtons:Array;
private var codeSelected:Boolean;
private var nameSelected:Boolean;
private var xmlDatabase:XML;
private var dbFile:File;
public var xmlList:XMLList;
private var totalProducts:uint;
private var totalItems:uint = 0;
private var productExists:Boolean;
private var productId:Number;
private var XMLReader:xmlReader;
public function DatabaseScreen() {
allButtons = [searchPanel.search_btn, addNewPanel.addNew_btn, dbStatsPanel.xls_btn, searchPanel.code_radio, searchPanel.name_radio];
init();
}
private function init():void
{
XMLReader = new xmlReader();
//adding event listeners..
for(var i:int = 0; i<allButtons.length; i++)
{
allButtons[i].addEventListener(MouseEvent.MOUSE_OVER, onOver, false, 0, true);
allButtons[i].addEventListener(MouseEvent.MOUSE_OUT, onOut, false, 0, true);
allButtons[i].addEventListener(MouseEvent.MOUSE_DOWN, onDown, false, 0, true);
allButtons[i].addEventListener(MouseEvent.MOUSE_UP, onUp, false, 0, true);
allButtons[i].addEventListener(MouseEvent.CLICK, onClick, false, 0, true);
allButtons[i].buttonMode = true;
}
//creating a new file for the database
dbFile = File.documentsDirectory.resolvePath("BlackCat/Database.xml");
xmlDatabase = new XML();
getXML();
saveXML();
getTotalItems();
dbStatsPanel.items.text = String(totalItems);
}
private function getXML():void
{
if(dbFile.exists)
{
var stream:FileStream = new FileStream();
stream.open(dbFile, FileMode.READ);
xmlDatabase = new XML(stream.readUTFBytes(stream.bytesAvailable));
stream.close();
xmlList = xmlDatabase.Product;
dbStatsPanel.products.text = xmlList.length();
XMLReader.xmlData = xmlList;
XMLReader.updateXMLList(xmlList);
}
else
{
xmlDatabase = <Products></Products>
}
}
public function getXMlList():XMLList
{
return xmlList;
}
private function getTotalItems():void
{
for(var i:int = 0; i < xmlList.length(); i++)
{
totalItems += uint(xmlList[i].#Qty);
}
}
private function saveXML():void
{
var stream:FileStream = new FileStream();
stream.open(dbFile, FileMode.WRITE);
stream.writeUTFBytes(xmlDatabase.toXMLString());
}
private function onDown(evt:MouseEvent):void
{
evt.target.scaleX = evt.target.scaleY = .8;
}
private function onUp(evt:MouseEvent):void
{
evt.target.scaleX = evt.target.scaleY = 1;
}
private function onOver(evt:MouseEvent):void
{
evt.target.alpha = .5;
}
private function onOut(evt:MouseEvent):void
{
evt.target.alpha = 1;
evt.target.scaleX = evt.target.scaleY = 1;
}
private function onClick(evt:MouseEvent):void
{
switch(evt.target.name)
{
case "code_radio":
codeSelected = true;
nameSelected = false;
searchPanel.code_radio.gotoAndStop(1);
searchPanel.name_radio.gotoAndStop(2);
break;
case "name_radio":
nameSelected = true;
codeSelected = false;
searchPanel.code_radio.gotoAndStop(2);
searchPanel.name_radio.gotoAndStop(1);
break;
case "addNew_btn":
//Checking if the product already exists..
for(var i:int = 0; i < xmlList.length(); i++)
{
if(xmlList[i].#code == addNewPanel.add_code_txt.text)
{
productExists = true;
productId = i;
}
}
if(productExists)
{
var PQty:uint = uint(xmlList[productId].#Qty);
var PQtoAdd:uint = uint(addNewPanel.add_qty_txt.text);
PQty += PQtoAdd;
xmlList[productId].#Qty = String(PQty);
productExists = false;
}
else
{
xmlDatabase.appendChild(<Product code={addNewPanel.add_code_txt.text}
name={addNewPanel.add_name_txt.text} Price={addNewPanel.add_price_txt.text}
Qty={addNewPanel.add_qty_txt.text}></Product>);
}
totalItems += uint(addNewPanel.add_qty_txt.text);
xmlList = xmlDatabase.Product;
dbStatsPanel.products.text = xmlList.length();
dbStatsPanel.items.text = String(totalItems);
XMLReader.updateXMLList(xmlList);
saveXML();
trace(xmlDatabase);
break;
}
}
public function setVisiblity(visibility:Boolean):void
{
switch(visibility)
{
case true:
this.visible = true;
break;
case false:
this.visible = false;
break;
}
}
public function getXMLList():XMLList
{
return xmlList;
}
}
}
And I have another class named "NewOrder", in this class I am trying to access the xmlList from the "DatabaseScreen" class but I am unable to do so.
package {
import flash.display.MovieClip;
import flash.events.MouseEvent;
import com.greensock.TweenMax;
import flash.filesystem.File;
import flash.filesystem.FileStream;
import flash.filesystem.FileMode;
public class NewOrder extends MovieClip {
private var allButtons:Array;
private var shoppingCart:Array;
private var scroller:FlickScroll;
private var db:DatabaseScreen;
private var XMLReader:xmlReader;
public function NewOrder() {
this.visible = false;
init(db);
}
private function init(dbase:DatabaseScreen):void
{
XMLReader = new xmlReader();
trace(XMLReader.xmlData);
scroller = new FlickScroll(masker, container, 84.05, -500);
addChild(scroller);
allButtons = [scan_btn, print_invoice];
shoppingCart = [];
for(var i:int = 0; i < allButtons.length; i++)
{
allButtons[i].addEventListener(MouseEvent.MOUSE_OVER, onOver, false, 0, true);
allButtons[i].addEventListener(MouseEvent.MOUSE_OUT, onOut, false, 0, true);
allButtons[i].addEventListener(MouseEvent.MOUSE_DOWN, onDown, false, 0, true);
allButtons[i].addEventListener(MouseEvent.MOUSE_UP, onUp, false, 0, true);
allButtons[i].mouseChildren = false;
allButtons[i].buttonMode = true;
}
}
private function onOver(evt:MouseEvent):void
{
evt.target.alpha = .5;
}
private function onOut(evt:MouseEvent):void
{
evt.target.alpha = 1;
evt.target.scaleX = evt.target.scaleY = 1;
}
private function onDown(evt:MouseEvent):void
{
evt.target.scaleX = evt.target.scaleY = .8;
}
private function onUp(evt:MouseEvent):void
{
evt.target.scaleX = evt.target.scaleY = 1;
if(evt.target.name == "scan_btn")
{
var cartElement:CartElement = new CartElement();
container.addChild(cartElement);
cartElement.x = 0;
cartElement.alpha = 0;
TweenMax.to(cartElement, .4, {alpha:1});
shoppingCart.push(cartElement);
cartElement.id_txt.text = String(shoppingCart.length) + " - ";
if(shoppingCart.length < 2)
{
cartElement.y = container.height - 30;
}
else
{
cartElement.y = container.height + 5;
}
}
}
}
}
And there is a Main class in which I handle all the screens , e.g DatabaseScreen, NewOrder.. Which means I have added these to the display list in the Main class. To access the xmlList from the DatabaseScreen , I tried creating a new instance in the NewOrder class, but it creates to DatabaseScreen(s). I also tried creating another class named "xmlReader":
package {
public class xmlReader {
public var xmlData:XMLList;
public function xmlReader() {
}
public function updateXMLList(updatedList:XMLList):void
{
xmlData = updatedList;
}
}
}
In the databaseScreen class, as soon as I populate the xmlList , I set the xmlData of the xmlReader class equal to the xmlList from the databaseScreen class. And when I trace the XMLReader.xmlData in the databaseScreen , it works fine . But when I do the same thing in the NewOrder class, I get "null" in the output window.
How do I solve this problem. Any help is greatly appreciated.
You will need to pass a reference into the Order class to have access to the DatabaseScreen class. Something like this.
var ds = new DatabaseScreen();
var or = new NewOrder(ds)
Inside the NewOrder you can save the ref.
public class NewOrder {
private var screens:DatabaseScreens;
public function NewOrder(ds:DatabaseScreens) {
screens = ds;
// Now you can call screens.xmlList
}
}

Error 1006: Not a function

I am getting the error in the title when trying to access a method in another class. I have the main class, ZombieBots, which is linked to a movie clip of the same name. I then have 3 more movie clips which all get added to the ZombieBots clip during runtime, and each of these have their own classes.
When I attempt to access a method within the ZombieBots class from one of the other 3 classes, I get error 1006.
The function I am attempting to access in the ZombieBots class, that cannot be accessed:
package {
import flash.events.*;
import flash.display.MovieClip;
import flash.geom.Rectangle;
public class ZombieBots extends MovieClip{
private var pLives:int;
private var pScore:int;
private var pSkill:int;
private var pItems:int;
private var characterMC:Character;
private var cGameObjs:Array;
public function ZombieBots() {
/*cGameObjs = new Array();
addCharacter();
addItems();
addBots();
pLives = 5 - pSkill;
pScore = 0;
pItems = pSkill + 5;*/
resetGame();
}
private function addCharacter():void{
trace("Adding the character");
if (!characterMC){
var myBorder:Rectangle = new Rectangle(35,35,600,480);
var myXY:Array = [38, 400];
var myChar:int = Math.ceil(Math.random()*3);
var myKeys:Array = [37,39,38,40];
var myDistance:int = myChar * 3;
characterMC = new Character(myBorder, myXY, myKeys, myChar, myDistance);
addChild(characterMC);
}
else{
characterMC.x = 38;
characterMC.y = 510;
characterMC.gotoAndStop(pSkill);
}
}
private function addItems():void{
trace("yeah boi");
var mySkill:int = Math.ceil(Math.random() *3);
var myMaxItems:int = mySkill + 5;
trace(mySkill);
trace(myMaxItems);
trace(this);
for (var i:int = 0; i < myMaxItems; i++){
var thisItem:Item = new Item(this, characterMC, mySkill);
thisItem.name = "item" + i;
cGameObjs.push(thisItem);
addChild(thisItem);
}
pSkill = mySkill;
updateScores();
}
private function addBots():void{
trace("adding the bots bra");
var myBorder:Rectangle = new Rectangle(100,100,400,350);
var mySkill:int = Math.ceil(Math.random()*3);
var myMaxBots:int = mySkill +10;
for (var i:int = 0; i < myMaxBots; i++){
var thisBot:Bot = new Bot(myBorder, characterMC, mySkill);
thisBot.name = "bot" + i;
cGameObjs.push(thisBot);
addChild(thisBot);
}
}
private function updateScores():void{
scoreDisplay.text = String(pScore);
itemsDisplay.text = String(pItems);
livesDisplay.text = String(pLives);
msgDisplay.text = "Orc Invasion";
}
public function updateLives(myBot:MovieClip):void{
trace("update lives");
pLives--;
pScore -= myBot.getPts();
var myIndex:int = cGameObjs.indexOf(myBot);
cGameObjs.splice(myIndex, 1);
if (pLives > 0){
updateScores();
}
else{
gameOver(false);
}
}
public function updateItems(myItem:MovieClip):void{
trace("update items");
pItems--;
pScore += myItem.getPts();
var myIndex:int = cGameObjs.indexOf(myItem);
cGameObjs.splice(myIndex, 1);
if (pItems > 0){
updateScores();
}
else{
gameOver(true);
}
}
private function gameOver(bool:Boolean):void{
trace("Game over dawg");
updateScores();
if(bool){
msgDisplay.text = "Good job buddy";
}
else{
msgDisplay.text = "You suck dawg";
}
removeLeftovers();
}
private function resetGame():void{
playAgainBtn.visible = false;
playAgainBtn.removeEventListener(MouseEvent.CLICK,playAgain);
cGameObjs = new Array();
addCharacter();
addItems();
addBots();
pLives = 5 - pSkill;
pScore = 0;
pItems = pSkill + 5;
updateScores();
}
private function playAgain(evt:MouseEvent):void{
resetGame();
}
private function removeLeftovers():void{
trace("Removing leftover items and bots");
for each(var myObj in cGameObjs){
myObj.hasHitMe();
myObj = null;
}
playAgainBtn.visible = true;
playAgainBtn.addEventListener(MouseEvent.CLICK, playAgain);
}
}
}
and this is the class where I am attempting to access this function within one of the other 3 classes:
package {
import flash.display.MovieClip;
import flash.events.*;
import ZombieBots;
public class Item extends MovieClip{
private var cNumItem:int;
private var cNumPts:int;
private var characterMC:MovieClip;
private var ZombieBot:ZombieBots;
public function Item(myZB:ZombieBots, myChar:MovieClip, mySkill:int=1) {
ZombieBot = myZB;
cNumItem = Math.ceil(Math.random() * (mySkill * 3 + 1));
characterMC = myChar;
this.addEventListener(Event.ADDED_TO_STAGE,initItem);
addEventListener(Event.ENTER_FRAME, checkCollision);
}
private function initItem(evt:Event):void{
this.gotoAndStop(cNumItem);
cNumPts = cNumItem * 25;
setPosition();
this.removeEventListener(Event.ADDED_TO_STAGE,initItem);
}
private function setPosition():void{
this.x = (Math.ceil(Math.random() * 10)*50);
this.y = (Math.ceil(Math.random()*10)*35);
}
private function checkCollision(evt:Event){
if (characterMC.hitTestObject(this)){
ZombieBot.updateItems(this);
hasHitMe();
}
}
public function hasHitMe():void{
trace("remove");
removeEventListener(Event.ENTER_FRAME, checkCollision);
this.parent.removeChild(this);
}
public function getPts():int{
return cNumPts;
}
}
}
can anyone help?
updateItems is not a MovieClip method. It's a method of your ZombieBots class.
Casting your ZombieBots instance (which I am assuming is root) as a MovieClip, will only allow you to use it's class methods or methods it has inherited.
Try this :
var zombieBotsInstance:ZombieBots = root as ZombieBots;
zombieBotsInstance.updateItems(this);

Error #1010 in level setup class

I'm having problem with a piece of code of mine, and it seems to be in this following class:
package
{
import flash.display.MovieClip;
//levels are 11x9
public class Level extends MovieClip
{
var level1:Array=new Array(
1,1,1,1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,1,
1,0,0,1,0,0,0,0,0,0,1,
1,0,0,1,1,1,0,0,0,1,1,
1,0,0,0,0,0,0,1,1,0,1,
1,1,1,1,1,1,1,1,1,1,1);
var grid:Array = new Array(11);
public function Level()
{
for (var i = 0; i < 9; i++)
{
grid.push(new Array(9));
}
for (var xr=0; xr<11; xr++)
{
for (var yr=0; yr<9; yr++)
{
var type = level1[yr * 11 + xr];
var obj:Wall = new Wall(xr*50,yr*50,type);
grid[xr][yr] = obj;
if (type!=0)
{
addChild(obj);
}
}
}
}
}
}
Now I've done some work, and the error is Error Code #1010: Term undefined and has no properties.
Even more specific, I did some debugging and determined the exact line to be
grid[xr][yr]=obj;
Any help is appreciated.
enter code here
enter code here
change
grid.push(new Array(9));
to
grid[i]=new Array(9);
[EDIT]
Actually try this
var level1:Array=new Array(
1,1,1,1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,1,
1,0,0,1,0,0,0,0,0,0,1,
1,0,0,1,1,1,0,0,0,1,1,
1,0,0,0,0,0,0,1,1,0,1,
1,1,1,1,1,1,1,1,1,1,1);
var grid:Array = new Array(11);
public function Level()
{
for(var row=0;col<11;row++){
grid[col] = new Array(9);
for(var col=0;col<9;col++){
var type = level1[row* 11 + col];
var obj:Wall = new Wall(col*50,row*50,type);
grid[col][row] = obj;
if (type!=0){
addChild(obj);
}
}
}
}

Stage properties in custom class, not Document Class

I need to use stage.width/height in my CustomClass so I found some topics about it.
if (stage)
{
init(ar,firma,kontakt,oferta,naglowek,tekst,dane);
}
else
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
But in my case it won't work because it isn't document class, I think. Any other solution?
UPDATE:
CLASS CODE
package
{
import fl.transitions.Tween;
import fl.motion.easing.*;
import flash.filters.*;
import flash.events.MouseEvent;
import flash.display.Stage;
import flash.display.MovieClip;
import flash.ui.Mouse;
import flash.display.*;
public class Wyjazd extends MovieClip
{
public function Wyjazd(ar:Array=null,firma:Object=null,kontakt:Object=null,oferta:Object=null,naglowek:Object=null,tekst:Object=null,dane:Object=null)
{
if (stage)
{
//The stage reference is present, so we're already added to the stage
init(ar,firma,kontakt,oferta,naglowek,tekst,dane);
}
else
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
public function init(ar:Array,firma:Object=null,kontakt=null,oferta:Object=null,naglowek:Object=null,tekst:Object=null,dane:Object=null):void
{
//Zmienne "globalne" dla funkcji
var time:Number;
var wciecie:Number;
var wciecie2:Number;
var offset:Number = 15.65;
var offset2:Number = 20;
var posX:Array = new Array(12);
var posY:Array = new Array(12);
var spr:Array = new Array(12);
var targetLabel:String;
var wybranyOb:Object = ar[0];
var names:Array = new Array('Szkolenie wstępne BHP','Szkolenie okresowe BHP','Szkolenie P.Poż','Kompleksowa obsługa P.Poż','Pomiar środowiska pracy','Szkolenie z udzielania pierwszej pomocy','Ocena ryzyka zawodowego','Przeprowadzanie postępowań po wypadkowych','Przeprowadzanie audytów wewnętrznych ISO','Hałas w środowisku komunalnym','Medycyna pracy','Szkolenia dla kierowców');
//Pobieranie pozycji
for (var i:Number = 0; i<ar.length; i++)
{
posX[i] = ar[i].x;
posY[i] = ar[i].y;
}
//Filtry
function increaseBlur(e:MouseEvent,docPos:Number):void
{
var myBlur:BlurFilter =new BlurFilter();
myBlur.quality = 3;
myBlur.blurX = 10;
myBlur.blurY = 0;
}
//Funkcje
function startPos():void
{
time = 0.2;
for (var i:Number = 0; i<ar.length; i++)
{
//if (wybranyOb.name == ar[i].name)
//{
//var wybranyPos:Tween = new Tween(ar[i],"x",Linear.easeOut,ar[i].x,posX[i],0.01,true);
//wybranyPos = new Tween(ar[i],"y",Linear.easeOut,-30,posY[i],time,true);
//}
//else
//{
var position:Tween = new Tween(ar[i],"x",Linear.easeOut,ar[i].x,posX[i],time,true);
position = new Tween(ar[i],"y",Linear.easeOut,ar[i].y,posY[i],time,true);
//}
//time = 0.2;
}
position = new Tween(naglowek,"x",Linear.easeOut,naglowek.x,2000,time,true);
position = new Tween(tekst,"x",Linear.easeOut,tekst.x,2000,time,true);
position = new Tween(dane,"x",Linear.easeOut,dane.x,2000,0.25,true);
}
//Nasłuchy
oferta.addEventListener(MouseEvent.CLICK, wyskokOferta);
oferta.addEventListener(MouseEvent.MOUSE_OVER,glowOferta);
oferta.addEventListener(MouseEvent.MOUSE_OUT,unglowOferta);
kontakt.addEventListener(MouseEvent.CLICK,wyskokKontakt);
kontakt.addEventListener(MouseEvent.MOUSE_OVER,glowKontakt);
kontakt.addEventListener(MouseEvent.MOUSE_OUT,unglowKontakt);
firma.addEventListener(MouseEvent.CLICK,wyskokFirma);
firma.addEventListener(MouseEvent.MOUSE_OVER,glowFirma);
firma.addEventListener(MouseEvent.MOUSE_OUT,unglowFirma);
function glowFirma(e:MouseEvent):void
{
var myGlow:GlowFilter=new GlowFilter();
myGlow.color = 0xe6da13;
myGlow.inner = true;
firma.filters = [myGlow];
}
function unglowFirma(e:MouseEvent):void
{
firma.filters = [];
}
function glowKontakt(e:MouseEvent):void
{
var myGlow:GlowFilter=new GlowFilter();
myGlow.color = 0xe6da13;
myGlow.inner = true;
kontakt.filters = [myGlow];
}
function unglowKontakt(e:MouseEvent):void
{
kontakt.filters = [];
}
function glowOferta(e:MouseEvent):void
{
var myGlow:GlowFilter=new GlowFilter();
myGlow.color = 0xe6da13;
myGlow.inner = true;
oferta.filters = [myGlow];
}
function unglowOferta(e:MouseEvent):void
{
oferta.filters = [];
}
function wyskokKontakt(e:MouseEvent):void
{
startPos();
var tweenKontakt = new Tween(dane,"x",Linear.easeOut,2000,350,0.25,true);
}
function wyskokFirma(e:MouseEvent):void
{
startPos();
trace("Firma");
}
function wyskokOferta(e:MouseEvent):void
{
time = 0.2;
wciecie = 15.65;
wciecie2 = 20.05;
for (var i:Number = 0; i < ar.length; i++)
{
var tween:Tween = new Tween(ar[i],"x",Sine.easeOut,ar[i].x,oferta.x + wciecie,time,true);
tween = new Tween(ar[i],"y",Sine.easeOut,ar[i].y,oferta.y + wciecie2,time,true);
ar[i].addEventListener(MouseEvent.CLICK,onClick);
spr[i] = i;
time += 0.02;
wciecie += offset;
wciecie2 += offset2;
}
}
function onClick(e:MouseEvent)
{
startPos();
time = 0.2;
var k:Number = 0;
targetLabel = e.currentTarget.name;
for (var i:Number = 0; i < ar.length; i++)
{
if (targetLabel==ar[i].name)
{
//wybranyOb = ar[i];
var tween:Tween = new Tween(ar[i],"x",Linear.easeOut,ar[i].x,posX[i],time,true);
tween = new Tween(ar[i],"y",Linear.easeOut,ar[i].y,posY[i],time,true);
tween = new Tween(naglowek,"x",Linear.easeOut,2000,60,0.2,true);
tween = new Tween(tekst,"x",Linear.easeOut,2000,500,0.25,true);
naglowek.text = names[i];
}
else
{
var tween1:Tween = new Tween(ar[i],"x",Linear.easeOut,ar[i].x,posX[i],time,true);
tween1 = new Tween(ar[i],"y",Linear.easeOut,ar[i].y,posY[i],time,true);
}
//time += 0.02;
}
}
}
}
}
Hope it will helps.
I expect you are getting an error from the init function which expects lots of parameters but might just get one Event. It helps when you post here if you post the compile or runtime errors you are getting along with source code.
I think this should work for you, I've made a rough version which you can learn from and apply to your own class
public class CustomClass extends MovieClip
{
protected var _company:String;
protected var _data:Object;
public function CustomClass( company:String='', data:Object=null )
{
_company = company;
_data = data;
if (stage)
{
init();
}
else
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event=null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
//do something with _data
//do something with _company
}
}
Hopefully you can see the concept here, place your constructor variables in class variables when you create the class, then if on the stage call init() which uses those class variables or add an event listener which will call init(passing in an event this time) and then use the same class variables to do what you want.
Note how I remove the event listener when it isn't needed any more as well.