AS3 Scrolling Movieclip - actionscript-3

I have a problem with my code whereby I have a spawned vertical movieclip where there are button instances in it which makes it look like a list.
The problem is that I am trying to recreate a iOS-style drag scrolling. When I hold and drag my movieclip, it works fine, scrolling up and down. But when I release my left mouse button, It registers a click on one of my buttons.
I tried to remove the event listeners on the buttons but the scrolling only works once, after I released my left mouse button, the whole scrolling does not work the second time.
Is it possible to have maybe like a mouse drag (up or down) ignoring the button click listeners however when the user want to click the button instead, the scrolling won't kick in?
My buttons' class
public function PlaceOneButtons()
{
for (var a=0; a<buttons.length; a++)
{
stationsone1[a].addEventListener(clicked,StationSelectOne);
stationsone2[a].addEventListener(clicked,StationSelectOne);
stationsone3[a].addEventListener(clicked,StationSelectOne);
stationsone4[a].addEventListener(clicked,StationSelectOne);
stationsone5[a].addEventListener(clicked,StationSelectOne);
}
}
My Main (spawner) class
package
{
import flash.display.MovieClip;
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.ui.*;
import flash.utils.*;
import flash.media.*;
import IconSpawn;
import Scrolling;
public class MainClass extends MovieClip
{
private var iconspawn:IconSpawn = new IconSpawn();
private var touchay:int = new int;
private var touchPoint:int = new int;
private var touchPoint2:int = new int;
private var touchString:int = new int;
private var AYint:int = new int;
private var touchTimer:Timer = new Timer(150,1);
private var endTime:Timer = new Timer(1,1);
private var speed:int = new int;
public static var scrollDiff:int = new int;
public static var doubleDiff:int = new int;
public static var dragging:Boolean = new Boolean
//private var scrolling:Scrolling = new Scrolling();
//public static var Ystore:Point;
public function MainClass()
{
// constructor code
AYint = IconSpawn.A_Y.y;
}
public function startApp()
{
addChild(iconspawn);
iconspawn.MenuSpawn();
dragging = false;
}
public function directionsApp()
{
addChild(iconspawn);
iconspawn.KeyboardOne();
}
public function placeOneApp()
{
addChild(iconspawn);
iconspawn.PlaceOneSpawn();
Evtlistener();
}
private function Evtlistener()
{
addEventListener(Event.ENTER_FRAME,update);
addEventListener(MouseEvent.MOUSE_DOWN,spawnTouch);
addEventListener(MouseEvent.MOUSE_UP,endScroll);
}
public function directionsApp2()
{
addChild(iconspawn);
iconspawn.KeyboardTwo();
}
public function update(evt:Event)
{
//trace(touchTimer);
//trace(touchString);
touchPoint2 = mouseY;
scrollDiff = touchPoint2 - touchPoint;
doubleDiff = scrollDiff - scrollDiff;
trace(dragging);
if(dragging == true)
{
//iconspawn.PlaceOneButtons();
}
}
public function spawnTouch(evt:MouseEvent)
{
touchPoint = mouseY;
touchTimer.addEventListener(TimerEvent.TIMER,timerTouch);
endTime.addEventListener(TimerEvent.TIMER,endTimer);
touchTimer.start();
dragging = true;
touchay = IconSpawn.A_Y.y;
}
public function timerTouch(evt:TimerEvent):void
{
if(dragging == true)
{
addEventListener(Event.ENTER_FRAME,startScroll);
}
}
public function startScroll(evt:Event)
{
if(mouseY > 540 && mouseY < 1510)
{
IconSpawn.A_Y.y = touchay + (touchPoint2 - touchPoint);
}
}
public function endScroll(evt:MouseEvent)
{
removeEventListener(MouseEvent.MOUSE_DOWN,spawnTouch);
removeEventListener(Event.ENTER_FRAME,startScroll);
touchTimer.reset();
endTime.start();
}
private function endTimer(evt:TimerEvent):void
{
dragging = false;
Evtlistener();
}
}
}
Help will be appreciated! Have been stuck at this problem for days now.
UPDATE: Added new updated code
Hi guys, now my problem is that after I scroll my movieclip, the code will listen out for scrollDiff if its = 0.
When scrollDiff is 0, the buttons of the movieclip is clickable but if its more or less than that, the buttons are not clickable. Now my new problem is that after I release my left click, the code does not update the scrollDiff to 0, so user have to double click to select the button. Help!
package
{
import flash.display.MovieClip;
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.ui.*;
import flash.utils.*;
import flash.media.*;
import IconSpawn;
import Scrolling;
public class MainClass extends MovieClip
{
private var iconspawn:IconSpawn = new IconSpawn();
private var touchPoint:int = new int;
private var touchPoint2:int = new int;
private var AYint:int = new int;
private var touchTimer:Timer = new Timer(150,1);
private var endTimer:Timer = new Timer(150,1);
private var IconSpwnY:int = new int;
private var touchbool:Boolean = new Boolean
public static var scrollDiff:int = new int;
//private var scrolling:Scrolling = new Scrolling();
//public static var Ystore:Point;
public function MainClass()
{
// constructor code
}
public function startApp()
{
addChild(iconspawn);
iconspawn.MenuSpawn();
}
public function directionsApp()
{
addChild(iconspawn);
iconspawn.KeyboardOne();
}
public function placeOneApp()
{
AYint = IconSpawn.A_Y.y;
addChild(iconspawn);
iconspawn.PlaceOneSpawn();
addEventListener(Event.ENTER_FRAME,update);
addEventListener(MouseEvent.MOUSE_DOWN,spawnTouch);
addEventListener(MouseEvent.MOUSE_UP,endScroll);
touchbool = false;
//IconSpawn.container.mouseChildren = true;
}
public function directionsApp2()
{
addChild(iconspawn);
iconspawn.KeyboardTwo();
}
public function update(evt:Event)
{
touchPoint2 = mouseY;
scrollDiff = touchPoint2 - touchPoint;
trace(scrollDiff);
}
public function spawnTouch(evt:MouseEvent)
{
touchPoint = mouseY;
touchTimer.addEventListener(TimerEvent.TIMER,timerTouch);
touchTimer.start();
IconSpwnY = IconSpawn.A_Y.y;
if(scrollDiff == 0)
{
IconSpawn.container.mouseChildren = true; //Important <-
}
else
{
IconSpawn.container.mouseChildren = false; //Important <-
}
}
public function timerTouch(evt:TimerEvent):void
{
addEventListener(Event.ENTER_FRAME,startScroll);
touchbool = true
}
public function startScroll(evt:Event)
{
if(mouseY > 0 && mouseY < 1510)
{
IconSpawn.A_Y.y = IconSpwnY + (touchPoint2 - touchPoint);
}
}
public function endScroll(evt:MouseEvent)
{
removeEventListener(MouseEvent.MOUSE_DOWN,spawnTouch);
removeEventListener(Event.ENTER_FRAME,startScroll);
endTimer.addEventListener(TimerEvent.TIMER,endTiming);
endTimer.start();
trace("CALLL")
scrollDiff = touchPoint2 - touchPoint;
//touchTimer.reset();
}
private function endTiming(evt:TimerEvent)
{
IconSpawn.container.mouseChildren = true;
addEventListener(MouseEvent.MOUSE_DOWN,spawnTouch);
//addEventListener(Event.ENTER_FRAME,startScroll);
scrollDiff = 0;
}
}
}

