Creating Falling Snow in AS3/Flash - actionscript-3

So I am trying to create random, falling snow in a Flash application. Using the following code I have my snow appearing at a random point on the screen.
var mc:snowFalling = new snowFalling();
addChild(mc);
var result:Number = Math.random() * 100;
var randomX:Number = Math.random() * stage.stageWidth;
mc.x = randomX;
snowFalling is the linkage name.
I am unsure how to have the snow both appear multiple times and respawn. Could someone give me a rundown of the code I will need to do this.

First, you need to create as many snowflakes on the screen as you'd like to have. Then, you need to move each snow flake every frame tick. Something like the following is ONE way you could do it. (there are many ways to accomplish this).
var flakes:Vector.<snowFalling> = new Vector.<snowFalling>(); //an array to store all your snow flakes
var mc:snowFalling;
var mc2:snowFalling;
var columns:int = 5;
var rows:int = 7;
var columnWidth:Number = stage.stageWidth / columns;
var rowHeight:Number = stage.stageHeight / rows;
//make 5 columns
for (var i:int = 0; i < columns; i++) {
mc = new snowFalling();
mc.x = (columnWidth * i);// + (Math.random() * (columnWidth * .25)); //to randomize the x position within the column size
addChild(mc);
flakes.push(mc);
//make 7 rows in each column
for (var j:int = 0; j < rows; j++) {
mc2 = new snowFalling();
mc2.x = mc.x;
mc2.y = (rowHeight * j);// + (Math.random() * (rowHeight * .25)); //to randomize the y within the row size
addChild(mc2);
flakes.push(mc2);
}
}
//run the enterFrame function below every frame tick of the application
this.addEventListener(Event.ENTER_FRAME, enterFrame);
function enterFrame(e:Event):void {
//loop through each snowflake in the flakes array
for (var i:int = 0; i < flakes.length; i++) {
flakes[i].y += 2; //move it down 2 pixels
//check to see if it's off screen, if so, move back to the top of the screen (less it's height so it's just off screen at the top)
if (flakes[i].y > stage.stageHeight) flakes[i].y = -flakes[i].height;
}
}
Or, if you wanted a traditional spawn type method, this:
//create a container to hold all the snowflakes
var snowContainer:Sprite = new Sprite();
addChild(snowContainer);
//this function creates a snowflake and puts it at the top of the screen in a random x spot
function spawnFlake(e:Event = null):void {
var mc:snowFalling;
snowContainer.addChild(mc);
mc.x = Math.random() * (stage.stageWidth - mc.width);
mc.y = -mc.height; //just off screen at the top
}
//create a timer that will call the spanFlake function every second
var timer:Timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER, spawnFlake);
timer.start();
this.addEventListener(Event.ENTER_FRAME, enterFrame);
//every frame, iterate through all the children of snowContainer and move the flakes down 2 pixels
function enterFrame(e:Event):void {
var flake:snowFalling;
var i:int = snowContainer.numChildren;
//we need to iterate backwards because we are potentially removing items (which would throw our i value out of whack if iterating forwards)
while(i--){
flake = snowContainer.getChildAt(i) as snowFalling;
flake.y += 2;
//if out of bounds, remove the flake
if (flake.y > stage.stageHeight) {
snowContainer.removeChild(flake);
}
}
}

Related

AS3 - Array called into a new function... HOW?

