How to slowly move item up and down? - actionscript-3

I need to do simple thing, by clicking button 1 time, slowly move item1 by 100 px up and move down by 100 px. I've tried this, but item1 immediately increasing by 50px and immediately decreasing by 50px, I need to make It slower.
var moving:Boolean = false;
if(!moving){
item1.y -= 50;
moving = true;
}
else {
item1.y += 50;
moving = false;
}

You could set up a max moving value like 50, and then move the item1 on the Y with 1, and decrease that max value by 1. When the max value reaches 0, the item reached it's destiny.
if(!moving){
item1.y-=1;
maxValue--;
if(maxValue==0){
//reached final position
}
}

Use a Timer object. Declare that object inside of your class. Then, when the button has been clicked, set the object to a new instance of a Timer that will run very quickly and for many iterations, add an event listener to your new Timer, and in the event listener, apply much smaller increments or decrements to item1.y. For example:
private var m_tmr:Timer;
private function buttonClickHandler(pEvent:MouseEvent):void
{
// This is the function that's called when the button's clicked.
if (m_tmr == null)
{
m_tmr = new Timer(200, 0);
m_tmr.addEventListener(TimerEvent.TIMER, onTimer);
m_tmr.start();
}
}
private function onTimer(pEvent:TimerEvent):void
{
// The first several times this function is called (should be around every
// 200 milliseconds), increment item1.y by 1 or 2 or something else small.
// After the first many times, start decrementing item1.y by the same amount.
// Then call m_tmr.removeEventListener(TimerEvent.TIMER, onTimer);
}

