I need to get the object circles to continue repeat going down the screen, but I'm having trouble finding the right code - actionscript-3

import flash.display.MovieClip;
import flash.events.Event;
public class rainfall extends MovieClip {
public function rainfall() {
// rainfall
var i:int;
for (i = 0; i< 50; i++)
{
//variables
var mc:MovieClip = new MovieClip ();
//theStage, and alpha properties
mc.x = Math.random() * stage.stageWidth ;
mc.y = Math.random() * 400 * 4 ;
mc.alpha = Math.random()* 2;
mc.graphics.beginFill(0x0000FF);
mc.graphics.drawCircle(0,0,20);
//trace
trace(i);
addChild(mc);
mc.addEventListener(Event.ENTER_FRAME, moveDown) ;
}
function moveDown(e:Event):void
{ //fall speed
e.target.y += 1 ;
}
}
having a lot of trouble trying to figure out how to get the circles to repeat down the screen in a continueous loop, I'm fairly new to actionscript 3 but any tips on what im doing wrong or what I need to get it to loop threw

Try something like this:
import flash.display.Sprite;
import flash.display.Shape;
import flash.display.DisplayObject;
import flash.events.Event;
package{
public class Rainfall extends Sprite {//class names should be title case
private var numDrops = 50;//this make it easier to configure
private var dropRadius = 20;
private var maxY;
public function Rainfall() {
addEventListener(Event.ADDED_TO_STAGE,init);//make sure the stage property will not be null
}
private function init(event:Event):void{
maxY = stage.stageHeight;//getters can be slow, store the height so it can be reused for each drop reset
var i:int;
for (i = 0; i < numDrops; i++){
var mc:Shape = new Shape();//if no interactivity is needed, Shape is the simplest/lightest class to use for drawing
mc.x = Math.random() * stage.stageWidth ;
mc.y = Math.random() * 400 * 4 ;
mc.alpha = 0.1 + Math.random() * 0.9;//alpha values are from 0 to 1.
mc.graphics.beginFill(0x0000FF);
mc.graphics.drawCircle(0,0,dropRadius);
addChild(mc);
}
addEventListener(Event.ENTER_FRAME, moveDown) ;
}
private function moveDown(e:Event):void
{ //fall speed
for(var i:int = 0 ; i < numDrops; i++){
var drop:DisplayObject = getChildAt(i);
drop.y += 1 ;
if(drop.y > maxY) drop.y = -dropRadius;//if the drop exits the screen downards, place it back at the top (above the visible area)
}
}
}
}
It's not tested code, so you might run into syntax errors, but the ideas are commented:
You need to use a conditional for your problem: if the drop's vertical position is greater than the stage's height, then the drop's vertical position should reset back to the top of the stage(`if(drop.y > maxY) drop.y = -dropRadius;a)
Although not necessary if you're just getting started, here are a few tips on efficiency/speed when working in flash:
MovieClip is a dynamic class (you can add properties to instances on the fly) but also has a cost. Since you only need to render/draw elements and no events or children are needed, this makes your circles perfect candidates for using the Shape class. Also, your main class can be a Sprite since you're not using a timeline
Getters and setters can be a bit slow in actionscript. It's a healthy habbit to cache/store values that don't change much over time for reuse as local variables for faster access.
Not as much a performance issue:a common pitfall is not having the stage initialized on a display object, resulting in an annoying and for beginners puzzling null object reference errors. If you use the stage property on a DisplayObject(Shape/Sprite/MovieClip), it's best to make sure it's been added to the stage (and the stage property isn't null) using the ADDED_TO_STAGE event
Good luck!

Related

AS3 Projectile moves incorrectly

So I'm currently attempting to make a prototype for a Bullet Hell game and I've run into a bit of a dead end.
So far I can move my player perfectly, the boss moves back and forth as he is supposed to, however the projectiles have some funny behaviour. Basically, when the boss moves left/right, so do the projectiles as if they are stuck to him. They move on the y as they are supposed to, except they stop just short of the player and move no further, so I'm hoping anyone can take a look at my code and give me a hand with what's going on.
Note: Ignore the rotation stuff, that's for later implementation, I was just laying the ground work.
Projectile.as
package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
public class Projectile extends MovieClip
{
private var stageRef:Stage;
private var _xVel:Number = 0;
private var _yVel:Number = 0;
private var rotationInRadians = 0;
private const SPEED:Number = 10;
public function Projectile(stageRef:Stage, x:Number, y:Number, rotationInDegrees:Number)
{
this.stageRef = stageRef;
this.x = x;
this.y = y;
this.rotation = rotationInDegrees;
this.rotationInRadians = rotationInDegrees * Math.PI / 180;
}
public function update():void
{
this.y += SPEED;;
if(x > stageRef.stageWidth || x < 0 || y > stageRef.stageHeight || y < 0)
{
//this.removeChild(this); <- Causing a crash, will fix later
}
}
}
}
Boss.as
package
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Boss extends MovieClip
{
private var stageRef:Stage;
private var _vx:Number = 3;
private var _vy:Number = 3;
private var fireTimer:Timer;
private var canFire:Boolean = true;
private var projectile:Projectile;
public var projectileList:Array = [];
public function Boss(stageRef:Stage, X:int, Y:int)
{
this.stageRef = stageRef;
this.x = X;
this.y = Y;
fireTimer = new Timer(300, 1);
fireTimer.addEventListener(TimerEvent.TIMER, fireTimerHandler, false, 0, true);
}
public function update():void
{
this.x += _vx;
if(this.x <= 100 || this.x >= 700)
{
_vx *= -1;
}
fireProjectile();
projectile.update();
}
public function fireProjectile():void
{
if(canFire)
{
projectile = new Projectile(stageRef, this.x / 200 + this._vx, this.y, 90);
addChild(projectile);
canFire = false;
fireTimer.start();
}
}
private function fireTimerHandler(event:TimerEvent) : void
{
canFire = true;
}
}
}
Edit: Current suggestions have been to do the following:
stage.addChild(projectile); and this.parent.addChild(projectile); both which have the projectile firing from the top left corner (0, 0) and not constantly firing from the current center of the Boss.
The other issue, which has been untouched, is the fast that the projectile stops moving after a certain point and remains on the screen.
Another Edit:
After commenting out the code with the timer I have found that the projectile stops moving entirely. The reason why it was stopping after a certain amount of time was due to the timer, when the timer elapsed the projectile stopped and another would fire.
So now I need the projectile to constantly fire and move until it hits the edge of the screen, any ideas?
The problem is you are 'addChild'ing your projectiles to your Boss as opposed the stage (or the same display level as your Boss). When your Boss moves, your projectiles will move relative to him (ie, when he moves sideways, so will they).
When your boss fires a projectile, use a custom event to trigger a fireProjectile method in the Class that is your Boss' display parent. Instantiate your projectiles there and addChild them to the same object to which you addChild your Boss (possibly the stage?).
Alternatively, if you don't want to use a custom event, in your current fireProjectile method change the addChild line to:
this.parent.addChild(projectile);
This will add projectiles to the parent object of your Boss. Although that line seems, slightly, like cheating to me.

