Updated TouchEvent Properties? - actionscript-3

Let's say I have this very simple function:
function pressingDown(e:TouchEvent):void
{
trace(e.pressure);
}
As you can see, it will trace the pressure of the user's touch, but how do I keep this updated?
For example, the user doesn't move their finger at all and my program needs to detect the pressure of their touch all the time. What Touch Event should I use for this? Does it exist? If it doesn't, what can I do to achieve what I'm asking for, or can I achieve it at all without a 3rd party library/ANE?

I have never used e.pressure before, though I don't know this would work.
But might as well throw out some idea, in case it helps.
Try Event.ENTER_FRAME
package {
public class TouchApp extends MovieClip {
var _currentTouchEvent:TouchEvent;
public function TouchApp()
{
this.addEventListener(TouchEvent.TOUCH_BEGIN, pressingDown);
}
function pressingDown(e:TouchEvent):void
{
_currentTouchEvent = e;
//When touch is down, do this function every frame.
this.addEventListener(Event.ENTER_FRAME, whileBeingTouched);
//Add EventListener to catch "touchEnd" event.
this.stage.addEventListener(TouchEvent.TOUCH_END, onTouchEndHandler);
}
function whileBeingTouched(evt:Event):void
{
//Action to do every frame.
trace(_currentTouchEvent.pressure);
}
function onTouchEndHandler(e:TouchEvent):void
{
if (_currentTouchEvent) _currentTouchEvent = null;
this.removeEventListener(Event.ENTER_FRAME, whileBeingTouched);
this.stage.removeEventListener(TouchEvent.TOUCH_END, onTouchEndHandler);
}
}
}

Related

How to make a class file apply an eventhandler to instance or object on main stage asides from itself?

