AS3 Turret and bullet error - actionscript-3

I have been struggling with a as3 and flash game that i am trying to make. Everything looks fine, but still the bullet are stuck inside the cannon. When i use my mouse to shoot, instead of going out to a location, it just get stuck inside the cannon:
Got 3 as3 documents, and one flash document:
Ships.as
package{
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
public class Ship extends Sprite{
private var speed:int;
private var target:Point;
function Ship(){
speed=2+Math.random()*5;
//trace("Made a Ship!");
//set the target for the ships
target = new Point(Math.random()*500, Math.random()*500);
//target.x = Math.random()*500;
//target.y = Math.random()*500;
//addEventListener(Event.ENTER_FRAME, update);
}
function update(){
//Set the ships to point the target
var dx = target.x - x;
var dy = target.y - y;
var angle = Math.atan2(dy, dx)/Math.PI*180;
rotation = angle;
x=x+Math.cos(rotation/180*Math.PI)*speed;
y=y+Math.sin(rotation/180*Math.PI)*speed;
//New target
var hyp = Math.sqrt((dx*dx)+(dy*dy));
if(hyp < 5){
target.x = Math.random()*500;
target.y = Math.random()*500;
}
}
}
}
Game.as
package{
import flash.display.MovieClip;
import flash.events.Event;
public class Game extends MovieClip{
var ships:Array;
public function Game(){
trace("Made that game!");
addEventListener(Event.ENTER_FRAME, loop);
//set up the ship array
ships = new Array();
}
function loop(e:Event){
if(numChildren<10){
var s = new Ship();
addChild(s);
s.x = Math.random()*stage.stageWidth;
s.y = Math.random()*stage.stageHeight;
s.rotation = Math.random()*360;
//Add the ship to the list of ships
ships.push(s);
}
//Make a for loop to iterate through all the ship
for(var count=0; count<ships.length; count++){
ships[count].update();
//Add a new for loop to go through all the bullets
}
}
}
}
}
}
Turret.as
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Turret extends MovieClip{
//Properties goes here
var shotCooldown:int;
var bullets:Array;
const MAX_COOLDOWN = 10;
public function Turret(){
//Set the Shot Cooldown
shotCooldown = MAX_COOLDOWN;
bullets = new Array();
addEventListener(Event.ENTER_FRAME, update);
addEventListener(Event.ADDED_TO_STAGE, initialise);
}
function initialise(e:Event)
{
stage.addEventListener(MouseEvent.CLICK, fire);
}
function fire(m:MouseEvent)
{
//If we are allowed to shoot
if(shotCooldown<=0)
{
//Reset the Shot Cooldown
shotCooldown=MAX_COOLDOWN;
//Spawn a Bullet
var b = new Bullet();
b.rotation = rotation;
b.x = x;
b.y = y;
//Add the bullet to the list of bullets
bullets.push(b);
parent.addChild(b);
play();
}
}
function update(e:Event)
{
//Reduce the Shot Cooldown by 1
//shotCooldown=shotCooldown-1;
//shotCooldown-=1;
shotCooldown--;
if(parent != null)
{
var dx = parent.mouseX - x;
var dy = parent.mouseY - y;
var angle = Math.atan2(dy, dx) / Math.PI * 180;
rotation = angle;
}
}
}
}

They are stuck in place maybe because you are not moving them at all? If you are then please show me where. Try adding to the turret's enter frame event the following code:
for (var a:int = 0; bullets.length > a ; a++)
{
var temp:MovieClip;
temp = bullets[a] as Bullet;
var vel:Point = new Point();
vel.x = temp.target.x-temp.x;
vel.y = temp.target.y-temp.y;
vel.normalize(4);
temp.x += vel.x;
temp.y += vel.y;
}
And make an as file for the Bullet Class and add this:
package
{
import flash.geom.Point;
public class Bullet extends MovieClip
{
public var target:Point = new Point();
public function Bullet()
{
target.x = stage.mouseX;
target.y = stage.mouseY;
}
}
}

In Turret class bullets are added to the stage and array but doesn't have updated every frame like ships. See your own comment about updating bullets!

Related

how to reference a hit test object between .as files [AS3]

