Creating Top Down Shooter in Adobe Flash CS4 using ActionScript 3 but bullets behaving weirdly - actionscript-3

I am making a TDS in Flash CS4 using AS3 but there seems to be a problem. It's hard to explain so I'm gonna link the flash file. Click this.
This is the first time uploading a file for sharing so for those who can't or are unable to download the file, this is what happens:
Player has mouse rotation that is, Player looks at where the mouse is. On Mouse down I've put the script for creating bullets. The bullets are being created alright. But when the bullets move that's when the problem arises. Say that at position and rotation X, I shot 5 bullets and they are moving in X direction. Now if I shoot a bullet in Y position and rotation, the bullet that was created there goes in Y direction but so do all the other bullets that were created in the X position and direction. They change their course.
Here is the code for the game.
package {
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.MouseEvent;
import flash.ui.Keyboard;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Mouse;
import flash.events.TimerEvent;
public class Main extends MovieClip {
var player : Player = new Player();
//Customizable Weapon Settings
var bulletNumber:Number;//number of bullets per shot
var bulletOffset:Number;//bigger number = less acurate
var bulletSpeed:Number;//pixels per frame
var bulletMaxAge:Number;//1000 = 1 second
var reloadSpeed:Number;//1000 = 1 second
var randomNum:Number;
public static var xSpeed:Number;
public static var ySpeed:Number;
var bulletAngle:Number;
var timer:Number=0;
var flag:Boolean;
//other variables (do not edit)
var mouseClicked:Boolean=false;
var radians:Number=Math.PI/180;
public function Main() {
player.x=stage.stageWidth/2;
player.y=stage.stageHeight/2;
stage.addChild(player);
player.gotoAndStop(5);
loadWeapon("Machine Gun");
addEventListener(Event.ENTER_FRAME,on_enter_frame);
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, onMouseUpHandler);
}
public function onMouseDownHandler(event:MouseEvent) {
//trace("Mouse Down");
mouseClicked=true;
flag=true;
}
public function onMouseUpHandler(event:MouseEvent) {
//trace("Mouse Up");
mouseClicked=false;
flag=false;
timer=0;
}
public function loadWeapon(weaponType:String) {
switch (weaponType) {
case "Machine Gun" :
//bulletNumber = 100;
bulletOffset=10;
bulletSpeed=10;
bulletMaxAge=1000;
break;
}
}
function on_enter_frame(e:Event) {
trace("Click: "+ mouseClicked);
fireWeapon();
}
function fireWeapon() {
//check if mouse is clicked
//if true, create bullet
if (mouseClicked) {
createBullet();
player.gotoAndStop(10);
} else {
player.gotoAndStop(1);
}
}
public function createBullet() {
var bullet : Bullet2= new Bullet2();
bullet.x=player.x;
bullet.y=player.y;
if (flag) {
timer++;
if (timer==10) {
trace("lol");
//calculate random bullet offset.
randomNum = Math.random() * (bulletOffset);
//set bullet firing angle
bulletAngle = (player.rotation + randomNum) * radians;
//set bullet speed based on angle
xSpeed=Math.cos(bulletAngle)*bulletSpeed;
ySpeed=Math.sin(bulletAngle)*bulletSpeed;
//trace (bulletAngle);
stage.addChild(bullet);
bullet.addEventListener(Event.ENTER_FRAME, runForest);
//mouseClicked = false;
timer=0;
}
}
function runForest(e:Event) {
bullet.x+=xSpeed;
bullet.y+=ySpeed;
}
}
}
}
Things that I've tried:
1) I put the "runForest()" funtion outside of "createbullet()" function which give me a "1120: Access of undefined property bullet." Error. (Which doesn't make sense since I am giving it a enter frame event listener.)
2) For solving this, I made the bullet variable global and declared it inside the "createbullet()" function like this- "var bullet : Bullet2;" And inside createbullet()- "bullet = new Bullet2();" That gives me a completely different output.
3) I put the "runForest()" function in its own class file. But the same thing is happening.
I was referring to a Tutorial that used AS2. This is the link.
Help me solve this please.
Thanks!