You have to tell Flash to re-draw the screen after each incremental move. An excellent way to do this is with an ENTER_FRAME loop:
var moving:Boolean = false;
const initY = item1.y; // your starting y value
const limitY = initY - 100; // your move will end here
if(!moving){
moving = true;
addEventListener(Event.ENTER_FRAME,moveit)
function moveit(e)
{
item1.y -=1
if (item1.y < limitY)
removeEventListener(Event.ENTER_FRAME,moveit)
}
you have to removeEventListener(...) once you've got to where you want to be, otherwise the loop will go on and hog memory and performance.
UPDATE
So, to move up on a mouse click, you'd do this:
var moving:Boolean = false;
const initY = item1.y; // your starting y value
const limitY = initY - 100; // your move will end here
stage.addEventListener(MouseEvent.CLICK, moveUp)
function moveUp(e)
{
stage.removeEventListener(MouseEvent.CLICK, moveUp)
if(!moving){
moving = true;
addEventListener(Event.ENTER_FRAME,moveit)
function moveit(e)
{
item1.y -=1;
if (item1.y < limitY)
{
removeEventListener(Event.ENTER_FRAME,moveit);
item1.y = limitY;
moving = false;
}
}
}
Instead of targeting stage you may just want to target your button when you use the addEventListener method to register the listener function with the mouse click.
To move back to the start position, apply the same idea to another button or another MouseEvent. For instance you could move up on MOUSE_DOWN and move down on MOUSE_UP.
There are more sophisticated things you can do inside the listener functions (in this case the moving functions). You could apply "easing" to the beginning and ending of the moves so that the motion seems more natural. But, you'll have to read up on that - this answer is too long already!

I would like participate in this conversation. My version of object movement without If statements. Movement is based on trigonometric function:
var objectToAnimate:Shape = new Shape();
objectToAnimate.graphics.beginFill(0x009900);
objectToAnimate.graphics.drawCircle(0, 0, 20);
addChild(objectToAnimate);
//Place it somewhere
objectToAnimate.x = objectToAnimate.y = 200;
//Config for movement
var step:Number = 1; //really slow... 1° per frame
var maxOffsetY:Number = -100; //Move object maximum on 100px top
var cursor:Number = -90;
var position: Number = objectToAnimate.y; // catch current position
var timer:Timer = new Timer(30, 180);
timer.addEventListener(TimerEvent.TIMER, updateAnimation);
timer.start();
function updateAnimation(e:TimerEvent):void {
objectToAnimate.y = position + Math.cos(cursor * Math.PI / 180) * maxOffsetY;
cursor += step;
}

Related

How to apply drag and drop function to all frames in movie clip? Actionscript3

Each frame contain 1 text field. I apply the code on timeline.
But it only gets applied to the last object, which means that I can only drag and drop the last object. Why?
How can I improve this so that I can drag and drop all objects?
for(var j:uint=0; j<3; j++)
{
var q:Ans = new Ans();
q.stop();
q.x = j * 300+50;// set position
q.y = 500;
var r:uint = Math.floor(Math.random() * q_list.length);
q.qface = q_list[r];// assign face to card
q_list.splice(r,1);// remove face from list;
q.gotoAndStop(q.qface+1);
q.addEventListener(MouseEvent.MOUSE_DOWN, startAnsDrag);
q.addEventListener(MouseEvent.MOUSE_UP, stopAnsDrag);
q.addEventListener(Event.ENTER_FRAME, dragAns);
addChild(q);// show the card
}
//----------------------------drag
// offset between sprite location and click
var clickOffset:Point = null;
// user clicked
function startAnsDrag(event:MouseEvent) :void
{
clickOffset = new Point(event.localX, event.localY);
}
// user released
function stopAnsDrag(event:MouseEvent) :void
{
clickOffset = null;
}
// run every frame
function dragAns(event:Event) :void
{
if (clickOffset != null)
{ // must be dragging
q.x = clickOffset.x+mouseX+135;
q.y = clickOffset.y+mouseY;
}
}
Make a new layer in the timeline just for your drag-and-drop code, which you can remove from your other actionscript. Put the code on the first frame in that layer. Now click on and select the last frame on that layer in which you want the code to be effective (probably the last frame of the MovieClip). Press F5 to draw-out the range of frames which will be affected by the code. Voila!

changing a target crosshair color in actionscript 3

I am stuck at a very basic problem which I am not quite able to figure out. I have 4 alienships and a crosshair which moves around with the mouse. I want to change the color of my crosshair to red when it is near one of the alienships. Both my alienships and crosshair are classes which extend movieclip. I use them in my main document class inside a main game loop which is triggered by the Enter_Frame event listener.
Here is my logic that checks for the same
private var objColor:ColorTransform = new ColorTransform();
private function overlayCursorMove() : void {
var initialColor:ColorTransform = new ColorTransform();
initialColor.color = 0xD3D3D3;
for(var i = 0; i < alienShipArray.length; i++){
var currentShip:AlienShip = alienShipArray[i];
if(currentShip.getDistance(overlayCursor.x - currentShip.x, overlayCursor.y - currentShip.y) <= 30 ){
overlayCursor.transform.colorTransform = objColor;
}
else if(currentShip.getDistance(overlayCursor.x - currentShip.x, overlayCursor.y - currentShip.y) > 30 ){
overlayCursor.transform.colorTransform = initialColor;
}
}
}
Below is the custom getDistance function inside the AlienShip class
public function getDistance(delta_x:Number, delta_y:Number):Number
{
return Math.sqrt((delta_x*delta_x)+(delta_y*delta_y));
}
overlayCursor is my crosshair which moves around with my mouseX and mouseY positions. I have 4 alienships on my stage and all of them are stored inside the alienShipArray.
I am just calculating the distance between my crosshair and the currentship position to check if its less than a certain amount to change the crosshair color else if distance is greater change it back to previous color.
Surprisingly the logic only works for the very last ship in the array that is when the loop reaches i = 3 ( alienShipArray[3] ). For the rest of the ship the color of the crosshair stays the same!
You need to break out of your loop when you encounter an intersection, otherwise your loop will continue to run and the other non-intersecting aliens will cause the else if part of your condition to test true, and your crosshair will be changed back to its initial color.
That would explain why your code only works with the last alien in the loop, as there are no further iterations in that instance to reset the color.
Something like the following should do it (untested):
private var objColor:ColorTransform = new ColorTransform();
private function overlayCursorMove() : void {
var initialColor:ColorTransform = new ColorTransform();
initialColor.color = 0xD3D3D3;
for(var i:uint = 0; i < alienShipArray.length; i++) {
var currentShip:AlienShip = alienShipArray[i];
// Reset cursor back to initial color
overlayCursor.transform.colorTransform = initialColor;
if(currentShip.getDistance(overlayCursor.x - currentShip.x, overlayCursor.y - currentShip.y) <= 30 ) {
// Intersection found, change the cursor color
overlayCursor.transform.colorTransform = objColor;
// And break out of the loop so further iterations don't reset it
break;
}
}
// No intersections found, cursor remains in its initial state
}

Flash AS3: Error with stop button for game?

I am making a small game from a tutorial where you hit small tofu's with your cursor and gather up points and accuracy - I have implemented a start button that works and goes to frame(2), where the game starts.
I would like to create a stop button but when i make a button in the scene - the button does not function (cant click on it) and when i hit a tofu it gets the 1009 error? (Cannot access a property or method of a null object reference.)
The game works when i have no stop button but i can't exit the game.
How can i create a stop button or a menu inside the game that allows the user to go back to a previous scene or stop the game?
// define some global variables which let you track the player's statistics.
var hits:int = 0;
var misses:int = 0;
var shots:int = 0;
var cDepth:int = 100;
var level:int = 1;
// define some runtime variables which are used in calculations.
var xSpeed:Number = 3;
var stageWidth:Number = 480;
var stageHeight:Number = 580;
/* attach the crosshair_mc movie clip instance from the Library onto the Stage.
This clip is used as a custom mouse cursor. */
var crosshairClip:MovieClip = new crosshair_mc();
crosshairClip.mouseEnabled = false;
addChild(crosshairClip);
// hide the mouse cursor
Mouse.hide();
/* every time the mouse cursor moves within the SWF file,
update the position of the crosshair movie clip instance on the Stage. */
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
function mouseMoveHandler(event:MouseEvent):void {
crosshairClip.x = event.stageX;
crosshairClip.y = event.stageY;
};
/* when the mouse button is clicked, check to see if the cursor is within the boundaries of the Stage.
If so, increment the number of shots taken. */
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
function mouseDownHandler(event:MouseEvent):void {
if (bg_mc.hitTestPoint(event.stageX, event.stageY, false)) {
shots++;
updateStats();
}
};
// define a TextFormat which is used to format the stats_txt text field.
var my_fmt:TextFormat = new TextFormat();
my_fmt.bold = true;
my_fmt.font = "Arial";
my_fmt.size = 12;
my_fmt.color = 0xFFFFFF;
// create a text field to display the player's statistics.
var stats_txt:TextField = new TextField();
stats_txt.x = 10;
stats_txt.y = 0;
stats_txt.width = 530;
stats_txt.height = 22;
addChild(stats_txt);
// apply the TextFormat to the text field.
stats_txt.defaultTextFormat = my_fmt;
stats_txt.selectable = false;
updateStats();
// add an onEnterFrame event to the main timeline so new tofu is constantly added to the game.
stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
function enterFrameHandler(event:Event):void {
// randomly add new target's to the Stage.
if (randRange(0, 20) == 0) {
var thisMC:MovieClip;
// attach a new instance of the tofu instance from the library onto the Stage, and give it a unique depth.
var randomTofu:Number = randRange(1, 3);
switch (randomTofu) {
case 1:
thisMC = new tofu1_mc();
break;
case 2:
thisMC = new tofu2_mc();
break;
case 3:
thisMC = new tofu3_mc();
break;
default:
return;
break;
}
cDepth++;
// set the starting postition of the current target movie clip so it is just off to the left of the Stage.
thisMC.x = -thisMC.width;
/* create a random number between 80 and 100.
This is used to set the current movie clip's scale,
alpha and speed that it moves across the Stage. */
var scale:int = randRange(80, 100);
/* set the _xscale and _yscale properties of the current movie clip.
This allows for some minor variations of the targets within the game. */
thisMC.scaleX = scale / 100;
thisMC.scaleY = scale / 100;
thisMC.alpha = scale / 100;
thisMC.speed = xSpeed + randRange(0, 3) + level;
/* set a random _y value for the target.
Now, instead of all targets flying along the same path,
they vary their vertical position slightly. */
thisMC.y = Math.round(Math.random() * 350) + 65;
thisMC.name = "tofu" + cDepth;
/* create an onEnterFrame handler that executes a couple dozen times per second.
Update the target's position on the Stage. */
thisMC.addEventListener(Event.ENTER_FRAME, tofuEnterFrameHandler);
thisMC.addEventListener(MouseEvent.CLICK, tofuClickHandler);
addChild(thisMC);
// swap the custom cursor to the higher depth
swapChildren(thisMC, crosshairClip);
}
};
/* create a function to update the player's statistics on the Stage.
You're displaying number of shots taken, number of targets "hit",
number of targets "missed", the percentage of hits vs misses,
overall accuracy (number of shots taken vs number of hit targets). */
function updateStats() {
var targetsHit:Number = Math.round(hits/(hits+misses)*100);
var accuracy:Number = Math.round((hits/shots)*100);
if (isNaN(targetsHit)) {
targetsHit = 0;
}
if (isNaN(accuracy)) {
accuracy = 0;
}
stats_txt.text = "shots:"+shots+"\t"+"hits: "+hits+"\t"+"misses: "+misses+"\t"+"targets hit: "+targetsHit+"%"+"\t"+"accuracy: "+accuracy+"%"+"\t"+"level:"+level;
}
/* create a function that returns a random integer between two specified numbers.
This allows you to add some subtle differences in size and speed for the movie clips on the Stage. */
function randRange(minNum:Number, maxNum:Number):Number {
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
function tofuEnterFrameHandler(event:Event):void {
var tofuMC:MovieClip = event.currentTarget as MovieClip;
/* move the target horizontally along the Stage.
Currently all targets will move from left to right. */
tofuMC.x += tofuMC.speed;
/* slightly decrement the _y position of the current target movie clip.
This makes it appear like the targets are flying slightly higher as they move across the Stage. */
tofuMC.y -= 0.4;
/* if the current position of the target is no longer on the Stage,
count the target as a "miss" and delete the instance.
If the instance wasn't deleted from the Stage,
the user's computer would eventually slow to a crawl. */
if (tofuMC.x > stageWidth) {
misses++;
updateStats();
removeChild(tofuMC);
tofuMC.removeEventListener(Event.ENTER_FRAME, tofuEnterFrameHandler);
}
}
// when the target movie clip instance is pressed, count it as a "hit".
function tofuClickHandler(event:MouseEvent):void {
var tofuMC:MovieClip = event.currentTarget as MovieClip
// update the player's stats
hits++;
if ((hits%40) == 0) {
level++;
}
updateStats();
/* go to the movie clip's label named "hit"
(which allows you to show a clever animation when the instance is hit.) */
tofuMC.gotoAndPlay("hit");
// create an onEnterFrame event for the current movie clip instance.
tofuMC.addEventListener(Event.ENTER_FRAME, tofuHitEnterFrameHandler);
/* delete the onPress event handler.
This makes it so the target cannot continually be clicked while it is falling from the sky. */
tofuMC.removeEventListener(MouseEvent.CLICK, tofuClickHandler);
tofuMC.removeEventListener(Event.ENTER_FRAME, tofuEnterFrameHandler);
}
function tofuHitEnterFrameHandler(event:Event):void {
var tofuMC:MovieClip = event.currentTarget as MovieClip;
// set some local variables that you'll use to animate the target falling from the sky.
var gravity:int = 20;
var ymov:int = tofuMC.y + gravity;
// ***** xmov *= 0.5;
// increment the rotation of the current movie clip clock-wise by 5 degrees.
tofuMC.rotation += 5;
/* set the _x and _y properties of the movie clip on the Stage,
this allows us to make the target look like it is semi-realistically
falling from the sky instead of just dropping straight down. */
tofuMC.x += xSpeed;
tofuMC.y = ymov;
/* after the _y position is off of the Stage,
remove the movie clip so that the coordinates aren't continually calculated */
if (tofuMC.y > stageHeight) {
removeChild(tofuMC);
tofuMC.removeEventListener(Event.ENTER_FRAME, tofuHitEnterFrameHandler);
}
}
The stage is confused, because some objects don't exist when you change frames, so you have to remove all of your events from the stage:
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
stage.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
And then you can call the gotoAndStop() function to whatever frame you want...

timerEvent within enterFrame function?

I'm calling a timerEvent function from enterFrame, it's running the timerEvent function on everyFrame. Is there a way to control it?
I've got my bullets firing function with timerEvent of 500, so it shoots a bullet every half a second on 24fps. It's working fine for now. Now I want to change bullet speed and skin with respect to weapon.
////////////////////////////////
//this function is called first time within an EnterFrame function
///////////////////////////////
function weaponCheck():void
{
switch (weaponState)
{
case STATE_GUN :
gun();
break;
case STATE_DOUBLE_GUN :
doubleGun();
break;
}
}
function gun():void
{
trace("single gun");
laserTimer = new Timer(600);
laserTimer.addEventListener(TimerEvent.TIMER, timerListener);
laserTimer.start();
function timerListener(e:TimerEvent):void
{
var tempLaser:MovieClip = new Laser();
var tempGunBlast:MovieClip = new Gun_blast_01();
tempLaser.x = player.x +((player.width/2)+12);
tempLaser.y = player.y;
tempGunBlast.x = stage.mouseX + 104;
tempGunBlast.y = tempLaser.y;
Lasers.push(tempLaser);
addChildAt(tempLaser,1);
addChildAt(tempGunBlast, 3);
if (tempGunBlast.currentFrame >= tempGunBlast.totalFrames)
{
removeChild(tempGunBlast);
}
}
}
function doubleGun():void
{
trace("Double gun");
doubleGunTimer = new Timer(400);
doubleGunTimer.addEventListener(TimerEvent.TIMER, timerListener2);
doubleGunTimer.start();
function timerListener2(e:TimerEvent):void
{
var tempLaser:MovieClip = new doubleG();
var tempGunBlast:MovieClip = new Gun_blast_01();
tempLaser.x = player.x +((player.width/2)+12);
tempLaser.y = player.y;
tempGunBlast.x = stage.mouseX + 104;
tempGunBlast.y = tempLaser.y;
Lasers.push(tempLaser);
addChildAt(tempLaser,1);
addChildAt(tempGunBlast, 3);
if (tempGunBlast.currentFrame >= tempGunBlast.totalFrames)
{
removeChild(tempGunBlast);
}
}
}
///////////////////////////////////////////////////
//Following function is called within an enterFrame event function
/////////////////////////////////////////////////
function playGame():void
{
weaponCheck();
blah1();
blah2();
blah3();
testForEnd();
}
function testForEnd():void
{
if (level == 3)
{
laserTimer.stop();
weaponState = STATE_DOUBLE_GUN;
weaponCheck();
}
}
So when the game runs for first time, it works fine and uses the timer event of 600 to hit the bullets, but when level == 3 and weaponState changes, the 2nd firing function doubleGun(); is called but it starts to fire the bullets on a per frame count, not on a controlled timerEvent. Please Help. Thanks.
Why don't you drop timers and use enter frame listener as a manner to count time? You are already calling weaponCheck() from an enterframe listener. Make it so that the actual gun() and doublegun() calls will only generate animation, such as firin' mah lazers and blasts, and the main function will just count time.
function weaponCheck():void
{
this.reloading+=this.weaponFiringSpeed; // you alter this to make your weapon fire slower or faster
if (this.reloading<FULLY_RELOADED) return; // we are not yet ready to fire
this.reloading=0;
switch (weaponState) // and here we fire with the gun state
{
case STATE_GUN :
gun();
break;
case STATE_DOUBLE_GUN :
doubleGun();
break;
}
}
function gun():void
{
trace("single gun");
var tempLaser:MovieClip = new Laser();
var tempGunBlast:MovieClip = new Gun_blast_01();
tempLaser.x = player.x +((player.width/2)+12);
tempLaser.y = player.y;
tempGunBlast.x = stage.mouseX + 104;
tempGunBlast.y = tempLaser.y;
Lasers.push(tempLaser);
addChildAt(tempLaser,1);
addChildAt(tempGunBlast, 3);
}
And similarly double gun. FULLY_RELOADED is a constant, reloading is a variable used to track time, it should be a property of the one who's firing.
Note, this approach requires you to manage your "tempGunBlast"s elsewhere, perhaps in the very weaponCheck function, if so, modify it as follows:
function weaponCheck():void
{
if (tempGunBlast) if (tempGunBlast.currentFrame >= tempGunBlast.totalFrames)
removeChild(tempGunBlast);
this.reloading+=this.weaponFiringSpeed; // you alter this to make your weapon fire slower or faster
if (this.reloading<FULLY_RELOADED) return; // we are not yet ready to fire
... // rest of code unchanged
You will most likely not be able to copypastely implement this, but please try.

Record Paper.js path object and redraw again later

I draw with a mouse Paper.js. I need to keep these strokes and replay them at the same rate as in the video replay. How can I accomplish this?
In paper.js, the onFrame() function is called up to 60 times per second, while the onMouseMove() function "is called when the mouse moves within the project view", and contains the position of the mouse. By using both functions you can store the mouse motions and replay them later with close to the same time between positions.
var mousePosition = null;
function onMouseMove(event) {
if (mousePosition != null) {
var path = new Path();
path.strokeColor = 'black';
path.moveTo(mousePosition);
path.lineTo(event.point);
}
mousePosition = event.point;
}
var recordedPositions = [];
var delayFrames = 60;
function onFrame(event) {
if (mousePosition != null) {
recordedPositions.push(mousePosition);
if (recordedPositions.length > delayFrames) {
var path = new Path();
path.strokeColor = 'red';
delayedPositionIndex = recordedPositions.length - delayFrames;
path.moveTo(recordedPositions[delayedPositionIndex - 1]);
path.lineTo(recordedPositions[delayedPositionIndex]);
}
}
}
I do not know the timing accuracy/resolution/dependability of onFrame(). Alternatively you could just use javascript timing events as in this answer: How can I use javascript timing to control on mouse stop and on mouse move events