how to make full jump with single press - actionscript-3

This is a very simple question but even after googling i am not getting the right idea.
i have a hero who i want to make jump. i have written the code in my logic but the problem is i have to hold the key to perform the whole jump. lets say it will go y-= 20but if i hold my button its going the full distance. But if i click once its not going/ passing the full distance.
i want to make my hero jump the whole way with a single press, i mean just 1 press not holding down the button.
here is my code
import flash.display.Stage;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.display.MovieClip;
import flash.events.Event;
var grav:int = 0;
var floor = 450;
var jumping:Boolean = false;
stage.addEventListener(KeyboardEvent.KEY_DOWN , keyDownHandaler);
stage.addEventListener(KeyboardEvent.KEY_UP , KeyUpHandaler);
stage.addEventListener(Event.ENTER_FRAME , update);
function gravity ():void
{
hero.y += grav;
if (hero.y+hero.height/2 <floor){
grav++;
}
else {
grav = 0;
hero.y = floor - hero.height/2 ;
}
}
function keyDownHandaler(Devent:KeyboardEvent):void
{
if (Devent.keyCode == Keyboard.W)
{
jumping = true;
}
}
function KeyUpHandaler (Uevent:KeyboardEvent):void
{
if (Uevent.keyCode == Keyboard.W)
{
jumping = false;
}
}
function update(Levent:Event):void
{
if (jumping)
{
hero.y -= 20;
}
gravity();
}

I think the trick you need to work out is keeping the "jumping" flag set until the entire jump sequence is finished. Currently you have it resetting as soon as the button lifts up, then setting again when it's re-pressed.
There is actually no reason to turn off the jumping flag just because the user lifted the button.
Right here:
hero.y += grav;
if (hero.y+hero.height/2 <floor){
grav++;
}
You have a check to see if the character has hit the floor. It should be there that the jump sequence finishes.
All the stuff you do to your character should not be tracked on the KEY being DOWN. It should be tracked on the jumping=true. The key being pressed just starts the sequence. And you do need to keep that flag so as not to start the sequence again if it's already running.

Added because the first answer is already pretty long. This is an answer with the requested re-write of the OP's code: (Read notes at the end)
import flash.display.Stage;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
import flash.display.MovieClip;
import flash.events.Event;
var grav:double = 0.025; //Change this to make gravity stronger or weaker.
var gravInc:double = .2; //Changed to "double" because int is too large an increment. If double doesn't work, try float or decimal.
var floor = 450;
var jumping:Boolean = false;
stage.addEventListener(KeyboardEvent.KEY_DOWN , keyDownHandaler);
stage.addEventListener(KeyboardEvent.KEY_UP , KeyUpHandaler);
stage.addEventListener(Event.ENTER_FRAME , update);
function gravity ():void
{
if (hero.y+hero.height/2 < floor){
//grav++; //not needed
gravInc = gravInc - grav; //GravInc starts strong, and gradually decreases. It will eventully be less than zero, and start negetive.
hero.y -= gravInc; //The effect of which is the chracter will move upward until gravity takes over, and make hero move downward - increaseing speed until it hits the floor.
} else {
//grav = 0; Not needed
hero.y = floor - hero.height/2 ;
//We've hit the floor. Stop jump sequence
jumping = false;
}
}
function keyDownHandaler(Devent:KeyboardEvent):void
{
if (Devent.keyCode == Keyboard.W)
{
if (jumping==false) { //The character is not already jumping
//This initiates the jump sequence
//set up the jump sequence by resetting the gravInc and setting jumping to true
gravInc = .2;
jumping = true;
//Start the jump now so that the character is off the floor
hero.y -= gravInc;
}
}
}
function KeyUpHandaler (Uevent:KeyboardEvent):void
{
if (Uevent.keyCode == Keyboard.W)
{
// jumping = false;
// Not needed here
}
}
function update(Levent:Event):void
{
// This whole thing goes. It is not needed because the jumping==true will handle it.
// if (jumping)
// {
// hero.y -= 20;
// }
if ( jumping==true ){
gravity();
}
}
I have no way of testing this code. I commented out the parts of your code that were unnecessary, and I added in the things that you'd need to make it function.
ActionScript syntax is very similar to JavaScript. So I'm including this link as a sort-of demo to show how the whole gravity thing works in an actual program. Bounding balls
View the source on that page.
Hopefully this does the trick for you.