While you're moving set <container_mc>.mouseChildren = false. When the container clip stops moving, set the mouseChildren property to 'true'.

Adding to Craig's answer (which I definitely recommend implementing, to make life easier!), here is the list of the event listeners you should have hooked up for this to work as planned. This is theory, so you may have to play around with it a bit.
container.addEventListener(MouseEvent.MOUSE_DOWN, response);: You'll want to raise some sort of flag that the mouse is down, and wait for the next mouse event, which determines the action.
container.addEventListener(MouseEvent.MOUSE_MOVE, response);: If the mouse is down, disable child clicking (Craig's answer) and initiate dragging. You'll also want to raise a dragging flag.
container.addEventListener(MouseEvent.MOUSE_UP, response);: If the dragging flag is raised, stop drag and enable child clicking. If it isn't raised, do nothing, so the item can take over from there.
item.addEventListener(MouseEvent.MOUSE_UP, itemResponse);: Your click action.
Theoretically, this should work fine with your nested MovieClips, as long as you use MouseEvent.MOUSE_UP as the listener on them (as shown above). Using MouseEvent.MOUSE_DOWN or MouseEvent.CLICK may mess your timing up. However, I'd experiment a bit to find the right combination, as I could be wrong on that last point.

Related

How to define that a child should only appear in one scene?

We are making an space impact game. Here are 3 of our classes. Our problem is that when we create our InimigoNoite, they appear all over the game(menus, other levels, etc), instead of only appearing in the Scene that we want. How should we restrict the child to only appear in the CenárioCidade?
We've tried to use gotoandPlay, addChildAt, and also tried to create the Inimigo not in the Main class, but in the Inimigo class itself, but it doesnt appear at all. Please can someone help us? Thank you very much!
KEY.as
package {
import flash.display.Stage;
import flash.events.Event;
import flash.events.KeyboardEvent;
public class Key {
private static var initialized:Boolean = false;
private static var keysDown:Object = new Object();
public static function initialize(stage:Stage) {
if (!initialized) {
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, keyReleased);
stage.addEventListener(Event.DEACTIVATE, clearKeys);
initialized = true;
}
}
public static function isDown(keyCode:uint):Boolean
{
return Boolean(keyCode in keysDown);
}
private static function keyPressed(event:KeyboardEvent):void {
keysDown[event.keyCode] = true;
}
private static function keyReleased(event:KeyboardEvent):void {
if (event.keyCode in keysDown) {
delete keysDown[event.keyCode];
}
}
private static function clearKeys(event:Event):void {
keysDown = new Object();
}
}
}
INIMIGO NOITE.as
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
public class InimigoNoite extends MovieClip{
var speed:Number;
static var list:Array = new Array();
var balaTimer: Timer;
function InimigoNoite(){
list.push(this);
this.x = 1160;
this.y = 150 + (450-150) * Math.random();
speed = Math.random()*5 + 5;
addEventListener("enterFrame", enterFrame);
var intervalo: Number = Math.random()*500 + 1000;
balaTimer = new Timer(intervalo);
balaTimer.addEventListener("timer", bala);
balaTimer.start();
}
function enterFrame (e:Event){
this.x -= speed;
if(this.x < -100){
matar();
return;
}
if(this.hitTestObject(SpaceImpact.navecnoite)){
matar();
}
}
function matar(){
var explosao = new ExplosaoNoite();
stage.addChild(explosao);
explosao.x = this.x;
explosao.y = this.y;
balaTimer.stop();
balaTimer.removeEventListener("timer",bala);
removeEventListener("enterFrame", enterFrame);
stage.removeChild(this);
for(var i in list){
if(list[i] == this){
delete list[i];
}
}
}
function bala(e:Event){
var b = new BalaInimigo();
b.x = this.x -50;
b.y = this.y;
stage.addChild(b);
}
}
}
MAIN.as
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
public class SpaceImpact extends MovieClip{
static var navecnoite:MovieClip;
var inimigoNoiteTimer:Timer;
function SpaceImpact(){
Key.initialize(stage);
inimigoNoiteTimer = new Timer(8000);
inimigoNoiteTimer.addEventListener("timer", criaInimigo);
inimigoNoiteTimer.start();
}
function criaInimigo(e:Event){
var inimigo = new InimigoNoite();
stage.addChild(inimigo);
addChildAt(inimigo, 3);
}
}
}
You never stop the timer. So your inimigo is created and added every 8seconds.
Stop the timer in criaInimigo and/or use the timerComplete Event
function SpaceImpact(){
Key.initialize(stage);
inimigoNoiteTimer = new Timer(8000,1);
inimigoNoiteTimer.addEventListener(TimerEvent.TIMER_COMPLETE, criaInimigo);
inimigoNoiteTimer.start();
}
function criaInimigo(e:Event){
//inimigoNoiteTimer.stop();//only needed if you use the 'timer'-Event
var inimigo = new InimigoNoite();
stage.addChild(inimigo);
addChildAt(inimigo, 3);
}
Right when you application starts, you are creating a new InimigoNoite every 8 seconds. Since you are adding them to the stage, they will appear over top anything you have on your timeline.
The issue (besides creating them when the application starts and never stopping your timer), is that when you through code use addChild, that child will stay on the screen until it's explicitly removed via removeChild (or one of it's parents are - but since the parent is stage that isn't going to happen).
I see that your have a hit test in the InimigoNoite class that can potentially remove it, but I don't see anywhere else where you remove it (so if the hit test never happens, it will never be removed from the stage regardless of scene).
It seem though that the solution to your problem is more advice on how to architect your application.
Don't use scenes.
Your best bet is to create a class file for each distinct state of your game. So something like this as a basic example:
Main Menu State
Game Play State(either 1 game state that encompasses all levels, or one state for each level - or both - depending on how much functionality changes between levels)
Game Over State
Make your game state class files extend Sprite or MovieClip, and if you want you can even create a new MovieClip in flash pro and attach the class to that (thereby being able to drop visual assets on the timeline).
So then your Main class would just be in charge of managing states (and any anything else that is global to the application)
package{
import flash.display.MovieClip;
import flash.events.Event;
public class SpaceImpact extends MovieClip {
private var menu:Menu; //Assumes you have a Menu.as class file
private var game:MainGame; //MainGame.as file
private var gameOver:GameOver; //GameOver.as file
public function SpaceImpact(){
Key.initialize(stage);
goMenu();
}
public function goMenu(e:Event = null):void {
removeAll();
menu = new Menu();
addChild(menu);
menu.addEventListener(Event.COMPLETE, startGame,false,0,true);
}
private function removeMenu():void {
if(menu){
if(menu.parent) removeChild(menu); //remove it from the screen
menu = null;
}
}
public function startGame(e:Event = null):void {
removeAll();
game = new MainGame();
addChild(game);
game.addEventListener(Event.COMPLETE, gameOver,false,0,true);
}
private function removeGame():void {
if(game){
if(game.parent) removeChild(game); //remove it from the screen
game = null;
}
}
public function gameOver(e:Event = null):void {
removeAll();
gameOver = new GameOver();
addChild(gameOver);
gameOver.addEventListener(Event.COMPLETE, goMenu,false,0,true);
}
private function removeGameOver():void {
if(gameOver){
if(gameOver.parent) removeChild(gameOver); //remove it from the screen
gameOver = null;
}
}
private function removeAll():void {
removeGameOver();
removeMenu();
removeGame();
}
}
}
then, your game state for example:
MainGame.as
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
public class MainGame extends MovieClip {
private var inimigoNoiteTimer:Timer;
public function MainGame() {
this.addEventListener(Event.ADDED_TO_STAGE, addedToStage, false, 0, true); //don't do anything until this object has been added to the screen
}
private function addedToStage(e:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, addedToStage);
//start spawning
inimigoNoiteTimer = new Timer(8000);
inimigoNoiteTimer.addEventListener("timer", criaInimigo);
inimigoNoiteTimer.start();
}
function criaInimigo(e:Event){
var inimigo = new InimigoNoite();
addChild(inimigo);
}
//when whatever happens that makes your game finished
function gameComplete():void {
dispatchEvent(new Event(addEventListener.COMPLETE));
}
}
}

