I added animation to the timeline of my movie clip, now its no longer colliding with objects as it did before - actionscript-3

I'm working on a platform game in AS3 for Flash. There is of course a player character and enemies for him to interact with. I first made a simple placeholder graphic for the enemy while I worked on the code. I got the enemy to move back and forth between two bumpers with code. He also collides with the player, sending them back to the start screen. Now that I got the code working, I wanted to add some animations to the enemies so they walk instead of just skate across the ground. I added the animations to the timeline of the enemy movie clip. Now when I test the game, the animations play fine and the enemy begins to move, but he passes through the first bumper and doesn't collide with the player at all. If I force the movie clip to stop and not play the collision starts to work again. What would be causing this?
This is the code within the main timeline of the .fla file.
addEnemiesToLevel1();
addBumpersToLevel1();
function addEnemiesToLevel1():void
{
addEnemy(700, -54);
addEnemy(1341, -54);
addEnemy(2187, -54);
}
function addBumpersToLevel1():void
{
addBumper(900, -80);
addBumper(644, -80);
addBumper(1135, -90);
addBumper(1380, -90);
addBumper(2053, -90);
addBumper(2226, -90);
}
function addEnemy(xLocation:int, yLocation:int):void
{
var enemy:Enemy = new Enemy(xLocation, yLocation);
back.addChild(enemy);
enemy.addEventListener(Event.REMOVED, enemyRemoved);
enemyList.push(enemy);
}
function addBumper(xLocation:int, yLocation:int):void
{
var bumper:Bumper = new Bumper(xLocation, yLocation);
back.addChild(bumper);
bumper.visible = false;
bumperList.push(bumper);
}
//corralling the bad guys with bumpers
if (enemyList.length > 0){ //enemies left in the enemyList?
for (var k:int = 0; k < enemyList.length; k++){ // for each enemy in the enemyList
if (bumperList.length > 0){
for (var h:int = 0; h < bumperList.length; h++){ // for each bumper in the List
if ( enemyList[k].hitTestObject(bumperList[h]) ){
enemyList[k].changeDirection();
}
}
}
}
}
//player and enemy collisions
if (enemyList.length > 0){ //enemies left?
for (var m:int = 0; m < enemyList.length; m++){ // for each enemy in the enemyList
if ( enemyList[m].hitTestObject(player) ){
trace("player collided with enemy");
gotoAndStop(4);
enemyList[m].removeSelf();
}
}
}
}
This is the enemy class file.
package {
import flash.display.MovieClip;
import flash.events.Event;public class Enemy extends MovieClip {
private var xSpeedConst:int = 2;
private var flip:int = 1;
public function Enemy(xLocation:int, yLocation:int) {
// constructor code
x = xLocation;
y = yLocation;
addEventListener(Event.ENTER_FRAME, loop);
}
public function loop(e:Event):void {
if ((flip%2) == 1){
x += xSpeedConst;
} else if((flip%2) == 0){
x += (-xSpeedConst);
}
}
public function removeSelf():void {
trace("remove enemy");
removeEventListener(Event.ENTER_FRAME, loop);
this.parent.removeChild(this);
}
public function changeDirection():void{
trace("x ="+x);
flip++;
this.scaleX *= -1;
}
}
}

I had a problem that was very similar to this:
2D Platform Game using hitTestPoint:glitches
My problem was that my character's hitTestPoint wouldn't work after I animated the character. However, it wasn't because of the animation, it was because of my turning code for the character. I was using scaleX to flip the character. However, this flipped the points nested within the character as well (which were used to handle my collisions). I notice that you also flipped the character's scale:
public function changeDirection():void{
trace("x ="+x);
flip++;
this.scaleX *= -1;
}
Perhaps you are having the same problem as I did. If so, try removing this line of code for now:
this.scaleX *= -1;
...and see what happens...We can figure out what to do next from there
Drake Swartzy

Related

Some of the collisions are not responding

