Actionscript3, why does this happen? - actionscript-3

I'm get the delta time for each frame, and this is how i do it..
private var currFrame:Number,lastFrame:Number,delta:Number,playerX:Number = 10;
public function step(e:Event):void
{
trace(playerX);
currFrame = getTimer();
delta = (currFrame - lastFrame) / 1000;
lastFrame = currFrame;
playerX += (delta);
}
And the result is 'NaN' on every frame. But this works
private var currFrame:Number,lastFrame:Number=0,delta:Number,playerX:Number = 10;
public function step(e:Event):void
{
trace(playerX);
currFrame = getTimer();
delta = (currFrame - lastFrame) / 1000;
lastFrame = currFrame;
playerX += (delta);
}
the difference if you don't notice is "lastFrame:Number=0"
Any idea why, im moving from java to Actionscript3, so the more information the better :)
gettimer is this: import flash.utils.Timer;

Your code, lastFrame:Number=0, is setting the value of lastFrame to 0 when it is created. If the value of lastFrame isn't set to 0, then it's value is undefined. In AS2, undefined would get treated like 0. In AS3, undefined is treated like NaN.
Doing any calculation with NaN returns NaN. For example: 5 + NaN = NaN.So the first time you run your function you are doing this:
delta = (currFrame - NaN) / 1000; //set delta to NaN
lastFrame = currFrame; // sets lastFrame to something besides NaN
playerX += (delta); //sets playerX to NaN
Now your lastFrame isn't NaN, it seems like things should be working, however, playerX is now NaN, so the line:
playerX += (delta); // will always be NaN now, even if delta is not NaN
Will keep playerX at NaN forever. Because NaN + Anything is still NaN. So NaN += Anything is always NaN.

Related

Simple click and hit flash game

I am trying to create a simple game like whack a mole, what I want is for instead of mole make rectangle appear and disappear quickly on screen and the player has to click it more rectangles he click more his score increases.
I think it's a fairly simple game but my problem is:
How do I make the rectangles appear and disappear on screen at random position also at increasing speeds as the timer is decreasing? i.e speed of rectangles appearing and disappearing increases as the time reduces, there is a countdown time as player gets to play for 30 sec.
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
var inc:Number = 1;
var gogo:Timer = new Timer(inc*1000);
var val:Number = 30;
var counter = val;
var time2:Timer = new Timer(1000+speed);
var speed:Number = 50;
timee.text = counter;
box.addEventListener(MouseEvent.CLICK, st);
function st(event:MouseEvent):void
{
gogo.start();
time2.start();
}
gogo.addEventListener(TimerEvent.TIMER, res);
function res(ev:TimerEvent):void
{
if(counter == 0){
gogo.stop();
}else{
val = val - inc;
counter = val;
timee.text = counter;
}
}
stage.addEventListener(Event.ENTER_FRAME, yea);
function yea(e:Event):void{
speed += 50;
}
It seems to me that you need a math.random() method.
explained here
I'd personally have every successful 'hit' lower a "blinkSpeed" variable by either a set fraction of a second or a percentage and use that variable as my random input "max" number. That way it would decrease the time it could be available for automatically as they play.
Hello
Well, that wouldn't be much hard! Here's a clue.
Step1 : Create a new movieclip.
Step2 : Right click on your movie clip in the library. Click properties. Check the "Export for ActionScript" checkbox. Name the class MyEnemy (for example).
Step3 : Go to the frame and pull the Actions window.
Now put this code in it :
var mc:MyEnemy= new MyEnemy() // creates a instance of the movieclip.
addChild(mc); // adds the movie clip to the stage.
Step 4 : Now that we have added a new movieclip to the stage. To add it at a random x location in the stage, you need to make use of mc's x and y fields and the Math.random() function.
Example of Math.random() :
var randomThing:Number = Math.random() * 100 // returns a number between n, where 0 <= n < 100
Now, for example, we need both x and y values relative to the stage you must multiply Math.random() with the stage's width instead. As follows :
var randomX:Number = Math.random() * stage.stageWidth // returns a number between n, where 0 <= n < stage.stageWidth
var randomY:Number = Math.random() * stage.stageWidth // returns a number between n, where 0 <= n < stage.stageWidth
And! The magic final code would be :
mc.x = randomX;
mc.y = randomY;
Edit 1 : To add multiple "mc" movieclips to stage, we would use loops, do the follow :
stage.addEventListener(Event.ENTER_FRAME, doSimple);
function doSimple (ev:Event) {
var mc:MyEnemy = new MyEnemy();
var randomX:Number = Math.random() * stage.stageWidth // returns a number between n, where 0 <= n < stage.stageWidth
var randomY:Number = Math.random() * stage.stageWidth // returns a number between n, where 0 <= n < stage.stageWidth
for (var i:Number=1; i<=10;i++){ //i is a number, you can discard the 'i<=10' if you want an infinite loop.
addChild(mc);
}
mc.x = randomX;
mc.y = randomY;
trace("yes");
}
Conclusion : I look forward for your feedback!