Multitouch as3 problems

I have a little problem with multitouch in as3.
Recently started a project in connection with my student practice.
This is to be a small game for android.
Are used to control two virtual joysticks and that's the problem with them.
As long as I use one of them or the other separately all works very well. However, when I try to use two at the same time, one of them is blocked and the object which moves begin to move in a random way and I can not control it.
Here is my code:
joystick.as:
package com.controls {
import flash.events.TouchEvent;
import flash.ui.Multitouch;
import flash.ui.MultitouchInputMode;
import flash.display.Sprite;
import flash.events.Event;
import flash.display.MovieClip;
import flash.geom.Rectangle;
import com.controls.JoystickKnob;
import com.Hero;
import com.Fire;
import com.greensock.*;
import com.greensock.easing.*;
public class Joystick extends MovieClip {
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
private var my_x:Number;
private var my_y:Number;
private var knob:JoystickKnob;
private var hero:Hero;
private var fire:Fire;
private var knob_tween:TweenLite;
public function Joystick(margin_left, margin_bottom, hero_mc) {
var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x696969);
circle.graphics.drawCircle(50, 50, 60);
circle.graphics.endFill();
addChild(circle);
my_x = margin_left;
my_y = margin_bottom;
hero = hero_mc;
if (stage) {
init();
} else {
addEventListener(Event.ADDED_TO_STAGE,init);
}
}
private function init(e:Event = null):void {
if (hasEventListener(Event.ADDED_TO_STAGE)) {
removeEventListener(Event.ADDED_TO_STAGE,init);
}
this.x = my_x + this.width / 2;
this.y = stage.stageHeight - my_y - this.height / 2;
knob = new JoystickKnob();
knob.x = 0;
knob.y = 0;
knob.origin_x = 0;
knob.origin_y = 0;
addChild(knob);
this.addEventListener(TouchEvent.TOUCH_BEGIN, onTouchBegin, true);
knob.addEventListener(TouchEvent.TOUCH_MOVE, onTouchMove, true);
stage.addEventListener(TouchEvent.TOUCH_END, onTouchEnd, true);
knob.buttonMode = true;
}
private function onTouchBegin(event:TouchEvent):void {
knob.x = this.mouseX;
knob.y = this.mouseY;
onTouchMove(null);
}
private function onTouchMove(event:TouchEvent):void {
if (knob_tween) {
knob_tween.kill();
}
this.addEventListener(Event.ENTER_FRAME, knobMoved);
knob.startDrag(false, new Rectangle( - this.width /2, - this.height /2, this.width, this.height));
}
private function knobMoved(event:Event):void {
// LEFT OR RIGHT
if (knob.x > 15) {
hero.move_right = true;
hero.move_left = false;
} else if (knob.x < -15) {
hero.move_right = false;
hero.move_left = true;
} else {
hero.move_right = false;
hero.move_left = false;
}
// UP OR DOWN
if (knob.y > 15) {
hero.move_down = true;
hero.move_up = false;
} else if (knob.y < -15) {
hero.move_down = false;
hero.move_up = true;
} else {
hero.move_down = false;
hero.move_up = false;
}
}
private function onTouchEnd(event:TouchEvent):void {
knob.stopDrag();
hero.move_left = false;
hero.move_up = false;
hero.move_right = false;
hero.move_down = false;
if (this.hasEventListener(Event.ENTER_FRAME)) {
this.removeEventListener(Event.ENTER_FRAME, knobMoved);
}
mover();
}
private function mover():void {
knob_tween = new TweenLite(knob, 0.5, {x: knob.origin_x, y:knob.origin_y, ease:Bounce.easeOut});
}
}
}
joystickKnob.as:
package com.controls {
import flash.display.Sprite;
import flash.display.MovieClip;
public class JoystickKnob extends MovieClip {
private var _origin_x:Number;
private var _origin_y:Number;
private var knob:Class;
public function JoystickKnob() {
var circle:Sprite = new Sprite();
circle.graphics.beginFill(0x32CD32);
circle.graphics.drawCircle(50, 50, 35);
circle.graphics.endFill();
addChild(circle);
}
public function get origin_x():Number {
return _origin_x;
}
public function set origin_x(o_x:Number):void {
_origin_x = o_x;
}
public function get origin_y():Number {
return _origin_x;
}
public function set origin_y(o_y:Number):void {
_origin_y = o_y;
}
}
}
Second joystick code looks the same, except that it is stored in files joystick2.as, joystickKnob2.as.
This is the main class of my program:
package com {
import flash.events.TouchEvent;
import flash.display.MovieClip;
import flash.events.MouseEvent;
import com.controls.Joystick;
import com.controls.Joystick2;
import com.Hero;
import com.Fire;
public class MyApp extends MovieClip {
private var joystick:Joystick;
private var hero:Hero;
private var joystick2:Joystick2;
private var fire:Fire;
public function MyApp() {
hero = new Hero();
hero.x = stage.stageWidth/1.7;
hero.y = stage.stageHeight/1.7;
addChild(hero);
fire = new Fire();
fire.x = stage.stageWidth/1.7;
fire.y = stage.stageHeight/1.7;
addChild(fire);
joystick = new Joystick(-350, 100, hero);
addChild(joystick);
joystick2 = new Joystick2(600, 100, fire);
addChild(joystick2);
}
}
}
When using the two joysticks at the same time, the problem also occurs with the knob graphics - instead move in a specific area, one of them almost always moves to the other end of the screen, near the area of the second joystick.
Has anyone of you already encountered such a problem and knows how to remedy it?
Best regards and thank you in advance for your help
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT; does not support multiple fingers as written in de documentation:
For user interaction with multiple points of contact (such as several fingers moving across a touch screen at the same time) use the related GestureEvent, PressAndTapGestureEvent, and TransformGestureEvent classes. And, use the properties and methods of these classes to construct event handlers that respond to the user touching the device.
so you want Multitouch.inputMode = MultitouchInputMode.GESTURE;
This post shows up when searching for info on touch_point so I want to make sure it's correct.
TOUCH_POINT does support multiple touch points. Each touch is unique and given a unique id. You can have 100s of simultaneous touches.
TOUCH_POINT is what you use if you want to code your own touch handlers. GESTURE is TOUCH_POINTs handled for you. GESTURE decides if the touchpoints are swiping, tapping, etc. TOUCH_POINT is like a mouse event - the raw event.

