I am drawing a circular line to varying degrees. I wish the animation to last about 0.5 seconds. For reasons I can not work out its running very slowly.
What is weird is that if I skip the tween and call the function tweenToNext it renders instantly.
var degrees:int;
var posX:int = 102;
var posY:int = 102;
var rad:int = 100;
var mc:MovieClip = new MovieClip();
addChild(mc);
mc.graphics.lineStyle(5, 0xFF0000, 1);
mc.graphics.moveTo(posX, posY - rad)
mc.i = -Math.PI / 2;
tweenToNext();
function tweenToNext(per:Number = 360):void {
degrees += 1;
if (mc.i <= (3 * Math.PI / 2) && degrees < per) {
var x:Number = posX + Math.cos(mc.i) * rad;
var y:Number = posY + Math.sin(mc.i) * rad;
mc.graphics.lineTo(x, y);
mc.i += Math.PI / 180;
TweenLite.to(mc, 0.001, {onComplete:tweenToNext});
}
}
I have tried Timer and setTimeout but these produce the same slow speed.
Flash application runs on frame-to-frame basis: frame render - script execution - frame render - script execution - frame render - script execution - and so on. That also means that whatever smallest delay you're putting there, the next call will not happen before next script execution phase, basically, next frame. Thus - guess what - your circle drawing takes 360 frames. 12 seconds if you have 30 FPS, for example.
If you want to make something synchronize with the real time, you need a different approach. I didn't check if this works, but I hope you'll get the idea and fix the mistakes if any.
var degrees:int;
var posX:int = 102;
var posY:int = 102;
var rad:int = 100;
var mc:MovieClip = new MovieClip;
addChild(mc);
mc.graphics.lineStyle(5, 0xFF0000, 1);
mc.graphics.moveTo(posX, posY + rad);
// Now, magic time.
// Save time since app start (in milliseconds).
var startTime:int = getTimer();
// 1000 milliseconds = 1 second.
var drawingTime:int = 1000;
// Store the maximum degree to draw.
var degreeLimit:int = 360;
// Call it every frame.
mc.addEventListener(Event.ENTER_FRAME, onDraw);
function onDraw(e:Event):void
{
// Now we need to check how much time passes since last frame
// and update the drawing accordingly.
var timeProgress:Number = (getTimer() - startTime) / drawingTime;
var drawingProgress:Number = degrees / degreeLimit;
// When the drawing progress catches the time progress
// the loop will end. It will resume on the next frame.
while (drawingProgress < timeProgress)
{
degrees += 1;
// It's better than a property on target canvas,
// which could be Sprite or Shape, they wouldn't take random fields.
var anAngle:Number = degrees * Math.PI / 180;
var tox:Number = posX + Math.cos(anAngle) * rad;
var toy:Number = posY + Math.sin(anAngle) * rad;
mc.graphics.lineTo(tox, toy);
// We should know when to stop it.
if (dergees >= degreeLimit)
{
mc.removeEventListener(Event.ENTER_FRAME);
return;
}
// Update the drawing progress.
drawingProgress:Number = degrees / degreeLimit;
}
}
Related
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!
I have a monster that produces crystals. I want each crystal to orbit the monster, but when there is more than one crystal, I want them to orbit at an equal distance from each other. I've been trying to get this to work using two blocks of code I already have, but each one does something different and i need one block of code that does it all.
This block simply allows an object to orbit another:
orbitRadius = 110;
angle += orbitSpeed;
rad = (angle * (Math.PI / 180));
orbitX = monster.x + orbitRadius * Math.cos(rad);
orbitY = monster.y + orbitRadius * Math.sin(rad);
Here's a video of what it looks like:
https://www.youtube.com/watch?v=ACclpQBsjPo
This block of code arranges crystals around the monster based on the amount of crystals there are:
radius = 110;
angle = ((Math.PI * 2) / targetArray.length) * targetArray.indexOf(this);
orbitX = monster.x - (radius * Math.cos(angle));
orbitY = monster.y - (radius * Math.sin(angle));
And here's this video: https://www.youtube.com/watch?v=TY0mBHc2A8U
I do not know how to both space the crystals equally and make them circle around the monster at the same time. What needs to be done in order to achieve this?
1) Hierarchical way: put crystals into the same container so they spread equally (like you are doing on the second video) then rotate the container.
2) Math way.
Implementation:
public class Orbiter extends Sprite
{
// Pixels.
public var radius:Number = 100;
// Degrees per second.
public var speed:Number = 360;
public var items:Array;
public var lastTime:int;
public function start()
{
stop();
rotation = 0;
items = new Array;
lastTime = getTimer();
addEventListener(Event.ENTER_FRAME, onFrame);
}
public function stop():void
{
items = null;
removeEventListener(Event.ENTER_FRAME, onFrame);
}
public function onFrame(e:Event = null):void
{
var aTime:int = getTimer();
rotation += speed * (aTime - lastTime) / 1000;
lastTime = aTime;
for (var i:int = 0; i < items.length; i++)
{
// Get the object.
var anItem:DisplayObject = items[i];
// Get the object's designated position.
var aPos:Point = getPosition(i);
// Follow the position smoothly.
anItem.x += (aPos.x - anItem.x) / 10;
anItem.y += (aPos.y - anItem.y) / 10;
}
}
private function getPosition(index:int):Point
{
// Calculate the angle with regard to the present items amount.
var anAngle:Number = (rotation - 360 / items.length) * Math.PI / 180;
var result:Point = new Point;
// Figure the position with regard to (x,y) offset.
result.x = x + radius * Math.cos(anAngle);
result.y = y + radius * Math.sin(anAngle);
return result;
}
}
Usage:
var O:Orbiter = new Orbiter;
// Define the offset.
O.x = monster.x;
O.y = monster.y;
// Set radius and rotation speed.
O.radius = 110;
O.speed = 270;
// Enable the rotation processing.
O.start();
// Append items to orbit.
O.items.push(Crystal1);
O.items.push(Crystal2);
O.items.push(Crystal3);
You can change radius and speed any time, as well as add/remove items, thanks to motion smoothing that all will look equally fine.
I have a sprite in a movie symbol that I would like to hover back and forth within a 360 radius. I was hoping to make it smooth and random. Never really venturing from its original xy cordinates.
I've tried to create some stipulations with if statements and a starting momentum. Like this:
var num = 2;
stage.addEventListener(Event.ENTER_FRAME, hover);
function hover(evt:Event):void{
//start it moving
cloudWhite.y += num;
cloudWhite.x += num;
//declare these variables
var cX = cloudWhite.x;
var cY = cloudWhite.y;
// object travels 10 pixels
var cXP = cX + 10;
var cXN = cX - 10;
var cYP = cY + 10;
var cYN = cY - 10;
// if object goes 10 pixels reverse direction of momentum (maybe)
if (cX >= cXP) {
num = -2;
}
if (cX <= cXN){
num = 2;
}
if (cY >= cYP) {
num = 2;
}
if (cY <= cYN){
num = 2;
}
Clearly this is super wrong because when it runs the object just either goes to 0,0 or to some place that only the math gods know of.
I am clearly a noob at this kind of math so i apologize but I am very excited to learn the trig behind this.
Thank you for your help and thank you for reading.
You are setting all your variables inside the ENTER_FRAME loop, so none of your conditions ever evaluates to true. On every single frame you are doing this:
cloudWhite.x += 2;
cX = cloudWhite.x;
cXP = cX + 10; // Must == cloudWhite's previous x + 10 + 2;
cXN = cX - 10; // Must == cloudWite's previous x -10 + 2;
if(cX > cXP)... // Can never be true.
if(cX < cXN)... // Can never be true.
What you need to do is:
1) Store the original position of cloudWhite somewhere outside the loop, and store it before the loop begins.
2) Define your bounds relative to the original position of cloudWhite, again before your loop begins. Also define the amount you are going to change the position with each iteration.
3) Start your loop.
4) Increment the current position of cloudWhite on each iteration. Add a little random in here if you want the shape to move in a random manner.
5) Check if the new position of cW is outside your bounds and adjust the direction if it is.
The sample below is crude and jerky but I don't know exactly what effect you're looking for. If you want smoother, longer movements in each direction, consider using the Tween class or a Tween library such as the popular Greensock one, instead of incrementing / decrementing the position manually. There's a useful discussion of this here: http://www.actionscript.org/forums/archive/index.php3/t-163836.html
import flash.display.MovieClip;
import flash.events.Event;
// Set up your variables
var original_x:Number = 100; // Original x
var original_y:Number = 100; // Original y
var x_inc:Number = 5; // X Movement
var y_inc:Number = 5; // Y Movenent
var bounds:Number = 50; // Distance from origin allowed
// Doesn't take into account width of object so is distance to nearest point.
// Create an MC to show the bounds:
var display:MovieClip = addChild(new MovieClip()) as MovieClip;
display.graphics.lineStyle(1, 0x0000FF);
display.graphics.beginFill(0x0000FF, 0.5);
display.graphics.drawRect(0-bounds, 0-bounds, bounds * 2, bounds *2);
display.x = original_x;
display.y = original_y;
addChild(display);
// Create our moving mc:
var mc:MovieClip = addChild(new MovieClip()) as MovieClip;
mc.graphics.beginFill(0xFF0000, 1);
mc.graphics.drawCircle(-10, -10, 20);
// Position it:
mc.x = original_x;
mc.y = original_y;
addChild(mc);
// Loop:
function iterate($e:Event = null):void
{
// Move the mc by a random amount related to x/y inc
mc.x += (Math.random() * (2 * x_inc))/2;
mc.y += (Math.random() * (2 * y_inc))/2;
// If the distance from the origin is greater than bounds:
if((Math.abs(mc.x - original_x)) > bounds)
{
// Reverse the direction of travel:
x_inc == 5 ? x_inc = -5 : x_inc = 5;
}
// Ditto on the y axis:
if((Math.abs(mc.y - original_y)) > bounds)
{
y_inc == 5 ? y_inc = -5 : y_inc = 5;
}
}
// Start the loop:
addEventListener(Event.ENTER_FRAME, iterate);
This should get you started. I'm sure there are any number of other ways to do this with formal trig, but this has the benefit of being very simple, and just an extension of your existing method.
I have a movie clip (goalkeeper) with different positions in different frames (inside), I would like to play a random frame after executing a function to make the goalkeeper move to a determinate position, there are 6 frames with 6 different positions so I need to play 1 position randomly, this is the code that should go to the random number after ball is kicked:
function moveBall()
{
var targetX:Number = mouseX;
var targetY:Number = mouseY;
var angle = Math.atan2(targetY,targetX);
ball.x = mouseX + Math.cos(angle);
ball.y = mouseY + Math.sin(angle) ;
ballRotation = true;
if (ballRotation==true)
{
goalkeeper_mc.gotoAndStop( Random Frame);//Here is when I need to go and play the random frame everytime function is executed
}
Thanks a lot for your help guys, sorry for bothering again, I searched the web for some examples but I found many of them really complicated for a newbie like me.
refer a following code.
you must randomize from 1 frame to last Frame.
Math.random () of the range is greater than 0 and less than 1(floating-value). by use it implements available.
function moveBall()
{
var targetX:Number = mouseX;
var targetY:Number = mouseY;
var angle = Math.atan2(targetY,targetX);
ball.x = mouseX + Math.cos(angle);
ball.y = mouseY + Math.sin(angle) ;
ballRotation = true;
if (ballRotation==true)
{
goalkeeper_mc.gotoAndStop(int(Math.random * (goalkeeper_mc.totalFrames)+1));
}
}
goalkeeper_mc.gotoAndStop(1 + Math.floor(Math.random() * goalkeeper_mc.totalFrames));
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Main_fla::MainTimeline/BulletFire()[Main_fla.MainTimeline::frame32:68]. Is occurring and I have no idea why...PLEASE HELP, it has been days of me troubleshooting this and i am completely lost. Thanks, also, for some reason when I fire the bullet it only goes at 45 degrees and 225 degrees...Thanks guys
//Create an array to hold multiple sprites
var mySpriteHolder:Array = [];
//Create a counter to keep track of the number of sprites
var lbCounter:int = 0;
//Maximum number of sprites on the canvas
var maxLB:int = 1;
//Keypress Code
stage.addEventListener(MouseEvent.CLICK, dropBullet);
//Function for the mouse event to fire bullet
function dropBullet(evt:MouseEvent):void{
var bcos:Number = Math.cos((Turret.rotation) * Math.PI / 180);
var bsin:Number = Math.sin((Turret.rotation) * Math.PI / 180);
//starting x and y
var startx:Number = Turret.x + (15 * bcos);
var starty:Number = Turret.y + (15 * bsin);
//calculates where the bullet needs to go by aiming in front of the gun
var endx:Number = Turret.x + (50 * bcos);
var endy:Number = Turret.y + (50 * bsin);
var Bullet:MovieClip = new bullet();
Bullet.x = startx;
Bullet.y = starty;
Bullet.xspeed = (endx - startx)/5;
Bullet.yspeed = (endx - startx)/5;
mySpriteHolder.push(Bullet);
stage.addChild(Bullet);
//this calls the move down function
stage.addEventListener(Event.ENTER_FRAME,BulletFire);
}
//Function to shoot bullet
function BulletFire(evt:Event):void{
var Bullet:MovieClip;
//Use a for loop to move the Bullets
for(var i:int=0; i<=mySpriteHolder.length; i++){
Bullet = mySpriteHolder[i];
//Bounds Collision
if(Bullet.hitTestObject(Up)){
Bullet.yspeed*=-1;
}
if(Bullet.hitTestObject(Lower)){
Bullet.yspeed*=-1;
}
if(Bullet.hitTestObject(Left)){
Bullet.xspeed*=-1;
}
if(Bullet.hitTestObject(Right)){
Bullet.xspeed*=-1;
}
//Blockade Collision
for(var t in myBlockadeHolder){
if(Bullet.hitTestObject(myBlockadeHolder[t])){
trace("test");
}
}
//Target Collision
for(var c in mytargetHolder){
if(Bullet.hitTestObject(mytargetHolder[c])){
stage.removeChild(Bullet);
mySpriteHolder.splice(i,1);
lbCounter --;
mytargetHolder[c].y = Math.random()*390 + 10;
mytargetHolder[c].x = Math.random()*390 + 10;
while(mytargetHolder[c].hitTestObject(Turret)){
mytargetHolder[c].y = Math.random()*390 + 10;
mytargetHolder[c].x = Math.random()*390 + 10;
}
}
for(var a in mytargetHolder){
for(var s in mytargetHolder){
while(mytargetHolder[a].hitTestObject(mytargetHolder[s])&& a!=s){
mytargetHolder[a].y = Math.random()*390 + 10;
mytargetHolder[a].x = Math.random()*390 + 10;
}
}
for(var g in myBlockadeHolder){
while(mytargetHolder[a].hitTestObject(myBlockadeHolder[g])&& a!=g){
mytargetHolder[a].y = Math.random()*390 + 10;
mytargetHolder[a].x = Math.random()*390 + 10;
}
}
}
}
Bullet.y += Bullet.yspeed;
Bullet.x += Bullet.xspeed;
}
}
mySpriteHolder.splice(i,1);
This line is probably causing some unexpected results (and possibly your error) as you're splicing objects from the array your loop is working incrementally from. It's important to understand that when you splice an object in AS3 you're effectively removing that element and all indices that follow move down the splicing amount. Try working backwards in the loop instead:
for(var i:int=mySpriteHolder.length-1; i>=0; i--){
Also, this line should be moved out of your MouseClick Event as you're adding multiple ENTER_FRAME events every time a bullet is placed. As it is right now it's going to do an additional bulletFire() pass every time you mouse click:
stage.addEventListener(Event.ENTER_FRAME,BulletFire);
For a start:
for (var i:int = 0; i < mySpriteHolder.length; i++) {
...
i.e. change <= to <. If i becomes mySpriteHolder.length then you'll get an out-of-bounds exception.
Next:
stage.removeChild(Bullet);
mySpriteHolder.splice(i--, 1);
i.e. when you remove the current element from the array, you also decrement the index i. It'll get incremented again in the next iteration, so you'll be at the same index. For example, if you delete the 5th element, you want to look at the new 5th element (previously the 6th) in the next iteration, as opposed to the new 6th element (previously the 7th). In your current code, you're inadvertently skipping one - not to mention that itself could give you an out-of-bounds exception.
By "out-of-bounds" I mean Bullet being undefined.