I want to define my variables in my game document class, then use some of those variables in my Movement class. However, when I use these variables in my movement class I get tons of Compiling Errors saying that they're all undefined.
Thus my question is, why are my public variables not passed over to my other class? I have imported the class by doing import game; so this leaves me confussed. I'm probably just doing it wrong, but help is much appreciated.
Timeline
addChild((new Movement));
Game Document Class
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class game extends MovieClip
{
public var area1:Boolean = true;
public var area2:Boolean = false;
public var area3:Boolean = false;
public var player1:Boolean = true;
public var playerPosKeeper_mc:MovieClip = new mc_PlayerPosKeeper();
public var up_dpad:MovieClip = new dpad_Up();
public var down_dpad:MovieClip = new dpad_Down();
public var left_dpad:MovieClip = new dpad_Left();
public var right_dpad:MovieClip = new dpad_Right();
public var menu_dpad:MovieClip = new dpad_Menu();
public var run_dpad:MovieClip = new dpad_Menu();
public var barrierRoof1_game:MovieClip = new game_BarrierRoof();
public var barrierRoof2_game:MovieClip = new game_BarrierRoof();
public var barrierSide1_game:MovieClip = new game_BarrierSide();
public var barrierSide2_game:MovieClip = new game_BarrierSide();
public function game()
{
trace("SUCCESS | Constructed Game Class");
}
}
}
Movement Class
package
{
import game;
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.TouchEvent;
import flash.net.dns.AAAARecord;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
public class Movement extends MovieClip
{
var inMotion:Boolean = false;
public function Movement()
{
trace("SUCCESS | Constructed Movement Class");
addChild(playerPosKeeper_mc);
playerPosKeeper_mc.x = 384;
playerPosKeeper_mc.y = 46;
addChild(up_dpad);
up_dpad.x = 55;
up_dpad.y = 336;
addChild(down_dpad);
down_dpad.x = 57;
down_dpad.y = 432;
addChild(left_dpad);
left_dpad.x = 19;
left_dpad.y = 372;
addChild(right_dpad);
right_dpad.x = 118;
right_dpad.y = 372;
addChild(menu_dpad);
menu_dpad.x = 61;
menu_dpad.y = 377;
addChild(run_dpad);
run_dpad.x = 684;
run_dpad.y = 369;
addChild(barrierRoof1_game);
barrierRoof1_game.x = 0;
barrierRoof1_game.y = 0;
addChild(barrierRoof2_game);
barrierRoof2_game.x = 0;
barrierRoof2_game.y = 470;
addChild(barrierSide1_game);
barrierSide1_game.x = 0;
barrierSide1_game.y = 0;
addChild(barrierSide2_game);
barrierSide2_game.x = 790;
barrierSide2_game.y = 0;
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
up_dpad.addEventListener(TouchEvent.TOUCH_BEGIN, moveUpTouchBEGIN);
up_dpad.addEventListener(TouchEvent.TOUCH_END, moveUpTouchEND);
}
public function moveUpTouchBEGIN(e:TouchEvent):void
{
trace("Touch Began")
}
public function moveUpTouchEND(e:TouchEvent):void
{
trace("Touch Ended")
}
}
}
You are confused because "public" does not mean "global". Declaring variable as public means you want to grant an access to it to any entity, given the entity knows where that variable is.
Lets see what you have there.
Top display object: stage.
Main timeline: game is a child of stage.
MovieClips up_dpad, down_dpad and so on, all are fields of the game instance.
Movement: instance is a child of game.
In the Movement you are trying to access up_dpad and others, but they are kept as fields of game instance and have nothing to do with the Movement instance. That's why they are outside of Movement's addressing context.
So, if you want to have these variables declared as game fields, you need to address them from the Movement in a correct way.
Forget the timeline. In the Game (for the sake's sake never call classes in lowercase unless at the gunpoint) which is, I believe, a root document class:
public function Game()
{
trace("SUCCESS | Constructed Game Class");
// Pass reference to this instance to the constructor.
var aMove:Movement = new Movement(this);
// Add it as a child.
addChild(aMove);
}
In Movement:
public function Movement(main:Game)
{
trace("SUCCESS | Constructed Movement Class");
// Access variables inside Game instance via given reference.
addChild(main.playerPosKeeper_mc);
main.playerPosKeeper_mc.x = 384;
main.playerPosKeeper_mc.y = 46;
// ...and so on
}
These are basics of Object Oriented Programming. If you want to access anything inside an object, you need to access the object first.
Related
I'm trying to do something very basic, add a movie clip from the library to the stage. I created a class called link that extends MovieClip. I have two movie clips in the library, the first one that is initially loaded contains buttons that should remove the first movie clip and load the second. However, I am unable to load the second using addChild(). I'm hoping that there is something obvious that I'm missing. I'm fairly new to AS3. Here is the code from the link class:
package classes.GEN1P0
{
import flash.display.SimpleButton;
import flash.display.*;
import flash.events.*;
import fl.controls.*;
import fl.transitions.easing.*;
import fl.transitions.TweenEvent;
public class link extends MovieClip
{
public var links:Vector.<SimpleButton > = new Vector.<SimpleButton >;
public var sourceMap:redMC = new redMC ;
public var sourceMap2:blueMC = new blueMC ;
public var panZoomMap:PanZoomMap = new PanZoomMap(sourceMap,704,556.3);
public var diagram:PanZoomMap = new PanZoomMap(sourceMap2,704.45,556.3);
public var zoomControls:ZoomControls = new ZoomControls(panZoomMap);
public var zoomControls2:ZoomControls = new ZoomControls(diagram);
public var navWindow:NavigatorWindow = new NavigatorWindow(panZoomMap);
public var navWindow2:NavigatorWindow = new NavigatorWindow(diagram);
public function link()
{
}
/////////////////////////////
//Vector for Links
/////////////////////////////
public function linkVector():void
{
for (var m:int = 0; m < 2; m++)
{
var linkNumb:SimpleButton = RunWise_GEN_1P0_Electrical_Schematic.sourceMap.panner.schematic.link_movies.getChildAt(m);
if ((linkNumb is SimpleButton))
{
links.push(linkNumb);
var linkName:String = links[m].name;
}
}
for (var n:int = 0; n<links.length; n++)
{
links[n].addEventListener(MouseEvent.CLICK, linkTo);
}
function linkTo(e:Event):void
{
addChild(diagram);
diagram.x = 291.35;
diagram.y = 22.15;
RunWise_GEN_1P0_Electrical_Schematic.panZoomMap.parent.removeChild(RunWise_GEN_1P0_Electrical_Schematic.panZoomMap);
switch (e.target.name)
{
case "PPOS":
trace ("PPOS");
break;
case "PYKPOS":
trace ("PYKPOS");
break;
}
}
}
//End Code Here
}
}
Should be as simple as
var _link:link = new link();
addChild(_link);
Note: Typically when you create a Class in AS3 you use uppercase for the first letter of the Class name
public class Link extends MovieClip
I'm making a game in full classes. so the timeline is empty. But I want to use another scene for the game intro, after the intro, it will proceed to the main menu of the game which I have created. Anyone got an idea? I haven't found any since a week ago... I don't really know about how to operate scenes from code in classes. Please help. Thanks!
Here is the main code :
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.MovieClip;
public class Main extends Sprite
{
public var field:Array;
//CALL EVERY CLASS
public var _money:Money = new Money();
public var _gold:Gold;
public var _hero:Hero;
public var _enemy:Enemy;
private var _pause:MovieClip = new Pause();
private var pauseLayer:MovieClip = new PauseLayer();
private var ts:TitleScreen;
public function Main():void
{
ts = new TitleScreen();
addChild(ts);
}
//GAME FUNCTION
public function onStage():void
{
_hero = new Hero(this);
_enemy = new Enemy(this);
_gold = new Gold(this);
setupField();
_gold.goldSet(stage);
_money.addText(stage);
_hero.displayHero(stage);
_enemy.displayEnemy(stage);
setPause();
_pause.addEventListener(MouseEvent.CLICK, pauseGame);
}
private function setPause():void
{
addChild(_pause);
_pause.x = 620;
_pause.y = 50;
_pause.buttonMode = true;
}
private function pauseGame (e:MouseEvent):void
{
stage.frameRate = 0;
addChild(pauseLayer);
pauseLayer.alpha = 0.5;
pauseLayer.parent.setChildIndex(pauseLayer,numChildren-1);
}
//SET UP FIELD ARRAY
private function setupField():void
{
var fieldSprite:Sprite=new Sprite();
addChild(fieldSprite);
fieldSprite.graphics.lineStyle(4);
field=new Array();
for (var a:int=0; a<6; a++)
{
field[a]=new Array();
for (var b:int=0; b<10; b++)
{
field[a][b]=0;
}
}
//DRAW FIELD
for (var i:int=0; i<5; i++)
{
for (var j:int=0; j<9; j++)
{
fieldSprite.graphics.drawRect(75+65*j,50+75*i,65,75);
}
}
}
}
}
Titlescreen class :
package
{
import flash.display.MovieClip;
import flash.events.MouseEvent;
import flash.display.Sprite;
public class TitleScreen extends Sprite
{
private var playBtn:MovieClip = new Resume();
public function TitleScreen()
{
playBtn.x = 50;
playBtn.y = 50;
playBtn.addEventListener(MouseEvent.CLICK, Play);
}
private function Play(e:MouseEvent):void
{
trace("a");
}
}
}
The most simple way would be using wrapper Sprites to hold each set of objects you probably want to be available as whole, say main menu, upgrades, storyline, etc etc. Then you just shift them in and out of display list to display corresponding "scene" with your Main class responsible of transition flow. But to do this you need to shift your game core functionality out of Main class into say Game class. That's how I have done the same thing in my game:
public class Main extends MovieClip {
private var so:SharedObject;
private var ui:UserInterface;
private var ts:TitleScreen;
private function init(e:Event = null):void
{
ui = new UserInterface();
ts = new TitleScreen();
ts.newButtonClicked = newGame;
ts.loadButtonClicked = loadGame;
ui.gotoMapBehavior = wentToMap;
addChild(ts);
}
Here, UserInterface is a class that has gaming logic inside, and TitleScreen is a main menu class. The functions are callbacks in Main:
private function newGame():void {
removeChild(ts); // hide title
if (!contains(ui)) addChild(ui);
SoundManager.playMusic(SoundManager.MUSIC_LEVELSELECT);
}
private function loadGame():void {
newGame();
ui.loadBattle(); // this should make UI load the battle from shared object (either supplied or received by itself)
}
private function wentToMap():void {
// we have just executed "go to map" from UI
removeChild(ui);
addChild(ts);
checkSO();
SoundManager.playMusic(SoundManager.MUSIC_INTRO);
}
The actual gaming logic does not interact with Main at all, except for shared object which is common for the entire project, but the link is received normally via SharedObject.getLocal(someName). The code is ugly, but could do for starters.
Save your game as SWF and make another project with timeline-animated intro. When the intro ends, make your project to load your game. Loader class can load other swf files. So, you don't need to edit your game classes.
I have a small project I'm trying to help learn as3. It is a variation from the book Foundation Game Design with Actionscript 3.0. I am using an fla only to have a document class. All art is loaded within the as files. In the book, he just put all the code in the document class, I followed along and it worked as expected. I am trying to break out the code into separate classes to get a handle on OOP. One class makes a background - Background.as, one makes a character - Character.as, and one makes a button, which I instantiate 6 times for 6 different buttons - GameButton.as. And of course there is GameWorld.as which is the document class. Everything loads and shows up as expected. However when I try and add an eventListener for the buttons, I don't get any response. I have tried putting the eventListener in the GameButton.as and also tried it in the GameWorld.as neither of which has worked. Also I pass a reference to the stage when instantiating the various classes, because when I tried to addChild in the GameWorld.as, nothing would show up. I searched the site and found something similar, but it didn't seem to help. Thank you in advance for any advice you my have. Here is the code:
GameWorld.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.DisplayObject
import flash.events.MouseEvent;
import GameButton;
import Character;
import Background;
[SWR(width = "550", height = "400", backgroundColor = "#FFFFFF", frameRate = "60")]
public class GameWorld extends Sprite
{
//public variables
//Background
public var gameBackground:Background;
//Character
public var catCharacter:Character;
//Buttons
public var upButton:GameButton;
public var downButton:GameButton;
public var growButton:GameButton;
public var shrinkButton:GameButton;
public var vanishButton:GameButton;
public var spinButton:GameButton;
public function GameWorld ()
{
//Add the background to the stage
gameBackground = new Background("../images/background.png", stage);
//Add the character(s) to the stage
catCharacter = new Character("../images/character.png", stage);
//Set initial character position
catCharacter.CharacterPos(225, 150);
//Add the buttons to the stage
upButton = new GameButton("../images/up.png", stage, 25, 25);
downButton = new GameButton("../images/down.png", stage, 25, 85);
growButton = new GameButton("../images/grow.png", stage, 25, 145);
shrinkButton = new GameButton("../images/shrink.png", stage, 425, 25);
vanishButton = new GameButton("../images/vanish.png", stage, 425, 85);
spinButton = new GameButton("../images/spin.png", stage, 425, 145);
//Button event handlers
upButton.addEventListener(MouseEvent.CLICK, upButtonHandler);
}
public function upButtonHandler(event:MouseEvent)
{
trace("You clicked the up button!");
catCharacter.CharacterMove(15);
}
}
}
GameButton.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.MouseEvent;
public class GameButton extends Sprite
{
//public variables
public var stageRef:Stage;
public var urlRequest:URLRequest;
public var gameButtonLoader:Loader;
public var gameButtonSprite:Sprite;
//Constructor
public function GameButton (urlRequest:String, stageRef:Stage, xPos:Number, yPos:Number)
{
this.stageRef = stageRef
this.urlRequest = new URLRequest();
gameButtonLoader = new Loader();
gameButtonSprite = new Sprite();
this.urlRequest.url = urlRequest;
gameButtonLoader.load(this.urlRequest);
gameButtonSprite.addChild(gameButtonLoader);
this.stageRef.addChild(gameButtonSprite);
gameButtonSprite.buttonMode = true;
gameButtonSprite.x = xPos;
gameButtonSprite.y = yPos;
}
}
}
Character.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
public class Character
{
//private variables
private var stageRef:Stage;
private var urlRequest:URLRequest;
private var characterLoader:Loader;
private var characterSprite:Sprite;
//public variables
public var character_x_pos:Number;
public var character_y_pos:Number;
//Constructor
public function Character (urlRequest:String, stageRef:Stage)
{
this.stageRef = stageRef;
this.urlRequest = new URLRequest();
characterLoader = new Loader();
characterSprite = new Sprite();
this.urlRequest.url = urlRequest;
characterLoader.load (this.urlRequest);
characterSprite.addChild (characterLoader);
this.stageRef.addChild (characterSprite);
characterSprite.mouseEnabled = false;
}
//Set the position of the character
public function CharacterPos(xPos:Number, yPos:Number):void
{
characterSprite.x = xPos;
characterSprite.y = yPos;
}
//Move the position of the character
public function CharacterMove( yPos:Number):void
{
characterSprite.y -= yPos;
}
}
}
Background.as
package
{
import flash.net.URLRequest;
import flash.display.Loader;
import flash.display.Sprite;
import flash.display.Stage;
public class Background
{
//Private variables
private var stageRef:Stage;
private var urlRequest:URLRequest;
private var backgroundLoader:Loader;
private var backgroundSprite:Sprite;
//Constructor
public function Background (urlRequest:String, stageRef:Stage)
{
this.stageRef = stageRef;
this.urlRequest = new URLRequest();
backgroundLoader = new Loader();
backgroundSprite = new Sprite();
this.urlRequest.url = urlRequest;
backgroundLoader.load (this.urlRequest);
backgroundSprite.addChild (backgroundLoader);
this.stageRef.addChild (backgroundSprite);
backgroundSprite.mouseEnabled = false;
}
}
}
All art is loaded within the as files.
This is not an approach I recommend. There's a reason God gave us the Flash IDE--and it's not to write code! Any time you're spending on layout and viduals in code is just wasted, unless you have an actual requirement to change the visuals at runtime. The fact that your paths are all hard-coded suggests that you don't have that requirement.
So let's step back and imagine that you have a Symbol that contains 6 Symbols that you've created as just Flash buttons (when you select Button as the Symbol type). These will be SimpleButtons, but in the Class below we're just going to type them as DisplayObject. The Class doesn't care what they are, but using Simplebutton gives them up, over, down and hit states that require no code.
Note that the below assumes you have "automatically declare stage instances" off, which is IMO the best way to do things.
package view {
public class NavBar extends Sprite {
//because you put these on stage in the Symbol, they will be available in the constructor
public var upButton:DisplayObject;
public var downButton:DisplayObject;
public var growButton:DisplayObject;
public var shrinkButton:DisplayObject;
public var rotateButton:DisplayObject;
public var vanishButton:DisplayObject;
//makes it easier to do the same setup on all buttons
protected var allButtons:Vector.<DisplayObject> = <DisplayObject>([upButton, downButton, growButton, shrinkButton, rotateButton, vanishButton]);
public function NavBar() {
super();
for each (var btn:DisplayObject in allButtons) {
btn.buttonMode = true;
btn.mouseChildren = false;
btn.addEventListener(MouseEvent.CLICK, onButtonClick);
}
}
protected function onButtonClick(e:MouseEvent):void {
switch (e.target) {
case upButton:
dispatchEvent(new CharacterEvent(CharacterEvent.UP));
break;
case downButton:
dispatchEvent(new CharacterEvent(CharacterEvent.DOWN));
break;
case growButton:
dispatchEvent(new CharacterEvent(CharacterEvent.GROW));
break;
case shrinkButton:
dispatchEvent(new CharacterEvent(CharacterEvent.SHRINK));
break;
case rotateButton:
dispatchEvent(new CharacterEvent(CharacterEvent.ROTATE));
break;
case vanishButton:
dispatchEvent(new CharacterEvent(CharacterEvent.VANISH));
break;
default:
break;
}
}
}
}
Note that there's zero layout code. This code is dependent on a custom Event Class. I'm going to write that Event Class so that it always bubbles. That way, it can be dispatched anywhere on the display list and received at the top level:
package control {
class CharacterEvent extends Event {
public static var UP:String = 'characterUp';
public static var DOWN:String = 'characterDown';
public static var GROW:String = 'characterGrow';
public static var SHRINK:String = 'characterShrink';
public static var ROTATE:String = 'characterRotate';
public static var VANISH:String = 'characterVanish';
public function CharacterEvent(type:String) {
super(type, true, true);//always bubbles
}
public function clone():Event {
return new CharacterEvent(type);
}
}
}
Now, if you want to manually handle instantiation of the Symbol that has view.NavBar as its base class, it will look like this:
package {
public var navBar:NavBar;
class GameWorld {
public function GameWorld() {
try {
var navClass:Class = getDefinitionByName('NavBarSymbol') as Class;
} catch (e:Error) {
trace('You need to have a Library symbol called NavBarSymbol');
}
if (navClass) {
navBar = new navClass() as NavBar;
//unnecessary layout code here
//Note that this is NOT the responsibility of the child Class!
addChild(navBar);
}
//instantiate character
...
//by listening to the whole Document, you can add other things that
//dispatch Character events on the display list, like a keyboard listener
addEventListener(CharacterEvent.UP, moveCharacterUp);
//listeners for the rest of the character events...
}
public function moveCharacterUp(e:CharacterEvent):void {
//character move logic
}
//other handlers
}
}
Personally, I'd just add the navBar to the stage, and then there's no need to manage it at all (not even reference it with a variable), simply add the event listeners for the various character events.
The root of your problem doesn't seem to be the character code. However, I'm going to give you a few "best practice" pointers about it.
The convention in AS3 is for Class members (properties and methods) to be camel case starting with a lower case letter. So, characterPos() and characterMove().
Your Class already contains character in the name, so really these should just be pos() and move() (though there's no need now to shorten position()).
The only thing your child Classes are doing with their references to the parent are adding themselves. They don't need and shouldn't have a reference to the parent for this purpose. It is the parent's responsibility to add the Children (or the responsibility of the Flash Player if you use the stage).
That said, you could give your Character a reference to the parent Class typed as IEventDispatcher and allow the Character to listen to this channel. This concept is called an event bus.
Note that the reason that so many people do what you're doing is that Adobe failed to document how to properly use OOP with the timeline. Unfortunately, by the time a few of us started documenting that around late 2009/early 2010, the damage was done and everyone assumed that if you wanted to write good code you had to pretend the timeline and stage didn't exist.
I know I've covered a lot of ground, and probably most of what I said directly contradicts what you thought you knew, so please don't hesitate to ask any questions you might have.
Edit: I have now included a Player.as and a addchild
I've been trying to understand how to do this all day and again learned a lot in doing so. But I've come to a point that i need help.
I know I have to do this: create a Collisions var in the Back1 class.
Because the background called Back1 is the movieclip that contains the Collisions image
I found a good site or 2 that does a good job of explaining variables and classes but i still don't get how i should solve this problem
Research after variables and classes:
http://www.republicofcode.com/tutorials/flash/as3variables/
http://www.photonstorm.com/archives/1136/flash-game-dev-tip-1-creating-a-cross-game-communications-structure
the above problem results in the folowing error but i believe it is caused by not creating a Collisions var in the Back1 class
ArgumentError: Error #1063: Argument count mismatch on Bumper(). expected: 2, value 0.
at flash.display::MovieClip/gotoAndStop() at
DocumentClass/onRequestStart()DocumentClass.as:64] at
flash.events::EventDispatcher/dispatchEventFunction() at
flash.events::EventDispatcher/dispatchEvent() at
MenuScreen/onClickStart()MenuScreen.as:18]
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.geom.Point;
import Bumper;
//import Back1;
public class Test extends MovieClip
{
public var leftBumping:Boolean = false;
public var rightBumping:Boolean = false;
public var upBumping:Boolean = false;
public var downBumping:Boolean = false;
public var leftBumpPoint:Point = new Point(-30,-55);
public var rightBumpPoint:Point = new Point(30,-55);
public var upBumpPoint:Point = new Point(0,-120);
public var downBumpPoint:Point = new Point(0,0);
public var scrollX:Number = 0;
public var scrollY:Number = 500;
public var xSpeed:Number = 0;
public var ySpeed:Number = 0;
public var speedConstant:Number = 4;
public var frictionConstant:Number = 0.9;
public var gravityConstant:Number = 1.8;
public var jumpConstant:Number = -35;
public var maxSpeedConstant:Number = 18;
public var doubleJumpReady:Boolean = false;
public var upReleasedInAir:Boolean = false;
public var keyCollected:Boolean = false;
public var doorOpen:Boolean = false;
public var currentLevel:int = 1;
public var animationState:String = "idle";
public var bulletList:Array = new Array();
public var enemyList:Array = new Array();
public var bumperList:Array = new Array();
public var back1:Back1;
public var collisions:Collisions;
//public var back1:Collisions = new Collisions ;
public var player:Player;
public function Test()
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event):void
{
player = new Player(320, 360);
back1 = new Back1();
collisions = new Collisions();
//back1.collisions = new Collisons();
addBumpersToLevel1();
}
public function addBumpersToLevel1():void
{
addBumper(500, -115);
addBumper(740, -115);
}
public function addPlayerTolevel1():void
{
addPlayer(320, 360);
}
public function loop(e:Event):void
{
trace("back1.collisions "+back1.collisions);
trace("back1 "+back1);
trace("collisions "+collisions);
if (back1.collisions.hitTestPoint(player.x + leftBumpPoint.x,player.y + leftBumpPoint.y,true))
{
just in case i've added Bumper.as
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Bumper extends MovieClip{
public function Bumper(xLocation:int, yLocation:int) {
// constructor code
x = xLocation;
y = yLocation;
addEventListener(Event.ENTER_FRAME, bumper);
}
public function bumper(e:Event):void{
//code here
}
}
}
Player.as
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Player extends MovieClip {
public function Player(xLocation:int, yLocation:int) {
// constructor code
x = xLocation;
y = yLocation;
}
// public function removeSelf():void {
// trace("remove enemy");
// removeEventListener(Event.ENTER_FRAME, loop);
// this.parent.removeChild(this);
// }
}
}
the Back1.as file (note it's got to be instanced wrong)
package {
import flash.display.MovieClip;
public class Back1 extends MovieClip {
//public var collisions:Back1;
//what should i put here?
}
}
I am not sure I understand completely what you mean. The question is phrased strange.
I assume you want to achieve a collision between your background object (The Back class) and a player object? I can't see from the code you have posted what the player object is since there is no such variable in your Test class.
To test a collision check between two objects use the following code:
if(someObject.hitTestObject(anotherObject))
Or in your case when using hitTestPoint:
if(back1.hitTestPoint(player.x, player.y,true))
Then again I don't know from the code you have posted how the back1 class looks like. If it extends a MovieClip or Sprite and you have a Player class that does the same (OR any DisplayObject) this should work.
This:
Argument count mismatch on Bumper(). expected: 2, value 0.
The error you get seems to come from another place not shown in your code. I would assume you did not pass any parameters into the Bumper class' constructor.
Btw, is this a Flash IDE sample or some other program such as FlashDevelop or FlashBuilder? If you are using the Flash IDE and are trying to attach code to a movie clip instance placed out on the scene I don't think its possible to pass parameters to it. Sorry been a while since I've worked in the Flash IDE.
EDIT:
Here's some sample code:
//:: Change Back1 class to this
package {
import flash.display.MovieClip;
public class Back1 extends MovieClip {
public function Back1()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0, 0, 50, 50);
graphics.endFill();
}
}
}
//:: Then in your Main class (Or the Test class) add the following
var player:Player = new Player(25, 25);
var collidable:Back1 = new Back1();
addChild(player);
addChild(collidable);
//:: Goes in your loop/update
if (collidable.hitTestPoint(player.x, player.y, true))
{
trace("HIT PLAYER");
}
How you apply the graphics to the Back1 class is up to you, I just drew a simple box. It could be anything.
Set default parameters for Bumper class:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Bumper extends MovieClip{
public function Bumper(xLocation:int = 0, yLocation:int = 0) {
// constructor code
x = xLocation;
y = yLocation;
addEventListener(Event.ENTER_FRAME, bumper);
}
public function bumper(e:Event):void{
//code here
}
}
}
the code below sets up a List object in the main controller class that uses a custom cell renderer (CustomListCell class). the CustomListCell class creates a Button object for the cell that will be used to delete itself from the List's DataProvider.
how can i properly access the parent List object from its custom cell renderer?
//Controller Class
private function createList():void
{
provider = new DataProvider(data);
list = new List();
list.width = 200;
list.height = 400;
list.rowHeight = 50;
list.dataProvider = provider;
list.setStyle("cellRenderer", CustomListCell);
}
-----
//CustomListCell Class
import fl.controls.Button;
public class CustomListCell extends Sprite implements ICellRenderer
{
public function CustomListCell()
{
var button:Button = new Button();
button.label = "Delete Cell";
button.addEventListener(MouseEvent_MOUSE_DOWN, deleteCellHandler);
addChild(button);
}
private function deleteCellHandler(evt:MouseEvent):void
{
//Access List/DataProvider Here
}
//required implemented ICellRenderer functions follow
}
UPDATE
the following is my working custom renderer that implements ICellRenderer with Flash v3 List component. the List's dataProvider consists of 2 elements for each cell: randomColor and randomNumber.
package
{
//Imports
import fl.controls.Button;
import fl.controls.List;
import fl.controls.listClasses.ICellRenderer;
import fl.controls.listClasses.ListData;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.geom.ColorTransform;
//Class
public class TouchListRenderer extends Sprite implements ICellRenderer
{
//Properties
private var cellWidthProperty:Number;
private var cellHeightProperty:Number;
private var dataProperty:Object;
private var listDataProperty:ListData;
private var selectedProperty:Boolean;
//Cell Display Objects
private var backgroundCanvas:MySprite = new MySprite();
private var numberTextField:TextField = new TextField();
private var button:Button = new Button();
//Constructor
public function TouchListRenderer()
{
}
//Size Setter (Getter Functions Intentionally Omitted)
public function setSize(width:Number, height:Number):void
{
cellWidthProperty = width;
cellHeightProperty = height;
}
//Data Setter
public function set data(value:Object):void
{
dataProperty = value;
}
//Data Getter
public function get data():Object
{
return dataProperty;
}
//List Data Setter
public function set listData(value:ListData):void
{
listDataProperty = value;
}
//List Data Getter
public function get listData():ListData
{
return listDataProperty;
}
//Selected Setter
public function set selected(value:Boolean):void
{
selectedProperty = value;
layout();
}
//Selected Getter
public function get selected():Boolean
{
return selectedProperty;
}
//Size And Layout
private function layout():void
{
var newColor:ColorTransform = new ColorTransform();
newColor.color = dataProperty.randomColor;
backgroundCanvas.transform.colorTransform = newColor;
backgroundCanvas.scaleX = cellWidthProperty / backgroundCanvas.width;
backgroundCanvas.scaleY = cellHeightProperty / backgroundCanvas.height;
numberTextField.text = dataProperty.randomNumber;
numberTextField.autoSize = TextFieldAutoSize.LEFT;
numberTextField.textColor = 0xFFFFFF;
numberTextField.x = 50;
numberTextField.y = cellHeightProperty / 2 - numberTextField.height / 2;
numberTextField.border = true;
numberTextField.selectable = false;
button.label = "Delete";
button.x = cellWidthProperty - button.width - 50;
button.y = cellHeightProperty / 2 - button.height / 2;
button.drawNow();
button.addEventListener(MouseEvent.MOUSE_DOWN, buttonClickEventHandler);
addChild(backgroundCanvas);
addChild(numberTextField);
addChild(button);
}
//Button Click Event Handler
private function buttonClickEventHandler(evt:MouseEvent):void
{
List(listDataProperty.owner).removeItemAt(listDataProperty.index);
}
//Style Setter
public function setStyle(style:String, value:Object):void
{
}
//Mouse State Setter
public function setMouseState(state:String):void
{
}
}
}
package
{
import flash.display.Sprite;
public class MySprite extends Sprite
{
public function MySprite()
{
graphics.beginFill(0xFF0000);
graphics.drawRect(0, 0, 10, 10);
graphics.endFill();
}
}
}
ugh! the answer was in front of me the whole time! next time remind me to check the docs:
List(listData.owner)
fl.controls.listClasses.ListData.owner
There are multiple ways to do this.
Here is a very hacky solution: Use an icon, and have that icon dispatch a close event.
The idea is you'll place a custom MovieClip in each list cell as icon. That icon will dispatch an event with the index of the cell clicked so you can remove it.
1st step: Make a basic custom event to pass cell index through:
package{
import flash.events.Event;
public class CloseEvent extends Event{
public static const CLOSE:String = 'close';
public var index:int;
public function CloseEvent(type:String,bubbles:Boolean = true,cancelable:Boolean=true){
super(type,bubbles,cancelable);
}
}
}
2nd step:: Draw a close icon or something, convert it to MovieClip and Export for Actionscript
3rd step: Add the event listener to dispatch the custom event when the close icon is clicked.
Inside the close icon Movie Clip I've placed the following actions:
import fl.controls.listClasses.CellRenderer;
//setup click
buttonMode = true;
if(parent) parent.mouseChildren = true;
addEventListener(MouseEvent.MOUSE_DOWN,dispatchClose);
//setup event
var closeEvent:CloseEvent = new CloseEvent(CloseEvent.CLOSE,true);
if(parent) closeEvent.index = CellRenderer(parent).listData.index;
//listen to click and pass on
function dispatchClose(event:MouseEvent):void {
dispatchEvent(closeEvent);
}
Very basic stuff, listen for mouse down, create an event and set the index and dispatch that event on click. The icon is added to a cell renderer, therefor the cell render is it's parent which it has a listData property among others, which holds the index of the cell.
So here's how the test snippet looks:
import fl.data.DataProvider;
var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1),icon:Close});
ls.dataProvider = dp;
addEventListener(CloseEvent.CLOSE,deleteItem);
function deleteItem(event:CloseEvent):void {
ls.removeItemAt(event.index);
}
Since the CloseEvent bubbles, we can catch it from outside the cell renderer's icon and tell the list to remove the item at that index. It's possible to do that within the icon, but it will be necessary to 'climb' up the hierarchy all the way to the list, and it's pretty hacky already.
I did this because, I was probably as lazy as #TheDarkIn1978 :P to implement the ICellRenderer functions. Then I looked at question code again and didn't understand why the custom cell extends a Sprite, when CellRenderer already implements the ICellRenderer functions already.
So here is my attempt to do it in a less hacky manner:
package{
import fl.controls.*;
import fl.controls.listClasses.*;
import fl.data.*;
import flash.events.*;
public class SCListCell extends CellRenderer implements ICellRenderer{
protected var closeButton:Button;
protected var closeEvent:CloseEvent;
override protected function configUI():void {
super.configUI();
closeButton = new Button();
closeButton.label = 'x';
closeButton.buttonMode = true;
closeButton.setSize(30,20);
closeButton.drawNow();
closeButton.addEventListener(MouseEvent.CLICK,close);
addChild(closeButton);
closeEvent = new CloseEvent(CloseEvent.CLOSE);
}
private function close(event:MouseEvent):void{
closeEvent.index = listData.index;
dispatchEvent(closeEvent);
}
override protected function drawLayout():void{
mouseChildren = true;
closeButton.x = width-closeButton.width;
}
}
}
Used the same CloseEvent to pass the index, and the custom cell has direct access to the listData object to fetch the index, so the sample snippet looks like this:
import fl.data.DataProvider;
var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1)});
ls.dataProvider = dp;
addEventListener(CloseEvent.CLOSE,deleteItem);
function deleteItem(event:CloseEvent):void {
ls.removeItemAt(event.index);
}
ls.setStyle('cellRenderer',SCListCell);
So to answer your question:
how can i properly access the parent
List object from its custom cell
renderer?
You can use the listData property of the cell renderer.
You can if you want to, but it means going up a few levels:
package{
import fl.controls.*;
import fl.controls.listClasses.*;
import fl.data.*;
import flash.events.*;
public class SCListCell extends CellRenderer implements ICellRenderer{
protected var closeButton:Button;
override protected function configUI():void {
super.configUI();
closeButton = new Button();
closeButton.label = 'x';
closeButton.buttonMode = true;
closeButton.setSize(30,20);
closeButton.drawNow();
closeButton.addEventListener(MouseEvent.CLICK,close);
addChild(closeButton);
}
private function close(event:MouseEvent):void{
List(this.parent.parent.parent).removeItemAt(listData.index);
}
override protected function drawLayout():void{
mouseChildren = true;
closeButton.x = width-closeButton.width;
}
}
}
Which leaves the list creation part as simple as:
import fl.data.DataProvider;
var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1)});
ls.dataProvider = dp;
ls.setStyle('cellRenderer',SCListCell);
CloseEvent isn't needed in this case.
HTH