as3 move towards function jitters on Y axis

As the title suggests, I've written a move towards function that works perfectly fine, except that it jitters on the Y axis.
The problem
It happens when the function is operating on the Y axis and the difference between the starting value and the target value is less than that between the starting value and the value to return - meaning that the value has gone past its target. as this point, it's supposed to set the returning value to the target value, but for the most part it's not. Except when it's operating on the x axis, in which case it works fine. It's really strange.
The code
here's the code I'm using for the function:
public static function LookAt(thisX:Number, thisY:Number, targetX:Number, targetY:Number, speed:Number = 0, startRot:Number = 0):Number
{
// Get the distances between the two parsed points
var xDif:Number = targetX - thisX;
var yDif:Number = targetY - thisY;
// Use a tangent formula to get the rotation to return in radians, then convert to degrees
var rot:Number = Math.atan2(xDif, yDif) * 180/Math.PI * -1 - 180;
// If a speed has been parsed
if (speed != 0)
{
// Ensure the parsed starting rotation is between -180 and 180
while (startRot > 180)
{startRot -= 360;}
while (startRot < -180)
{startRot += 360;}
// If the rotation previously calculated is less than the parsed starting rotation,
// return the starting rotation minus the speed. Otherwise, return the starting rotation
// plus the speed
return (rot > startRot) ? startRot + speed : startRot - speed;
}
else
{
return rot;
}
}
public static function PointAround (axisPos:Number, angle:Number, speed:Number, axis:String = "x"):Number
{
// Convert the parsed angle into radians
var fixedRot = angle * Math.PI / 180;
// Return the parsed position plus speed multiplied by the sine of the angle in radians for the x axis,
// or the cosine of the angle in radians for the y axis
return (axis == "x") ? axisPos + speed * Math.sin(fixedRot) : axisPos + speed * Math.cos(fixedRot) * -1;
}
public static function PointTowards(thisX:Number, thisY:Number, targetX:Number, targetY:Number, speed:Number, axis:String = "x"):Number
{
// Use the LookAt function to calculate a rotation for later use in this function
var workingAngle:Number = ExtraMath.LookAt (thisX, thisY, targetX, targetY);
var toReturn;
var thisVar:Number = (axis == "x") ? thisX : thisY;
var targetVar:Number = (axis == "x") ? thisX : thisY;
toReturn = ExtraMath.PointAround (thisVar, workingAngle, speed);
// BUGGY LINE
toReturn = (thisVar >= targetVar && toReturn <= targetVar
|| thisVar <= targetVar && toReturn >= targetVar)
? targetVar
: toReturn;
return toReturn;
}
and here's the code I'm using to test it:
public var c:Sprite;
public function TestZone()
{
// constructor code
stage.addEventListener(Event.ENTER_FRAME, Update);
}
private function Update (e:Event):void
{
c.x = ExtraMath.PointTowards(c.x, c.y, stage.mouseX, stage.mouseY, 5);
c.y = ExtraMath.PointTowards(c.x, c.y, stage.mouseX, stage.mouseY, 5, "y");
}
things I've tried already
turning the line into regular a regular if statement with curly brackets and all, and tracing the variables thisY, targetY and toReturn after it has been operated on. the really annoying thing is that it turns out it sometimes actually returns the right number, but then proceeds to bug out again
Using an absolute value instead of stage.mouseY in testing. bug occurs as usual
Performing the function on the Y axis before the X axis. no difference
Changing the condition for setting the variables thisVar and targetVar to (axis != x) and switching the if/else values. do difference
A few things may be causing the problem:
[LookAt]
return (rot > startRot) ? startRot + speed : startRot - speed;
This may cause overshooting. If rot is only very slightly different from startRot, you are still adding (or subtracting) a full speed increment. If the absolute distance between rot and startRot is less than speed, it should return rot regardless.
This reduces angular jittering.
[PointAround]
return (axis == "x") ? axisPos + speed * Math.sin(fixedRot) : axisPos + speed * Math.cos(fixedRot) * -1;
Watch out for operator precedence. You are expecting this line to be parsed as
(axis == "x") ?
(axisPos + speed * Math.sin(fixedRot)) :
(axisPos + speed * Math.cos(fixedRot) * -1);
But that may not be the case. The line may instead be interpreted as
(
(axis == "x") ?
(axisPos + speed * Math.sin(fixedRot)) :
axisPos
)
+ speed * Math.cos(fixedRot) * -1;
You can either memorize all precedence rules and make sure you never mistake them, or put parenthesis around to ensure it's doing the right thing. In this case you can simplify the expression to
axisPos + speed * (axis == "x" ? Math.sin(fixedRot) ? -Math.cos(fixedRot))
var thisVar:Number = (axis == "x") ? thisX : thisY;
var targetVar:Number = (axis == "x") ? thisX : thisY;
So thisVar and targetVar always have the same value? I don't understand what was supposed to happen here, and nobody seems to reassign those variables later.
c.x = ExtraMath.PointTowards(c.x, c.y, stage.mouseX, stage.mouseY, 5);
c.y = ExtraMath.PointTowards(c.x, c.y, stage.mouseX, stage.mouseY, 5, "y");
You are changing the position separately in each axis. It may work, but it's harder and error prone. For example
c.x = ...PointTowards(c.x ...);
c.y = ...PointTowards(c.x ...);
You are changing the value of c.x between the calls, so the first call to PointTowards see a different point from the second call. That may be the reason why the jittering only happens on the y axis. I suggest making a function that deals with box axis at once, or at the very least storing the old values of c.x and c.y:
var oldX:Number = c.x;
var oldY:Number = c.y;
c.x = ExtraMath.PointTowards(oldX, oldY, stage.mouseX, stage.mouseY, 5);
c.y = ExtraMath.PointTowards(oldX, oldY, stage.mouseX, stage.mouseY, 5, "y");
I fixed it! I changed the function to return a point object instead of a number and now it works perfectly