Using variable from another class as3

i separated one big file into multiple file to have it cleaned and i got a problem now.
I have my main.as, character.as, camera.as.
What i'm trying to do is access a variable from another class which i set later on that class. Ill show you what i mean.
From my main.as im loading each class and add them as child so it get displayed on screen.
public function buildGame()
{
var loadMap:Sprite = new nf_MapBuilder();
var xChar:Sprite = new nf_Character();
var xCam:Sprite = new nf_Camera();
var UserControl:nf_UserControl = new nf_UserControl();
addChild(loadMap);
addChild(xChar);
addChild(xCam);
addChild(UserControl);
}
Everything show on screen like it needed. Then it goes to my character.as:
package as3
{
import flash.display.Sprite;
import flash.events.Event;
public class nf_Character extends Sprite
{
public var character_pos:Array = new Array();
public var character_is_moving:Boolean = false;
public var character_x_dir:int = 0;
public var character_y_dir:int = 0;
public var character:hero = new hero();
public function nf_Character()
{
addEventListener(Event.ADDED_TO_STAGE,xCharLoad);
}
public function xCharLoad(e:Event)
{
character_pos = [2,2];
character.x=64*(character_pos[1]);
character.y=64*(character_pos[0]);
addChild(character);
}
}
}
There is the problem. I need to use those variable i set there in my character.as to use it in my camera.as:
package as3
{
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Rectangle;
import flash.display.StageScaleMode;
import as3.nf_Character;
public class nf_Camera extends Sprite
{
private var xChar:nf_Character = new nf_Character();
//Camera variables
var stageW2:Number;
var stageH2:Number;
var view:Rectangle;
public function nf_Camera()
{
addEventListener(Event.ADDED_TO_STAGE,xCamGo);
}
public function xCamGo(e:Event):void
{
trace("Camera pos - " + xChar.x + " " + xChar.character.y);
view = new Rectangle(0,0,stage.stageWidth,stage.stageHeight)
stageW2 = stage.stageWidth / 2 - 32;
stageH2 = stage.stageHeight / 2 - 32;
addEventListener(Event.ENTER_FRAME,CamView);
}
public function CamView(e:Event):void
{
view.x = xChar.character.x - stageW2;
view.y = xChar.character.y - stageH2;
scrollRect = view;
}
}
}
When it was all in one big file it was ok i just had to set the variable in the class and acessing it trough every function but now im kinda confused. Anyone see how i could do this?
In short, I think you should subscribe to an event from your character in your main class which is fired whenever the character moves. In the handler for that event you could call a method on the camera to set it's position according to the current position of the character.
main.as
private var xChar:Sprite = new nf_Character();
private var xCam:Sprite = new nf_Camera();
public function buildGame()
{
var loadMap:Sprite = new nf_MapBuilder();
var UserControl:nf_UserControl = new nf_UserControl();
// listen for when the character has moved
xChar.addEventListener(MoveEvent.MOVED, characterMovedHandler);
addChild(loadMap);
addChild(xChar);
addChild(xCam);
addChild(UserControl);
}
private function characterMovedHandler(event:MoveEvent):void
{
xCam.setPosition(xChar.x, xChar.y);
}
nf_Character.as
public class nf_Character extends Sprite
{
public var character_pos:Array = new Array();
public var character_is_moving:Boolean = false;
public var character_x_dir:int = 0;
public var character_y_dir:int = 0;
public var character:hero = new hero();
public function nf_Character()
{
addEventListener(Event.ADDED_TO_STAGE,xCharLoad);
}
public function xCharLoad(e:Event)
{
character_pos = [2,2];
character.x=64*(character_pos[1]);
character.y=64*(character_pos[0]);
addChild(character);
}
public function xCharMoved()
{
// Dispatch a custom event when the character moves
dispatchEvent(new MovedEvent(MovedEvent.MOVED));
}
}
nf_Camera.as
public class nf_Camera extends Sprite
{
private var xChar:nf_Character = new nf_Character();
//Camera variables
var stageW2:Number;
var stageH2:Number;
var view:Rectangle;
public function nf_Camera()
{
addEventListener(Event.ADDED_TO_STAGE,xCamGo);
}
public function xCamGo(e:Event):void
{
trace("Camera pos - " + xChar.x + " " + xChar.character.y);
view = new Rectangle(0,0,stage.stageWidth,stage.stageHeight)
stageW2 = stage.stageWidth / 2 - 32;
stageH2 = stage.stageHeight / 2 - 32;
// Probably only need one enterframe either in your character class or main
//addEventListener(Event.ENTER_FRAME,CamView);
}
public function setPosition(x:Number, y:Number):void
{
view.x = xChar.character.x - stageW2;
view.y = xChar.character.y - stageH2;
scrollRect = view;
}
}
Out of interest, how are you moving the character?
You can pass your character class instance to your camera class instance as an argument of the constructor. You will then have a reference to the character inside the camera class and you can access it's variables
// Inside buildGame() in main.
var xChar:nf_Character = new nf_Character();
var xCam:nf_Camera = new nf_Camera(xChar);
// Inside nf_Camera
public function nf_Camera(char:nf_Character) {
xChar = char;
}