Review this code:
//set bullet speed based on angle
xSpeed=Math.cos(bulletAngle)*bulletSpeed;
ySpeed=Math.sin(bulletAngle)*bulletSpeed;
then take a look at how these variables for speed are created:
public static var xSpeed:Number;
public static var ySpeed:Number;
You have 1 variable for the x direction of the speed. If there is only one variable, there can only be 1 value for speed.
that's why all your bullets are moving in the same direction, because they all share that one single value for speed, which causes them to go into the same direction.
Your Main class is doing everything at the moment and you should really refactor some of that code into several other classes.
Even your own understanding of the code you are writing is not reflected by the code, your comment says:
//set bullet speed based on angle
Now why is that bullet speed a variable of Main? Object oriented programming is made exactly for that. You can literally turn your plain English description of the desired behaviour into code.
When you say that you "want to have Bullets", then create a Bullet class.
When you say "each Bullet object should have its own speed", then add a property to that class that is the speed.
You will encounter the same problem with your weapons and the same solution applies.

Related

Cursor movement too fast for code to read

I have created a MOUSE_MOVE MouseEvent and a code to draw circles while I move the mouse cursor. The problem is, it doesn't draw out every single circle if I move the mouse too fast.
Here are the codes I have for the MOUSE_MOVE event.
stage.addEventListener(MouseEvent.MOUSE_MOVE, mCursor);
public function mCursor(e:MouseEvent):void
{
var cursor:Shape = new Shape();
cursor.graphics.beginFill(1, 1);
cursor.graphics.drawCircle(e.stageX, e.stageY, 10);
cursor.graphics.endFill();
addChild(cursor);
}
Would there be an arithmetic equation or physics formula to have it add every single circle such that it can draw a straight line without the blanks in between?
Just use
cursor.graphics.lineTo(…);
To draw a continuous line between points instead of adding discrete individual circles.
I erased the above codes and just added this one line of code cursor.graphics.lineTo(e.localX, e.localY); I tested it and there were blanks in between
You have to set the line width first by calling lineStyle() method of the graphics object. Otherwise the line width is zero (its default value).
Here's a full working document class:
package
{
import flash.display.Sprite;
import flash.display.Shape;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var cursor:Shape;
public function Main()
{
cursor = new Shape();
cursor.graphics.lineStyle(2);
addChild(cursor);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mCursor);
}
private function mCursor(e:MouseEvent):void
{
cursor.graphics.lineTo(e.stageX, e.stageY);
}
}
}
You likely have to fiddle around with moveTo in order to set an appropriate starting position. As the code is now, it starts at 0/0.

Actionscript 3.0 Movieclip modification on EXIT_FRAME