Sup everyone, well since my last post as been super fast to fix due to my tired eyes. I'm gonna ask you one more favor...
It's about an Array, so before i had only one "target" showing. So i thought my game was way to simple...
So i decided to add more target that moves, and place with random math...
Well they are correctly placed, but only one is moving. I think is the first one that is being created....
This is my line of code :
// Creating multiple targetwith ADDCHILD and ARRAY at different location //
var arraymc_target:Array = [];
for(var i:int = 1; i<8; i++)
{
var mc_target:target = new target();
mc_target.x = Math.floor(Math.random() * 400);
mc_target.y = Math.floor(Math.random() * 550);
addChild(mc_target);
arraymc_target.push(mc_target);
}
// Creating the TARGETS MOVEMENT //
function goesside_1(event:Event):void {
mc_target.x -= 2;
if (mc_target.x < -20){
mc_target.x = 550;
}
}
mc_target.addEventListener(Event.ENTER_FRAME, goesside_1);
// ----------------------------------------------- //
Your main issue is that in goesside_1, you're moving mc_target which is simply a reference to the last instance of target you created in the loop and pushed to the array.
Another quirk I noticed is that you're adding the ENTER_FRAME listener to one of your targets instead of to the stage.
What you want to do is add the listener to the stage, and then loop over each of the targets in your array:
var arraymc_target:Array = [];
for(var i:int = 1; i<8; i++)
{
var mc_target:target = new target();
mc_target.x = Math.floor(Math.random() * 400);
mc_target.y = Math.floor(Math.random() * 550);
addChild(mc_target);
arraymc_target.push(mc_target);
}
// Creating the TARGETS MOVEMENT //
function goesside_1(event:Event):void {
for each(var mc_target:target in arraymc_target)
{
mc_target.x -= 2;
if (mc_target.x < -20){
mc_target.x = 550;
}
}
}
stage.addEventListener(Event.ENTER_FRAME, goesside_1);

Positioning of Dynamically attached library objects in ActionScript 3.0

I am re-learning ActionScript, and I am trying to learn from
digitaldogbyte.com 'Dynamically attached library objects in ActionScript 3.0'. This example, in digialdogbyte, sets the position of each MovieClip across the X position. At high number of numberOfClips, the Objects run right and of the Stage, and out-of-view.
I am trying to adapt the following script to:
wrap the flow of objects to a new line when the edge of the Stage is reached
every other block is coloured red with text colour set to white
The ActionScript:
var numberOfClips:Number = 150;
var xStart:Number = 0;
var yStart:Number = 0;
var xVal:Number = xStart;
var xOffset:Number = 2;
for (var i:Number=0; i<numberOfClips; i++)
{
var mc:myClip = new myClip();
mc.name = "myClip"+(i+1);
this.addChild (mc);
mc.y = yStart;
mc.x = xVal;
xVal = mc.x + mc.width + this.xOffset;
mc.label_txt.text = (i).toString();
}
I'd be grateful if anyone could suggest ways to adapt this script as such.
Add something simple like:
var numberOfClips:Number = 150;
var grid:Rectangle = new Rectangle(0, 0, 20, 20);
for(var i:Number = 0; i < numberOfClips; i++)
{
var mc:myClip = new myClip();
addChild(mc);
mc.x = grid.x;
mc.y = grid.y;
grid.x += grid.width;
// If the new x position is outside of the stage, reset it and
// increase the y position.
if(grid.x + grid.width > stage.stageWidth)
{
grid.x = 0;
grid.y += grid.height;
}
}
You can adjust the width and height of the grid on line 2.

HitTest Multiple MovieClips with Array