Breakout with Flash: I need help to improve my Brick n Ball collision

I've been stuck on this problem for a very long time now, I've searched around alot and tried stuff, but nothing works. Some explanations are just very hard for me to understand as Im pretty new to programming overall and got alot to learn.
I have two problems
1: The ball wont collide with the bricks sometimes when the speed is too fast.
2: The ball is capable of hitting 2 bricks.
Both problems is related to the fact that 60 fps isnt enough for my type of collision detection to work properly.
I just need someone to explain in a simple way as possible what I need to do to make a collision detection that will prevent this from happen.
Here's my current collision code:
private function checkCollision(): void {
grdx = Math.floor((ball.x) / 28);
grdy = Math.floor((ball.y) / 14);
ngrdx = Math.floor((ball.x + dx) / 28);
ngrdy = Math.floor((ball.y + dy) / 14);
var flipX: Boolean = false;
var flipY: Boolean = false;
if ((grdy <= level.length - 1) &&
(ngrdy <= level.length - 1) &&
(grdy >= 0 && ngrdy >= 0)) {
if (testBlock(grdx, ngrdy)) {
flipY = true;
paddleFlag = 1;
}
if (testBlock(ngrdx, grdy)) {
flipX = true;
paddleFlag = 1;
}
if (testBlock(ngrdx, ngrdy)) {
flipX = true;
flipY = true;
paddleFlag = 1;
}
dx *= flipX ? -1 : 1;
dy *= flipY ? -1 : 1;
}
}
private function testBlock(xPos: int, yPos: int): Boolean {
if (level[yPos][xPos] > 0 && level[yPos][xPos] != 13) {
trace("hit on X,Y");
level[yPos][xPos] = 0;
breakBlock("Block_" + yPos + "_" + xPos);
trace("Block: " + totalBreaks + " / " + totalBlocks);
return true;
}
return false;
}
private function breakBlock(blockName: String): void {
if (this.getChildByName(blockName)) {
this.removeChild(this.getChildByName(blockName));
totalBreaks++;
}
}
Thank you and sorry for my bad english, its not my motherlanguage.
One solution is to move the ball in smaller iterations, multiple times in a given frame.
For example, and I am giving this solution assuming that you are moving the ball based on the time elapsed from the last frame.
Suppose that 30 milliseconds have elapsed since the last frame update. In that case you would update the movement/collision twice in that frame using 15 millisecond as your time elapsed.
The higher resolution of collision you want, the more iterations you would do.
Here's an example :
// class declarations
var lastFrame:Number;
var iterationsPerFrame:int;
function startGame():void
{
// lets specify 3 updates per frame
iterationsPerFrame = 3;
// save initial time
lastFrame = getTimer();
// create your listener
addEventListener(Event.ENTER_FRAME, update);
}
function update(e:Event):void
{
var currentFrame:Number = getTimer();
var deltaTime:Number = (currentFrame - lastFrame)/1000;
var iterationDelta:Number = deltaTime/iterationsPerFrame;
for (var index:int = 0;index < iterationsPerFrame;index++)
{
// I'm assuming dx,dy are the velocity of the ball, in pixels per second
ball.x += dx * iterationDelta;
ball.y += dy * iterationDelta;
// check collision
}
// set lastFrame to the currentFrame time, preparing for next frame
lastFrame = currentFrame;
// after this, your frame is going to render
}
You could work out how far the ball travels each frame (A) based on its speed, how far the ball is from the paddle (B) and if A > B manually trigger a collision that frame.
You're essentially checking every bricks X and Y coordinate to the balls X and Y coordinate, so if the bricks are stored in an array this becomes: Sqrt( Sqrd(p2.x - p1.x) + Sqrd(p2.y - p1.y))
for(var i=0; i<brickArray.length; i++)
{
var distance:Number = Math.sqrt((brickArray[i].x - ball.x) * (brickArray[i].x - ball.x) +
(brickArray[i].y - ball.y) * (brickArray[i].y - ball.y));
}
This is a very good tutorial on high speed collison detection:
http://www.newgrounds.com/bbs/topic/1072673