Related

stop() caller not working properly

I am making a brick breaker game with three frames. The first frame is the start screen, the second frame is the game itself, and the third frame is the "game over" screen (with a try again button). When I hit "Start game" the program jumps to the second frame and stops. If you fail to hit the ball with the racket, the program jumps to frame three.
My problem occurs here, because the program instantly jumps to the second frame again. Any idea why the stop(); caller fails to work? I have tried to remove all content from the last frame (except for the stop(); caller), but it still just skips back to frame 2.
I really can't figure out why this is happening. I am using Adobe Flash Professional CC. The only actionscript on frame 3 are "stop();". This is the entire code block on frame 2:
import flash.events.KeyboardEvent;
import flash.display.Stage;
import flash.events.Event;
import flash.ui.Keyboard;
import fl.transitions.Tween;
import fl.transitions.easing.*;
trace(currentFrame);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
this.addEventListener(Event.ENTER_FRAME, moveBall);
var rackert: bar = new bar();
rackert.name = "rackert";
rackert.y = 740;
rackert.x = 640;
addChild(rackert);
var ball: circle = new circle();
ball.y = 80;
ball.x = 640;
addChild(ball);
var ballXSpeed: Number = 12; //X Speed of the Ball
var ballYSpeed: Number = 12; //Y Speed of the Ball
function keyDown(e: KeyboardEvent) {
var key: uint = e.keyCode;
var step: uint = 35;
switch (key) {
case Keyboard.LEFT:
if (rackert.x > 0) {
var myTween: Tween = new Tween(rackert, "x", Regular.easeOut, rackert.x, rackert.x - step, 0.2, true);
} else rackert.x = 0;
break;
case Keyboard.RIGHT:
if (rackert.x + rackert.width < 1000) {
var myTween2: Tween = new Tween(rackert, "x", Regular.easeOut, rackert.x, rackert.x + step, 0.2, true);
} else rackert.x = 1000 - rackert.width;
break;
}
}
var gameOver: Boolean = false;
function moveBall(event: Event): void {
ball.x += ballXSpeed;
ball.y += ballYSpeed;
if (ball.x >= 1000 - (ball.width / 2)) {
ballXSpeed *= -1;
}
if (ball.x <= 0 + (ball.width / 2)) {
ballXSpeed *= -1;
}
if (ball.y >= stage.stageHeight) {
if (gameOver == false) {
gotoAndStop(3);
this.removeEventListener(Event.ENTER_FRAME, moveBall);
stage.removeEventListener(KeyboardEvent.KEY_DOWN, keyDown);
gameOver = true;
rackert.visible = false;
}
}
if (ball.y <= 22) {
ballYSpeed *= -1;
}
if (ball.hitTestObject(rackert)) {
calcBallAngle();
}
}
function calcBallAngle(): void {
var ballPosition: Number = ball.x - rackert.x;
trace("Position: " + ballPosition);
var hitPercent: Number = (ballPosition / (rackert.width - ball.width)) - .7;
trace("percent: " + hitPercent);
ballXSpeed = hitPercent * 10;
ballYSpeed *= -1;
}
function getRandom(min: Number, max: Number): Number {
return min + (Math.random() * (max - min));
}
Change this:
if (gameOver == false) {
gotoAndPlay(3); //gotoAndPlay(); caller
gameOver = true;
rackert.visible = false;
}
To:
if (gameOver == false) {
gotoAndStop(3); //gotoAndPlay(); caller
gameOver = true;
rackert.visible = false;
}
Difference is goToAndStop(). The default behavior is to "loop" an animation, so you tell it to go to frame 3 (last frame) and it "plays" through that frame back around to 1, then 2, where you most likely have a frame script that calls stop(); to stop the play head.
Update
I believe you that you're calling stop(); in frame 3. It seems like it should work and indeed it actually is, it's just not working on the object that you're expecting it to work on. Since you're using a frame script, stop(); is being called on the InteractiveObject who's scope the frame script is inside of. Let me clarify.
Frame 3 Of Stage
-> Child on frame three called FrameScriptsArePITA
-> Double click FrameScriptsArePITA and write a frame script "stop()", the script will do nothing but stop FrameScriptsArePITA from playing.
Watch your scope. That's part of why frame scripts are... best to avoid. Using your own DocumentClass and hooking everything in your design view into corresponding classes will make things easier to solve in AS3.
I finally found the issue. I had a timer event on frame 1, which caused the bug. I simply used removeEventListener for the timer function where i skip to frame 2. As Technick Empire said, you should always be cleaning up anything including even listeners as they can even interfere with the garbage collector and cause memory leaks.

