How should I set up my touch controls in starling? - button

I am developing a game in starling that has two controls. One will be the users left thumb touching anywhere on the left side of the screen, which drags the character up and down the y axis. The other control that I am having trouble implementing is a single button in the bottom right of the screen that will make the character fire a bullet.
My question is how do I set this up without having the character jump down to the bottom of the screen whenever the button is pressed.
Will I need to mess with multi-touch in order to get this running?
A more specific question I have is how do I define a rectangle for a sprite in starling? Since starling has no drawing API, I can't just do this...
touchLayer.graphics.beginFill(0x000000, 0);
touchLayer.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
touchLayer.graphics.endFill();
Currently my character drag is working, but the touch registers everywhere on the screen (im not sure how to make it just the left side of the screen...)
Any advise would be appreciated, thank you.
Here is the complete code for my InGame class as requested.
package screens
{
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.getTimer;
import objects.Enemy;
import objects.GameBackground;
import objects.Laser;
import objects.Scarlet;
import objects.SnowBall;
import starling.display.Button;
import starling.display.Sprite;
import starling.events.Event;
import starling.events.Touch;
import starling.events.TouchEvent;
import starling.utils.RectangleUtil;
import starling.utils.deg2rad;
public class InGame extends Sprite
{
private var startBtn:Button;
private var fireBtn:Button;
private var bg:GameBackground;
private var scarlet:Scarlet;
private var enemies:Array;
private var lasers:Array;
private var scarletLocation:Point;
private var lasersLayer:Sprite;
private var enemiesLayer:Sprite;
private var touchLayer:Sprite;
private var enemySpawnDelay:Number;
private var enemySpawnCounter:Number;
private var difficulty:Number;
private var difficultyRate:Number;
private var timePrevious:Number;
private var timeCurrent:Number;
private var elapsed:Number;
private var gameState:String;
private var playerSpeed:Number;
private const MIN_SPEED:Number = 650;
//private var scoreDistance:int;
private var gameArea:Rectangle;
private var touchArea:Rectangle;
private var shape:starling.display.Sprite = new starling.display.Sprite();
private var target:Point = new Point(100, 100);
private var touch:Touch;
private var touchX:Number;
private var touchY:Number;
public function InGame()
{
super();
this.addEventListener(starling.events.Event.ADDED_TO_STAGE, onAddedToStage);
}
private function onAddedToStage(event:Event):void
{
this.removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
drawGame();
}
private function drawGame():void
{
bg = new GameBackground();
this.addChild(bg);
scarlet = new Scarlet;
scarlet.x = stage.stageWidth/2;
scarlet.y = stage.stageHeight/2;
this.addChild(scarlet);
startBtn = new Button(Assets.getTexture("PlayBtn"));
startBtn.x = stage.stageWidth * 0.5 - startBtn.width * 0.5;
startBtn.y = stage.stageHeight * 0.5 - startBtn.height * 0.5 + 35;
this.addChild(startBtn);
fireBtn = new Button(Assets.getTexture("FireBtn"));
fireBtn.x = 675;
fireBtn.y = 435;
this.addChild(fireBtn);
//defines area scarlet can fly in
gameArea = new Rectangle(0, 15, stage.stageWidth, stage.stageHeight - 150);
}
public function disposeTemporarily():void
{
this.visible = false;
}
public function initialize():void
{
this.visible = true;
this.addEventListener(Event.ENTER_FRAME, checkElapsed);
scarlet.x = -stage.stageWidth;
scarlet.y = stage.stageHeight * 0.5;
gameState = "idle";
playerSpeed = 0;
difficultyRate = 0.3;
difficulty = 1;
enemySpawnDelay = enemySpawnCounter = 100;
enemies = new Array();
lasers = new Array();
scarletLocation = new Point(200, 400);
addEventListener(Event.ENTER_FRAME, update);
lasersLayer = new Sprite();
enemiesLayer = new Sprite();
touchLayer = new Sprite();
addChild(lasersLayer);
addChild(enemiesLayer);
addChild(touchLayer);
addEventListener(Event.ADDED_TO_STAGE, setupTouchLayer);
touchLayer.addEventListener(Event.TRIGGERED, shootLaser);
//scoreDistance = 0;
startBtn.addEventListener(Event.TRIGGERED, onStartBtnClick);
this.addEventListener(TouchEvent.TOUCH, onTouch);
}
private function onStartBtnClick(event:Event):void
{
startBtn.visible = false;
startBtn.removeEventListener(Event.TRIGGERED, onStartBtnClick);
launchScarlet();
}
private function launchScarlet():void
{
this.addEventListener(TouchEvent.TOUCH, onTouch);
this.addEventListener(Event.ENTER_FRAME, onGameTick);
}
private function onTouch(event:TouchEvent):void
{
touch = event.getTouch(stage);
touchX = touch.globalX;
touchY = touch.globalY;
target.x = event.touches[0].globalX;
target.y = event.touches[0].globalY;
}
private function onGameTick(event:Event):void
{
switch(gameState)
{
case"idle":
//Take off
if (scarlet.x < stage.stageWidth * 0.5 * 0.5)
{
scarlet.x += ((stage.stageWidth * 0.5 * 0.5 + 10) - scarlet.x) * 0.5;
scarlet.y = stage.stageHeight * 0.5;
playerSpeed += (MIN_SPEED - playerSpeed) * 0.05;
}
else
{
gameState = "flying";
}
break;
case"flying":
playerSpeed -= (playerSpeed - MIN_SPEED) * 0.01;
scarlet.y -= (scarlet.y - touchY) * 0.1;
if (-(scarlet.y - touchY) < 150 && -(scarlet.y - touchY) > -150)
{
scarlet.rotation = deg2rad(-(scarlet.y - touchY) * 0.075);
}
if (scarlet.y > gameArea.bottom - scarlet.height * 0.5)
{
scarlet.y = gameArea.bottom - scarlet.height * 0.5;
scarlet.rotation = deg2rad(0);
}
if (scarlet.y < gameArea.top + scarlet.height * 0.5)
{
scarlet.y = gameArea.top + scarlet.height * 0.5;
scarlet.rotation = deg2rad(0);
}
//scoreDistance += (playerSpeed * elapsed) * 0.1;
//trace(scoreDistance);
break;
case"over":
break;
}
}
//addapted from "Shoot"
private function setupTouchLayer(event:Event):void
{
touchLayer.graphics.beginFill(0x000000, 0);
touchLayer.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
touchLayer.graphics.endFill();
touchArea = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
}
private function shootLaser(event:TouchEvent):void
{
makeLaser(scarletLocation);
}
private function makeLaser(scarletLocation:Point):void
{
var newLaser:Laser = new Laser();
newLaser.x = scarletLocation.x;
newLaser.y = scarletLocation.y;
newLaser.xVel = 5;
newLaser.yVel = 5;
newLaser.addEventListener(Laser.PURGE_EVENT, purgeLaserHandler);
lasersLayer.addChild(newLaser);
lasers.push(newLaser);
}
private function purgeLaserHandler(event:Event):void
{
var targetLaser:Laser = Laser(event.target);
purgeLaser(targetLaser);
}
private function purgeLaser(targetLaser:Laser):void
{
targetLaser.removeEventListener(Laser.PURGE_EVENT, purgeLaserHandler);
try
{
var i:int;
for (i = 0; i < lasers.length; i++)
{
if (lasers[i].name == targetLaser.name)
{
lasers.splice(i, 1);
lasersLayer.removeChild(targetLaser);
i = lasers.length;
}
}
}
catch(e:Error)
{
trace("Failed to delete laser!", e);
}
}
private function makeEnemies():void
{
enemySpawnCounter++;
if (enemySpawnCounter > enemySpawnDelay)
{
enemySpawnCounter = 0;
enemySpawnDelay -= difficultyRate;
difficulty += difficultyRate;
makeEnemy();
}
}
private function makeEnemy():void
{
var i:int;
for (i = 0; i < Math.floor(difficulty); i++)
{
var newEnemy:Enemy = new SnowBall();
newEnemy.x = 925;
newEnemy.y = Math.random() * 375 + 50;
//trace(newEnemy.x); trace(newEnemy.y);
newEnemy.xVel = (-Math.random() * difficulty) - 5;
newEnemy.sinMeter = Math.random() * 10;
newEnemy.bobValue = Math.random() * difficulty;
newEnemy.addEventListener(Enemy.PURGE_EVENT, purgeEnemyHandler);
enemiesLayer.addChild(newEnemy);
enemies.push(newEnemy);
}
}
private function purgeEnemyHandler(event:Event):void
{
var targetEnemy:Enemy = Enemy(event.target);
purgeEnemy(targetEnemy);
}
private function purgeEnemy(targetEnemy:Enemy):void
{
targetEnemy.removeEventListener(Enemy.PURGE_EVENT, purgeLaserHandler);
try
{
var i:int;
for (i = 0; i < enemies.length; i++)
{
if (enemies[i].name == targetEnemy.name)
{
enemies.splice(i, 1);
enemiesLayer.removeChild(targetEnemy);
i = enemies.length;
}
}
}
catch(e:Error)
{
trace("Failed to delete enemy!", e);
}
}
private function newHitTest(laser:Laser):void
{
for each (var enemy:Enemy in enemies)
{
if (enemy.status != "Dead" && enemy.hitTest(new Point(laser.x, laser.y)))
{
enemy.destroy();
purgeLaser(laser);
}
}
}
private function checkElapsed(event:Event):void
{
timePrevious = timeCurrent;
timeCurrent = getTimer();
elapsed = (timeCurrent - timePrevious) * 0.001;
}
private function update():void
{
//trace(enemies.length, lasers.length);
for each (var enemy:Enemy in enemies)
{
enemy.update();
}
for each (var laser:Laser in lasers)
{
laser.update();
newHitTest(laser);
}
makeEnemies();
}
//addapted from "Shoot"
}
}