Bug in space movement FLASH

I'm new to flash and can't find the bug in my code. I want a space ship to be able to accelerate in a vector, to not be able to accelerate over a max velocity, to keep that velocity vector when it stops accelerating but then suffer from friction (space dust ,) ). (It happens in a 2d stage.)
I think my math is correct, but I get a bug with velVector sometimes returns NaN - here's my code:
var friction:Number = .96;
var force:Number = .1;
var maxVel:Number = 3;
var accVector:Object = new Object();
var velVector:Object = new Object();
var velocity:Number;
var acceleration:Number;
If the ship points in the right direction it executes function 'accelerate' and if not it executes function 'drift'. It always executes 'moveship'
function accelerate():void {
curRotation.vx = Math.cos(rotation/180*Math.PI);
curRotation.vy = Math.sin(rotation/180*Math.PI);
var angle:Number = Math.atan2(curRotation.vy, curRotation.vx);
velocity = Math.sqrt(velVector.vx^2 + velVector.vy^2); //get velocity in both directions
acceleration = (maxVel - velocity)/maxVel*force; //this is to make it harder to accelerate when it approaches maxvelocity
accVector.vx = Math.cos(angle) * acceleration; //accelerate in each dimension
accVector.vy = Math.sin(angle) * acceleration;
velVector.vx += accVector.vx; //add acceleration to velocity
velVector.vy += accVector.vy;
}
function drift():void {
velVector.vx *= friction; //decrease velocity when not accelerating
velVector.vy *= friction;
}
function moveShip():void {
trace("velocity", velocity)
x += velVector.vx; //move
y += velVector.vy;
}
Many thanks!
I guess, your problem is in using of unsafe math operations without values validation. So, your velVector depends on accVector which depend on acceleration. You have a division operation counting "acceleration" val. That's it:
acceleration = (maxVel - velocity)/maxVel*force;
In AS3 you CAN divide by zero, and you'll get Infinity in such situation. But, there is also a chance to get NaN in case you are dividing zero by zero:
var acceleration:Number = 0 / 0;
trace(acceleration); //NaN
If you try doing something with NaN writing the result in Number or untyped variable (not int!), you'll always get NaN:
var a:Number = 5 * NaN;
trace(a); //NaN
So, I here is an example, which gives NaN:
acceleration = 0 / 0; //NaN
accVector.vx = Math.cos(angle) * acceleration; //NaN regardless on "angel" value
velVector.vx += accVector.vx; //NaN regardless on "velVector" value.
I hope, this will help.