I'm pretty new with ActionScript 3 and I'm stuck with trying to perform the following above in a class file. I tried to look for a solution online, but I can't find a suitable answers, perhaps because I'm not looking for the right search terms, etc.
Anyway, I'm trying to make a basic animation in Adobe Animate CC in an FLA file, "Campfire.FLA", where pressing the mouse down on a Campfire causes a piece of Coal attaching to a levitating stick to glow, and cooldown upon letting go of the mouse button. On the main timeline, I can execute it fine, but I want to transfer the information to a class file/ document file, but to no avail.
The code is what I used on the FLA's main timeline, Frame 1, and it works below works perfectly fine:
stop();
/* Instance names:
Fire = Instance of "FireButton"; simplebutton.
STween = Instance of "Stick Tween"; MovieClip, simple tween animation the object, "MarshmallowStick" moving.
Stick = Instance of "Marshmallow Stick"; MovieClip.
CoalRock = Instance of "Coal"; MovieClip.
*/
Fire.addEventListener(MouseEvent.MOUSE_DOWN, RockHot)
function RockHot(e: MouseEvent): void {
stopPlayReverse();
// Causes Coal and Stick to play their animation upon clicking Fire.
STween.Stick.play();
STween.Stick.CoalRock.play();
}
Fire.addEventListener(MouseEvent.MOUSE_UP, RockCold)
function RockCold(e: MouseEvent): void {
STween.Stick.CoalRock.addEventListener(Event.ENTER_FRAME, playReverse, false, 0, true);
STween.Stick.gotoAndPlay(1);
// Upon letting go of mouse button, it causes the coal to cool down/ play reverse. Stick resets to Frame 1.
}
function playReverse(e: Event): void {
if (STween.Stick.CoalRock.currentFrame == 1) {
stopPlayReverse();
// If Coal is back on Frame 1, it stops.
} else {
STween.Stick.CoalRock.prevFrame();
// If Coal is not on Frame 1 it continues going reverse where it left off.
}
}
function stopPlayReverse(): void {
if (STween.Stick.CoalRock.hasEventListener(Event.ENTER_FRAME)) {
STween.Stick.CoalRock.removeEventListener(Event.ENTER_FRAME, playReverse);
// Stops the function playreverse()
}
}
However, when trying to migrate the information into an ActionScript File I ran into a couple of problems. First I tried making an ActionScript 3 class file for each of the objects above much of the information is blank because I had no idea how to communicate eventhandlers between them. Much of the information for the MovieClips have no information, "MarshmallowStick" is below:
package {
import flash.display.MovieClip;
public class MarshmallowStick extends MovieClip {
public function MarshmallowStick() {
// Empty, no constructor code.
}
}
}
For the "Fire" Class file I tried something like:
package {
import flash.display.*;
import flash.events.*;
import Coal;
public class FireButton extends SimpleButton {
public var CoalRock = Coal;
public function FireButton() {
Coalrock = new Coal ();
this.addEventListener(MouseEvent.CLICK, RockHot)
function RockHot(e: MouseEvent): void {
CoalRock.play();
trace("OK");
trace(CoalRock);
}
}
}
}
However, it turned out that upon testing, The file only appeared to create a new object named CoalRock, and is not related to the one on the mainstage. So clicking the FireButton causes only the new object to play.
I tried making a document class as seen below in a file named "Main.as":
package {
import flash.display.*;
import flash.events.*;
public class Main extends MovieClip {
public var Fire: FireButton;
public var CoalRock: Coal;
public var Stick: MarshmallowStick;
public var STween: StickTween;
public function Main() {
CoalRock = new Coal();
Fire = new FireButton();
Stick = new MarshmallowStick();
/*
addChild(Fire);
addChild(CoalRock);
addChild(Stick);
addChild(STween);
*/
// RIP, well it's pretty much the same code as above. Just without the nested symbols/ objects.
Fire.addEventListener(MouseEvent.MOUSE_DOWN, RockHot)
function RockHot(e: MouseEvent): void {
stopPlayReverse();
//Eye + Emblem glow
Stick.play();
CoalRock.play();
trace("OK");
}
Fire.addEventListener(MouseEvent.MOUSE_UP, RockCold)
function RockCold(e: MouseEvent): void {
CoalRock.addEventListener(Event.ENTER_FRAME, playReverse, false, 0, true);
Stick.gotoAndPlay(1);
}
function playReverse(e: Event): void {
if (CoalRock.currentFrame == 1) {
stopPlayReverse();
} else {
CoalRock.prevFrame();
}
}
function stopPlayReverse(): void {
if (CoalRock.hasEventListener(Event.ENTER_FRAME)) {
CoalRock.removeEventListener(Event.ENTER_FRAME, playReverse);
}
}
}
}
}
But it only turned out that it only affects objects added via the addChild() well as far as I have tested. But the main point of this is for the script to affect objects that already exist on the main stage/ scene.
If you want to see how it plays/ suppose to play out, you can take the main timeline code and paste it into an FLA file with instances of the ones provided.
I don't know how Stack will format it. / / is suppose to be multi-line comments.
That's one elaborate question.
The thing you (probably) need the most is some feudal hierarchy so that objects tend to their own and their direct children, but not deeper and totally not upwards:
Container → (interface method) → Child → (tends to own children)
Container ← (status event) ← Child
Normally, a child must not know of its parent and should communicate with status events. This way you can put such a child into any container with no risk of that child possibly reaching upwards expecting some parent structure that is not there.
So, your problems.
First. Accessing the objects that already exist on the main timeline. Well, the only trick is not to create new ones but to get references to the existing ones.
package
{
// Imports.
public class Main extends MovieClip
{
// If you have an instance of MarshmallowStick with the
// instance name "Stick" on the main timeline,
// you don't need to do anything else.
//
// Default publish settings are to auto-declare
// the main timeline instance into the
// appropriately named variable.
public var Stick:MarshmallowStick;
P.S. Figure the Stick out of Tween by yourself.
Second. To access Coal inside Stick you need to declare an appropriate variable inside the correspondent class. Also, it makes a lot of sense to put the things needed to play things forward and backward as close to the objects they operate as it is possible.
package
{
import flash.events.Event;
import flash.display.MovieClip;
public class MarshmallowStick extends MovieClip
{
// You don't seem to need a separate class for Coal.
// Having it as a regular MovieClip will suffice.
public var Coal:MovieClip;
// Call this to play animation forward.
public function playNormal():void
{
removeEventListener(Event.ENTER_FRAME, onReverse);
gotoAndPlay(1);
Coal.play();
}
// Call this to play animation backward.
public function playReverse():void
{
Coal.stop();
gotoAndPlay(1);
addEventListener(Event.ENTER_FRAME, onReverse);
}
// This method does not need to be seen from the outside
// so declare it as private rather than public.
private function onReverse(e:Event):void
{
if (Coal.currentFrame > 1)
{
Coal.prevFrame();
}
else
{
playNormal();
}
}
// Call this to stop playing into any direction.
public function stopPlaying():void
{
stop();
Coal.stop();
removeEventListener(Event.ENTER_FRAME, onReverse);
}
}
}
Third. Avoid declaring functions inside functions. You can read up what closures are and how to handle them in AS3, but for the time being (and probably for the foreseeable future) you won't need them.
package
{
// Imports.
public class Main extends MovieClip
{
public var Fire:SimpleButton;
public var Stick:MarshmallowStick;
public function Main()
{
Fire.addEventListener(MouseEvent.MOUSE_DOWN, makeHot);
// The rest of the code.
}
function makeHot(e:MouseEvent):void
{
Stick.playNormal();
trace("OK");
}
Fourth. Do not subclass buttons. It is pretty enough to create a simple class-free button and subscribe to its MouseEvent.CLICK or MouseEvent.MOUSE_DOWN events to process all the necessary actions in some place that knows what this buttons is for. I said that above already. Feudal hierarchy. Button should fire an event, then its holder should capture that event and react. The button itself should not know where it is or what its purpose is, even less to try doing things.

AS3 Accessing a movieclip that is inside of another movie clip and a child

I hope the title isn't too confusing.
I know you are able to access a movieclip that is inside another movieclip, like I had done;
function allowResourceCollection():void {
caveman.btn_CollectResources2.addEventListener(TouchEvent.TOUCH_TAP, checkResourceCollection);
}
but I have now changed it so that inside of the movieclip caveman there is another movieclip cavemanmenu that is AS Linkage btncavemanMenu and inside of cavemanmenu is btn_CollectResources2 so I tried the following;
function allowResourceCollection():void {
caveman.cavemanmenu.btn_CollectResources2.addEventListener(TouchEvent.TOUCH_TAP, checkResourceCollection);
}
and I get this error;
TypeError: Error #1009: Cannot access a property or method of a null
object reference. at
stoneApp_new_fla::MainTimeline/allowResourceCollection()[stoneApp_new_fla.MainTimeline::frame1:104]
I'm so confused at what is going on. All I am trying to do is by clicking on caveman, cavemanmenu pops up and I am able to tap on btn_CollectResources2 which is nested inside of cavemanmenu. Here is all the code in the section so you understand;
var myMovieClip:MovieClip = new btncavemanMenu();
//Caveman Menu
function allowTapCaveman():void {
caveman.addEventListener(TouchEvent.TOUCH_TAP, cavemanMenu);
}
function cancelTapCaveman():void {
caveman.removeEventListener(TouchEvent.TOUCH_TAP, cavemanMenu);
}
function cavemanMenu(event:TouchEvent):void {
addChild(myMovieClip);
myMovieClip.x = caveman.x;
myMovieClip.y = caveman.y;
//myMovieClip.addEventListener(TouchEvent.TOUCH_TAP, cavemanMenu);
//caveman.gotoAndStop(2);
//trace('2');
if (caveman.currentFrame == 2){
cancelTapCaveman();
allowTapCavemanClose();
}
}
function allowTapCavemanClose():void {
caveman.addEventListener(TouchEvent.TOUCH_TAP, cavemanMenuClose);
}
function cancelTapCavemanClose():void {
caveman.removeEventListener(TouchEvent.TOUCH_TAP, cavemanMenuClose);
}
function cavemanMenuClose(event:TouchEvent):void {
cancelTapCavemanClose();
removeChild(myMovieClip);
//caveman.gotoAndStop(1);
allowTapCaveman();
//trace('1');
}
function allowResourceCollection():void {
caveman.btncavemanMenu.btn_CollectResources2.addEventListener(TouchEvent.TOUCH_TAP, checkResourceCollection);
}
function cancelResourceCollection():void {
caveman.btn_CollectResources2.removeEventListener(TouchEvent.TOUCH_TAP, checkResourceCollection);
}
function checkResourceCollection(event:TouchEvent):void {
if(remaningActions >= 1){
spawnWood();
spawnFood();
spawnStone();
remaningActions -= 1;
updateTextBox();
}
if(remaningActions <= 0){
trace("not enough actions")
}
}
As you can see, I used to have it so it would just change the frame in the movieclip caveman but because I need to create multiple caveman then I need to be able to have the menu pop up below them wherever they are and creating a child and bringing it in like that was the only way I could find. Thanks.
The event bubbles so the depth of the dispatching MovieClip does not matter. In fact, it is easier to let them be handled by caveman.
function allowResourceCollection():void {
caveman.addEventListener(TouchEvent.TOUCH_TAP, checkResourceCollection);
}
I highly recommend following naming conventions ...

Actionscript 3: How do I get all classes using one enter frame function?

I'm making an adventure game in AS3 and have many classes. I heard it is best for performance if there is only one Enter Frame function and all update functions run from that.
I currently have a mainGameLoop in my main.as, what is the best way for all my classes to contain an update function running from this single enter frame function?
Here is an example of what I've done to run an update function in my Player class, but I don't like this solution at all.
If anyone could help it'd be much appreciated, thanks.
public class Main extends MovieClip
{
// Initialising variables...
private var m_SceneHandler:SceneHandler;
private var m_UserInput:UserInput;
public function Main()
{
// Adding main update function...
addEventListener( Event.ENTER_FRAME, mainGameLoop );
// Creating the scene handler...
m_SceneHandler = new SceneHandler();
addChild( m_SceneHandler );
}
private function mainGameLoop( event:Event )
{
doUpdate();
}
private function doUpdate():void
{
// Update player...
if (m_SceneHandler.m_aCurrentScene[0].m_Player)
{
m_SceneHandler.m_aCurrentScene[0].m_Player.doUpdate();
}
}
Use the composite pattern and code to an IUpdateable interface.
package view {
public interface IUpdateable {
function doUpdate():void;
}
}
In your main game loop, just switch out which object(s) should be updated:
package{
public class Main extends MovieClip implements IUpdateable {
protected var updateChildren:Vector. = new Vector.();
//other logic would manage who is currently updateable and who is not
public function doUpdate():void {
for each (var updateable:IUpdateable) {
updateable.doUpdate();
}
}
}
}
Then, if there are subcomponents that need to update, they could also be IUpdateable, and the higher level IUpdateable could call the method.

AS3: if-function doesn't listen to a boolean in another class

So... I'm working on a chess-game, and trying to make it so that a "public static boolean" (turn) dictates which player can make a move. This boolean is in a class (Board.as) which imports all the classes for all the chess-pieces (e.g. QueenW.as (for the White Queen)).
I've tried multiple ways: Trying to make functions not run anymore, and replacing the pieces (which are buttons) to other objects (non-clickable movieclips). Decided to go with the latter. I've traced the boolean in a chess-piece class, as well as the Board-class, in an ENTER_FRAME function. Both seem to trace it correctly when the value changes.
Problem is: Flash doesn't remove the chess-pieces and replaces them with a non-clickable object, even though the class in which it should happen (Board.as) does listen to the boolean when tracing. Anybody knows a solution?
A little piece of my code, which is relative to the problem:
Board class (which is the Documentclass for my .fla file)
package
{
import QueenWclass; //imports the class used for example.
public class Board extends MovieClip
{
public static var turn:Boolean = new Boolean; //creates public static bool.
var queenW:QueenWclass = new QueenWclass(); //creates aforementioned chess-piece.
var queenWnoturn:QueenWnoturn = new QueenWnoturn; //creates a non-clickable object.
}
public function Board()
{
turn = true;
this.addEventListener(Event.ENTER_FRAME, frameEnter);
addChild(queenW); //adds pieces to the screen.
}
if (turn == true)
{
}
if (turn == false)
{
removeChild(queenW); //Removes chess-piece.
addChild(queenWnoturn); //Adds a non-clickable object.
}
}
And my QueenWclass.as class:
package
{
public class QueenWclass extends MovieClip
{
var queenW:QueenW = new QueenW();
}
public function QueenWclass()
{
addChild(queenW);
this.addEventListener(MouseEvent.CLICK, CLICKqueenW);
}
function CLICKqueenW(event.MouseEvent):void
{
Board.turn = false;
}
}
I hope I wrote this example correctly and understandably. There's no real timelimit to my project as I already had to turn it in an hour ago (but still got a 6/10 because of effort and how far I've come with this rather complex game). I just want to finish it for myself... Thanks in advance!
Maybe the code has not been copied correctly or there is a small problem.
This code:
if (turn == true)
{
}
if (turn == false)
{
removeChild(queenW); //Removes chess-piece.
addChild(queenWnoturn); //Adds a non-clickable object.
}
Will only run once, when "Board" is created, it will not run when the state of "turn" changes.
Well, you have nothing that's listening for the boolean's change. The code that's checking the boolean is located in constructor, while the actual change is done in a MouseEvent.CLICK event listener. You have to either implement a function that's called repeatedly via Event.ENTER_FRAME listening, SetInterval(), or TimerEvent.TIMER (with a timer), or implement a publicly available property as a function, that would check which turn is it and do corresponding actions. The latter is a little better, as it works only when something is changed.
private static var _turn:Boolean=false;
public static function get turn():Boolean { return _turn; } // getter part
public static function set turn(value:Boolean):void // setter part
{
if (_turn==value) return; // no need to change turn
_turn=value;
if (_turn) YouGetATurn(); else EnemyGetsATurn();
// this part is what will get called when you change Board.turn
}

Flash: Listen to all events of a type with one eventlistener

It's not a matter of life or death but I wonder if this could be possible:
I got a couple of events from one type of custom event (FormEvent) now I got a FormListener that listens to all those events and handles them according to the event type. Instead of adding one eventListener at the time I wish to add all events at once.
so now it looks like this:
private function addListeners():void {
addEventListener(FormEvent.SHOW_FORM, formListener);
addEventListener(FormEvent.SEND_FORM, formListener);
addEventListener(FormEvent.CANCEL_FORM, formListener);
}
private function formListener(event:formEvent):void {
switch(event.type){
case "show.form":
// handle show form stuff
break;
case "send.form":
// handle send form stuff
break;
case "cancel.form":
// handle cancel form stuff
break;
}
}
but instead of adding every event one at the time I would rather be doing something like
private function addListeners():void {
addEventListener(FormEvent.*, formListener);
}
I wonder if something like this is possible, i would love it. I work with loads of events :)
You only really need one event listener in this case anyhow. That listener will be listening for any change with the form and a parameter equal to what the change was becomes available to the event listener function. I will show you, but please remember that this is a pseudo situation and normally I wouldn't dispatch an event off of something as simple as a method call because the dispatch is implied so there is no real need to listen for it.
First the Custom Event
package com.yourDomain.events
{
import flash.events.Event;
public class FormEvent extends Event
{
//Public Properties
public static const CANCEL_FORM:int = "0";
public static const SHOW_FORM:int = "1";
public static const SEND_FORM:int = "2";
public static const STATE_CHANGED:String = "stateChanged";
//Private Properties
private var formState:int;
public function FormEvent(formState:int):void
{
super(STATE_CHANGED);
formState = formState;
}
}
}
So we have just created our custom event class and we have set it up so that we can catch the state through the listener function as I will demonstrate once done with the pseudo form class that will dispatch the for said custom event.
Remember that this is all hypothetical as I have no idea what your code looks like or how your implementing things. What is important is to notice that when I dispatch the event I need to send a parameter with it that reflects what the new state is.
package com.yourDomain.ui
{
import flash.events.Event;
import flash.events.EventDispatcher;
import com.yourDomain.events.FormEvent;
public class Form extends EventDispatcher
{
public function Form():void
{
//Anything you want form to do upon instantiation goes here.
}
public function cancelForm():void
{
dispatchEvent(new Event(FormEvent.CANCEL_FORM);
}
public function showForm():void
{
dispatchEvent(new Event(FormEvent.SHOW_FORM);
}
public function sendForm():void
{
dispatchEvent(new Event(FormEvent.SEND_FORM);
}
}
}
And finally we create the document class that will listen for it. Please know that I realize it isn't logical to create a listener that fires when you call a method of a class because you obviously know you called the method, but for this example it will due.
package com.yourDomain.ui
{
import com.yourDomain.ui.Form;
import com.yourDomain.events.FormEvent;
//Form is in the same package so we need not import it.
public class MainDocumentClass
{
private var _theForm:Form;
public function MainDocumentClass():void
{
_theForm = new Form();
_theForm.addEventListener(FormEvent.STATE_CHANGED, onFormStateChange, false, 0, true);
/*
The following three method calls each cause the
FormEvent.STATE_CHANGE event to be dispatched.
onFormStateChange is notified and checks what
the last change actually was.
*/
_theForm.cancelForm();
_theForm.showForm();
_theForm.sendForm();
}
private function onFormStateChange(e:FormEvent):void
{
switch(e.formState)
{
case CANCEL_FORM:
trace('The form was canceled');
break;
case SHOW_FORM:
trace('The form was revealed');
break;
case SEND_FORM:
trace('The form was sent');
break;
}
}
}
}
I hope that this was helpful, its late and I may have to revise some things later, but this should help get an understanding of how to make your own events and to customize how things work.
I don't know of any routines that let you do that directly, but you could write your own. The syntax here won't be perfect, but here's a first pass:
private function addMultipleEventListeners( evts:Array, callback:function ):void
{
for each( var evt:Event in evts )
{
addEventListener( evt, callback );
}
}
You could then call that routine like so:
var evts:Array = [ FormEvent.SHOW_FORM, FormEvent.SEND_FORM, FormEvent.CANCEL_FORM ];
addMultipleEventListeners( evts, formListener );