I'm building a scrollbar.
On MouseDown I start a repeating timer to position the Scrollbar-Button(Slider).
When it reaches minimum/maximum it jitters (switching between min/max and stage.mouseY…)
How can I prevent that?
private function onTime(e:TimerEvent):void
{
if(this._scrollBtn.y < min)
{
this._scrollBtn.y = min;
}
else if(this._scrollBtn.y > max-this._scrollBtn.height)
{
this._scrollBtn.y = max-this._scrollBtn.height;
}
else
{
this._scrollBtn.y = stage.mouseY;
}
}
I'd recommend listening for the MouseEvent.MOUSE_MOVE instead of using a timer, that way you're only doing work if and when the mouse is moving.
Your problem is likely that your validating the position of the scroll handle "after" moving it, letting it be out of bounds for a while before the next update comes and moves it back.
There's also no reason in having this everywhere, unless it's explicitly needed.
private function onTime(e:TimerEvent):void
{
_scrollBtn.y = stage.mouseY;
if(_scrollBtn.y < min)
{
_scrollBtn.y = min;
}
else if(_scrollBtn.y > max - _scrollBtn.height)
{
_scrollBtn.y = max - _scrollBtn.height;
}
}
Related
I am using a fish as a mouse cursor but when i move it around my stage it only faces one direction. what I want it to do is change direction when i move it left or right.
This should allow you to control the timeline of the fish movieclip:
It works by listening for a change in the position of the mouse, which after detecting the speed in which it does this, moves the timeline of the desired movieclip forwards or backwards depending on the new direction of the mouse.
Taken from the following thread: https://forums.adobe.com/thread/1450102?tstart=0
var mc:MovieClip = MovieClip(this); // <- The timeline you want to control with mouse position
var maxScrollSpeed:int=100; // max fps for mc above
var m:Number;
var b:Number;
var prevFPS:int;
paramF(0,-maxScrollSpeed,stage.stageWidth,maxScrollSpeed);
this.addEventListener(MouseEvent.MOUSE_MOVE,scrollF);
function scrollF(e:Event):void
{
var fps:int = Math.round(m*mouseX+b);
if(prevFPS&&prevFPS!=fps)
{
if(fps!=0)
{
if(fps>0)
{
playF(mc,mc.currentFrame,mc.totalFrames,fps);
}
else
{
playF(mc,mc.currentFrame,1,-fps);
}
}
else
{
stopF(mc);
}
}
prevFPS=fps;
}
function playF(mc:MovieClip, m:int, n:int, fps:int):void
{
var playFFF2:Function = function(mc:MovieClip):void
{
if (mc.m<mc.n)
{
mc.nextFrame();
}
else
{
mc.prevFrame();
}
if (mc.currentFrame == mc.n)
{
clearInterval(mc.int);
}
//updateAfterEvent();
};
mc.m = m;
mc.n = n;
mc.fps = fps;
mc.gotoAndStop(mc.m);
clearInterval(mc.int);
mc.int = setInterval(playFFF2, 1000/mc.fps, mc);
}
function stopF(mc:MovieClip):void
{
clearInterval(mc.int);
}
function paramF(x1:Number,y1:Number,x2:Number,y2:Number):void
{
m=(y1-y2)/(x1-x2);
b=y1-m*x1;
}
Store the mouseX position in a variable. When the mouse moves, compare the new mouseX position with your stored variable (you can do this with the ENTER_FRAME or MOUSE_MOVE events). If the new position is greater than the previous position, set the scaleX to 1, if the new position is less than the previous position set the scaleX to -1 (or vice versa).
Update the stored value and repeat.
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;
}
I have a question about action script 3.
I am making a game, the basic rule of the game is:
an object falls from the top
the hero(user) has to avoid the object
if the object hits the ground or the hero: the hero dies or the object falls again from the top.
I am using the add child method for the object, and timer function for the fall.
the problem is:
when the object hits the ground, the function does not loop. it ends just like that. so there wont be any falling objects anymore.
please help me. thanks :)
stage.addEventListener(Event.ENTER_FRAME, addfire1);
function addfire1(e:Event):void
{
if (api1==false)//if object is not on the stage
{
randomx = randomRange();//generate random X
addChild(api);
api.x = randomx;//set x
api1 = true;//object is now on stage
}
if (api.hitTestObject(hero) || api.hitTestObject(ground))
{
falltimer.stop();
//stop timer;
falltimer.reset();
//reset fall Count to zero ;
removeChild(api);//object removed
api1=false;
}
}
function firefall(Event:TimerEvent):void
{
if (api1)
{
api.y += 20;//set speed y
}
}
Just separate the two cases: hero and floor.
if (api.hitTestObject(hero))
{
falltimer.stop();
//stop timer;
falltimer.reset();
//reset fall Count to zero ;
removeChild(api);//object removed
api1=false;
}
else if (api.hitTestObject(ground))
{
//reset object's position
api.y = -20;
}
Assuming there is only one object falling at the time I'd not remove the object but instead just move it to the original y position and a new x position. And instead of having the timer i'd create an update-function that runs every time you enter a frame.
stage.addEventListener(Event.ENTER_FRAME, update);
private function update(e:Event):void
{
if(!api1) //if object is not on the stage (same as api1==false)
{
addfire1();
}
if(api1) //if object if on stage (same as api1==true)
{
firefall();
}
}
private function addfire1(e:Event):void
{
randomx = randomRange();//generate random X
addChild(api);
api.x = randomx;//set x
api1 = true;//object is now on stage
if (api.hitTestObject(hero))
{
hitHero(); //execute what should happen to the hero when the he is hit
resetFire();
}
else if(api.hitTestObject(ground))
{
resetFire();
}
}
private function firefall(Event:TimerEvent):void
{
api.y += 20;//set speed y
}
private function resetFire():void
{
api.x = randomRange();
api.y = 0;
}
If you write it like this you don't have to mix stuff up. Try to keep everything seperated, one function does one thing. If you are making a big game try to seperate everything in classes.
Hopefully this fixes the problem and makes it easier for you to finish the game :)
I have two buttons that moves a movieclip up/down the Y-axis. How do I get the movieclip to stop at a certain height, and still be able to move it in the opposite direction?
I need this to work like this:
When you press the down-button, the movieclip goes downwards, but not past Y=500.
When you press the up-button, the movieclip goes upwards, but not past Y= 300.
I get the movieclip to stop at the correct point (500), but when it reaches this point it's stuck..
so it won't go upwards again if I press the up-button.
can someone help me please?:)
here's my code so far:
1) decrease = the down-button
2) increase = up-button
3) stempel = the movieclip I want to stop on the Y-axis
var moveStempel = 0;
decrease.addEventListener(MouseEvent.MOUSE_DOWN, decreasePressed);
decrease.addEventListener(MouseEvent.MOUSE_UP, removeEnterFrame);
increase.addEventListener(MouseEvent.MOUSE_DOWN, increasePressed);
increase.addEventListener(MouseEvent.MOUSE_UP, removeEnterFrame);
function decreasePressed(e:MouseEvent):void
{
moveStempel = 2;
addEnterFrame();
}
function increasePressed(e:MouseEvent):void
{
moveStempel = -2;
addEnterFrame();
}
// ADD ENTER FRAME
function addEnterFrame():void
{
this.addEventListener(Event.ENTER_FRAME, update);
}
function removeEnterFrame(e:MouseEvent):void
{
this.removeEventListener(Event.ENTER_FRAME, update);
}
function update(e:Event):void
{
if (stempel.y < 500)
{
stempel.y += moveStempel;
trace("inside");
}
else if (stempel.y > 500)
{
stempel.stop();
trace("outside");
}
In your code right now, once stempel has a y value greater than 500, it will never be able to move again.
There are two conditions when stempel can move: if it's moving down, it can't be at the bottom of the allowed area, and if it's moving up, it can't be at the top of the allowed area.
if ((stempel.y < 500 && moveStempel == 2) || (stempel.y > 300 && moveStempel == -2))
{
stempel.y += moveStempel;
trace("inside");
}
else
{
stempel.stop();
trace("outside");
}
I want that my spaceship gets louder when my mouse moves away from it (and vice versa). Problem is that my function produces an annoying crackling sound I can't get rid of when I move my mouse away from it (and vice versa). The sound file is ok so far. What can I try next?
shipSpeed = (abs(player.x - playerPrevPt.x) + abs(player.y - playerPrevPt.y)) / 2;//the ship's speed gets calculated
//this is used to determine whether the ship's volume of its sound shall be increased or decreased
if (shipSpeedPrev < shipSpeed) {
sndManager.increaseSound(Main.SOUND_BACKGROUND, false, .01);
} else if (shipSpeedPrev > shipSpeed) {
sndManager.decreaseSound(Main.SOUND_BACKGROUND, false, .01);
} else if (shipSpeedPrev == shipSpeed) {
} else {
}
shipSpeedPrev = (abs(player.x - playerPrevPt.x) + abs(player.y - playerPrevPt.y)) / 2;//this is another ship speed so I can compare them
//the decreaseSound-function is almost the same
public function increaseSound(soundName:String, isSoundTrack:Boolean = false, steps:Number = .1, targetVol:Number = 1):void {
if (isSoundTrack) {
if (soundTrackChannel != null) {
musicVolumeAdj.volume += steps;
if (musicVolumeAdj.volume >= targetVol) {
musicVolumeAdj.volume = targetVol;
}
soundTrackChannel.soundTransform = musicVolumeAdj;
}
} else {
soundVolumeAdj = new SoundTransform(incrSndVal, 0);
incrSndVal += steps;
soundVolumeAdj.volume += incrSndVal;
if (soundVolumeAdj.volume >= 1) {
soundVolumeAdj.volume = 1;
}
soundChannels[soundName].soundTransform = soundVolumeAdj;
}
}
Most likely the audio ends up being clipped when you increase the volume. Try to find out at what volume the clipping occurs, and then change your function so that it doesn't got beyond that volume.
Perhaps you could also re-author the audio file and reduce the overall volume, so that you can increase it more from your game.