AS3 MouseEvent.CLICK Interaction on Different Indexes

I'm currently working through a AS3 game tutorial on Lynda.com and am coming across a problem with the MouseEvent.CLICK and child indexes. The game is a simple point and shoot, where the player must shoot all of the approaching enemies before they get too close. It works initially, however the custom cursor I added displays behind the enemies. However when I try and adjust the index (I've used the addChildAt function and moving the addChild(cursor) line of code below the enemy container initializer) the on click interaction, which is supposed to remove the enemy when clicked on, doesn't work.
My document class:
package {
import flash.display.*;
import flash.utils.*;
import flash.events.*;
import flash.ui.*;
public class Game extends MovieClip {
public var cursor:Cursor;
public var enemy:Enemy;
public var numberOfEnemies:uint;
public var enemyContainer:MovieClip;
public var enemyTimer:Timer;
public function Game() {
addEventListener(Event.ADDED_TO_STAGE, init);
Mouse.hide();
}
public function init(event:Event):void {
cursor = new Cursor;
addChild(cursor);
stage.addEventListener(MouseEvent.MOUSE_MOVE, dragCursor);
numberOfEnemies = 10;
enemyTimer = new Timer(1000, numberOfEnemies);
enemyContainer = new MovieClip();
addChild(enemyContainer);
enemyTimer.addEventListener(TimerEvent.TIMER, createEnemies);
enemyTimer.start();
}
public function dragCursor(event:MouseEvent) {
cursor.x = this.mouseX;
cursor.y = this.mouseY;
}
public function createEnemies(event:TimerEvent):void {
enemy = new Enemy();
enemy.x = 25 + Math.random() * (stage.stageWidth - 75);
enemy.y = 25 + Math.random() * (stage.stageHeight - 75);
enemyContainer.addChild(enemy);
enemy.timerStart();
}
}
}
My enemy class:
package {
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.ui.Mouse;
import flash.events.*;
public class Enemy extends MovieClip {
public var scaleObj:Number = 0.50;
public var growTimer:Timer;
public function Enemy() {
scaleX = scaleObj;
scaleY = scaleObj;
addEventListener(MouseEvent.CLICK, shootEnemy);
}
public function timerStart() {
growTimer = new Timer(50);
growTimer.addEventListener(TimerEvent.TIMER, objectGrow);
growTimer.start();
}
public function objectGrow(event:TimerEvent):void {
if(scaleObj <= 1.0) {
scaleObj += 0.01;
scaleX = scaleObj;
scaleY = scaleObj;
}
else {
killEnemy();
}
}
public function killEnemy():void {
this.parent.removeChild(this);
growTimer.stop();
}
public function shootEnemy(event:MouseEvent):void {
killEnemy();
}
}
}
There also is a cursor class, however there is no code beyond the package and class definers. Please let me know of any questions or comments you might have, thanks.
Most likely the Cursor object is intercepting the mouse click since it is above the Enemy object.
You can stop the Cursor from intercepting mouse events by setting in the cursor class:
this.mouseEnabled = false;
this.mouseChildren = false;
Also, you should ideally be using a native mouse cursor instead of manually creating your own. Check out this Adobe tutorial for an example.
Set your Cursor instance to not receive mouse events itself as it would block the click events from getting to the objects behind it. Code would be something like
cursor = new Cursor;
cursor.mouseEnabled = false;
cursor.mouseChildren = false;

