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.
Related
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);
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);
}
}
}
I'm in the process of creating a simple Flash game using ActionScript 3.0 and have come across an issue when spawning my obstacles onto the scene. My aim is to have approximately 10 points across the x axis (remaining at the same y axis) and when spawning the obstacles into my scene it will pick 2-4 of those points randomly and spawn them on them.
I've got the obstacles to spawn randomly but cannot figure out how to make them spawn at random set points, from a list. If anyone could help, I would be much appreciative. Thanks
EDIT:
The code I have so far:
var a:Array = new Array();
for (var count=0; count< 5; count++) {
a[count] = new asteroidOne();
a[count].x = 100 * count + (Math.floor(Math.random() * 200));
a[count].y = 100;
addChild(a[count]);
}
// Asteroid obstacle spawning 2.0
player.addEventListener(Event.ENTER_FRAME, obstacleMove);
function obstacleMove(evt:Event):void {
for (var i=0; i< 5; i++) {
a[i].y += 5;
if (a[i].y == 480) {
a[i].y = 0;
}
if (player.hitTestObject(a[i])) {
trace("HIT");
}
}
}
Assuming you have your spawn points in an array, you could do the following:
var spawnPoints:Array = [100,200,250,300,450,500,600,800]; //your list of spawn x locations
spawnPoints.sort(randomizeArray); //lets randomize the spwanPoints
function randomizeArray(a:*, b:*):int {
return ( Math.random() < .5 ) ? 1 : -1;
}
var a:Vector.<asteroidOne> = new Vector.<asteroidOne>(); //the array for your astroids - changed to vector for possible performance and code hint improvement (basically the same as Array but every object has to be of the specified type)
for (var count:int=0; count < 5; count++) {
a.push(new asteroidOne());
a[count].x = spawnPoints.pop(); //pop removes the last element from the array and returns it
a[count].y = 100;
addChild(a[count]);
}
EDIT
To address you comments, here is a decent example:
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
var spawnTimer:Timer = new Timer(10000); //timer will tick every 10 seconds
spawnTimer.addEventListener(TimerEvent.TIMER, spawn, false, 0, true); //let's run the spawn function every timer tick
spawnTimer.start();
var spawnPoints:Array = [100,200,250,300,450,500,600,800]; //your list of spawn x locations
var spawnAmount:int = 5; //how many asteroids to have on the screen at once (you could increase this over time to make it more difficult)
var asteroids:Vector.<asteroidOne> = new Vector.<asteroidOne>(); //the array for your asteroids - changed to vector for possible performance and code hint improvement (basically the same as Array but every object has to be of the specified type)
spawn(); //lets call it right away (otherwise it will won't be called until the first timer tick in 10 seconds)
//calling this will spawn as many new asteroids as are needed to reach the given amount
function spawn(e:Event = null):void {
if(asteroids.length >= spawnAmount) return; //let's not bother running any of the code below if no new asteroids are needed
spawnPoints.sort(randomizeArray); //lets randomize the spwanPoints
var spawnIndex:int = 0;
var a:asteroidOne; //var to hold the asteroid every loop
while (asteroids.length < spawnAmount) {
a = new asteroidOne();
a.x = spawnPoints[spawnIndex];
spawnIndex++; //incriment the spawn index
if (spawnIndex >= spawnPoints.length) spawnIndex = 0; //if the index is out of range of the amount of items in the array, go back to the start
a.y = 100;
asteroids.push(a); //add it to the array/vector
addChild(a); //add it to the display
}
}
player.addEventListener(Event.ENTER_FRAME, obstacleMove);
function obstacleMove(evt:Event):void {
//this is the same as a backwards for loop - for(var i:int=asteroids.length-1;i >= 0; i--)
var i:int = asteroids.length;
while(i--){ //since we are potentially removing items from the array/vector, we need to iterate backwards - otherwise when you remove an item, the indices will have shifted and you'll eventually get an out of range error
asteroids[i].y += 5;
if (asteroids[i].y > stage.stageHeight || asteroids[i].x > stage.stageWidth || asteroids[i].x < -asteroids[i].width || asteroids[i].y < -asteroids[i].height) {
//object is out of the bounds of the stage, let's remove it
removeChild(asteroids[i]); //remove it from the display
asteroids.splice(i, 1); //remove it from the array/vector
continue; //move on to the next iteration in the for loop
}
if (player.hitTestObject(asteroids[i])) {
trace("HIT");
}
}
}
function randomizeArray(a:*, b:*):int {
return ( Math.random() < .5 ) ? 1 : -1;
}
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.
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 )