i'm trying to make a top down shooter game, and have been following tutorials here: http://gamedev.michaeljameswilliams.com/2008/09/17/avoider-game-tutorial-1/
and here: as3gametuts.com/2013/07/10/top-down-rpg-shooter-4-shooting/
i've managed to get shooting and movement, but i need to get a hit test object to register when the bullet (defined in its own seperate as class file) and the enemy (also defined in seperate file) come into contact. code below:
Enemy code:
package
{
import flash.display.MovieClip;
public class Enemy extends MovieClip
{
public function Enemy()
{
x = 100;
y = -15;
}
public function moveDownABit():void
{
y = y + 3;
}
}
}
Bullet code:
package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Bullet extends MovieClip
{
private var stageRef:Stage;
private var speed:Number = 10;
private var xVel:Number = 0;
private var yVel:Number = 0;
private var rotationInRadians = 0;
public var enemy:Enemy;
public function Bullet(stageRef:Stage, X:int, Y:int, rotationInDegrees:Number):void
{
this.stageRef = stageRef;
this.x = X;
this.y = Y;
this.rotation = rotationInDegrees;
this.rotationInRadians = rotationInDegrees * Math.PI / 180;
}
public function bullethit():void{
if (Bullet.hitTestObject(enemy)){
gameTimer.stop();
}
}
public function loop():void
{
xVel = Math.cos(rotationInRadians) * speed;
yVel = Math.sin(rotationInRadians) * speed;
x += xVel;
y += yVel;
if(x > stageRef.stageWidth || x < 0 || y > stageRef.stageHeight || y < 0)
{
this.parent.removeChild(this);
}
}
}
}
Main.as document class code:
package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Main extends MovieClip
{
public var player:Player;
public var bulletList:Array = []; //new array for the bullets
public var enemy:Enemy;
public var gameTimer:Timer;
public function Main():void
{
player = new Player(stage, 320, 240);
stage.addChild(player);
enemy = new Enemy();
addChild( enemy );
gameTimer = new Timer( 25 );
gameTimer.addEventListener( TimerEvent.TIMER, moveEnemy );
gameTimer.start();
stage.addEventListener(MouseEvent.CLICK, shootBullet, false, 0, true);
stage.addEventListener(Event.ENTER_FRAME, loop, false, 0, true); //add an EventListener for the loop
}
public function moveEnemy( timerEvent:TimerEvent ):void
{
enemy.moveDownABit();
}
public function loop(e:Event):void //create the loop function
{
if(bulletList.length > 0) //if there are any bullets in the bullet list
{
for(var i:int = bulletList.length-1; i >= 0; i--) //for each one
{
bulletList[i].loop(); //call its loop() function
}
}
}
public function shootBullet(e:MouseEvent):void
{
var bullet:Bullet = new Bullet(stage, player.x, player.y, player.rotation);
bullet.addEventListener(Event.REMOVED_FROM_STAGE, bulletRemoved, false, 0, true); //triggers the "bulletRemoved()" function whenever this bullet is removed from the stage
bulletList.push(bullet); //add this bullet to the bulletList array
stage.addChild(bullet);
}
public function bulletRemoved(e:Event):void
{
e.currentTarget.removeEventListener(Event.REMOVED_FROM_STAGE, bulletRemoved); //remove the event listener so we don't get any errors
bulletList.splice(bulletList.indexOf(e.currentTarget),1); //remove this bullet from the bulletList array
}
}
}
As Vesper said, you'll want to do your checks in the Main class. You've already got a game loop set up, so you can just add the check in there:
public function loop(e:Event):void //create the loop function
{
if(bulletList.length > 0) //if there are any bullets in the bullet list
{
for(var i:int = bulletList.length-1; i >= 0; i--) //for each one
{
bulletList[i].loop(); //call its loop() function
// check to see if the enemy has been hit
if(enemy.hitTestObject(bulletList[i]))
{
// the enemy has been hit by the bullet at index i
}
}
}
}
Since you currently only have a single enemy, you're just testing each bullet against that one enemy. If you had more enemies, you'd want to keep an array of references to those enemies and do a nested loop, checking to see if any of the enemies were hit by any of the bullets.

AS3 / Flash - Error #1009: Cannot access a property or method of a null object reference