I have this baffling problem with Flash AS3 that I have been attempting to solve for a long time. I have a notion that perhaps this is a bug with the flash player, but perhaps you can shed some insight.
I have a MovieClip in Flash that is a star for 10 frames, a circle for another 10, and then a square for another 10, after which it will gotoAndPlay(1), replaying the animation. This MovieClip extends an AS3 class I have called FlipClip.
FlipClip has a function in it called reverseClip. This function's purpose is to flip certain graphic children around an axis every time Flash launches the EXIT_FRAME event.
public function FlipClip()
{
//as soon as this is instantiated, add the eventListener
addEventListener(Event.EXIT_FRAME,flipTheClip);
}
public function flipTheClip(e:Event)
{
trace("currentFrame = " + currentFrame);
//for sake of simplicity, we will flip every child
for (var i=0; i<numChildren; i++)
{
var targetClip = getChildAt(i);
var axis = 10;
//if the target child has not already been flipped...
if (Math.abs(targetClip.scaleX) / targetClip.scaleX != -1)
{
//reverse the child's direction with scaleX and move based on the axis
targetClip.scaleX *= -1;
var dist:Number = targetClip.x - axis;
targetClip.x = axis - dist;
}
}
}
The obvious outcome is that every time we exit a frame, all of the graphic elements are flipped horizontally around x=10, and every ten frames the shape of the MovieClip changes from a star, to a circle, to a square. Right?
Nope.
The MovieClip does successfully flip around that axis, but then a strange problem occurs. The animation stops. The MovieClip is stuck as an eternal star. And Flash doesn't even recognize that the animation has stopped, as we get this output over and over;
currentFrame = 1
currentFrame = 2
currentFrame = 3
currentFrame = 4
...
currentFrame = 30
currentFrame = 1
All the way up to 30, at which point it goes back to one. The clip is still playing, but somehow the graphic elements are not updating!
Is this a problem with the flash player? Is this a problem with the code? Any help is appreciated!
I've uploaded the files for the .fla and .as on dropbox. I'm still figuring out how to embed something like that, but for now I'm gonna hope this link works for you.
https://www.dropbox.com/sh/hcljutesblichpp/AABKQ4Kn8OTwfTaeh0I3nnOZa?dl=0
UPDATE:
If I convert every individual shape into a MovieClip within the parent MovieClip, it plays correctly. However, this is not very memory efficient or feasible with complex animations. Hopefully this bit of information can help you solve the problem.
There are couple of thing which you need to take care.
You don't need to flip element based on the numChildren as it always
return 1 as on each frame you will get single children.
you also don't need to do the check another condition
Math.abs(targetClip.scaleX) / targetClip.scaleX != -1 to set the
flip.
And also you need to use ENTER_FRAME instead of EXIT_FRAME.
ENTER_FRAME works for the current frame whereas EXIT_FRAME works for
previous frame.
Use the below code.
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.utils.setTimeout;
public class FlipClip extends MovieClip
{
var mInstance
var prevX;
public function FlipClip()
{
//as soon as this is instantiated, add the eventListener
addEventListener(Event.ENTER_FRAME,flipTheClip);
mInstance = this;
//mInstance.visible = false;
}
public function flipTheClip(e)
{
this.scaleX *= -1;
prevX = this.x;
if(this.scaleX < 0)
this.x = prevX + this.width
else
this.x = prevX - this.width
}
}
}
Paste above code in FlipClip.as file and change the frame rate to 1.
You need to update the moviClip placement based on your requirement.
Hope above answer solve your problem.
You need to remove listener for EXIT_FRAME before playing animation. Also you are Flipping your movieClip here but not adding any code for playing it.
Paste below code in your FlipClip.as file.
package
{
import flash.display.MovieClip;
import flash.events.*;
import flash.utils.setTimeout;
public class FlipClip extends MovieClip
{
var mInstance
public function FlipClip()
{
//as soon as this is instantiated, add the eventListener
addEventListener(Event.EXIT_FRAME,flipTheClip);
mInstance = this;
mInstance.visible = false;
}
private function playallAnimation()
{
this.gotoAndPlay(1);
}
public function flipTheClip(e)
{
removeEventListener(Event.EXIT_FRAME,flipTheClip);
//for sake of simplicity, we will flip every child
for (var i=0; i<numChildren; i++)
{
var targetClip = getChildAt(i);
var axis = 10;
//if the target child has not already been flipped...
if (Math.abs(targetClip.scaleX) / targetClip.scaleX != -1)
{
//reverse the child's direction with scaleX and move based on the axis
targetClip.scaleX *= -1;
var dist:Number = targetClip.x - axis;
targetClip.x = axis - dist;
}
}
setTimeout(function()
{
mInstance.visible = true;
playallAnimation();
},200);
}
}
}
Hope this will work for you.

Keeping Object in Stage-Flash