Flash AS3 (shape class) CPU usage and optimization

I'm new to Flash Actionscript 3.0 and object programming in general. I'm trying to create a simple game, which is drawing a shape based on steering.
public class Player extends Shape
{
public var X,Y,v,vX,vY,size,a,r:Number;
public var k,counter,leftKey,rightKey,_color:uint;
public var line:Shape = new Shape();
public var dot:Shape = new Shape();
/*...*/
/*constructor, giving values to variables here, not important*/
/*...*/
public function Move():void
{
a=a+0.05*k;
//player controls k parameter k=0 by default
//k=1 when right key pressed
//k=-1 when left key pressed
vX=v*Math.cos(a);
vY=v*Math.sin(a);
X=X+vX;
Y=Y+vY;
dot.x=X+vX*size/(2*v);
dot.y=Y+vY*size/(2*v);
if (counter==0)
{
line.graphics.lineTo(X,Y);
if (Math.random()<0.008) counter=12;
} else
{
line.graphics.moveTo(X, Y);
counter--;
}
}
}
Function Move is in my Player class, which is called from inifinite TimerEvent function in my Main Class
public function mainLoop(TimerEvent:Event):void
{
for (var i:uint=0; i<players; i++) player[i].Move();
}
It seems to be working well at the beginning but after some time CPU usage raises dramatically and game becomes unplayble. I belivie it's caused by my shape (line) getting more and more complex.
Is there some reasonable way to optimize it? Can I somehow draw a line in less consuming way? I tried to convert it to bitmap but that looked ugly and didn't really help.
Thanks and cheers!
You're right in assuming that your slowdown in coming from your shape code - vector data is redrawn every frame in flash, so the more complex it is, the longer it takes to draw. Some solutions, depending on what you're willing to do:
Your fidelity is way to high - you're calling your Move function every frame; you probably don't need it that high, as the difference in movement since the last frame is probably less than a pixel. Sample your position every X frames instead (where X is the level of fidelity your willing to go down to). This can be done with a simple counter in the enter frame
If you don't need to keep the entire history of the drawing, put all your points into an array/vector, culling the length as needed. Then every frame, do a line.graphics.clear() and just draw the points in the array
If you do need to keep the entire history, then keep a BitmapData under your line (e.g. the size of the stage). Every so often, draw the line to the BitmapData and call clear() on your graphics to get right of the vector data. You shouldn't notice any loss in quality (set smoothing to true when you're drawing)
I'd do the first point in any case, then choose between the second and third, depending on your use case
Expanding my comment, try something like this:
public class Player extends Shape
{
public var X,Y,v,vX,vY,size,a,r:Number;
public var k,counter,leftKey,rightKey,_color:uint;
public var line:Shape = new Shape();
public var dot:Shape = new Shape();
/*...*/
/*constructor, giving values to variables here, not important*/
/*...*/
public function Player(){
//draw shapes
graphics.lineStyle(1);
graphics.drawCircle(0,0,r);
graphics.lineTo(size,0);//can't test this now, but make sure the line is in the same direction as rotation 0 (guessing it's to the right)
//your other constructor code here
}
public function Move():void
{
a=a+0.05*k;
//player controls k parameter k=0 by default
//k=1 when right key pressed
//k=-1 when left key pressed
vX=v*Math.cos(a);
vY=v*Math.sin(a);
X=X+vX;
Y=Y+vY;
x=X+vX*size/(2*v);
y=Y+vY*size/(2*v);
rotation = a * 57.2957795;//quick'n'dirty radians to degrees
}
and if you want to draw the trails you can try something like this:
var canvas:Bitmap = new BitmapData(state.stageWidth,stage.stageHeight,true,0xFF000000);
var ct:ColorTransform = new ColorTransform(1,1,1,.1);
public function mainLoop(TimerEvent:Event):void
{
for (var i:uint=0; i<players; i++) {
player[i].Move();
canvas.draw(player[i],player[i].transform.concatenatedMatrix,ct);
}
}
Hope this makes sense.
Update
Here is a standalone code snippet to illustrate the idea above(which has untested syntax):
package {
import flash.display.Bitmap;
import flash.geom.ColorTransform;
import flash.display.BitmapData;
import flash.text.TextField;
import flash.ui.Keyboard;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.utils.Dictionary;
import flash.display.Sprite;
public class PlayerMoveTest extends Sprite {
private var keys:Dictionary = new Dictionary();
private var players:Vector.<Player> = new Vector.<Player>();
private var trails:BitmapData;
private var fade:ColorTransform = new ColorTransform(1,1,1,.1);
public function PlayerMoveTest() {
addEventListener(Event.ADDED_TO_STAGE,init);
}
private function init(e:Event):void{
trails = new BitmapData(stage.stageWidth,stage.stageHeight,true,0x00FFFFFF);
addChild(new Bitmap(trails));
for(var i:int = 0 ; i < 2; i++){
var p:Player = addChild(new Player(10+i*10)) as Player;
p.x = stage.stageWidth * .5;
p.y = stage.stageHeight * .5;
players.push(p);
}
stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP,onKeyUp);
stage.addEventListener(Event.ENTER_FRAME,update);
}
private function onKeyDown(e:KeyboardEvent):void{
keys[e.keyCode] = true;
}
private function onKeyUp(e:KeyboardEvent):void{
keys[e.keyCode] = null;
}
private function update(e:Event):void{
if(keys[Keyboard.LEFT] != undefined) {players[0].a -= .05;players[1].a += .05;}
if(keys[Keyboard.RIGHT] != undefined) {players[0].a += .05;players[1].a -= .05;}
if(keys[Keyboard.UP] != undefined) {players[0].s += .15;players[1].s -= .15;}
if(keys[Keyboard.DOWN] != undefined) {players[0].s -= .15;players[0].s += .15;}
for(var i:int = 0 ; i < players.length; i++) {
players[i].move();
trails.draw(players[i],players[i].transform.concatenatedMatrix,fade);
}
}
}
}
import flash.display.*;
class Player extends Shape{
public var vx:Number,vy:Number,a:Number,size:Number,r:Number,s:Number;
public function Player(size:Number){
init(size);
}
private function init(size:Number):void{
vx = vy = a = s = 0;
this.size = size;
this.r = size * .25;
graphics.lineStyle(1);
graphics.drawCircle(0,0,r);
graphics.lineTo(size,0);
}
public function move():void{
rotation = a * 57.2957795;
vx = Math.cos(a) * s;
vy = Math.sin(a) * s;
x += vx;
y += vy;
if(x < 0) x = 0;
if(y < 0) y = 0;
if(x > stage.stageWidth) x = stage.stageWidth-width;
if(y > stage.stageHeight) y = stage.stageHeight-height;
}
}
You can test this code here and here's a preview:
Use the arrow keys to drive(up arrow accelerates, left/right steer).
The first player is the smaller one, having the correct controls, the other is simply mirroring the previous controls)