I know this is a common question, but I've looked through all of the others and couldn't figure out a solution for my problem.
I've debugged and found the offending line of code, but I'm not sure what exactly it is that's wrong with it or how to fix it.
Code below - the error is thrown when "enemy.movement();" calls the movement function in the Enemy class. The first 2 lines of code(var xDist and var yDist) or specifically flagged.
package
{
import flash.display.MovieClip;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.Event;
public class zombiestandoffMain extends MovieClip
{
static public var enemy:Enemy;
static public var player:Player;
public var gameTimer:Timer;
public var crosshair:Crosshair;
public var army:Array;
public function zombiestandoffMain()
{
//enemy = new Enemy();
//addChild( enemy );
army = new Array();
var newEnemy = new Enemy;
army.push( newEnemy );
addChild( newEnemy );
player = new Player();
addChild( player );
crosshair = new Crosshair();
addChild( crosshair );
crosshair.x = mouseX;
crosshair.y = mouseY;
gameTimer = new Timer( 25 );
gameTimer.addEventListener( TimerEvent.TIMER, onTick );
gameTimer.start();
}
public function onTick( timerEvent:TimerEvent ):void
{
var newEnemy:Enemy = new Enemy;
army.push( newEnemy );
addChild( newEnemy );
crosshair.x = mouseX;
crosshair.y = mouseY;
for each ( var enemy:Enemy in army ) {
enemy.movement();
}
//if ( player.hitTestObject( enemy ) )
//{
//}
}
}
}
And the Enemy class:
package
{
import flash.display.MovieClip;
import flash.geom.Point;
import flash.events.Event;
public class Enemy extends MovieClip
{
public var sideSpawn = int(Math.random() * 3)
public function Enemy()
{
if (sideSpawn == 0) {//top
x = Math.random() * 800;
y = 200;
} else if (sideSpawn == 1) {//left
x = -20;
y = (Math.floor(Math.random() * (1 + 800 - 200)) + 200);
} else if (sideSpawn == 2) {//right
x = 800 + 20;
y = (Math.floor(Math.random() * (1 + 800 - 200)) + 200);
} else { //bottom
x = Math.random() * 800;
y = 800 + 20;
//(Math.floor(Math.random() * (1 + high - low)) + low);
}
}
public function movement():void {
var xDist = Math.abs(zombiestandoffMain.enemy.x - zombiestandoffMain.player.x);
var yDist = Math.abs(zombiestandoffMain.enemy.y - zombiestandoffMain.player.y);
if (xDist > yDist) {
if (zombiestandoffMain.enemy.x > zombiestandoffMain.player.x)
zombiestandoffMain.enemy.x-=2;
else zombiestandoffMain.enemy.x+=2;
} else {
if (zombiestandoffMain.enemy.y > zombiestandoffMain.player.y)
zombiestandoffMain.enemy.y-=2;
else zombiestandoffMain.enemy.y+=2;
}
}
}
}
My best guess is that the x and y coords for enemy are null - but I've tried inserting values for the coords and still get the same error.
Thank you for any help!
You've only declared enemy, you must also define it. Set enemy inside zombiestandoffMain to a new Enemy obect:
enemy = new Enemy();
I guess it's with the zombiestandoffMain you are referencing in the movement() method. I do not see any definition of it in the Enemy Class. if it is meant to be defined manually in the flash environment or somewhere make sure that this property is (zombiestandoffMain) is reference properly. Hope that helps

Make three MovieClips appear and disappear inside a snowglobe when shaken