AS3: Error 1009: Null reference

I am making a game in ActionScript 3. I have a Menu Class with a method that renders a Menu.
I make an instance of Menu in my Main class, and then call the method. When I debug the application I get a null reference error. This is the code of the menu class:
package
{
import flash.display.MovieClip;
import menucomponents.*;
public class Menu extends MovieClip
{
public function Menu()
{
super();
}
public function initMenuComponents():void{
var arrMenuButtons:Array = new Array();
var btnPlay:MovieClip = new Play();
var btnOptions:MovieClip = new Options();
var btnLikeOnFacebbook:MovieClip = new LikeOnFacebook();
var btnShareOnFacebook:MovieClip = new ShareOnFacebook()
arrMenuButtons.push(btnPlay);
arrMenuButtons.push(btnOptions);
arrMenuButtons.push(btnLikeOnFacebbook);
arrMenuButtons.push(btnShareOnFacebook);
var i:int = 0;
for each(var item in arrMenuButtons){
item.x = (stage.stageWidth / 2) - (item.width / 2);
item.y = 100 + i*50;
item.buttonMode = true;
i++;
}
}
}
}
Thanks in advance.
Your issue is likely that stage is not populated yet when your for loop runs. Try the following:
public class Main extends MovieClip {
public function Main() {
super();
var menu:Menu = new Menu();
//it's good practice - as sometimes stage actually isn't populated yet when your main constructor runs - to check, though in FlashPro i've never actually encountered this (flex/flashBuilder I have)
if(stage){
addedToStage(null);
}else{
//stage isn't ready, lets wait until it is
this.addEventListener(Event.ADDED_TO_STAGE,addedToStage);
}
}
private function addedToStage(e:Event):void {
menu.addEventListener(Event.ADDED_TO_STAGE,menuAdded); //this will ensure that stage is available in the menu instance when menuAdded is called.
stage.addChild(menu);
}
private function menuAdded(e:Event):void {
menu.initMenuComponents();
}
}