ActionScript 3: Bullet Ricocheting - actionscript-3

I've been having a problem with my Actionscript code. I am fairly new to Flash and AS3, so I apologize if my code seems crude or rudimentary, but I'm doing this as best as I can.
Well, in this project I'm trying to get a bullet to ricochet off a wall once. If it hits a wall again after ricocheting, the bullet will disappear.
I've created a for loop which moves the bullets, in an array. At the same time, I try to keep track of each bullet's individual number of ricochets. This works fine when I shoot a first bullet - it will ricochet and then disappear after hitting another wall. However, every bullet I fire after that disappears on the first wall it hits, before it has ricocheted. I've tried to get this to work but I just can't seem to do it.
I would be grateful if somebody could show me the problem, or suggest a change to my code.
Here is a link to my code as it is now.
Thanks, to anybody who helps.

Here are some suggestions I have:
1: Create a Bullet class that tracks its own collisions against walls. I'd also move the clearBullet() method into the bullet class itself.
public class Bullet extends Sprite
{
public var collisions:int = 0;
public var xv:Number = 0;
public var yv:Number = 0;
public function clear():void
{
if(parent)
parent.removeChild(this);
}
}
2: Update your loop to deal with this new info.
for each(var i:Bullet in bulletholder)
{
// Move bullet.
// Check for collision.
// When there is a collision, do this:
i.collisions ++;
if(i.collisions >= 2)
{
var n:int = bulletholder.indexOf(i);
bulletholder.splice(n, 1);
i.clear();
}
else
{
// Deal with changing bullet position.
}
}

I see at least a couple of problems with your code:
Your ricochetcount is clearly out of sync. i.e. you need to delete an element from that array as well.
When you delete an element from the bulletholder array (via clearBullet), you're still incrementing i, which means you end up inadvertently skipping an element.
Also I'm not sure why you need clearBullet(). You already have the index i as well as a reference to the bullet object right there in the main loop.

Related

AS3 tween object not working with .hitTestObject()

I am having a major problem in my new browser app.
Okay so I made game where different cubes (squares) spawn at the top of the screen and I use the Tween class to make them go down the screen and then disappear.
However I want to detect a collision when a cube hits the player (that is also a flying cube).
I tried everything, truly everything but it does not seem to work. The problematic thing is that when I remove the "Tween" function it does detect collision with the hitTestObject method but when I add the "Tween" line collision won't be detected anymore.
It looks like this:
function enemiesTimer (e:TimerEvent):void
{
newEnemy = new Enemy1();
layer2.addChild(newEnemy);
newEnemy.x = Math.random() * 700;
newEnemy.y = 10;
if (enemiesThere == 0)
{
enemiesThere = true;
player.addEventListener(Event.ENTER_FRAME, collisionDetection)
}
var Tween1:Tween = new Tween(newEnemy, "y", null, newEnemy.y, newEnemy.y+distance, movingTime, true);
}
And the collision detection part:
private function collisionDetection (e:Event):void
{
if (player.hitTestObject(newEnemy))
{
trace("aaa");
}
}
I am desperate for some information/help on the topic, it's been bugging me for days.
Thanks for your time, I would be very happy if someone could help me out^^
First, make sure the "newEnemy" instance and the "player" instance are within the same container. If they are not, their coordinate systems might not match up and could be the source of your problem.
Otherwise, you need to keep a reference to each enemy instance you create. It looks like you are only checking against a single "newEnemy" variable which is being overwritten every time you create a new enemy. This might be why you can successfully detect collision between the player and the most recent "enemy" instance.
So... you need a list of the enemies, you can use an Array for that.
private var enemyList:Array = [];
Every time you create an enemy, push it to the Array.
enemyList.push(newEnemy);
In your "collisionDetection" function, you need to loop through all of the enemies and check if the player is touching any of them.
for(var i:int = 0; i < enemyList.length; i++)
{
var enemy = enemies[i];
if (player.hitTestObject(enemy))
{
trace("Collision Detected!");
enemy.parent.removeChild(enemy); // remove the enemy from the stage
enemies.splice(i, 1); // remove the enemy from the list
}
}
I'd suggest that you move to TweenMax, it just might solve your problem, and in my experience it's much better in every possible way.
Scroll down the following page to see a few variations of this library, I myself use TweenNano, they're completely free of charge:
https://greensock.com/gsap-as
I think some plugins cost money, but I doubt you'll ever need them.

How to remove element from Array and child from stage