Movement in AS3

I am learning AS3. How can I move a symbol?
My Code
var counter:int = new int();
counter = 0;
var point:symbol1 = new symbol1();
addChild(point);
point.x = 25 + 50;
point.y = 25 + 50;
stage.addEventListener(KeyboardEvent.KEY_DOWN, move_handler);
function move_handler(e) {
if (e.keyCode == Keyboard.SPACE) {
while (counter < 200)
{
trace(counter);
point.x += 1;
counter += 1;
}
}
}
But when I press space the symbol is to fast. How can edit the speed of the point?
You need to use an ENTER_FRAME event :
stage.addEventListener(Event.ENTER_FRAME,stageEnterFrame);
function stageEnterFrame(e:Event):void{
displayObject.x+=1
}
The displayList is updated only after code execution, that's why your object move so 'fast'.
This link may help you understand the process.
At the moment you are waiting for the user to press the space bar and then moving the symbol to the right by one pixel 200 times.
But as OXMO456 has said all 200 times that it moves to the right happen at the same time as if you had manually typed "point.x += 1;" 200 times.
if your intention is to only let it move to the right 200 times then you could replace the while statement with an if statement:
if(counter<200){
trace(counter);
point.x+=1;
counter+=1;
}
You could then change the speed it moves at by changing the number after "point.x+=".
An even better way of changing the speed would be by using a variable to make it clearer what the number does. This also makes it easier to use that number for other things, like moving in other directions at the same speed.
Here's what the finished code would look like with these changes and a bit of clean up:
var counter:int = 0; // setting this variable as you define it saves space
var speed:Number = 1; // here's the speed variable (declared as a number so you can have fractions)
var point:symbol1 = new symbol1();
addChild(point);
point.x = 75; // 25+50 is 75, one less thing for flash to work out
point.y = 75;
stage.addEventListener(KeyboardEvent.KEY_DOWN, move_handler);
function move_handler(e) {
if (e.keyCode == Keyboard.SPACE) {
if (counter < 200)
{
trace(counter);
point.x += 1;
counter += 1;
}
}
}
Does that make sense?
Do it like this:
Point.x += 0.2; instead of point.x += 1;
this event type is what you want:
' stage.addEventListener(Event.ENTER_FRAME,enterFrameHandler)'
Use tween:
import libraries:
import fl.transitions.Tween;
import fl.transitions.easing.*;
import fl.transitions.TweenEvent;
var myTween:Tween = new Tween(ball, "x", Strong.easeOut, ball.x, ball.x + 100, 5, true);
This code moving your object ("ball") to 100 on "x" axis in 5s.
Your while loop is making it fast, if you remove your while statement then it will work on SPACE DOWN
Welcome to the world of AS3.
Your description of your problem is a little vague, but i think i know what you what to do. You want to tween a display object (symbol1) 200 px right everytime you hit space? if so, here is how you do it:
import flash.events.KeyboardEvent;
import flash.events.Event;
var destinationX:int = 0; // this contains the point's destination x
var point:symbol1 = new symbol1(); // best practice is to name all your classes starting with upper case, like Symbol1, not symbol1
addChild(point);
point.x = 25 + 50;
point.y = 25 + 50;
stage.addEventListener(KeyboardEvent.KEY_DOWN, move_handler);
stage.addEventListener(Event.ENTER_FRAME, render);// run render function every frame
function move_handler(e:KeyboardEvent):void{// another best practice, when injecting a variable into a function declare what type the variable is, in this case e is a KeyboardEvent. :void when not returning any values from the function, basically all functions you make in the beginning should look like this
if (e.keyCode == Keyboard.SPACE) {
destinationX += 200;// add 200 to destinationX
}
}
function render(e:Event):void{ // runs every frame, if you set your fps to 30, then this will run 30 times a second
if(destinationX > point.x){//Check if point's destination x is more than the points current x position
point.x += 1;// add 1 to points x. you can change this if you want it to go faster
}
}
Check out the Greensock library - it will take all the onEnterFrame complexity out for you and has some great features.
Full doc and examples at http://www.greensock.com/
You need this
var counter:int = new int();
var vel = 1; //<------- Move 1 pixel by frame
counter = 0;
var point:symbol1 = new symbol1();
addChild(point);
point.x = 25 + 50;
point.y = 25 + 50;
stage.addEventListener(KeyboardEvent.KEY_DOWN, move_handler);
function move_handler(e) {
if (e.keyCode == Keyboard.SPACE) {
stage.addEventListener(Event.ENTER_FRAME,moveEnterFrame);
stage.removeEventListener(KeyboardEvent.KEY_DOWN, move_handler);
}
}
function moveEnterFrame(e:Event):void{
point.x += vel;
counter ++;
if(counter >= 200){
stage.removeEventListener(Event.ENTER_FRAME,moveEnterFrame);
counter = 0;
stage.addEventListener(KeyboardEvent.KEY_DOWN, move_handler);
}
}
ENTER_FRAME is the same of While.
stage.addEventListener(Event.ENTER_FRAME, nameFunction); //this event execute fps ones on default 24 frames for seconds
var speed:int = 5;
function nameFunction(ev:Event){
simbol.x += speed;
}
Draw anything and name it in the instance name box ..... so this well speed up and down by the space key ...... i use the frame rate
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
stage.addEventListener(Event.ENTER_FRAME,stageEnterFrame);
var fremCount:int;
var upDown:int;
function stageEnterFrame(e:Event):void{
if(fremCount<30 && upDown==0){
box.x+=1
fremCount++
}
if(fremCount==30){
upDown=1;
trace("For next : "+fremCount , upDown);
}
if(upDown==1){
box.x-=1
fremCount--;
}
if(upDown==1 && fremCount==0){
upDown=0;
}
}
stage.addEventListener(KeyboardEvent.KEY_DOWN, myKeyDown);
function myKeyDown(e:KeyboardEvent):void{
if (e.keyCode == Keyboard.SPACE){
trace("Success!"+stage.frameRate);
stage.frameRate += 5;
if (stage.frameRate>150){stage.frameRate=0;}
}
}
import flash.events.Event;
var point:MovieClip = new Symbol1();
addChild(point);
point.x = 25 + 50;
point.y = 25 + 50;
stage.addEventListener(KeyboardEvent.KEY_DOWN, move_handler);
function move_handler(e)
{
if (e.keyCode == Keyboard.SPACE)
{
stage.addEventListener(Event.ENTER_FRAME, moveRight);
}
}
function moveRight(evt:Event):void
{
point.x+=1;
}
I think this is exactly what you need. Firtly you create and call upon the key_down function. Inside this function you want to call for the move function itself. This is the function I created at the bottom. To make it stop at for example 200px I suggest to work with an if-statement and a removeEventlistener.
Please note that I changed some small codings eg "var point:MovieClip = new Symbol1(); " to make it appropriate for my symbol.
why not declare your counter variable as Number (not as int)
var counter:Number = new Number();
then change your statment as
point.x += 0.1;
counter += 0.1;
this will slow down your Point movieclip. you can change motion by changing 0.1 to any value you want.
The reason why your symbol is too fast is that your while loop iterates your point.x value 200 times in only one loop. To limit your symbol position, you must use an if statement instead of a while loop:
var point:symbol1 = new symbol1();
point.x = 75; // 25 + 50;
point.y = 75; // 25 + 50;
addChild(point);
const SPEED:Number = 0.7;
const DX:int = 200; // distance to cover
var counter:Number = 0; // counts the distance covered
stage.addEventListener(KeyboardEvent.KEY_DOWN, move_handler);
function move_handler(e:KeyboardEvent):void
{
if (e.keyCode == Keyboard.SPACE && counter < DX)
{
point.x += SPEED;
counter += SPEED;
trace(counter); // stops at 200
}
}
Use the Enter Frame method.
Please don't hardcode as well :P
If you are starting you may want to consider giving one of the many existing tween engines in order to get smooth results quickly.