I used a creative cow tutorial to create my own snow globe that moves and snow reactivates - it really is a great tutorial.
What I'm trying to do is Change between 3 Movie clips in the ActionScript - But each time I add my movie clip names - Or try and add a simple visibility code I break my snow globe actions.
I have my MovieClip instances named friendsSceneThree, BuddiesSceneTwo and HatsOffSceneOne. I would think they'd be good but somewhere I'm missing something. Right now I can't get the code to even SEE The movieclips I'm getting a simple:
TypeError: Error #1006: value is not a function.at SnowGlobeContainer/update()
Down in the 'if drag' Update is where I'd like to Change from One MClip to the Next.
What Am I Not Seeing?!?! Any help would be greatly appreciated! Thanks
Here is the ActionScript:
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.geom.Point;
public class SnowGlobeContainer extends Sprite {
public var snowForeground:SnowGeneratorCircle;
public var snowBackground:SnowGeneratorCircle;
public var friendsSceneThree:MovieClip;
public var buddiesSceneTwo:MovieClip;
public var hatsOffSceneOne:MovieClip;
public var drag:Boolean = false;
public var over:Boolean = false;
public var startPos:Point = new Point;
public var mouseDownOffset:Point = new Point;
public var bounds:Rectangle = new Rectangle;
public var vel:Point = new Point(0,0);
public var pos:Point = new Point(x,y);
public var old:Point = new Point(x,y);
public var gravity:Number = 5+(Math.random()*1);
public var restitution:Number = 0.5;
public var friction:Number = 0.9;
public function SnowGlobeContainer() {
// save some initial persistant properties
startPos.x = this.x;
startPos.y = this.y;
old.x = this.x;
old.y = this.y;
bounds.x = 0;
bounds.y = 0;
bounds.width = 600;
bounds.height = startPos.y;
// add mouse interaction listeners and show the cursor on rollover
this.mouseChildren = false;
this.useHandCursor = true;
this.buttonMode = true;
this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
this.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
this.addEventListener(Event.ENTER_FRAME, update);
}
protected function onMouseOver(e:MouseEvent=null):void { over = true; }
protected function onMouseOut(e:MouseEvent=null):void { over = false; }
protected function onMouseDown(e:MouseEvent=null):void {
// Save the offset of your mouse when you first start dragging. Same functionality as startDrag(false)
mouseDownOffset.x = mouseX;
mouseDownOffset.y = mouseY;
drag = true;
}
protected function onMouseUp(e:MouseEvent=null):void {
vel.x = vel.y = 0;
pos.x = x;
pos.y = y;
drag = false;
}
public function update(e:Event):void {
// this if/else statement controls the mouse over and out instead of using event listeners
if(mouseY < -175 || mouseY > 175 || mouseX < -175 || mouseX > 175){
if(over) onMouseOut();
}else{
if(!over) onMouseOver();
}
if(drag){
// drag around..
this.x = parent.mouseX - mouseDownOffset.x;
this.y = parent.mouseY - mouseDownOffset.y;
// keep this thing on the table :)
if(y >= bounds.height) y = bounds.height;
// if you "shake" or move the mouse quickly, we are going to reset the snow particles
var d:Point = new Point(Math.abs(old.x - x), Math.abs(old.y - y));
if(d.x > 50 || d.y > 50 ){
snowForeground.reset();
snowBackground.reset();
friendsSceneThree.visible = false;
}
// update the history position
old.x = x;
old.y = y;
vel.y = (y-old.y)/2;
}else{
// if you drop this object it should have a bit of realistic falling..
vel.y += gravity;
pos.y += vel.y;
// bounce
if(pos.y > bounds.height){
pos.y = bounds.height;
vel.y *= -(Math.random()*restitution);
}
y = pos.y;
}
}
}
}
I appreciate the help -- If you haven't noticed I'm new to all of this scripting. I'm looking in on lynda.com and other forums. the SnowGeneratorCircle.as is:
package {
import flash.display.Sprite;
import flash.events.Event;
public class SnowGeneratorCircle extends Sprite {
var totalFlakes:int = 500;
var flakes:Array = new Array();
public function SnowGeneratorCircle() {
addSnowFlakes();
addEventListener(Event.ENTER_FRAME, update);
}
protected function addSnowFlakes():void{
for(var i:int=0; i<totalFlakes; i++){
var f:SnowFlake = new SnowFlake();
addChild(f);
flakes.push(f);
}
}
public function reset():void{
for(var i:int=0; i<totalFlakes; i++){
var f:SnowFlake = flakes[i];
f.reset();
}
}
public function update(e:Event=null):void {
for(var i:int=0; i<totalFlakes; i++){
var f:SnowFlake = flakes[i];
f.update(0);
}
}
}
}
I debugged - didn't clean up the code, because every time I did - it broke the actions. So I left the code with the double spacing. That's how it went in when I copied and pasted from the tutorial anyway.
Here's the error on line 173 - which is the MovieClip I'd like to have change.
Attempting to launch and connect to Player using URL /Volumes/Lacie Biggest S2S/GRaid/Veronica
/V/Rubio/Work/SUBARU/SnowGlobe Subaru/SnowGlobeAnima/snowGlobeShakev3.swf
[SWF] Volumes:Lacie Biggest S2S:GRaid:Veronica:V:Rubio:Work:SUBARU:SnowGlobe >Subaru:SnowGlobeAnima:snowGlobeShakev3.swf - 468081 bytes after decompression
TypeError: Error #1006: value is not a function.
at SnowGlobeContainer/update()[/Volumes/Lacie Biggest S2S/GRaid/Veronica/V/Rubio/Work/SUBARU
/SnowGlobe Subaru/SnowGlobeAnima/SnowGlobeContainer.as:173]
I just don't know how to get the actionscript to find my MovieClips and then swap them out wt each shake of the globe.

hitTest not working