So I am currently attempting to remove an element from the array 'zombie_horde' as well as remove the child from the stage. My aimed result, a movie clip that is part of an array israndomly played and when finished playing, the frame changes to a gameover frame.
This is my code:
part of the big loop:
for each (var zom:Betherino in zombie_horde)
{
var frame = zom.currentFrame
trace(frame)
if(frame == zom.lastframe)
{
updatearray()
}
else{
zom.gotoAndStop(frame+1)
}
functions:
function updatearray()
{
zombie_horde.splice();
trace('spliced')
}
function removeBetherino()
{
stage.removeChild(Betherino)
}
This is what I have so far. I am wondering how I am supposed to continue to tackle this situation of removing the movie clip (AS Linkage 'Betherino') from not only the array but also the stage
Sorry I am still new to stack Overflow :(
I havent gotten up to the change frame part any suggestions on ideas would be great!
To "Remove the element from the array and the stage then go to a gameover frame", there's three steps:
Remove the element from the array
Remove the element from stage
Jump to a game over frame.
The last one, I think that's best left to you. There's no code related to gameover frames in your question, so I can't help you there.
The other elements, however...
for each (var zom:Betherino in zombie_horde){
var frame = zom.currentFrame
trace(frame)
if(frame == zom.lastframe)
{
updatearray()
}
else{
zom.gotoAndStop(frame+1)
}
}
You go through each zombie in the zombie horde, and if it's at its last frame, you try to remove it.
This implies that these zombies simply play through an animation and then disappear. Sounds strange to me. Is that really want you want the code to do?
Next... you use updatearray to remove the zombies from the array. But you do so via zombie_horde.splice(). That doesn't work. If you look at the documentation for splice then you'll see that it takes 2+ arguments: startIndex:int, deleteCount:uint, ... values. That is, the first argument is the start index to start deleting at, the second argument specifies how many you want to delete, and any arguments after that are added back in the list.
zombie_horde.splice(zombie_horde.indexOf(zom), 1);
will do what you're looking for, when inlined.
As for removing the element from stage, you need to pass an object. stage.removeChild(Betherino) is not the correct way, inline and use stage.removeChild(zom) instead. That makes for this function:
for each (var zom:Betherino in zombie_horde){
var frame = zom.currentFrame
trace(frame)
if(frame == zom.lastframe)
{
zombie_horde.splice(zombie_horde.indexOf(zom), 1);
stage.removeChild(zom);
//go to gameover frame and exit for loop
}
else{
zom.gotoAndStop(frame+1)
}
}
The "go to gameover frame" comment still needs to be replaced with the relevant code.

How to construct nested eventlisteners in AS3

Working a bit with AS3 and hit a wall on how to program through this situation. I have a class which represents a number say 103. I have a movieclip for each digit which I add to a holding movieclip and then add to the stage. I want to enable the ability to single click a digit like the zero in the number 103 and have it react since it is an individual movieclip and at the same time double click the entire number and have that react. Is there a way to cleanly do this wtihout confusing the code below is what I have thus far.
public function test()
{
numberimage = new MovieClip();
var images:Vector.<MovieClip> = generateNumericArray("");
for (var i:int = 0; i < String(value).length; i++) {
var temp:MovieClip = parsevalue(String(value).substr(i,1),images);
temp.x = i*50;
temp.addEventListener(MouseEvent.CLICK,click)
numberimage.addChild(temp);
}
numberimage.addEventListener(MouseEvent.MOUSE_DOWN,drag);
numberimage.addEventListener(MouseEvent.MOUSE_UP,drop);
numberimage.addEventListener(MouseEvent.MOUSE_OVER,doubleClick);
stage.addChild(numberimage);
}
any help on this would be much appreciated
Do, doubleclick on clip : stop listening to main movie, and listen now to sub clips. On click outside the main clip, listen back to the main movie and stop listening to its children.
Not sure if this is 100% what you are looking for: use the following, depending on what you are adding the listener to. You do have to enable double clicking first
numberimage.doubleClickEnabled = true;
numberimage.addEventListener(MouseEvent.DOUBLE_CLICK, click);

AS3 - Trying to declare the value of a Movie Clip

Okay, I have the following code in my Bullet.as file:
public var impact:MovieClip;
public function Bullet():void
{
addEventListener(Event.ADDED_TO_STAGE, whenAdded);
}
function whenAdded(e:Event)
{
if(this is zArrow){
power = -1;
speed = 15;
impact = arrowImpact;
trace(impact);
}
if(this is Dice){
power = -Math.round(Math.random()*5 + 1);
speed = 10;
impact = diceImpact
}
}
See, I am trying to set the value of "public var impact:MovieClip" as the movie clip "arrowImpact" or "diceImpact". What I want is whenever a bullet collides with an enemy, it leaves an impact image behind and I'm trying to change what impact is shown depending on what bullet is colliding.
I am able to change all of the other variables like power and speed using this setup, but I can't declare which impact movie clip the "impact" movie clip variable is.
From the way I understand your question now, you want to pull these specific movie clips from the Library. If I am not mistaken. To do this, you need to pair each of the movie clips in the library to an AS class that extends MovieClip.
Make sure you check "Export for Actionscript" and create the class you want for each. Then, in your code for the Bullet, you can create a new instance of them. So have it say:
impact = new ArrowImpact)();
or DiceImpact depending on your classes.
Hope this is along the lines of what you wanted.
In order to use these, I would recommend creating a getImpact method along the lines of:
public function getImpactMC():MovieClip
{
return impact;
}
Then all you need to do in your main Document is addChild the proper impact from this method. However, be aware that you need to adjust the x and y values of the impactMC before adding it as a child on the stage to make sure that it displays in the proper position.
Glad this helps!

I can't seem to access automatically named objects (instance##) placed on the stage in AS3, am I missing something?

I have a movieclip in the library that is added to the stage dynamically in the document class's actionscript. This movieclip contains many many child images that were imported directly from photoshop at their original positions (which must be preserved).
I do not want to manually name every single image instance, as there are dozens upon dozens.
I have already gone through and manually converted the images to symbols, as apparently flash won't recognize the "bitmap" objects as children of a parent movieclip in AS3 (numChildren doesn't see the bitmaps, but it sees the symbols).
I have an array filled with references to the dozens of children, and I loop through it, checking if each one is under the mouse when clicked. However, somehow, it is not detecting when I click over the items unless I manually name the child symbols (I tested by manually naming a few of them -- those ones became click-sensitive.)
I have already done trace() debugging all throughout the code, verifying that my array is full of data, that the data is, in fact, the names of the instances (automatically named, IE instance45, instance46, instance47, etc.), verifying that the function is running on click, verifying that the code works properly if I manually name the symbols.
Can any one see what's going wrong, or what aspect of flash I am failing to understand?
Here is the code:
//check each animal to see if it was clicked on
private function check_animal_hits():void
{
var i:int = 0;
var animal:Object = this.animal_container;
for (i=0; i<animal.mussels.length; i++)
{
if (this.instance_under_cursor(animal.mussels[i].name))
{
var animal_data = new Object();
animal_data.animal = "mussel";
this.send_data(animal_data);
}
}
}
Here is the code for the instance_under_cursor() method:
// Used for finding out if a certain instance is underneath the cursor the instance name is a string
private function instance_under_cursor(instance_name)
{
var i:Number;
var pt:Point = new Point(mouseX,mouseY);
var objects:Array = stage.getObjectsUnderPoint(pt);
var buttons:Array = new Array ;
var o:DisplayObject;
var myMovieClip:MovieClip;
// add items under mouseclick to an array
for (i = 0; i < objects.length; i++)
{
o = objects[i];
while (! o.parent is MovieClip)
{
o = o.parent;
}
myMovieClip = o.parent as MovieClip;
buttons.push(myMovieClip.name);
}
if (buttons.indexOf(instance_name) >= 0)
{
return true;
}
return false;
}
Update:
I believe I have narrowed it down to a problem with getObjectsUnderPoint() not detecting the objects unless they are named manually.
That is the most bizarre way to find objects under mouse pointer... There is a built-in function that does exactly that. But, that aside, you shouldn't probably rely on instance names as they are irrelevant / can be changed / kept solely for historical reasons. The code that makes use of this property is a subject to refactoring.
However, what you have observed might be this: when you put images on the scene in Flash CS, Flash will try to optimize it by reducing them all to a shape with a bitmap fill. Once you convert them to symbols, it won't be able to do it (as it assumes you want to use them later), but it will create Bitmpas instead - Bitmap is not an interactive object - i.e. it doesn't register mouse events - no point in adding it into what's returned from getObjectsUnderPoint(). Obviously, what you want to do, is to make them something interactive - like Sprite for example. Thus, your testing for parent being a MovieClip misses the point - as the parent needs not be MovieClip (could be Sprite or SimpleButton or Loader).
But, if you could explain what did you need the instance_under_cursor function for, there may be a better way to do what it was meant to do.