im developing a game; its like a space craft going horizontally and enemy crafts coming oppositely..Enemies are destroyed only when it collides with the trail of the craft.
Here is the main class:
public function Velocity() {
//int static var
trailspeed = 10;
shipspeed = 5;
//init ship//
ship = new Ship();
ship.x = 337;
ship.y = 216;
//int arrays
enemies = new Array();
//init starting state
score = 0;
health = 100;
//Events
addEventListener(Event.ENTER_FRAME, motion);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keydown);
stage.addEventListener(KeyboardEvent.KEY_UP, keyup);
//init container and trail
_cont = new MovieClip();
//addChild
addChild(_cont);
addChild(ship);
timerset();
}
public function motion(e:Event){
//adding the trails
trail = new Trail();
trail.x = ship.x;
trail.y = ship.y;
_cont.addChild(trail);
checkcollision();
}
public function checkcollision(){
for(var _e:int = enemies.length - 1; _e >=0; _e--){
for(var _t:int = _cont.numChildren - 1; _t >=0; _t--){
if(enemies[_e].hitTestObject(_cont.getChildAt(_t))){
enemies[_e].remove();
return;
}
}
}
}
public function removeenemies(_e:Enemy){
for(var i in enemies){
if(enemies[i] == _e){
enemies.splice(_e);
}
}
}
and here is the Enemy class:
public class Enemy extends MovieClip {
private var _speed:Number;
public function Enemy(ypos, speed) {
this.x = 550;
this.y = ypos;
_speed = speed;
addEventListener(Event.ENTER_FRAME, motion);
}
public function motion(e:Event){
this.x -= _speed;
checkoffscreen();
}
public function remove(){
MovieClip(parent).removeenemies(this);
MovieClip(parent).removeChild(this);
removeEventListener(Event.ENTER_FRAME, motion);
return;
}
public function checkoffscreen(){
if(this.x < 0){
MovieClip(parent).removeenemies(this);
MovieClip(parent).removeChild(this);
removeEventListener(Event.ENTER_FRAME, motion);
}
}
}
}
The problem here is after 2 or 3 successful collision detections one goes undetected.. and hence the chances is like 2/3 ...how can i program a 100% successful collision???pls help
I want to recommend not to delete objects from within themselves, instead have a simple isDead boolean inside the the Enemy and in the main class when you loop through enemies check if isDead is set to true, if so then remove the object from the array and delete it from the Stage; no need for removeenemies().
Back to the real problem you're having. You're doing a good job iterating through the list of enemies in reverse since you do expect to remove some objects, that of course results in shift of entries in the array.
It's hard to say what's wrong with this code. I'd say lose removeenemies(). Move any collision testing inside the Enemy and in the Main keep everything in a nice linear update function like so:
public function update() {
for(var i:int = enemies.length - 1; i >=0; i--){
var enemy:Enemy = enemies[i];
enemy.checkCollision(); // Can set isDead = true;
if(enemy.isDead) {
enemies.splice(i);
removeChild(enemy);
}
}
}
Finally I found out the answer.
the problem was with the removeenemies function
replacing splice(_e) wtih splice(_e, 1) solved the problem

Remove bullet when hit a wall