Oh wow, well a very simple way to solve this problem is to simply enable multi-touch.
Starling.multitouchEnabled = true;
However this still leaves the problem of my character jumping to the bottom of the screen when I press the button in the bottom right IF I am not touching the screen already to control the character... not really a big deal but it would look better if this didn't happen.

Related

Need soution for equalizer in flex?

I have developed a small application for testing 5 band equalizer in flex. I found the code in this link Flex Equalizer
The equalizer works fine.But i am not able to seek the desired position while playing the mp3 file.Following is my code....How to solve this problem?
import __AS3__.vec.Vector;
import mx.events.FlexEvent;
import spark.components.VSlider;
public static const BUFFER_SIZE:int = 8192;
public static const SAMPLE_RATE:int = 44100;
private var _Position:Number=0;
private var timer:Timer = new Timer(1000);
private const _soundURI:String = "testfile.mp3";
private var _out_snd:Sound = new Sound();
private const _eqL:EQ = new EQ();
private const _eqR:EQ = new EQ();
private var _loop_snd:Sound = new Sound();
// For storing dynamically created VSliders
private const _sliders_vect:Vector.<VSlider> = new Vector.<VSlider>();
private var _channel:SoundChannel = new SoundChannel();
private var _samples:ByteArray;
protected function view1_initializeHandler(event:FlexEvent):void
{
// TODO Auto-generated method stub
timer.addEventListener(TimerEvent.TIMER,timerFunction);
pgHolder.addEventListener(MouseEvent.CLICK,seekf);
setupEQ();
loadSound();
}
private function timerFunction(event:TimerEvent):void
{
_Position = _channel.position;
pgHolder.value=_Position;
}
private function seekf(event:MouseEvent):void
{
_channel.stop();
_Position = (pgHolder.contentMouseX/pgHolder.width)*_loop_snd.length;
startPlay();
}
private function loadSound():void
{
_Position=0;
_loop_snd.addEventListener(Event.COMPLETE, loadSoundComplete);
_loop_snd.addEventListener(IOErrorEvent.IO_ERROR, loadSoundError);
_out_snd.addEventListener(SampleDataEvent.SAMPLE_DATA, processSound);
_loop_snd.load(new URLRequest(_soundURI));
}
private function loadSoundComplete(event:Event):void
{
pgHolder.minimum=0;
pgHolder.maximum=_loop_snd.length;
timer.start();
startPlay();
}
private function startPlay():void
{
_channel=_out_snd.play(_Position);
}
private function loadSoundError(event:Event):void
{
trace("loadError");
}
// Create Sliders for changing EQ gain
private function setupEQ():void
{
var slider:VSlider;
for (var i:int = 0; i < _eqL.gains.length; i++) {
slider = new VSlider();
slider.x = (i * 35);
slider.y = 20;
slider.value = .9;
slider.maximum = 1;
slider.snapInterval=0.1;
slider.minimum = 0;
slider.addEventListener("change", changeEQHandler);
addElement(slider);
_sliders_vect[i] = slider;
}
var event:Event = new Event("change");
changeEQHandler(event);
}
private function processSound(event:SampleDataEvent):void
{
//trace("loading");
if(_Position>=_loop_snd.length)
{
_channel.stop();
}
_samples = new ByteArray();
var len:Number = _loop_snd.extract(_samples,BUFFER_SIZE);
var i:int=0;
var l:Number;
var r:Number;
if ( len < BUFFER_SIZE ) { // If end of MP3, start over
len += _loop_snd.extract(_samples,BUFFER_SIZE-len,0);
}
_samples.position = 0;
trace("len" + len + "//" + _channel.position + "//" +_samples.length);
while (i < BUFFER_SIZE) {
event.data.writeFloat(_eqL.compute(_samples.readFloat()));
event.data.writeFloat(_eqR.compute(_samples.readFloat()));
i++;
}
}
// Update EQ gains when sliders are changed
private function changeEQHandler(event:Event):void
{
var i:int = 0;
for(i = 0; i < _eqL.gains.length; i++){
_eqL.gains[i] = _sliders_vect[i].value * 2;
}
for(i = 0; i < _eqR.gains.length; i++){
_eqR.gains[i] = _sliders_vect[i].value * 2;
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:HSlider width="100%" height="100%" id="pgHolder">
</s:HSlider>
When you handle the slider change, I see you calculate the new _Position, but _Position is not bindable and its never used set set the player position.
This is just pseudo-code, but shouldn't you do something like:
private function seekf(event:MouseEvent):void
{
_channel.stop();
_channel.position = (pgHolder.contentMouseX/pgHolder.width)*_loop_snd.length;
_channel.start();
}
Just looking at your code, when you set _Position = _channel.position, you are simply getting a value, not a reference. My guess is that you need to set _channel.position

Checkbox itemrender of Advanced grid does not hold proper selections on next open event of tree in Flex 4

I have a checkbox in AdvancedDataGrid as GroupItemrenderer.I have selected certain child nodes in tree and closed its parent,later when I reopen the same parent node,selected child nodes are not those that i selected.How to retain the correct selections in checkbox.??
Also am unable to set the value for checkbox (GroupItemRenderer) by default from component and also unable to access the value for checkbox in Data property.
package
{
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.ui.Keyboard;
import mx.collections.ICollectionView;
import mx.collections.IHierarchicalCollectionView;
import mx.collections.IHierarchicalData;
import mx.collections.IViewCursor;
import mx.controls.AdvancedDataGrid;
import mx.controls.Alert;
import mx.controls.CheckBox;
import mx.controls.Image;
import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
import mx.controls.advancedDataGridClasses.AdvancedDataGridGroupItemRenderer;
import mx.controls.advancedDataGridClasses.AdvancedDataGridListData;
import mx.core.FlexGlobals;
import mx.core.mx_internal;
use namespace mx_internal;
public class CheckADGRenderer extends AdvancedDataGridGroupItemRenderer
{
protected var myImage:Image;
public var status:String = "false";
// set image properties
private var imageWidth:Number = 6;
private var imageHeight:Number = 6;
private var inner:String = "inner.png";
protected var myCheckBox:CheckBox;
static private var STATE_SCHRODINGER:String = "schrodinger";
static private var STATE_CHECKED:String = "checked";
static private var STATE_UNCHECKED:String = "unchecked";
public function CheckADGRenderer ()
{
super();
mouseEnabled = false;
}
private function toggleParents(item:Object,adg:AdvancedDataGrid,state:String):void
{
if (item == null)
{
return;
}
else
{
item.#state = false;
toggleParents(adg.getParentItem(item), adg, getState (adg, adg.getParentItem(item)));
}
}
private function toggleChildren (item:Object, adg:AdvancedDataGrid, state:String):void
{
if (item == null)
{
return;
}
else
{
//item.#state = state;
var adgCollection:IHierarchicalCollectionView = adg.dataProvider as IHierarchicalCollectionView;
var adgHD:IHierarchicalData = adgCollection.source;
if (adgHD.hasChildren(item))
{
var children:ICollectionView = adgCollection.getChildren (item);
var cursor:IViewCursor = children.createCursor();
while (!cursor.afterLast)
{
toggleChildren(cursor.current, adg, state);
cursor.moveNext();
}
}
}
}
private function getState(adg:AdvancedDataGrid, parent:Object):String
{
var noChecks:int = 0;
var noCats:int = 0;
var noUnChecks:int = 0;
if (parent != null)
{
var adgCollection:IHierarchicalCollectionView = adg.dataProvider as IHierarchicalCollectionView;
var cursor:IViewCursor = adgCollection.getChildren(parent).createCursor();
}
if ((noChecks > 0 && noUnChecks > 0) || (noCats > 0))
{
return STATE_SCHRODINGER;
}
else if (noChecks > 0)
{
return STATE_CHECKED;
}
else
{
return STATE_UNCHECKED;
}
}
private function imageToggleHandler(event:MouseEvent):void
{
myCheckBox.selected = !myCheckBox.selected;
checkBoxToggleHandler(event);
}
var selectArr:Array = new Array();
private function checkBoxToggleHandler(event:MouseEvent):void
{
if (data)
{
var myListData:AdvancedDataGridListData = AdvancedDataGridListData(this.listData);
var selectedNode:Object = myListData.item;
var adg:AdvancedDataGrid = AdvancedDataGrid(myListData.owner);
var toggle:Boolean = myCheckBox.selected;
if (toggle)
{
toggleChildren(data, adg, STATE_CHECKED);
}
else
{
toggleChildren(data, adg, STATE_UNCHECKED);
}
var parent:Object = adg.getParentItem (data);
toggleParents (parent, adg, getState (adg, parent));
//Alert.show(selectArr.toString()+"\t\t"+selectArr.length+"\t\t"+selectArr[0].length+"\t\t"+adg.selectedIndices.length);
}
}
override protected function createChildren():void
{
super.createChildren();
myCheckBox = new CheckBox();
myCheckBox.setStyle( "verticalAlign", "middle" );
myCheckBox.addEventListener( MouseEvent.CLICK, checkBoxToggleHandler );
addChild(myCheckBox);
}
private function setCheckState (checkBox:CheckBox, value:Object, state:Boolean):void
{
if (state == STATE_CHECKED)
{
checkBox.selected = state;
}
else if (state == STATE_UNCHECKED)
{
checkBox.selected = false;
}
else if (state == STATE_SCHRODINGER)
{
checkBox.selected = false;
}
checkBox.selected = state;
}
override public function set data(value:Object):void
{
super.data = value;
var myListData:AdvancedDataGridListData = AdvancedDataGridListData(this.listData);
//var adg:AdvancedDataGrid = AdvancedDataGrid(myListData.owner);
var selectedNode:Object = myListData.item;
myCheckBox.selected = AdvancedDataGridListData(super.listData).item.show;
//var adg:AdvancedDataGrid = AdvancedDataGrid(myListData.owner);
//setCheckState (myCheckBox, value, Boolean(value.state));
}
override protected function commitProperties():void
{
super.commitProperties();
var dg:AdvancedDataGrid = AdvancedDataGrid(listData.owner);
var column:AdvancedDataGridColumn =
dg.columns[listData.columnIndex];
label.wordWrap = dg.columnWordWrap(column);
}
/**
* #private
*/
override protected function measure():void
{
super.measure();
var w:Number = data ? AdvancedDataGridListData(listData).indent : 0;
if (disclosureIcon)
w += disclosureIcon.width;
if (icon)
w += icon.measuredWidth;
if (myCheckBox)
w += myCheckBox.measuredWidth;
// guarantee that label width isn't zero because it messes up ability to measure
if (label.width < 4 || label.height < 4)
{
label.width = 4;
label.height = 16;
}
if (isNaN(explicitWidth))
{
w += label.getExplicitOrMeasuredWidth();
measuredWidth = w;
}
else
{
label.width = Math.max(explicitWidth - w, 4);
}
measuredHeight = label.getExplicitOrMeasuredHeight();
if (icon && icon.measuredHeight > measuredHeight)
measuredHeight = icon.measuredHeight;
if (myCheckBox && myCheckBox.measuredHeight > measuredHeight)
measuredHeight = myCheckBox.measuredHeight;
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
if(super.data)
{
if (super.icon != null)
{
myCheckBox.x = super.icon.x;
myCheckBox.y = (unscaledHeight - myCheckBox.height) / 2;
super.icon.x = myCheckBox.x + myCheckBox.width + 17;
if (icon.x + icon.width > unscaledWidth)
icon.setActualSize(0, unscaledHeight);
super.label.x = super.icon.x + super.icon.width + 3;
super.label.setActualSize(Math.max(unscaledWidth - super.label.x, 4), unscaledHeight);
}
else
{
myCheckBox.x = super.label.x;
myCheckBox.y = (unscaledHeight - myCheckBox.height) / 2;
super.label.x = myCheckBox.x + myCheckBox.width + 17;
super.label.setActualSize(Math.max(unscaledWidth - super.label.x, 4), unscaledHeight);
}
if (myCheckBox.x + myCheckBox.width > unscaledWidth)
myCheckBox.visible = false;
}
trace(label.width);
}
}
}
I am using 2D array as dataprovider to ADG.
My post :
how to add an attribute to an existing array dynamically in Flex , is associated with the above post.
I suspect you haven't written any code to set the default state of the Checkbox based on data.
Generically, your itemRenderer's Checkbox state should be stored as part of the data. When the
itemRenderer is initialized, set the checkbox to checked--or not--based on the property in your data element. When the Checkbox is clicked; change that same property in your data element.
This approach will sync your itemRenderer's display state up with your data.
If you want a more specific answer, you'll have to share some code so we can see what you're doing.

How to change the loading clock in Flex

How can I replace the loading clock in Flex at the cursor to something like loading wheel in the middle of page instead of cursor
I loathe that little clock. A clock on the mouse just tells the user that something is busy, but they don't know what. It is much better to display a progress indicator visually NEAR the thing that it is showing the progress of!
So, my solution is to enforce a ban on CursorManager, and instead supply your own progress indicator.
Example: A submit button in a form. You know that the submittal is asynchronous and it will take an indeterminate amount of time. So after the user clicks the button and the request is executed, display a little spinner to the direct right of the button. When the request is complete, hide the spinner. It's very sad to see a user who is worried that her actions did not accomplish anything--so give them a way of determining that your application is indeed functioning!
To go along with Jonathon Dumaine's answer, here's an example of the Spinner class I use as a busy indicator in my apps. Just remember to call the stop() method when you first load it since it will use memory in your app if it's playing even when visible is set to false. You can call the play() method when you want it to start spinning again.
Spinner.as
package {
import flash.events.TimerEvent;
import flash.utils.Timer;
import mx.core.FlexGlobals;
import mx.core.UIComponent;
import mx.events.FlexEvent;
import mx.styles.CSSStyleDeclaration;
import mx.styles.StyleManager;
[Style(name="tickColor",type="uint",format="Color",inherit="no")]
public class Spinner extends UIComponent {
private static var STYLE_TICK_COLOR:String = "tickColor";
private var tickColorChanged:Boolean;
private static var classConstructed:Boolean = classConstruct();
// Make sure we create the ticks the first time updateDisplayList is called
private var creation:Boolean = true;
private var fadeTimer:Timer;
private var _isPlaying:Boolean;
private var _numTicks:int = 12;
private var numTicksChanged:Boolean;
private var _size:Number = 30;
private var sizeChanged:Boolean;
private var _tickWidth:Number = 3;
private var tickWidthChanged:Boolean;
private var _speed:int = 1000;
[Bindable] public var fadeSpeed:int = 600;
public var autoPlay:Boolean = true;
public function Spinner() {
super();
addEventListener(FlexEvent.CREATION_COMPLETE, handleCreationComplete);
addEventListener(FlexEvent.REMOVE, handleUnloading)
}
private function handleCreationComplete(e:FlexEvent):void {
removeEventListener(FlexEvent.CREATION_COMPLETE, handleCreationComplete);
if (autoPlay) {
play();
}
}
/**
* Set the height and width based on the size of the spinner. This should be more robust, but oh well.
*/
override protected function measure():void {
super.measure();
width = _size;
height = _size;
}
/**
* Override the updateDisplayList method
*/
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
if (tickColorChanged || numTicksChanged || sizeChanged || tickWidthChanged || creation) {
creation = false;
// Find out whether it's playing so we can restart it later if we need to
var wasPlaying:Boolean = _isPlaying;
// stop the spinning
stop();
// Remove all children
for (var i:int = numChildren - 1; i >= 0; i--) {
removeChildAt(i);
}
// Re-create the children
var radius:Number = size / 2;
var angle:Number = 2 * Math.PI / _numTicks; // The angle between each tick
var tickWidth:Number = (_tickWidth != -1) ? _tickWidth : size / 10;
var tickColor:uint = getStyle(STYLE_TICK_COLOR);
var currentAngle:Number = 0;
for (var j:int = 0; j < _numTicks; j++) {
var xStart:Number = radius + Math.sin(currentAngle) * ((_numTicks + 2) * tickWidth / 2 / Math.PI);
var yStart:Number = radius - Math.cos(currentAngle) * ((_numTicks + 2) * tickWidth / 2 / Math.PI);
var xEnd:Number = radius + Math.sin(currentAngle) * (radius - tickWidth);
var yEnd:Number = radius - Math.cos(currentAngle) * (radius - tickWidth);
var t:Tick = new Tick(xStart, yStart, xEnd, yEnd, tickWidth, tickColor);
t.alpha = 0.1;
this.addChild(t);
currentAngle += angle;
}
// Start the spinning again if it was playing when this function was called.
if (wasPlaying) {
play();
}
tickColorChanged = false;
numTicksChanged = false;
sizeChanged = false;
tickWidthChanged = false;
}
}
private static function classConstruct():Boolean {
if (!FlexGlobals.topLevelApplication.styleManager.getStyleDeclaration("Spinner")) {
// If there is no CSS definition for StyledRectangle,
// then create one and set the default value.
var newStyleDeclaration:CSSStyleDeclaration = new CSSStyleDeclaration();
newStyleDeclaration.setStyle(STYLE_TICK_COLOR, 0x000000);
FlexGlobals.topLevelApplication.styleManager.setStyleDeclaration("Spinner", newStyleDeclaration, true);
}
return true;
}
override public function styleChanged(styleProp:String):void {
if (styleProp == STYLE_TICK_COLOR) {
tickColorChanged = true;
invalidateDisplayList();
}
}
/**
* Begin the circular fading of the ticks.
*/
public function play():void {
if (! _isPlaying) {
fadeTimer = new Timer(speed / _numTicks, 0);
// addEventListener for the ticking going forward
fadeTimer.addEventListener(TimerEvent.TIMER, handleTicking);
fadeTimer.start();
_isPlaying = true;
}
}
/**
* Start the Tick at each Timer.
*/
public function handleTicking(e:TimerEvent):void {
var tickNum:int = int(fadeTimer.currentCount % _numTicks);
if (numChildren > tickNum) {
var tick:Tick = getChildAt(tickNum) as Tick;
tick.fade(fadeSpeed != 1 ? fadeSpeed : speed * 6 / 10);
}
}
/**
* Start the Tick at each Timer.
*/
public function handleUnloading(e:FlexEvent):void {
stop();
removeEventListener(FlexEvent.REMOVE, handleUnloading);
trace("Removing "+this.uid.toString());
}
/**
* Stop the spinning.
*/
public function stop():void {
if (fadeTimer != null && fadeTimer.running) {
_isPlaying = false;
fadeTimer.removeEventListener(TimerEvent.TIMER, handleTicking);
fadeTimer.stop();
}
}
/**
* The overall diameter of the spinner; also the height and width.
*/
[Bindable]
public function set size(value:Number):void {
if (value != _size) {
_size = value;
sizeChanged = true;
invalidateDisplayList();
invalidateSize();
}
}
public function get size():Number {
return _size;
}
/**
* The number of 'spokes' on the spinner.
*/
[Bindable]
public function set numTicks(value:int):void {
if (value != _numTicks) {
_numTicks = value;
numTicksChanged = true;
invalidateDisplayList();
}
}
public function get numTicks():int {
return _numTicks;
}
/**
* The width of the 'spokes' on the spinner.
*/
[Bindable]
public function set tickWidth(value:int):void {
if (value != _tickWidth) {
_tickWidth = value;
tickWidthChanged = true;
invalidateDisplayList();
}
}
public function get tickWidth():int {
return _tickWidth;
}
/**
* The duration (in milliseconds) that it takes for the spinner to make one revolution.
*/
[Bindable]
public function set speed(value:int):void {
if (value != _speed) {
_speed = value;
fadeTimer.stop();
fadeTimer.delay = value / _numTicks;
fadeTimer.start();
}
}
public function get speed():int {
return _speed;
}
public function get isPlaying():Boolean {
return _isPlaying;
}
}
}
Tick.as
package {
import flash.display.Sprite;
import mx.effects.Fade;
public class Tick extends Sprite {
private var tickFade:Fade = new Fade(this);
public function Tick(fromX:Number, fromY:Number, toX:Number, toY:Number, tickWidth:int, tickColor:uint) {
this.graphics.lineStyle(tickWidth, tickColor, 1.0, false, "normal", "rounded");
this.graphics.moveTo(fromX, fromY);
this.graphics.lineTo(toX, toY);
}
public function fade(duration:Number):void {
tickFade.alphaFrom = 1.0;
tickFade.alphaTo = 0.1;
tickFade.duration = duration;
tickFade.play();
}
}
}
You can hide the cursor rather than calling setBusyCursor on the CursorManager use http://www.igorcosta.com/flex3/doc/mx/managers/CursorManager.html#hideCursor() then just toggle the visibility of an overlay with your loading graphic.
You can use CursorManager.showCursor(); and CursorManager.removeBusyCursor(); to show and remove busy cursor.

Flex 3: Timer Won't Stop

I'm using Flex 3 with Flash 9.
I'm trying to make a timer that will run once after 1 second. Unfortunately, me timer keeps repeating. How do I get it to stop?
public var myTimer:Timer = new Timer(1000, 1);
private function visFunc():void {
myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, imageProducer);
myTimer.start();
}
private function imageProducer(event:TimerEvent):void {
var img:Image = new Image;
img.source = image_path;
img.x = 56;
img.y = (tf.y + tf.height + 40);
radioVBox.addChildAt(img, 0);
this.height = radioVBox.y + radioVBox.height +110;
myTimer.stop();
myTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, imageProducer);
}
Thank you.
-Laxmidi
I'd change my code to the following and run some tests, since I don't see any major issues... HOWEVER, if you're not debugging and/or don't have a debugger version of flashplayer running, something may be blowing up on the vbox.addChild line (for example -- null vbox). If your imageProducer function is cool, then your issue is outside of the 'calling' function.
private var myTimer : Timer;
private function visFunc():void
{
if(myTimer != null)
{
tearDownTimer();
}
myTimer = new Timer(1000,1);
myTimer.addEventListener(TimerEvent.TIMER_COMPLETE, imageProducer);
myTimer.start();
}
private function tearDownTimer():void
{
if(myTimer)
{
myTimer.stop();
myTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, imageProducer);
myTimer = null;
}
}
private function imageProducer(event:TimerEvent):void
{
var img:Image = new Image();
img.source = image_path;
img.x = 56;
img.y = (tf.y + tf.height + 40);
radioVBox.addChildAt(img, 0);
this.height = radioVBox.y + radioVBox.height +110;
tearDownTimer();
}