I am making a game for my class which is similar to Space Invaders/Galaga. I'm new to ActionScript and coding really, I have created an enemy class for which I have it spawn and then move in the x direction. I'm just wondering how I would go about having my enemy move down after it has reached the end of my stage which is 700x500 and then proceed to go to other side, I'm assuming planting an if statement in my enemy class, just unsure on how to go about it, any help will do, much appreciated guys.
Enemy Class
package
{
import flash.display.MovieClip;
public class Enemy extends MovieClip
{
public function Enemy()
{
x = 60;
y = 30;
}
public function moveDownABit():void
{
}
public function moveRight():void
{
x = x + 2;
}
public function moveDown():void
{
}
public function moveLeft():void
{
}
public function moveUp():void
{
}
}
}
Game
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
public class SpaceVigilanteGame extends MovieClip
{
public var enemy:Enemy;
public var avatar:Avatar;
public var gameTimer:Timer;
var gameWidth:int = 0;
var gameHeight:int = 0;
public function SpaceVigilanteGame()
{
enemy = new Enemy();
addChild( enemy );
avatar = new Avatar();
addChild( avatar );
gameWidth = stage.stageWidth;
gameHeight = stage.stageHeight;
gameTimer = new Timer( 25 );
gameTimer.addEventListener( TimerEvent.TIMER, moveEnemy );
gameTimer.start();
}
public function moveEnemy( timerEvent:TimerEvent ):void
{
//enemy.moveDownABit();
if(enemy.x+enemy.width+2<=gameWidth)
{
enemy.moveRight();
}
else if(enemy.y+enemy.height+2<=gameHeight)
{
enemy.moveDown();
}
else if(enemy.x-2>=0)
{
enemy.moveLeft();
}
else if(enemy.y-2>=0)
{
enemy.moveUp();
}
}
}
}
This is pretty basic stuff.
Lets assume you have 4 functions in your Enemy class, moveDown, moveUp, moveRight and moveLeft.
We need to know the width and height of the area the Enemy will move around in, either by hardcoding (will bite you in the butt later on, possibly) or by doing it more dynamic like this:
var gameWidth:int = stage.stageWidth;
var gameHeight:int = stage.stageHeight;
stage.stageWidth or its Height counterpart will give you the size of your SWF movie in pixels, with scaling and so on.
You already have a Timer set up in your Document Class, every 80ms the function moveEnemy will get executed. An alternative approach is to use Event.ENTER_FRAME and execute a function every frame.
Now think about it, every time your function gets called, the enemy will move down a bit. As you said, there should be some kind of...checking mechanism. But we shouldn't put it in the Enemy class, the Enemy doesn't need to know when to stop, that's the problem of the Document class. Ideally, you should be able to use that Enemy in every sort of Class, right? So giving the Enemy boundaries will just be a lot of work when the Document Class could do it instead.
The solution is very easy, you need to check the position of your enemy against the dimensions of your stage every time you want to move your Enemy.
Essentially:
private var gameWidth:int = 0;
private var gameHeight:int = 0;
public function SpaceVigilanteGame(){
//...your init code for enemy
gameWidth = stage.stageWidth;
gameHeight = stage.stageHeight;
//...your timer code
}
public function moveEnemy(timerEvent:TimerEvent):void{
//lets first check if we can go to the right
if(enemy.x+enemy.width+2<=gameWidth){
//so, we take the right outermost border of your enemy by taking its x-position and adding its width. To check if a step right would be out of bounds, we add the amount it WOULD move
//as an example, your enemy has the x-position 100, and is 200 pixel wide, is 100+200+2 smaller or equal to 700 (your stage width)? Yes it is, thus you can move it
enemy.moveRight();
}
else if(enemy.y+enemy.height+2<=gameHeight){
//but what happens if we can't go right? we jump to this additional if condition that will check if the enemy can move down
//same thing as above, but instead we use y-position and the heights
enemy.moveDown();
}
else if(enemy.x-2>=0){
//if we can't move right or down, try left instead
//this time we only need the x-position of the enemy, because we need to look at the leftmost border
enemy.moveLeft();
}
else if(enemy.y-2>=0){
//same deal with going up
enemy.moveUp();
}
}
This is untested code, but I hope you're getting the general gist of this example. The problem here is though that the Enemy will always attempt to move right first. When you start at x:0,y:0 he will move right until he hits the end, then move down until he hits an end, then move left and right alternatively forever.
Movement 101:
If you want to move to the right x = x + 1
If you want to move to the left x = x - 1
If you want to move up y = y - 1
If you want to move down y = y + 1

Movieclips clashing with bitmap mask

I am trying to reveal this movie clip image which is originally a bitmap but needs to be used as a bitmap for this purpose. for some reason it's not working ...
It's not throwing any errors... I need this image to be masked as the user presses on it... and later be compared with another bitmap to carry out a function. but for some reason as I mentioned before it's not working out. can somebody please help me?? this is the code for it...
import flash.display.Graphics;
import flash.display.MovieClip;
import flash.display.BitmapData;
var mouseclick:Number=0;
var maskedbg_mc:maskedbg = new maskedbg ();
var masking:Sprite = new Sprite()
addChild (maskedbg_mc);
maskedbg_mc.x = 18;
maskedbg_mc.y = 343;
var bitmapDataCopy:BitmapData = new BitmapData(742,165,true,0x00FFFFFF);
var b:Bitmap = new Bitmap(bitmapDataCopy);
bitmapDataCopy.draw(maskedbg_mc);
b.mask = masking;
var Testing:BitmapData = new BitmapData(maskedbg_mc.width, maskedbg_mc.height, true, 0x00000000);
addChild(masking);
stage.addEventListener(MouseEvent.MOUSE_DOWN, Pressing);
stage.addEventListener(MouseEvent.MOUSE_MOVE, Moving);
stage.addEventListener(MouseEvent.MOUSE_UP, Lifting);
function Pressing(event:MouseEvent):void {
mouseclick = 1;
}
function Moving(event:MouseEvent):void {
if (mouseclick == 1) {
masking.graphics.beginFill(0x000000);
masking.graphics.drawEllipse(mouseX, mouseY, 70, 60);
masking.graphics.endFill();
}
}
function Lifting(event:MouseEvent):void {
mouseclick = 0;
}
if ( bitmapDataCopy.compare(Testing) ==0 )
{
trace ("Awesomness")
}
Overlooking your code, I notice you are not adding "b" (the masked DisplayObject) to the display list, while you are adding "maskedbg_mc" which actually isn't being masked in your code. Do you have a reason for having these 2 display objects?
I would recommend you following actionscript coding conventions:
http://sourceforge.net/adobe/flexsdk/wiki/Coding%20Conventions/
Your code looks quite confusing when you have both variables and functions with initial letter in uppercase, they look like classes.