I have a MovieClip exported to ActionScript called smallGainPoints. What i want to do is create multiple instances of this MovieClip on the stage in a linear or diagonal path. When this is accomplished i want a hitTestObject to take place between the Points array and the Player. The points are added to stage where i would want them to be, but the HitTest wont initiate.
Here is how i set up the Functions:
This Function is added in my Gameloop which is called from an onEnterFrame handler:
private function checkPlayerHitPoints():void
{
for (var j:int = 0; j < aPointsArray.length; j++)
{
//get current points in j loop
var currentPoints:smallGainPoints = aPointsArray[j];
//test if player is hitting current point
if (player.hitTestObject(currentPoints))
{
//remove point on stage
currentPoints.destroyPoints()
//remove point from array
aPointsArray.splice(j, 1);
nScore += 5;
updateHighScore();
}
}
}
Im not sure if i did this right but i want to add multiple instances of the points in a line so the player can gather as much points as possible. So i created a function and set the positions then added the function in my constructor as so addPointsToStage() so it doesn't loop every frame.
private function addPointsToStage():void
{
for (var i = 0; i < nPoints; i++)
{
points = new smallGainPoints();
stage.addChild(points);
points.x = (stage.stageWidth / 2);
points.y = (stage.stageHeight / 2);
points = new smallGainPoints();
stage.addChild(points);
points.x = (stage.stageWidth / 2) + 200;
points.y = (stage.stageHeight / 2);
}
This is how I initiated the array:
public var points:smallGainPoints;
private var nPoints:Number = 5;
private var aPointsArray:Array;
Then in my Constructor i added:
aPointsArray = new Array();
So the points are added to the stage but the hittest doesnt work. Please help!
In your addPointsToStage method, you never add your smallGainPoints object to the array.
After this line:
points = new smallGainPoints();
Push the new points object onto the aPointsArray array:
aPointsArray.push(points);
EDIT:
A better way to add your points in a row might be like this:
private function addPointsToStage():void
{
var startPoint:Point = new Point(stage.stageWidth / 2, stage.stageHeight / 2);
var spacing:Number = 50;
for (var i = 0; i < nPoints; i++)
{
points = new smallGainPoints();
aPointsArray.push(points);
addChild(points);
points.x = startPoint.x + (spacing * i);
points.y = startPoint.y;
}
}
This for loop will add a bunch of smallGainPoint objects in a row, starting from the center of the screen and going right.

AS3 which item in an array has the lower value?

I’m trying to make a game like tower defence in AS3 and currently cant find solution to check which item in an array has the lower value of distance between enemy and turret, in order to choose which enemy to attack first.
I'm really stuck with this problem and asking for your help.
Here is a short code:
var enemyArray:Array = new Array();
var turretArray:Array = new Array();
addEventListener(Event.EnterFrame, loop);
// adding enemies
for(var i:int=0; i<3; i++){
var enemy:Enemy = new Enemy();
...
...
enemyArray.push(enemy);
addChild(enemy);
}
// adding turret
for(var t:int=0; t<2; t++){
var turret:Turret = new Turret();
...
...
turret.destinationX = 0;
turret.destinationY = 0;
turret.distance = 0;
turretArray.push(turret);
addChild(turret);
}
// loop
function loop(event:Event):void{
for(var j:int=enemyArray.length-1; j>=0; j--){
for(var k:int=turretArray.length-1; k>=0; k--){
// getting destination
turretArray[k].destinationX = turretArray[k].x - enemyArray[j].x;
turretArray[k].destinationY = turretArray[k].y - enemyArray[j].y;
// getting distance between turret and enemy
turretArray[k].distance = Math.sqrt(turretArray[k].destinationX*turretArray[k].destinationX+turretArray[k].destinationY*turretArray[k].destinationY);
// here i need to get min value from all turrets distance
}
}
}
Looks like you just need to be keeping track of the lowest value you've found as you go rather than overwriting it every time (if I've understood your code, correctly).
// loop
function loop(event:Event):void{
for(var k:int=turretArray.length-1; k>=0; k--)
{
turretArray[k].distance = -1;
for(var j:int=enemyArray.length-1; j>=0; j--)
{
var dx = turretArray[k].x - enemyArray[j].x;
var dy = turretArray[k].y - enemyArray[j].y;
var dist = Math.sqrt(dx * dx + dy * dy);
if(dist < turretArray[k].distance || turretArray[k].distance < 0)
{
turretArray[k].distance = dist;
turretArray[k].destinationX = dx;
turretArray[k].destinationY = dy;
}
}
}
}
Here, we store the initial distance value found in turretArray[k].distance, and only overwrite that if we find a lower one. We set it to -1 each time so we can tell if it's been set, yet, or not.
This is the equation you want:
http://www.mathopenref.com/coorddist.html
sqrt( (turret1X - turret2x)^2 + (turret1Y - turret2Y)^2 )

Error #1009, ActionScript 3, Bullet is null

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.