Rotating movieclip and changing to a particular frame (S.O.S)

i would apreciate if someone help me with some coding.
i have this code that i previously get to rotate a movieclip with the mouse, and get to another frame, for a college work (we only did the tweens, just learned the basic coding) but i cant get no result.
import flash.events.Event;
import flash.events.MouseEvent;
knob_mc.addEventListener(MouseEvent.MOUSE_DOWN, rotate);
stage.addEventListener(MouseEvent.MOUSE_UP, endrotate );
var angle:Number=0
function rotate(e:Event):void
{
stage.addEventListener(MouseEvent.MOUSE_MOVE,rotate);
var position:Number = Math.atan2(mouseY - knob_mc.y,mouseX - knob_mc.x);
angle=(position/Math.PI) *180;
knob_mc.rotation = angle;
}
function endrotate(e:MouseEvent):void
{
knob_mc.removeEventListener(MouseEvent.MOUSE_DOWN, rotate);
stage.removeEventListener(MouseEvent.MOUSE_UP, menu);
stage.removeEventListener(MouseEvent.MOUSE_MOVE,rotate);
knob_mc.addEventListener(MouseEvent.MOUSE_DOWN,rotate);
}
function menu(e:MouseEvent):void
{
if ( angle >=1 && angle <= 100 )
{
gotoAndPlay(2);
}
else if (angle >=100 && angle < 340) {
gotoAndPlay(2);
}
You will need to put the code that adds the event listener for the rotate function somewhere outside the rotate callback. As it is, it is never being called.
function rotate(e:Event):void
{
var position:Number = Math.atan2(mouseY - knob_mc.y,mouseX - knob_mc.x);
angle=(position/Math.PI) *180;
knob_mc.rotation = angle;
}
stage.addEventListener(MouseEvent.MOUSE_MOVE,rotate);

Why are my array movie clips getting harder to click when they get faster?

I am making a game where insects come down from the top of the screen, and the user must kill them. The insects are in an array. Each time the user kills them, the score goes up..after a while the insects get faster and faster. When they get faster, some of them don't get killed when you click them. You have to click multiple times for them to die. I want them to get killed in one click, but this isn't working when they get faster!
function makeEnemies():void
{
var chance:Number = Math.floor(Math.random() * 150);
if (chance <= + level)
{
//Make sure a Library item linkage is set to Enemy...
tempEnemy = new Enemy();
//Math.random(); gets a random number from 0.0-1.0
tempEnemy.x = Math.round(Math.random() * 1000);
addChild(tempEnemy);
enemies.push(tempEnemy);
tempEnemy.speed = enemyBaseSpeed + ((level - 1) * speedLevelInc);
}
}
function moveEnemies():void
{
var tempEnemy:MovieClip;
for (var i:int =enemies.length-1; i>=0; i--)
{
tempEnemy=enemies[i];
if (tempEnemy.dead)
{
score++;
score++;
roachLevel.score_txt.text = String(score);
enemies.splice(i,1);
}
else // Enemy is still alive and moving across the screen
{
//rotate the enemy between 10-5 degrees
tempEnemy.rotation += (Math.round(Math.random()*.4));
//Find the rotation and move the x position that direction
tempEnemy.x -= (Math.sin((Math.PI/180)*tempEnemy.rotation))*tempEnemy.speed;
tempEnemy.y += (Math.cos((Math.PI/180)*tempEnemy.rotation))*tempEnemy.speed;
if (tempEnemy.x < 10)
{
tempEnemy.x = 11;
}
if (tempEnemy.x > stage.stageWidth - offset)
{
tempEnemy.x = stage.stageWidth - offset;
}
if (tempEnemy.y > stage.stageHeight)
{
removeEnemy(i);
lives--;
roachLevel.lives_txt.text = String(lives);
}
}
}
}
function removeEnemy(id:int)
{
removeChild(enemies[id]);
enemies.splice(id,1);
}
There is also code inside the insect.
import flash.events.MouseEvent;
import flash.display.MovieClip;
import fl.motion.Animator;
import flash.events.*;
play();
var MainTimeLine = MovieClip(root);
var mysound:squish = new squish();
this.addEventListener(MouseEvent.CLICK, kill);
this.dead = false;
function kill(e:MouseEvent):void
{
this.dead=true;
mouseChildren=false
mysound.play();
gotoAndPlay(21);
this.removeEventListener(MouseEvent.CLICK, kill);
flash.utils.setTimeout(removeSelf,2000);
}
function removeSelf():void
{
this.parent.removeChild(this);
}
You shouldn't remove an enermy from the array while iterating it.
You make enemies.splice(i,1); in your loop iterating from enemies.length to 0. While you changing your array size, you don't adjust the loop condition.
I think your main issue might be that you are reusing your insects, maybe pooling them. If you do this, you need to make sure that you are adding the eventListener for the click again when recycling.
If you are adding the listener in the constructor, that will only execute when the insect is created, not when you recycle him.
Your issue is the setTimeOut(), which is causing a memory leak. Using a timer is much safer, but if you must use it, keep a reference to the call and clear it when you no longer need it.
Also, the code you posted doesn't show where you're adding a listener to MainTimeline or parent, but if you are you need to remove that as well before the insect can be garbage collected.

How to get mt character to attack

I'm trying to create a beat em up game and right now i got my character attacking. I have 3 attack animation so far and works just about. This is what i want, if the player presses the attack button then the character will attack and if the player keeps pressing the attack button it will continue with its attack sequence (Note: I do no want if the player holds down the key, has to be a key press).
The problem is if you keep mashing the attack button it attacks but the problem is it goes to the next attack animation as soon as the attack button is down and I don't want that. How can i make it go to the next attack animation once the current attack animation has completely finished instead of jumping to the next frame midway of it's current attack animation. So i want the character to finish its attack and if the player still keys in the attack key it will go to the next attack frame otherwise it will stop. This is what i have done so far
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
public class Player extends MovieClip
{
//Attack variables
var Attacking:Boolean = false;
var Punches:int = 0;
var Punching:Boolean = false;
public function Player()
{
stage.addEventListener(KeyboardEvent.KEY_DOWN,KeyPressed);
addEventListener(Event.ENTER_FRAME,Update);
}
function KeyPressed(event:KeyboardEvent):void
{
//Note: I need these listeners here
stage.removeEventListener(KeyboardEvent.KEY_DOWN, KeyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, KeyUp);
//If A key is down
if (event.keyCode == 65)
{
Attacking = true;
Punching = true;
Punches++;
}
}
function Update(event:Event)
{
//If player is not attacking
if (Attacking == false)
{
Punching = false;
Punches = 0;
}
else if (Attacking == true)
{
if (Punching == true)
{
gotoAndStop('Jab' + Punches);
}
}
}
function KeyUp(event:KeyboardEvent)
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, KeyPressed);
}
}
}
Also within the last frame of every attack animation i have put down
import flash.display.MovieClip;
import flash.events.Event;
stop();
MovieClip(parent).Attacking = false;
MovieClip(parent).Punches = 0;
Not sure if this method is the best way around it or should i create a extended class/arrays if so how will i do this
Change
if (Punching == true)
{
gotoAndStop('Jab' + Punches);
}
To
if (Punching && !Attacking)
{
gotoAndStop('Jab' + Punches);
}
So basically, it will make sure that an animation isn't already playing before it (re)plays the animation.
Edit: Even though you are calling gotoAndStop while still on that frame, it will replay the animations of any children MovieClips.