ArgumentError: Error #2025 when removeChild

I wrote a AS3 class to make a Counter function. Click and hold mouse in blue area to define a value. I try to show a indicator picture to users that reminding the variation.
But when I drag mouse a little quick in the blue area a error will occur:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
at test/get2()
I have read some similar issue posts, but I can't fix this. Could you give me any help? Thank you!
Download .fla and .as in CS6
Download .fla and .as in CS5
The code is below:
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.events.MouseEvent;
import flash.text.TextFormat;
import flash.events.Event;
public class test extends Sprite{
var i:int=20; //Set a var for the number displayed in stage.
var mx1:Number; //Set a var to save MouseY when MOUSE_DOWN
var mx2:Number; //Set a var to save MouseY when MOUSE_UP
var num:int=0; //Set a var to calculate result
var sub1:subbar1=new subbar1();
var sub2:subbar2=new subbar2();
var sub3:subbar3=new subbar3();
var add1:addbar1=new addbar1();
var add2:addbar2=new addbar2();
var add3:addbar3=new addbar3();
public function test() {
init1(); //Set TextField and addEventListener
initbar(); //Set indicator picture position when drag mouse
}
private function init1():void{
label=new TextField();
label.text=String(i);
label.width=280;
label.selectable=false;
label.x=140;
label.y=90;
addChild(label);
Controler.addEventListener(MouseEvent.MOUSE_DOWN,get1); //addEventListener to bluearea
}
private function initbar(){
sub1.x=sub2.x=sub3.x=add1.x=add2.x=add3.x=30;
sub1.y=35;
sub2.y=55;
add3.y=sub3.y=75;
add2.y=95;
add1.y=115;
}
private function get1(evt:MouseEvent):void{
mx1=mouseY;
trace(mx1);
Controler.removeEventListener(MouseEvent.MOUSE_DOWN,get1);
stage.addEventListener(MouseEvent.MOUSE_UP,get2); //addEventListener to MOUSE_UP
stage.addEventListener(Event.ENTER_FRAME,lifebar); //add ENTER_FRAME to display indicator picture when move mouse
}
private function get2(evt:MouseEvent):void{
mx2=mouseY;
trace(mx2);
if(mx2<=135&&mx2>=35&&mouseX<=130&&mouseX>=50){ //Limited enable area as the blue area
if(num>=4){ //Set i value depends on num
i=i-3;
}else if(num<=-4){
i=i+3;
}else{
i=i-num;
}
label.text=String(i);
}
if(num==1){ //remove indicator picture when MOUSE_UP
removeChild(sub1);
}
if(num==2){
removeChild(sub1);
removeChild(sub2);
}
if(num>=3){
removeChild(sub1);
removeChild(sub2);
removeChild(sub3);
}
if(num==-1){
removeChild(add1);
}
if(num==-2){
removeChild(add1);
removeChild(add2);
}
if(num<=-3){
removeChild(add1);
removeChild(add2);
removeChild(add3);
}
stage.removeEventListener(MouseEvent.MOUSE_UP,get2);
Controler.addEventListener(MouseEvent.MOUSE_DOWN,get1);
stage.removeEventListener(Event.ENTER_FRAME,lifebar);
}
private function lifebar(evt:Event):void{ //Set a ENTER_FRAME to display indicator picture
num=(mouseY-mx1)/12+1;
trace(num);
if(mouseY!=mx1&&num==1){
addChild(sub1);
}
if(num==2){
addChild(sub2);
}
if(num==3){
addChild(sub3);
}
if(num==-1){
addChild(add1);
}
if(num==-2){
addChild(add2);
}
if(num==-3){
addChild(add3);
}
}
}
}
You are attempting to remove display objects that have not yet been added as a child to the display list.
Even though sub1 has been instantiated, it has not been added at the time you attempt to remove it:
Before calling removeChild(obj) on the display object, first test if it has been added as a child by evaluating whether if(contains(obj)) is true.
At line 67 in test.as, you should perform condition testing to see if sub1 has been added to the display list:
if(num==1) {
if(contains(sub1)) // test to see if sub1 is on the display list
removeChild(sub1);
}
If this issue continues with other children, you should add additional testing in blocks like these:
if(num==2){
removeChild(sub1);
removeChild(sub2);
}