I am trying to use the Five3d package to draw a sprite in 3d and animate it then create a shape on the root of the app and overlay it over the sprite in 3d as it moves. I have tried everything to get it to work but can't seem to get it to line up properly. It looks like the perspective is out. I had it working after inspecting the relationship between the 3d x,y and global x,y which lead me to write the method 'local3dToGlobalXY' shown below but this only worked when the stage was 1024 / 768, strange. I was told that the Sprite2d in the Five3d package does this but can't get that to work either. It has the same results as my 'local3dToGlobalXY' method.
I have put an example up here and the project for the example is here.
The red star is a sprite that is in 3d and the two crosshairs are draw into different scopes. One is drawn into a Sprite2d which is what I was recomended to do and the other is drawn into the root.
Hopefully someone has encountered this or can point out what I have done wrong.
Thanks, J
/**
* ...
* #author James Jordan
*/
public class Main extends Sprite
{
private var s3D:Sprite3D;
private var _scene:Scene3D;
private var _s:Sprite3D;
private var star3D:Shape3D;
private var t:Timer;
private var crossHairs2D:Sprite;
private var otherPlane:Sprite2D;
private var _plane:Sprite3D;
private var crossHairsRoot:Sprite;
private var animationPlane:Sprite3D;
private var crossHairsPlane:Sprite2D;
private var starsPlane:Sprite3D;
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
animationPlane = new Sprite3D();
starsPlane = new Sprite3D();
animationPlane.addChild(starsPlane);
crossHairsPlane = new Sprite2D();
animationPlane.addChild(crossHairsPlane);
_scene = new Scene3D();
_scene.x = stage.stageWidth / 2;
_scene.y = stage.stageHeight / 2;
_scene.addChild(animationPlane);
addChild(_scene);
star3D = drawStar(starsPlane);
crossHairs2D = drawGlobalShape(crossHairsPlane, 0xff000, 10);
crossHairsRoot = drawGlobalShape(root, 0x0000ff, 5);
t = new Timer(1000, 0);
t.addEventListener(TimerEvent.TIMER, onTimer);
t.start();
}
private function onTimer(e:TimerEvent):void
{
TweenLite.to(star3D, 1, { x:(Math.random() * stage.stageWidth) - (stage.stageWidth/2), y:(Math.random() * stage.stageHeight) - (stage.stageHeight / 2), z:(Math.random() * 500), onUpdate:onTweenUpdate } );
}
private function onTweenUpdate():void
{
var p:Point = local3dToGlobalXY(starsPlane, new Point3D(star3D.x, star3D.y, star3D.z));
crossHairs2D.x = p.x - stage.stageWidth / 2;
crossHairs2D.y = p.y - stage.stageHeight / 2;
crossHairsRoot.x = p.x;
crossHairsRoot.y = p.y;
}
private function local3dToGlobalXY(_s:Sprite3D, p3d:Point3D):Point
{
var m:Matrix3D = _s.concatenatedMatrix;
var newP3d:Point3D = m.transformPoint(p3d);
var globalPoint:Point = _s.local3DToGlobal(new Vector3D(newP3d.x, newP3d.y, newP3d.z));
return globalPoint;
}
private function drawStar(parent:Sprite3D):Shape3D {
var starShape:Shape3D = new Shape3D();
DrawingUtils.star(starShape.graphics3D, 5, 30, 20, (45 / 180) * Math.PI, 0xff0000);
parent.addChild(starShape);
return starShape;
}
private function drawGlobalShape(p:*, c:uint, lineWeight:Number):Sprite
{
var d:Sprite = new Sprite();
d.graphics.lineStyle(lineWeight, c);
d.graphics.moveTo( -20, 0);
d.graphics.lineTo(20, 0);
d.graphics.moveTo( 0, -20);
d.graphics.lineTo(0, 20);
d.graphics.endFill();
p.addChild(d);
return d;
}
}
It's your perspective and Z coordinate. Remove the random Z tween in the TweenLite.to statement and you'll see that they line up perfectly.
What exactly are you trying to do here? Other than offset the star, the Z param doesn't seem to add anything (scaling based on distance from observer)?
Related
I used a creative cow tutorial to create my own snow globe that moves and snow reactivates - it really is a great tutorial.
What I'm trying to do is Change between 3 Movie clips in the ActionScript - But each time I add my movie clip names - Or try and add a simple visibility code I break my snow globe actions.
I have my MovieClip instances named friendsSceneThree, BuddiesSceneTwo and HatsOffSceneOne. I would think they'd be good but somewhere I'm missing something. Right now I can't get the code to even SEE The movieclips I'm getting a simple:
TypeError: Error #1006: value is not a function.at SnowGlobeContainer/update()
Down in the 'if drag' Update is where I'd like to Change from One MClip to the Next.
What Am I Not Seeing?!?! Any help would be greatly appreciated! Thanks
Here is the ActionScript:
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.geom.Point;
public class SnowGlobeContainer extends Sprite {
public var snowForeground:SnowGeneratorCircle;
public var snowBackground:SnowGeneratorCircle;
public var friendsSceneThree:MovieClip;
public var buddiesSceneTwo:MovieClip;
public var hatsOffSceneOne:MovieClip;
public var drag:Boolean = false;
public var over:Boolean = false;
public var startPos:Point = new Point;
public var mouseDownOffset:Point = new Point;
public var bounds:Rectangle = new Rectangle;
public var vel:Point = new Point(0,0);
public var pos:Point = new Point(x,y);
public var old:Point = new Point(x,y);
public var gravity:Number = 5+(Math.random()*1);
public var restitution:Number = 0.5;
public var friction:Number = 0.9;
public function SnowGlobeContainer() {
// save some initial persistant properties
startPos.x = this.x;
startPos.y = this.y;
old.x = this.x;
old.y = this.y;
bounds.x = 0;
bounds.y = 0;
bounds.width = 600;
bounds.height = startPos.y;
// add mouse interaction listeners and show the cursor on rollover
this.mouseChildren = false;
this.useHandCursor = true;
this.buttonMode = true;
this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
this.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
this.addEventListener(Event.ENTER_FRAME, update);
}
protected function onMouseOver(e:MouseEvent=null):void { over = true; }
protected function onMouseOut(e:MouseEvent=null):void { over = false; }
protected function onMouseDown(e:MouseEvent=null):void {
// Save the offset of your mouse when you first start dragging. Same functionality as startDrag(false)
mouseDownOffset.x = mouseX;
mouseDownOffset.y = mouseY;
drag = true;
}
protected function onMouseUp(e:MouseEvent=null):void {
vel.x = vel.y = 0;
pos.x = x;
pos.y = y;
drag = false;
}
public function update(e:Event):void {
// this if/else statement controls the mouse over and out instead of using event listeners
if(mouseY < -175 || mouseY > 175 || mouseX < -175 || mouseX > 175){
if(over) onMouseOut();
}else{
if(!over) onMouseOver();
}
if(drag){
// drag around..
this.x = parent.mouseX - mouseDownOffset.x;
this.y = parent.mouseY - mouseDownOffset.y;
// keep this thing on the table :)
if(y >= bounds.height) y = bounds.height;
// if you "shake" or move the mouse quickly, we are going to reset the snow particles
var d:Point = new Point(Math.abs(old.x - x), Math.abs(old.y - y));
if(d.x > 50 || d.y > 50 ){
snowForeground.reset();
snowBackground.reset();
friendsSceneThree.visible = false;
}
// update the history position
old.x = x;
old.y = y;
vel.y = (y-old.y)/2;
}else{
// if you drop this object it should have a bit of realistic falling..
vel.y += gravity;
pos.y += vel.y;
// bounce
if(pos.y > bounds.height){
pos.y = bounds.height;
vel.y *= -(Math.random()*restitution);
}
y = pos.y;
}
}
}
}
I appreciate the help -- If you haven't noticed I'm new to all of this scripting. I'm looking in on lynda.com and other forums. the SnowGeneratorCircle.as is:
package {
import flash.display.Sprite;
import flash.events.Event;
public class SnowGeneratorCircle extends Sprite {
var totalFlakes:int = 500;
var flakes:Array = new Array();
public function SnowGeneratorCircle() {
addSnowFlakes();
addEventListener(Event.ENTER_FRAME, update);
}
protected function addSnowFlakes():void{
for(var i:int=0; i<totalFlakes; i++){
var f:SnowFlake = new SnowFlake();
addChild(f);
flakes.push(f);
}
}
public function reset():void{
for(var i:int=0; i<totalFlakes; i++){
var f:SnowFlake = flakes[i];
f.reset();
}
}
public function update(e:Event=null):void {
for(var i:int=0; i<totalFlakes; i++){
var f:SnowFlake = flakes[i];
f.update(0);
}
}
}
}
I debugged - didn't clean up the code, because every time I did - it broke the actions. So I left the code with the double spacing. That's how it went in when I copied and pasted from the tutorial anyway.
Here's the error on line 173 - which is the MovieClip I'd like to have change.
Attempting to launch and connect to Player using URL /Volumes/Lacie Biggest S2S/GRaid/Veronica
/V/Rubio/Work/SUBARU/SnowGlobe Subaru/SnowGlobeAnima/snowGlobeShakev3.swf
[SWF] Volumes:Lacie Biggest S2S:GRaid:Veronica:V:Rubio:Work:SUBARU:SnowGlobe >Subaru:SnowGlobeAnima:snowGlobeShakev3.swf - 468081 bytes after decompression
TypeError: Error #1006: value is not a function.
at SnowGlobeContainer/update()[/Volumes/Lacie Biggest S2S/GRaid/Veronica/V/Rubio/Work/SUBARU
/SnowGlobe Subaru/SnowGlobeAnima/SnowGlobeContainer.as:173]
I just don't know how to get the actionscript to find my MovieClips and then swap them out wt each shake of the globe.
I am building a simple flash game where user can drag objects from a tool-box and drag over to an area. On dragging the object, I create a clone of that object and place it over the area. Here is my code that works somewhat fine..
package {
imports...
public class DocumentClass extends MovieClip {
//variables...
var someArray:Array = new Array();
var totalObjs = 5;
var objOnStage:Array = new Array();
var ogx;
var ogy;
public function DocumentClass() {
// constructor code
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
_width = stage.stageWidth;
_height = stage.stageHeight;
setGameObjects();
}//constructor close
//scaling Functions
public function scalingheight(clip:MovieClip, percent:Number){
var ratio = clip.width / clip.height;
clip.height = percent * _height;
clip.width = clip.height * ratio;
}
public function scalingwidth(clip:MovieClip, percent:Number){
var ratio = clip.height / clip.width;
clip.width = percent * _width;
clip.height = clip.width * ratio;
}
public function setGameObjects():void{
mc_toolbox = new mctoolbox;
addChild(mc_toolbox);
mc_toolbox.x = mc_toolbox.y = 0;
scalingwidth(mc_toolbox, 0.08);
mc_toolbox.height = _height;
mc_board = new mcboard;
addChild(mc_board);
mc_board.x = mc_toolbox.width;
mc_board.y = 0;
scalingwidth(mc_board, 0.75);
mc_board.height = _height;
mc_optbox = new mcoptbox;
addChild(mc_optbox);
scalingwidth(mc_optbox, 0.10);
mc_optbox.height = _height;
mc_optbox.x = _width - mc_optbox.width;
mc_optbox.y = 0;
setobjects();
}
public function setobjects():void{
for(var i = 1; i <= totalObjs; i++){
var className:String = "obj" + i;
var ClassReference:Class = getDefinitionByName(className) as Class;
var myInstance = new ClassReference;
addChild(myInstance);
scalingwidth(myInstance, 0.08);
someArray.push(myInstance);
myInstance.x = stage.stageWidth - 0.09 * _width;
myInstance.y = myInstance.height * (i-1);
}
for(var i = 1; i <= totalObjs; i++){
someArray[i-1].addEventListener(MouseEvent.MOUSE_DOWN, startMove);
someArray[i-1].addEventListener(MouseEvent.MOUSE_UP, stopMove);
}
}
function startMove(evt:MouseEvent):void {
//clone your movieclip here
ogx = evt.currentTarget.x;
ogy = evt.currentTarget.y;
evt.currentTarget.startDrag();
}
function stopMove(evt:MouseEvent):void {
var newobj = new evt.currentTarget.constructor;
addChild(newobj);
newobj.width = evt.currentTarget.width;
newobj.height = evt.currentTarget.height;
newobj.x = evt.currentTarget.x;
newobj.y = evt.currentTarget.y;
evt.currentTarget.x = ogx;
evt.currentTarget.y = ogy;
evt.currentTarget.stopDrag();
objOnStage.push(newobj);
}
}//class close
}//package close
My problem arises when I drag one object on the area and then I drag one more on the previous object. In such case the mouse up event is not called and hence the object movieclip does not clone itself. I think I am making some silly mistake, please guide.
I got this solved. The second movieclip came behind the first so I just brought it in front of all other movieclips while dragging using this
function startMove(evt:MouseEvent):void {
//clone your movieclip here
ogx = evt.currentTarget.x;
ogy = evt.currentTarget.y;
var myobj = evt.currentTarget as DisplayObject;
setChildIndex(myobj, numChildren - 1); // < The solution
evt.currentTarget.startDrag();
}
Try, removing MouseEvent.MOUSE_UP after dropping the object on the stage like so,
evt.currentTarget.removeEventListener(MouseEvent.MOUSE_UP, stopMove);
I'm trying to use vectors to make an enemy track a target (player's ship). However, I keep getting Error 1046. Any advice? The error occurs on the line containing the drawForceVector function in the Game.as file.
Here is my Game.as file code:
package{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Vector3D;
import flash.text.TextField;
public class Game extends MovieClip
{
public static var mouse :Vector3D = new Vector3D(100, 100);
public var boids :Vector.<Boid> = new Vector.<Boid>;
public var forces :Sprite;
public function Game() {
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e :Event) :void {
var i :int, boid :Boid;
for (i = 0; i < 2; i++) {
boid = new Boid(stage.stageWidth * Math.random(), stage.stageHeight * Math.random(), 20 + Math.random() * 20);
addChild(boid);
boids.push(boid);
}
forces = new Sprite();
addChild(forces);
}
public function update():void {
var i :int;
forces.graphics.clear();
for (i = 0; i < boids.length; i++) {
boids[i].update();
drawForces(boids[i]);
}
}
private function drawForces(boid :Boid) :void {
var desired :Vector3D = boid.desired.clone();
var velocity :Vector3D = boid.velocity.clone();
var steering :Vector3D = boid.steering.clone();
velocity.normalize();
desired.normalize();
steering.normalize();
// Force vectors
drawForceVector(boid, velocity, 0x00FF00);
drawForceVector(boid, desired, 0x454545);
drawForceVector(boid, steering, 0x0000FF);
// Target
forces.graphics.lineStyle(1, 0x323232);
forces.graphics.beginFill(0x323232);
forces.graphics.drawCircle(mouse.x, mouse.y, 10);
forces.graphics.endFill();
}
private function drawForceVector(boid :Boid, force :Vector3D, color :uint, scale :Number = 100) :void { //ERROR OCCURS ON THIS LINE
forces.graphics.moveTo(boid.x + boid.width / 2, boid.y + boid.height / 2);
forces.graphics.lineStyle(2, color);
forces.graphics.lineTo(boid.x + force.x * scale, boid.y + force.y * scale);
}
}
}
Boid.as Code:
package {
import flash.display.MovieClip;
import flash.geom.Vector3D;
import flash.object.Vector3D;
public class Boid extends MovieClip
{
public static const MAX_FORCE :Number = 0.4;
public static const MAX_VELOCITY :Number = 3;
public var position :Vector3D;
public var velocity :Vector3D;
public var target :Vector3D;
public var desired :Vector3D;
public var steering :Vector3D;
public var mass :Number;
public function Boid(posX :Number, posY :Number, totalMass :Number = 20) {
position = new Vector3D(posX, posY);
velocity = new Vector3D(-1, -2);
target = new Vector3D(310, 240);
desired = new Vector3D(0, 0);
steering = new Vector3D(0, 0);
mass = totalMass;
truncate(velocity, MAX_VELOCITY);
x = position.x;
y = position.y;
graphics.beginFill(0xFF0000);
graphics.drawRect(0, 0, 20, 20);
graphics.endFill();
}
private function seek(target :Vector3D) :Vector3D {
var force :Vector3D;
desired = target.subtract(position);
desired.normalize();
desired.scaleBy(MAX_VELOCITY);
force = desired.subtract(velocity);
return force;
}
public function truncate(vector :Vector3D, max :Number) :void {
var i :Number;
i = max / vector.length;
i = i < 1.0 ? 1.0 : i;
vector.scaleBy(i);
}
public function update():void {
target = Game.mouse;
steering = seek(target);
truncate(steering, MAX_FORCE);
steering.scaleBy(1 / mass);
velocity = velocity.add(steering);
truncate(velocity, MAX_VELOCITY);
position = position.add(velocity);
x = position.x;
y = position.y;
}
}
}
Main.as Code:
package {
import flash.display.Sprite;
import flash.events.*;
[SWF(width = "600", height = "480")]
public class Main extends Sprite
{
private var game :Game = new Game();
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
stage.addEventListener(Event.ENTER_FRAME, enterFrame);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
stage.frameRate = 30;
addChild(game);
}
private function mouseMove(e :MouseEvent) :void {
Game.mouse.x = e.stageX;
Game.mouse.y = e.stageY;
}
private function enterFrame(e :Event) :void {
game.update();
}
}
}
Thank you very much.
The target version of the player must be higher than the one you've got - Flash Player 9. As seen by the reference, it's said that Vector3D is included in: Runtime Versions: Flash Player 10, AIR 1.5. So basically you are building for so old Flash Player, that it still doesn't have this class inside it.
Simply change the target version to the latest possible one, and be sure it's higher than Flash Player 10. That will do the job! :)
I got a tank.
I got a hero (controllable character).
The tank has a nested movieclip which has a very thin surface area.
Yet, the thing detects a collision when it's not even touching the hero.
public class tank_sight extends MovieClip
{
private var _root:MovieClip;
public function tank_sight()
{
addEventListener(Event.ADDED, beginClass);
}
private function beginClass(event:Event):void
{
_root = MovieClip(root);
addEventListener(Event.ENTER_FRAME, loop);
}
private function loop(event:Event):void
{
if(this.hitTestObject(_root.hero.hitbox))
{
this.gotoAndStop(2);
trace("HIT");
fire();
}
else
{
this.gotoAndStop(1);
}
}
private function fire():void
{
var shell:Shell = new Shell(x, y, rotation - 180);
_root.addChild(shell);
}
}
What's wrong? I don't get it.
EDIT: Sight is rotating, so that's probably why. I tried using this code on the player class:
point = _root.tanks.barrel.sight.localToGlobal(new Point());
if(this.hitTestPoint(point.x, point.y, false))
{
trace("HIT");
}
But it doesn't work.. It never traces "HIT", unless I stand in some weird location at certain times.
hitTestObject works with nested objects also (display objects that have different parents), you should check logic of your game, and do some tests.
Simple example:
var squareHolder:Sprite = new Sprite();
var squareInner:Shape = new Shape();
var hitHolder:Sprite = new Sprite();
var hitCircle:Shape = new Shape();
hitCircle.graphics.beginFill(0x990000);
hitCircle.graphics.drawCircle(0, 0, 20);
squareInner.graphics.beginFill(0x009900);
squareInner.graphics.drawRect(0, 0, 40, 40);
addChild(squareHolder);
squareHolder.addChild(squareInner);
squareHolder.x = 200;
squareHolder.y = 100;
squareInner.x = 50;
squareInner.y = 50;
stage.addChild(hitHolder);
hitHolder.addChild(hitCircle);
hitCircle.transform.matrix = new Matrix(1, 0.5, 0.5, 1, 30, 30);
stage.addEventListener(MouseEvent.MOUSE_MOVE, function (e:MouseEvent):void {
hitHolder.x = e.stageX;
hitHolder.y = e.stageY;
if (hitCircle.hitTestObject(squareInner)) {
trace("Ding!");
}
});
Whatever you do with hitCircle (visible=false, trasparent fill, transformations) it will still work.
Iam trying to create a simple method in AS3 that adds 10 circles, each 30px in diameter in a column down the left-hand-side of the stage, so the first appears in the top-left corner and the last in the bottom-right. I would appreciate any help here. Thanks.
My current code follows: - It currently just returns 10 circles with no positioning.
package
{
import flash.display.*;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Circles extends MovieClip
{
private var timer:Timer = new Timer(100, 10);
public function Circles()
{
timer.addEventListener(TimerEvent.TIMER, createCircles);
timer.start();
}
private function createCircles(e:TimerEvent):void
{
var bcircle:MovieClip = new MovieClip();
var xpos:int = 0;
var ypos:int = 0;
bcircle.graphics.beginFill(0x0033CC);
bcircle.graphics.drawCircle(xpos,ypos,15);
bcircle.graphics.endFill();
bcircle.x = Math.random() * stage.stageWidth;
bcircle.y = Math.random() * stage.stageHeight;
addChild(bcircle);
}
}
}
bcircle.x = Math.random() * stage.stageWidth;
bcircle.y = Math.random() * stage.stageHeight;
These are the lines you want to be paying attention to as these lines control where each circle is placed when added to the stage.
Circle diameter = 30px, stage height (for example) = 400px.
30 goes into 400 13.33 times (400/30) so each circle needs to be spaced 13.3px further down than the last.
You can store a variable that counts how many circles are already on the stage and use it to multiply 13.3 to find the appropriate y value:
var i:int = 0;
private function createCircles(e:TimerEvent):void
{
var bcircle:MovieClip = new MovieClip();
var xpos:int = 0;
var ypos:int = 0;
bcircle.graphics.beginFill(0x0033CC);
bcircle.graphics.drawCircle(xpos,ypos,15);
bcircle.graphics.endFill();
bcircle.x = 0;
bcircle.y = (30 + 13.3) * i; // First circle placed at 0, Second placed at 43.3...
i++; // Increment i each time function is called
addChild(bcircle);
}
You can apply a similar method to then increment the x position of each circle once i reaches 10 (10 circles have been placed), use a trigger to detect this: if(i == 10)
This might help ...
package {
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Circles extends Sprite {
private const _circles:Array = []; // reusable container
private var _timer:Timer;
public function Circles() {
_timer = new Timer(1000, 10);
_timer.addEventListener(TimerEvent.TIMER, timer_timerHandler);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE, timer_timerCompleteHandler);
_timer.start();
}
private function createCircle():Sprite {
const sprite:Sprite = new Sprite();
drawCircleInGraphics(sprite.graphics);
addChild(sprite);
return sprite;
}
private function drawCircleInGraphics(graphics:Graphics, color:uint = 0x0033CC, radius:uint = 15):void {
graphics.beginFill(color);
graphics.drawCircle(0, 0, radius);
graphics.endFill();
}
private function createNewCircleAndPositionIt():void {
_circles[_circles.length] = createCircle();
if (_circles.length > 1) {
const last:Sprite = _circles[_circles.length - 1],
predecessor:Sprite = _circles[_circles.length - 2];
last.x = predecessor.x + 30;
last.y = predecessor.y + 30;
}
}
private function timer_timerHandler(event:TimerEvent):void {
createNewCircleAndPositionIt();
}
private function timer_timerCompleteHandler(event:TimerEvent):void {
_timer.removeEventListener(TimerEvent.TIMER, timer_timerHandler);
_timer.removeEventListener(TimerEvent.TIMER_COMPLETE, timer_timerCompleteHandler);
_timer = null;
}
}
}