I'm making an AS3 platform game where the player can shoot some bullets.
When the bullet is touching an enemy, the enemy die and the bullet is removed.
I've succeed do to that but now I'd like to remove the bullet if it hit a wall and I can't figure out how to do so.
So far, here's my code for removing the bullet when touching an enemy :
public function checkCollisions() {
// enemies
for(var i:int=enemies.length-1;i>=0;i--) {
if (hero.mc.hitTestObject(enemies[i].mc)) {
// is the hero jumping down onto the enemy?
if (hero.inAir && (hero.dy > 0)) {
enemyDie(i);
} else {
heroDie();
}
}
for (var j:int = 0; j < bulletList.length; j++) // for each bullet in the bulletList
{
if (enemies[i].mc.hitTestObject(bulletList[j]) )
{
trace("Bullet and Enemy are colliding");
enemyDie(i)
bulletList[j].removeSelf();
}
}
}
I've defined my wall and floor like this :
public function examineLevel() {
fixedObjects = new Array();
otherObjects = new Array();
for(var i:int=0;i<this.gamelevel.numChildren;i++) {
var mc = this.gamelevel.getChildAt(i);
// add floors and walls to fixedObjects
if ((mc is Floor) || (mc is Wall)) {
var floorObject:Object = new Object();
floorObject.mc = mc;
floorObject.leftside = mc.x;
floorObject.rightside = mc.x+mc.width;
floorObject.topside = mc.y;
floorObject.bottomside = mc.y+mc.height;
fixedObjects.push(floorObject);
}
}
I've tried to put this in my checkCollisions function but it's not working :
for(var k:int=0;k<fixedObjects.length;k++)
{
if (fixedObjects[k].hitTestObject(bulletList[j]) ){
trace("hit wall");
}
Do you know what do I have to put in order to remove the bullet when it's touching a wall (or floor) ?
Thx
The array fixedObjects holds references to Object instances. However, hitTestObject(obj) is a public function of the DisplayObject class, and the obj parameter needs to be an instance of DisplayObject.
If the code snippet you provided is exactly the same as what you used in your game, there should be runtime error messages generated.
Could you please verify whether this is the cause of failing to detect collision?

AS3 - Remove a Specific Instance of a MovieClip with removeChild() Function

I'm working on a Flash game for an assignment. It's a pretty standard missile defense-type game, with a rotating missile launcher in the center firing up at passing bombers above. The missiles and bombers are functioning correctly by themselves, but I'm running into a problem when I try to get the two to interact. Specifically, when a missile hits a bomber, I want the specific instances of that missile and that bomber to be removed from the screen and have their respective event listeners removed, but everything I've tried has failed and I can't seem to figure out just how to do it.
Here are the Main, Bomber, and Missile classes I'm working with:
The Main Class:
package {
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Main extends MovieClip {
public var background:Background;
public var launcher:Launcher;
public var mount:Mount;
public var missile:Missile;
public var salvo:Array = [];
public var bomber:Bomber;
public var squadron:Array = [];
/*
* This function sets up the permanent items (items that remain on-stage for
* the duration of the game) and adds event listeners that call functions to
* add non-permanent items to the stage
*/
public function Main() {
// Add background to the stage
background = new Background(stage);
stage.addChild(background);
stage.setChildIndex(background, 0);
// Add the rotating launcher to the stage
launcher = new Launcher(stage);
stage.addChild(launcher);
stage.setChildIndex(launcher, 1);
// Add the static mount to the stage (on top of launcher)
mount = new Mount(stage);
stage.addChild(mount);
stage.setChildIndex(mount, 2);
// Call loop() every new frame
stage.addEventListener(Event.ENTER_FRAME, loop);
// Call fire() every time the mouse is clicked
stage.addEventListener(MouseEvent.CLICK, fire);
}
/*
* This function runs every time the program enters a new frame, or 60 times
* every second. Each time this function runs, it tries to add a new Bomber
* to the squadron array and checks to see if there are any Missiles or
* Bombers currently in their respective arrays (and if so, calls a function
* to make them move).
*/
public function loop(evt:Event) {
// If the random number generated by Math.random() is less than
// waveLimiter, create a new Bomber and add it to the squadron array.
if(Math.random() < 0.02 /* Change this number to change how fast bombers spawn */) {
bomber = new Bomber(stage);
bomber.addEventListener(Event.REMOVED_FROM_STAGE, removeBomber); // If the Bomber is removed from the stage, call removeBomber() to remove its event handler.
squadron.push(bomber);
stage.addChild(bomber);
stage.setChildIndex(bomber, 1);
}
// Check to see if there is at least one missile in the salvo array, and
// if so, call Missile.velocity() to make it move.
if(salvo.length > 0) {
for(var i:int = salvo.length - 1; i >= 0; i--) {
salvo[i].velocity();
}
}
// Check to see if there is at least one bomber in the squadron array,
// and if so, call Bomber.fly() to make it move.
if(squadron.length > 0) {
for(var j:int = squadron.length - 1; j >= 0; j--) {
squadron[j].fly();
}
}
}
/*
* This function checks for a mouse click, and if it detects one, creates a
* new Missile and adds it to the salvo array.
*/
public function fire(evt:MouseEvent) {
missile = new Missile(stage, launcher.rotation);
missile.addEventListener(Event.REMOVED_FROM_STAGE, removeMissile); // If the Missile is removed from the stage, call removeMissile() to remove its event handler.
salvo.push(missile);
stage.addChild(missile);
stage.setChildIndex(missile, 1);
}
/*
* This function removes the EVENT LISTENER for the current Missile instance.
* It does not remove the Missile itself from the stage.
*/
public function removeMissile(evt:Event):void {
evt.currentTarget.removeEventListener(Event.REMOVED_FROM_STAGE, removeMissile);
salvo.splice(salvo.indexOf(evt.currentTarget), 1);
}
/*
* This function removes the EVENT LISTENER for the current Bomber instance.
* It does not remove the Bomber itself from the stage.
*/
public function removeBomber(evt:Event) {
evt.currentTarget.removeEventListener(Event.REMOVED_FROM_STAGE, removeBomber);
squadron.splice(squadron.indexOf(evt.currentTarget), 1);
}
}
}
The Bomber class:
package {
import flash.display.Stage;
import flash.display.MovieClip;
public class Bomber extends MovieClip {
var stageInstance:Stage;
var randomNumber:Number = Math.round(Math.random() * 1);
public function Bomber(stageInstance:Stage):void {
this.stageInstance = stageInstance;
if(randomNumber == 1) {
x = -39;
y = (Math.random() * 120) + 30;
}
else if(randomNumber == 0) {
scaleX *= -1;
x = 679;
y = (Math.random() * 120) + 30;
}
}
public function fly():void {
if(randomNumber == 1) {
x = x + 4;
}
else if(randomNumber == 0) {
x = x - 4;
}
if(x > 680 || x < -40) {
this.parent.removeChild(this);
}
}
}
}
The Missile Class:
package {
import flash.display.Stage;
import flash.display.MovieClip;
public class Missile extends MovieClip {
var stageInstance:Stage;
var velocityX:Number;
var velocityY:Number;
var speed:Number = 10;
var rotationRadians:Number;
var rotationDegrees:Number;
public function Missile(stageInstance:Stage, rotationDegrees:Number):void {
this.stageInstance = stageInstance;
x = 320;
y = 363;
rotation = rotationDegrees;
rotationRadians = rotationDegrees * Math.PI / 180;
}
public function velocity():void {
velocityX = Math.cos(rotationRadians) * speed;
velocityY = Math.sin(rotationRadians) * speed;
x += velocityX;
y += velocityY;
if(x > 640 || x < 0 || y > 480 || y < 0) {
this.parent.removeChild(this);
}
}
}
}
In the Main Class, I've tried adding something like this:
if(squadron.length > 0) {
for(var j:int = squadron.length - 1; j >= 0; j--) {
squadron[j].fly();
if(salvo.length > 0) {
if(missile.hitTestObject(squadron[j])) {
this.parent.removeChild(this);
}
}
}
}
But no luck. I've also tried using a trace statement, and it doesn't even give me an output, which leads me to think it's not even detecting collision at all. Any ideas?
Update: I added a few more details.
this represents the object on which the function is called. So
this.parent.removeChild(this); makes no sense when it is written in the main class.
When you write it in the Missile Class, this is the Missile instance, and this.parent is the stage.
Try replacing it with: stage.removeChild(missile), in the last sample of code you posted, and call removeMissile() just after.
Try to use stage.removeChild instead this.parent.removeChild(this);
Actually you have many problems in your code. First of all, you don't need to work with Stage. You can work with your main container Main. When you add object to the display list, don't do after setChildIndex. In your code It doesn't have any sense. Also you don't need any length conditions. And create light objects by extending Sprite, not MovieClip.
Code for your loop, for missiles:
private function loop(e: Event):void {
//...not full listing
var i:uint, j:uint, salvos:uint = salvo.length, bombers:uint = squadron.length, missile:Missle, bomber:Bomber;
var disposeMissiles:Array = [];
var disposeBombers:Array = [];
//Rendering missiles
for (i = 0; i < salvos; ++i) {
missile = salvo[i];
missile.valocity();
for (j = 0; j < bombers; ++j) {
bomber = squadron[j];
if (!bomber.isHitted() && missile.hitTestObject(bomber)) {
//Dispose both missile and bomber
bomber.setHitted = true;
disposeMissiles.push(missile);
disposeBombers.push(bomber);
}
}
}
//Clear lists and display list
disposeObjects(disposeMissiles, salvo);
disposeObjects(disposeBombers, squadron);
}
private function disposeObjects(objects:Array, from:Array):void {
//Create interface for both missiles and bombers, like IGameActor
var i:uint, len:uint = objects.length, objectToRemove:IGameActor;
for (i; i < len; ++i) {
objectToRemove = objects[i];
//Remove from the display list, in your design Parent is Stage
this.stage.removeChild(DisplayObject(objectToRemove));
//Release memory, links, event listeners
objectToRemove.dispose();
//Try manage also indexes, splice is slow operation
from.splice(from.indexOf(objectToRemove), 1);
}
}

Enemy to spawn at specific locations

I am new to as3, I tried to look for an answer to my question already. For a side scrolling game I have enemies set at certain locations, and I need them to spawn, not just show up once at these specific places in the game. These are excerpts from the timeline code concerning the problem.
var enemyList:Array = new Array();
function addEnemiesToLevel1():void
{
addEnemy (700, 125);
addEnemy (1000, 125);
addEnemy(2405, 125);
addEnemy(3300, -155);
}
if (enemyList.length > 0)
{
for (var i:int = 0; i < enemyList.length; i++)
{
function addEnemy(xLocation:int, yLocation:int):void
{
var enemy:Enemy = new Enemy(xLocation, yLocation);
back.addChild(enemy);
enemy.addEventListener(Event.REMOVED, enemyRemoved);
enemyList.push(enemy);
}
The enemy is tied to a class file controlling movement towards player
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Enemy extends MovieClip {
private var xSpeedConst:int = 6;
public function Enemy(xLocation:int, yLocation:int) {
// constructor code
x = xLocation;
y = yLocation;
addEventListener(Event.ENTER_FRAME, loop);
}
public function loop(e:Event):void {
x -= xSpeedConst;
}
public function removeSelf():void {
trace("remove enemy");
removeEventListener(Event.ENTER_FRAME, loop);
this.parent.removeChild(this);
}
}
}
The enemy is also set for collisions so I don't want to change the code too much, since I might spoil something. If I have to add Timer, please tell me where exactly, because I already tried that and failed. Thank you for your help.
Although I recommend not coding in the timeline, a working example timer setup in the timeline would look like this:
var timer:Timer = new Timer(2000,0);
timer.addEventListener(TimerEvent.TIMER, createEnemy);
function createEnemy(e:TimerEvent):void{
//create a new enemy, pass the x and y you want (xPos and yPos here)
//var xPos:int, yPos:int
var enemy:Enemy = new Enemy( xPos, yPos );
back.addChild(enemy);
}
timer.start();
You could also do a similar setup in your class files if you are generating enemies there. Again, doing this in the timeline will much harder to maintain and debug.

Bullets will only fire to the right?

I'm making a flash game for my course at college, I have been following a tutorial but been spinning it off for my own sake. One wall I hit is that when I fire a bullet, it will only fire to the right, with a little movement up or down, I have been trying to fix it for a while but nothing is happening and nothing works.
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Wizard extends MovieClip {
private var dx:Number;
private var dy:Number;
private var Bulletspeed:int;
public var Angle:Number;
public var newAngle:Number;
var shotCoolDown:int;
const MAX_COOLDOWN=20;
public function Wizard() {
//constructor
//Shot cool down
shotCoolDown=MAX_COOLDOWN;
addEventListener(Event.ENTER_FRAME, update);
//set up an event listener for when the turret is added to stage
addEventListener(Event.ADDED_TO_STAGE, initialise);
}
function initialise(e:Event) {
//reduce shot cool down by one
shotCoolDown=shotCoolDown-1;
//add a click listener to the stage
stage.addEventListener(MouseEvent.CLICK, fire);
}
function fire(m:MouseEvent) {
//Able to shoot
if (shotCoolDown<=0) {
//resets cool down
shotCoolDown=MAX_COOLDOWN;
//spawn bullet
var B = new Bullet();
//set position and rotation of the bullet
B.rotation=rotation;
B.x=x;
B.y=y;
//add the bullet the the wizard
parent.addChild(B);
}
}
function update():void {
//Shot cool down
shotCoolDown--;
//Make the Wizard face the mouse
if (parent!=null) {
dx=stage.mouseX-this.x;
dy=stage.mouseY-this.y;
Math.abs(dx);
Math.abs(dy);
var Angle=Math.atan2(dy,dx);
var newAngle = Angle * (180 / Math.PI);
if ((0 < newAngle) && (newAngle <= 90)) {
gotoAndPlay("Right");
} else if ((90 < newAngle) && (newAngle <= 180)) {
gotoAndPlay("Down");
} else if ((-180 < newAngle) && (newAngle <= -90)) {
gotoAndPlay("Left");
} else if ((-90 < newAngle) && (newAngle <= 0)) {
gotoAndPlay("Up");
}
this.rotation=Angle;
}
}
}
}
That's the code for my player class, with things such as bullets firing and what not. I think I know the problem, I need to link it to the rest of the Wizard update. But I don't know how, here is my bullet class if needed.
package {
import flash.display.Sprite;
import flash.events.Event;
public class Bullet extends Sprite {
private var speed:int;
private var myCharacter:Wizard;
public function Bullet() {
//constructor
speed = 10;
addEventListener(Event.ENTER_FRAME, update);
}
function update (e:Event) {
//Move in the direction the bullet is facing
x=x+Math.cos(rotation/180*Math.PI)*speed;
y=y+Math.sin(rotation/180*Math.PI)*speed;
//Clears bullet once it leaves the stage
if (x<0 || x>500 || y<0 || y>500) {
//removes the update listner
removeEventListener(Event.ENTER_FRAME, update);
parent.removeChild(this);
}
}
}
}
You're setting the Wizard's rotation to Angle, which is in radians; the rotation is then passed on to the Bullet, which expects its rotation to be in degrees. It's probably better to set this.rotation=newAngle; at the end of update(), as the UIComponent class expects that value in degrees and uses it for rotating its drawing.