Accessing timers within a actionscript class

I recently started programming in as3, and lately, I've started to learn object oriented programming. My problem is to access functions within a class. I guess that the "main" code is not very suitable for doing so, but I'm pretty much just asking for advice for every part of the code.
Main Code:
import flash.utils.Timer;
import flash.events.TimerEvent;
stage.addEventListener(MouseEvent.CLICK, makeCircle);
function makeCircle(event:MouseEvent):void
{
var s = new Circle();
addChild(s);
s.x = mouseX;
s.y = mouseY;
}
Class code (connected to a MovieClip circle with a MovieClip fill inside):
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.filters.BlurFilter;
import flash.geom.ColorTransform;
public class Circle extends MovieClip
{
private var t:Timer = new Timer(30,1000);
var time:Number = 0;
var size:Number;
var bf = new BlurFilter();
var ct:ColorTransform = new ColorTransform();
public function Circle()
{
// constructor code
t.addEventListener(TimerEvent.TIMER, updateCircle);
t.start();
ct.color = 0xffffff * Math.random();
fill.transform.colorTransform = ct;
fill.blendMode = "hardlight";
}
public function updateCircle(event:TimerEvent):void
{
time = t.currentCount / 10;
size = Math.pow(Math.E, - time) * Math.sin(5 * time) * (Math.log(time));
width = (size * 20 + 100 - time * 5) * 2;
height = (size * 20 + 100 - time * 5) * 2;
bf.blurX = time;
bf.blurY = time;
filters = [bf];
alpha = 1 - time / 20;
}
}
}
What I want to do is to remove the child of s (main code) when the t.currentCount (class code) is a set value (when the alpha value is 0).
Thanks in advance.
whay you want to do is do create either an even inside the Circle class that triggers when your timer completes (alpha == 0). The custom event would have to be caught in your main class.
To put a custom event listener in your main class write:
s.addEventListener("RemoveChild", removeChild)
add the handler function
function removeChild(e:Event)
{
removeChild(s);
}
in your circle class you can add the event when you want to trigger it:
this.dispatchEvent(new Event("RemoveChild");
Alternatively you control the Alpha value from your main class by placing the loop there and call removeChild(s); directly.
An easy way to get your custom events working is by using the AS3Signals framework.
Hope that helps

how to create element only after previous is on stage

How do i add a new element only after the previous one has passed the stage.stageWidth / 2
except by my way (the code below ,where i create a zone that the element will pass only one time)
PS:I dont want to do it like this cause the speed of movement will be different in time (it will slowly go up and down). Like from 3 to 6 by a easing factor of 0.005
so far i have this
import flash.display.MovieClip;
import flash.events.Event;
public class Main extends MovieClip
{
private var myArray:Array = new Array();
public function Main()
{
stage.addEventListener(Event.ENTER_FRAME, everyFrame)
var item:Box = new Box();
item.x = stage.stageWidth - 100
item.y = 40
addChild(item)
myArray.push(item)
}
private function everyFrame(ev:Event):void
{
var myBox:Box
for(var i:int = 0; i< myArray.length; i++)
{
myBox = myArray[i]
myBox.x -=3
if(myBox.x <= stage.stageWidth/2 && myBox.x >= stage.stageWidth/2 - 3)
{
trace("new Box")
var myNewBox:Box = new Box()
myNewBox.x = stage.stageWidth - 100
myNewBox.y = 40
addChild(myNewBox)
myArray.push(myNewBox)
}
if(myBox.x < 0 )
{
removeChild(myBox)
myArray.splice(i, 1)
trace(myArray.length)
}
}
}
}
Your code is already working and do things as you required.
The code looks like document class, but there is one little mistake that prevent it from execution. You forget package{...} wrap.
But you compiler should say you about this, didn't it?
You are right, using range can provide you bunch of problems then objects didn't get in it, or get several times.
To solve this you could not check area but only myBox.x<= stage.stageWidth/2 condition. After object met this condition, just remove element from array you use for checking and add it to array of objects which you check for leaving stage to delete them.
If you don't want make another array, you could add some property to every new Box.
For example - passedCenter and set it to false. Then change if statement for
if(myBox.x <= stage.stageWidth/2 && !myBox.passedCenter){
myBox.passedCenter=true;
//you stuff
}

How can I use Action Script 3.0 to make random placed Symbols fly by?

I'm trying to make a simple animation with Flash CS4 and Action Script 3.0 to make a number of Symbols fly by from right to left constantly. What I want is that once a symbol has reached the end of the screen it is destroyed and another one is placed at the start position.
I intend to give each symbol a random speed and create a random symbol each time one is 'destroyed'. Any clues where I can start?
As you seem new to flash as a platform I would think writing classes shouldn't be your first port of call when learning ActionScript. Definitely just play about on the timeline for now and learn the basics. As very simple solution to this, I would suggest creating a MovieClip in the library with a class name like 'MyBall'... then paste this onto the first frame of the main timeline et voila.
// Create some variables to store data
var numberOfBalls : int = 20;
var myBalls : Array = [];
var xVelocities : Array = [];
var maxXVelocitySpeed : Number = 5;
var minXVelocitySpeed : Number = 2;
// Add your orginal balls to the stage
for (var i : int = 0; i < numberOfBalls; i++)
{
var myBall : MyBall = new MyBall();
myBall.x = -(Math.random() * stage.stageWidth);
myBall.y = Math.random() * stage.stageHeight;
var xVelocity : Number = minXVelocitySpeed + (Math.random() * (maxXVelocitySpeed - minXVelocitySpeed));
myBalls.push(myBall);
xVelocities.push(xVelocity);
addChild(myBall);
}
// Add a listener for enter frame events
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
//Run this code on every frame to move the balls and reposition them if they are off the stage
function enterFrameHandler(event : Event) : void
{
for each( var myBall : MyBall in myBalls)
{
var ballIndex : int = myBalls.indexOf(myBall);
myBall.x += xVelocity[ballIndex];
if (myBall.x > stage.stageWidth)
{
myBall.x = -(Math.random() * stage.stageWidth);
myBall.y = Math.random() * stage.stageHeight;
}
}
}
First, turn your symbols into MovieClips. Then create a base class MySymbol.as for your symbols, something like:
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.geom.Point;
public class MySymbol extends MovieClip
{
public var speed:Number; // Pixels moved per frame
public function MySymbol(speed:Number, startPosition:Point)
{
this.speed = speed;
this.addEventListener(Event.ENTER_FRAME, update);
this.x = startPosition.x;
this.y = startPosition.y;
}
private function update():void
{
this.x -= this.speed;
if (this.x < 0 - this.width) { // We're at the left edge
this.removeEventListener(Event.ENTER_FRAME, update);
this.dispatchEvent(new Event(Event.COMPLETE));
}
}
}
}
Then make sure your movie clips are exported for AS3 (the "linkage" option on the item in the library). Make the class name for each item unique (e.g. MySymbol1, MySymbol2), and set the base class to MySymbol.
Your document class might look something like this:
package {
import flash.display.MovieClip;
import flash.events.Event;
import MySymbol; // Not strictly needed
public class DocumentClass extends flash.display.MovieClip
{
private static var SYMBOLS:Array = new Array(MySymbol1, MySymbol2);
public function DocumentClass()
{
// Create five symbols:
for (var i:int = 0; i < 5; i++) {
makeSymbol();
}
}
private function makeSymbol():void
{
// Pick a random symbol from the array:
var symType:Class = SYMBOLS[Math.random() * SYMBOLS.length];
// Construct the new symbol:
var loc:Point = new Point(stage.stageWidth, Math.random() * stage.stageHeight);
var sym:MySymbol = new symType(1 + Math.random() * 30, loc);
// Listen for the object hitting the left edge:
sym.addEventListener(Event.COMPLETE, remakeObject);
this.addChild(sym);
}
private function remakeObject(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, remakeObject);
this.removeChild(e.target);
// Replace the dead symbol:
makeSymbol();
}
}
}
It is a lot more efficient if instead of destroying and re-creating an object that flies off-stage you re-use the existing one and move it back to the right. But this is an optimization you can implement later, if things become slow.
Note that all the code above is UNTESTED and I have not coded AS3 in a while, so there's likely at least a few bugs in it. Hopefully it will serve as a good enough starting point.
Define a Circle (symbol) class that extends Sprite/Shape and has a velocity variable
Draw a circle (or whatever) with a random color
Math.floor(Math.random() * 0xffffff)
Assign a random value to velocity
minVelocity + Math.floor(Math.random() * velocityRange)
Create a start() method inside the Circle class that registers an enter frame handler
Increment this.y inside the enter frame handler, and dispatch a 'recycleMe' event if y is more than the max value.
Create N instances of Circle, addChild them, and call their start() methods.
listen to 'recycleMe' events on each of them, and reset the value of y from the handler.
Here's a few prompts to get you started.
MovieClips have an x and y property. If you were to add to these numbers over time you would see the MovieClip move along the x and/or y axis of the stage. Look into doing this using the Event.ENTER_FRAME which will allow you to change the values every time the screen is going to update.
Your stage will have a given width (a stageWidth property). You probably want to monitor when your MovieClip's x property is greater than the width of your stage. If it is remove (removeChild) it and add a new one (addChild) and place it back at the start x/y position.