I don't understand. HitTest is pretty basic but it won't work. I want my movieclip Faller to hitTest Touch1 but I get error 1061. I tought I had it done when I did fallerThingsLeft to hitTest Touch1 to tell me "HIT" on the score_txt, but it tells me Hit like 3 sec
before it really hits. I don't get it. can't someone tell me what im doing wrong
import flash.display.Graphics;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
var objectSpawner: Timer;
var fallers: Array;
function initGame(): void {
fallers = [];
objectSpawner = new Timer(1000);
objectSpawner.addEventListener(TimerEvent.TIMER, createEnemy);
objectSpawner.start();
addEventListener(Event.ENTER_FRAME, dropEnemies);
}
function createEnemy(e: TimerEvent): void {
var enemy: Faller = new Faller();
enemy.y = -stage.stageHeight;
enemy.x = Math.random() * 380;
MovieClip(enemy).cacheAsBitmap = true;
addChild(enemy);
fallers.push(enemy);
drawConnectors();
}
function dropEnemies(e: Event): void {
trace(fallers.length);
for each(var mc: Faller in fallers) {
mc.y += 10;
if (mc.y > stage.stageHeight * 2)
fallers.splice(fallers.indexOf(removeChild(mc)), 1);
drawConnectors();
}
}
function drawConnectors(): void {
if (fallers.length == 0) return;
var g: Graphics = this.graphics;
g.clear();
g.lineStyle(10,0xFFFFFF);
var mc: Faller = fallers[0];
g.moveTo(mc.x, mc.y);
for each(mc in fallers) g.lineTo(mc.x, mc.y);
}
init()
function init():void
{
var fallingThingsLeft:FallingThings = new FallingThings
(stage.stageWidth / 2, stage.stageHeight);
var fallingThingsRight:FallingThings = new FallingThings
(stage.stageWidth / 2, stage.stageHeight);
addChild(fallingThingsLeft);
addChild(fallingThingsRight);
fallingThingsRight.x = stage.stageWidth / 2;
}
import flash.events.Event;
this.addEventListener( Event.ENTER_FRAME, handleCollision)
function handleCollision( e:Event ):void
{
if(fallingThingsLeft.hitTestObject(Touch1))
{
output_txt.text = "HIT"
}
else
{
output_txt.text = "MISS"
}
}
Without seeing the objects, I can't be certain; however a common issue when getting started with hitTestObject is understanding the hit test is performed on the bounding box. See the image below. This will register a 'hit' with hitTestObject because the bounding boxes pass the hit test.

Animating with a for loop part 2

I have another question thats has been bugging me. It's kinda a follow up from my other question "Animating with a for loop?" Ok so I have that down, but how could I animate each ball to go randomly around the stage and not follow each other?
Here is my code:
ball is pulled from an external class named Ball.
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.text.TextField;
import flash.ui.Keyboard;
public class Dummy extends Sprite
{
private var balls:Array;
private var ball:Ball;
private var ballNum: Number = 10;
private var ax:Number = 4;
public function Dummy()
{
init();
}
private function init():void
{
balls = new Array();
for(var i:Number = 0; i < ballNum; i++)
{
ball = new Ball(Math.random() * 30);
ball.x = Math.random() * stage.stageWidth;
ball.y = Math.random() * stage.stageHeight;
addChild(ball);
balls.push(ball);
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
protected function onEnterFrame(event:Event):void
{
for(var i:int = 0; i < balls.length; i++)
{
balls[i].x += ax;
}
}
}
}
Give each ball object a different direction and use that to move the ball instead of the ax value.
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.text.TextField;
import flash.ui.Keyboard;
public class Dummy extends Sprite
{
private var balls:Array;
private var ball:Ball;
private var ballNum: Number = 10;
private var directions:Array = [new Point(-1,-1),new Point(0,-1),new Point(1,-1),
new Point(-1,0),new Point(1,0),
new Point(-1,1),new Point(0,1),new Point(1,1)];
public function Dummy()
{
init();
}
private function init():void
{
balls = new Array();
for(var i:Number = 0; i < ballNum; i++)
{
ball = new Ball(Math.random() * 30);
ball.x = Math.random() * stage.stageWidth;
ball.y = Math.random() * stage.stageHeight;
ball.direction = directions[Math.floor(Math.random()*directions.length)];
addChild(ball);
balls.push(ball);
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
protected function onEnterFrame(event:Event):void
{
for(var i:int = 0; i < balls.length; i++)
{
balls[i].x += balls[i].direction.x;
balls[i].y += balls[i].direction.y;
}
}
}
}
Give your Ball class properties for speed, and a method move() that will adjust their respective coordinates, and probably will be enhanced to check for collisions sometimes later, so that your balls could rebound of walls for example.
// Ball class additions follow
private var vx:Number;
private var vy:Number;
public function Ball() {
// ... original constructor here
var angle:Number=Math.random(2.0*Math.PI); // random angle
var vel:Number= MAX_VELOCITY*(0.5+0.5*Math.random()); // random velocity module
// define this constant^
vx=vel*Math.cos(angle);
vy=vel*Math.sin(angle); // composites of velocity
}
public function move():void {
this.x+=vx;
this.y+=vy;
}
// main class
protected function onEnterFrame(event:Event):void
{
for(var i:int = 0; i < balls.length; i++)
{
balls[i].move();
}
}