Continuos Timer and object for a game AS3

I am currently working on a game where you need to survive as long as possible while dodging questions that come your way. (all with AS3)
At the moment I am going from 1 scene to another in between the game field and the question field, but everytime I go to the question scene the timer in the game scene resets itself. I was wondering if it was possible to have the timer continue while being in the question scene?
Also I have a movable character in between the menus which incidentally are also made in different scenes and the player is able to move him around, and I would very much like him to stay in the last position he was in the next screen, as in I move him to the top right in the main menu and when I go to the options menu I want him to still be in the top right and not in his initial position.
As for my timer this is the code I am using at the moment:
import flash.utils.Timer;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.globalization.DateTimeFormatter;
var timer:Timer = new Timer(100);
timer.start();
timer.addEventListener(TimerEvent.TIMER, timerTickHandler);
var timerCount:int = 0;
function timerTickHandler(Event:TimerEvent):void
{
timerCount += 100;
toTimeCode(timerCount);
}
function toTimeCode(milliseconds:int) : void {
//create a date object using the elapsed milliseconds
var time:Date = new Date(milliseconds);
//define minutes/seconds/mseconds
var minutes:String = String(time.minutes);
var seconds:String = String(time.seconds);
var miliseconds:String = String(Math.round(time.milliseconds)/100);
//add zero if neccecary, for example: 2:3.5 becomes 02:03.5
minutes = (minutes.length != 2) ? '0'+minutes : minutes;
seconds = (seconds.length != 2) ? '0'+seconds : seconds;
//display elapsed time on in a textfield on stage
timer_txt.text = minutes + ":" + seconds+"." + miliseconds;
}
And my character is using this code:
/* Move with Keyboard Arrows
Allows the specified symbol instance to be moved with the keyboard arrows.
Instructions:
1. To increase or decrease the amount of movement, replace the number 5 below with the number of pixels you want the symbol instance to move with each key press.
Note the number 5 appears four times in the code below.
*/
var upPressed:Boolean = false;
var downPressed:Boolean = false;
var leftPressed:Boolean = false;
var rightPressed:Boolean = false;
rutte.addEventListener(Event.ENTER_FRAME, fl_MoveInDirectionOfKey);
stage.addEventListener(KeyboardEvent.KEY_DOWN, fl_SetKeyPressed);
stage.addEventListener(KeyboardEvent.KEY_UP, fl_UnsetKeyPressed);
function fl_MoveInDirectionOfKey(event:Event)
{
if (upPressed)
{
rutte.y -= 5;
}
if (downPressed)
{
rutte.y += 5;
}
if (leftPressed)
{
rutte.x -= 5;
rutte.scaleX = 1; // face left
}
if (rightPressed)
{
rutte.x += 5;
rutte.scaleX = -1; // face right
}
}
function fl_SetKeyPressed(event:KeyboardEvent):void
{
switch (event.keyCode)
{
case Keyboard.UP:
{
upPressed = true;
break;
}
case Keyboard.DOWN:
{
downPressed = true;
break;
}
case Keyboard.LEFT:
{
leftPressed = true;
break;
}
case Keyboard.RIGHT:
{
rightPressed = true;
break;
}
}
}
function fl_UnsetKeyPressed(event:KeyboardEvent):void
{
switch (event.keyCode)
{
case Keyboard.UP:
{
upPressed = false;
break;
}
case Keyboard.DOWN:
{
downPressed = false;
break;
}
case Keyboard.LEFT:
{
leftPressed = false;
break;
}
case Keyboard.RIGHT:
{
rightPressed = false;
break;
}
Thank you in advance for all the help you can give me.
Kind Regards.
in flash there is a fundamental aspect of how timeline and scenes works. Once you move away from a frame to another frame, The content of the frame and it's properties/states/actions are gone and reseted.
Personally I recommend you use a single scene with a timeline divided into frames labeled, there you can specify a layer for the actions and global variables, one for the user interface and another one for the specific actions of each frame. example:
So you never lose the reference of variables because the frame is not constantly recreated, all your important actions, including you timer, should be in your first frame.
I was testing, here you can see a working example: http://db.tt/FZuQVvt3. Here you can download the FLA file to be used as a base for your project: http://db.tt/RHG9G5lo