Creating a parallax on a tiling background

I am using the blitting technique that Jeff from 8bitrocket.com uses for creating tiles. I am trying to paint 2 layers of bitmapdata onto a bitmap. One the first layer is the background ( 1 image). and the second layer is the tiles. In that class below. the updateMap is the method that gets called in the loop to repaint the image.
package com.eapi
{
/**
* ...
* #author Anthony Gordon
*/
import com.objects.XmlManager;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.*;
import flash.display.BitmapData;
import flash.display.Bitmap
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.display.DisplayObject;
public class EngineApi extends MovieClip
{
public var images:Array;
public var world:Array;
//w stands for world, how big it is in columns and rows
private var wCols:Number = 50;
private var wRows:Number = 16;
public var wWidth:Number;
public var wHeight:Number;
//v stands for view, which means your field of view
public var vRows:Number;
public var vCols:Number;
public var vWidth:Number = 540;
public var vHeight:Number = 360;
//how big your indivual tile is
public var tileW:Number = 80;
public var tileH:Number = 80;
public var offsX:Number = 0;
public var offsY:Number = 0;
public var xEnd:Number = 0;
public var yEnd:Number = 0;
public var tilex:int;
public var tiley:int;
public var scrollx:Number = 0;
public var scrolly:Number = 0;
private var screen:Bitmap;
private var canvas:BitmapData;
private var buffer:BitmapData;
public var mapHolder:Array;
private var scrollLoop:Boolean;
private var minLoop:Number;
private var maxLoop:Number;
public var currentMap:Number = 0;
private var queue:Array;
public var currentCol:Number = 0;
public var currentRow:Number = 0;
public var enviroment:Array;
public var currentTileSheet:Number = 0;
private var layer1:Sprite;
private var layer2:Sprite;
private var layer3:Sprite;
private var layer4:Sprite;
private var layer5:Sprite;
public var background:BitmapData
protected var stageObject:Array;
protected var gameObjects:Array;
public function EngineApi(w:Number = 540,h:Number = 360, tw:Number = 50, th:Number = 50)
{
stageObject = new Array();
gameObjects = new Array();
//Add Layers
layer1 = new Sprite();
layer2 = new Sprite();
layer3 = new Sprite();
layer4 = new Sprite();
layer5 = new Sprite();
//end
images = new Array();
vWidth = w;
vHeight = h;
tileW = tw;
tileH = th;
queue = new Array();
mapHolder = new Array();
vCols = Math.floor(vWidth/tileW);
vRows = Math.floor(vHeight/tileH);
wWidth = wCols * tileW;
wHeight = wRows * tileH;
canvas = new BitmapData(vWidth,vHeight,true,0x000000);
buffer = new BitmapData(vWidth + 2 * tileW, vHeight + 2 * tileH ,false,0x000000);
screen = new Bitmap(canvas);
addChild(screen);
addChild(layer1);
addChild(layer2);
addChild(layer3);
addChild(layer4);
addChild(layer5);
}
public function addGameChild(object:IGameObject, layer:Number):void
{
switch(layer)
{
case 1:
layer1.addChild(DisplayObject(object));
break;
case 2:
layer2.addChild(DisplayObject(object));
break;
case 3:
layer3.addChild(DisplayObject(object));
break;
case 4:
layer4.addChild(DisplayObject(object));
break;
case 5:
layer5.addChild(DisplayObject(object));
break;
default:
}
if (object.IsDisplay == true)
gameObjects.push(object);
stageObject.push(object);
}
public function UpDateMap():void
{
offsX += scrollx;
offsY += scrolly;
tilex = int(offsX/tileW);
tiley = int(offsY/tileH);
xEnd = tilex + vWidth;
yEnd = tiley + vHeight;
var tileNum:int;
var tilePoint:Point = new Point(0,0);
var tileRect:Rectangle = new Rectangle(0, 0, tileW, tileH);
var rowCtr:int=0;
var colCtr:int=0;
for (rowCtr=0; rowCtr <= vRows; rowCtr++) {
for (colCtr = 0; colCtr <= vCols; colCtr++) {
currentCol = colCtr+tilex;
currentRow = rowCtr+tiley;
tileNum = mapHolder[currentMap][rowCtr+tiley][colCtr+tilex];
tilePoint.x = colCtr * tileW;
tilePoint.y = rowCtr * tileH;
tileRect.x = int((tileNum % 100))* tileW;
tileRect.y = int((tileNum / 100))* tileH;
buffer.copyPixels(images[currentTileSheet],tileRect,tilePoint);
}
}//End Loop
var bgRect:Rectangle = new Rectangle(0, 0, 544, 510);
var bgPoint:Point = new Point(0, 0);
var bufferRect:Rectangle = new Rectangle(0,0,vWidth,vHeight);
var bufferPoint:Point = new Point();
bufferRect.x = offsX % tileW;
bufferRect.y = offsY % tileH;
canvas.copyPixels(background,bgRect,bgPoint);
canvas.copyPixels(buffer,bufferRect,bufferPoint);
}//End UpdateMap
public function StartRender():void
{
addEventListener(Event.ENTER_FRAME, loop);
}
protected function loop(e:Event):void
{
UpDateMap();
UpdateObjects();
}
protected function UpdateObjects():void
{
for (var i:Number = 0; i < stageObject.length; i++)
{
stageObject[i].UpdateObject();
}
for (var g:Number = 0; g < stageObject.length; g++)
{
if (stageObject[g].Garbage && stageObject[g].IsDisplay)
{
removeChild(DisplayObject(stageObject[g]));
stageObject[g] = null;
}
else if (stageObject[g].Garbage == true && stageObject[g].IsDisplay == false)
{
stageObject[g] = null;
}
}
}
public function StopRender():void
{
removeEventListener(Event.ENTER_FRAME, loop);
}
}
}
It's not the complete code, but if I remove canvas.copyPixels(background,bgRect,bgPoint); or canvas.copyPixels(buffer,bufferRect,bufferPoint); I can see either or. If I paint them both then I can only see the one that painted last. My tile image is 128 x 32. 0 - 3. array 3 is transparent image. I used that hoping that I could see through the image and see the background. I was wrong.
At first it was an all black background, but then I changed the transparent constructor to true on the buffer variable. Now it shows a white background (like the stage), but still no background image.
I'm not sure I completely understand the example, but it looks like the issue is that you're using copyPixels--this should replace the old pixels in the canvas bmp with new values.
Try using draw for the foreground instead:
canvas.copyPixels(background, bgRect, bgPoint);
canvas.draw(buffer, transform, null, null, clipRect);
Also, I'm not sure why you're drawing the background image to a different rect than the foreground? There may be something there.
I took a seperate movieclip and used it as a parallax behind the blitting tiles.

Resources