Remove Object when Collision Detected in AS3 - actionscript-3

I'm making a game where your player (gun) shoots enemies (baddie) to gain score. I've set it up so you have three lives (lives) until it is game over. I am trying to add an addLife function that works by when your player collects an object (waterMelon), it gets a life. I have added a timer event that runs the function addLife, that adds an instance of the Movie clip to the stage every 5 seconds. In that function, ive created another function called checkCollisions, that is meant to check the collision of the player, to the object, remove the object from the stage, then add a life.
var timer2:Timer = new Timer(5000);
timer2.addEventListener(TimerEvent.TIMER, addLife);
timer2.start();
var watermelon:waterMelon = new waterMelon();
function addLife(evt:TimerEvent):void{
watermelon.x = Math.random() * stage.stageWidth;
watermelon.y = Math.random() * stage.stageHeight;
addChild(watermelon);
watermelon.push(waterMelon);
checkCollision();
}
function checkCollision(){
if (gun.hitTestObject(watermelon)){
removeChild(watermelon);
lives++;
livesDisplay.gotoAndStop(livesDisplay.currentFrame-1);
}
}
The only part of the code that works is the adding the watermelon to the stage, but when my player collides with it, it does not remove from the stage. Could someone please tell me how I make my watermelon completely be removed from the stage when the player collides with it, and add a life to my player. Once again, each object equals this; gun = player, waterMelon = object/watermelon, lives = lives, livesDisplay = physical display of lives.

You have tried to delete the array(watermelon) from the stage instead of the object(waterMelon). Although by the looks you are using arrays so you will have to find the index of the object colliding with the gun from the array watermelon. You do this with a for loop.
for (melonCount:int = 0; melonCount>watermelon.length;melonCount--)
{
if (gun.hitTestObject(watermelon[melonCount]))
{
removeChild(watermelon[melonCount])
watermelon.splice(melonCount, 1)
melonCount--
}
}

Related

How Can I Make AS3 Var Loop move speed on the Y Axis on repeat my university project

I'm tring to get the car image to move down the screen on the y Axis and make it a repeat and colide with another object
//creates the new Car
for (var c:int=0; c<8; c++){
var newcar = new car();
newcar.x = 55*c;
newcar.y = 100;
EntityArray.push(newcar);
stage.addChild(newcar);
trace("Car Created"+c)
}
How to make it colide with the following and remove it from screen
//creates the new Frog
for (var f:int=0; f<1; f++){
var newfrog = new frog();
newfrog.x = 210;
newfrog.y = 498;
EntityArray.push(newfrog);
stage.addChild(newfrog);
trace("Frog Created"+f)
}
[image][1][1]: https://i.stack.imgur.com/Ihsfx.png
Though I'm quite pleased to hear that today they still tell you about ActionScript at college, it's a bit hard
to give you advice here since I don't know what they've covered yet.
Generally speaking, you could realize this with a simple game loop, that runs periodically and in it's most simple
form:
checks user input (in your case most likely pressing left/right to move the frog)
update game state (move the cars & the frog ; check for collision)
draw everything to screen
For creating the periodical loop, Flash/ActionScript offers a powerful event called ENTER_FRAME. Once started, it
will fire with the framerate of the movie. So if you set your movie to 60fps, it will execute it's callback function
roughly every 17ms.
I assume your instances of Frog and Car extend Flash's Sprite or MovieClip class - so collision detection is also pretty
easy since you can use the inherited hitTestObject() method.
To make things a bit easier though I'd recommend that you don't put the reference to the frog instance inside the EntityArray.
Better use a global reference. (Also, you don't need a for-loop because there's just one frog)
As another sidenote, it's quite common that classnames start with a capital letter.
private var newfrog:frog; // defines a class variable we can access anywhere inside our class
//Later on instantiate new cars and the frog:
for (var c:int=0; c<8; c++){
var newcar = new car();
newcar.x = 55*c;
newcar.y = 100;
EntityArray.push(newcar);
stage.addChild(newcar);
}
newfrog = new frog();
newfrog.x = 210;
newfrog.y = 498;
stage.addChild(newfrog);
addEventListener(Event.ENTER_FRAME, loop); // register an ENTER_FRAME listener for the main game loop
private function loop(e:Event):void
{
var tempCar:car;
for(var a:int=0;a<EntityArray.length;a++)
{
tempCar=EntityArray[a]; // get a car from the EntityArray
tempCar.y++; // move it down on screen
if(tempCar.y>600) // if it's vertical position is greater than 600...
{
tempCar.y=0; // ...move it back to the top
}
if(newfrog.hitTestObject(tempCar)) // evaluates to true, if a car and the frog's bounding boxes overlap
{
trace("there's a collision!"); // do something
}
}
}

AS3: how do i stop two of the same function from playing at once?

i am using AS3 to create a function that will automatically play a movieclip all the way through and then remove it. my project is going to have a lot of animated cutscenes, so id like to be able to call this function, use the cutscene id like as a parameter, and then move on to the next. the problem is, im trying to use the function multiple times in a row to play clips sequentially, but they're all playing at the same time. is there a fix, or a better way to do this altogether?
playClip(new a_walk); //find a way to make these stop playing at the same time
playClip(new a_door);
//a_walk and a_door are the AS linkage class names for the movieclips im referring to
function playClip (clip:MovieClip):void {
addChildAt(clip, 0);
clip.mask = myMask;
clip.x=412.4;
clip.y=244.5;
clip.addEventListener(Event.ENTER_FRAME, checkframes);
function checkframes(event:Event) {
if (clip.currentFrame == clip.totalFrames) {
//trace("wow! youre an idiot!");
if (clip.parent) {
clip.parent.removeChild(clip);
trace (100);
return;
}
}
}
}
Sounds like you want a mechanism to play a queue of MovieClips? If so, here is a way you can accomplish this:
//create an array with the clips you want to play (in order), in my example here, the items can be a MovieClip derived Class, or a MovieClip instance
var playQueue:Array = [a_walk, a_door];
//create a var to store the currently playing clip
var currentClip:MovieClip;
playNext(); //call this when you want the queue of clips to start playing
function playNext():void {
//if there was an item previously playing (currentClip has a value), stop it and remove it/dispose of it
if(currentClip){
currentClip.stop(); //stop it from playing
currentClip.addFrameScript(currentClip.totalFrames-1, null); //remove the frame script that was added
currentClip.parent.removeChild(currentClip); //remove it from the display
currentClip = null;
}
//check if there's anything left to play
if(playQueue.length < 1) return;
var nextItem:* = playQueue.shift(); //shift retrieves and removes the first item in the array;
if(nextItem is Class){
//if it's a class, instantiate it
currentClip = new nextItem();
}else{
currentClip = MovieClip(nextItem);
}
//initialize the movie clip
addChildAt(currentClip, 0);
currentClip.gotoAndPlay(1);
//this is just what you were doing before:
currentClip.mask = myMask;
currentClip.x=412.4;
currentClip.y=244.5;
//add a command on the last frame of the movie clip to play the next item in the queue
currentClip.addFrameScript(currentClip.totalFrames-1, playNext);
//addFrameScript is 0 based, so 0 would refer to the first frame. This is why we subtract 1 to get the last frame
}
I should note, that addFrameScript is an undocumented function. It serves as a nice shortcut so you don't have to have an ENTER_FRAME listener checking currentFrame vs. totalFrames. Being undocumented however, one can not count on it's continued existence in future versions of the Flash/AIR runtimes (though it's been around for a long long time)
note
This answer is a work in progress. I'm waiting on a response from the OP.
// playClip(new a_door); don't call this yet, or they will just both play.
var clipData:CustomClass = new CustomClass(); // add an instance of a custom class to hold the value of the movie
//clip being played (so that you can use this value later in the event handler.)
// it will also hold a value of the next clip
clipData._currentClip = a_walk;
clipData._nextClip = a_door;
playClip(new a_walk);
function playClip (clip:MovieClip):void {
addChildAt(clip, 0);
clip.mask = myMask;
clip.x=412.4;
clip.y=244.5;
clip.addEventListener(Event.ENTER_FRAME, checkframes);
}
function checkframes(event:Event) {
if (clipData._currentClip.currentFrame == clipData._currentClip.totalFrames) {
//trace("wow! youre an idiot!");
if (clipData._currentClip.parent) {
playClip(clipData._nextClip);
clipData._currentClip.parent.removeChild(clipData._currentClip);
clipData._currentClip = clipData._nextClip; // moves the clips down
//clipData._nextClip = here we have
//a problem. Do these clips play in a set
//order, first to last? Or do the play out of
//order jumping back and forth? If so, how
//are you planning on controlling which clip
//plays next?
trace (100);
return;
}
}
}
I haven't checked this in Flash yet to see if it works, but I noticed that you are defining a function inside another function, which I don't think is good practice, so this might clean things up for you. Give it a try and let us know.
I'll try to fix my code above when I get a chance. In the meantime, you answered my question about playing the clips in order, so a simple solution would be to put all the clips in an array and then play them by playClip(clipArray[i]) and then when the clip ends and gets removed, do i++ and call the same function playClip(clipArray[i]) which will play the next clip in the array.

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.

globaltoLocal in addchild

I have an enemy that adds an attack movie clip. More specifically, this attack movie (We'll call it masterAttack) clip is a blank movie clip that acts like a super class, that will hold other attacks like a weak and strong attack. So when my enemy attacks using a timer, it adds the masterAttack on a global to local point.
Below is the Enemy timer attacking a tile the player is on:
if (Main.tileset[k].tileMiddle.hitTestObject(Main.player.visionPoint))
{
this.addChild(masterAttack);
var pt:Point = this.enemymagic.globalToLocal(new Point(Main.tileset[k].x, Main.tileset[k].y));
masterAttack.masterEnemyAttackTimer.start();
this.masterAttack.x = (pt.x);
this.masterAttack.y = (pt.y);
}
And Below is the masterAttack timer:
function mastertimer(event:TimerEvent) {
addChild(sludgeball); //This is one of the many attacks pickable by the masterAttack
sludgeball.enemyattackTimer.start();
if (this.sludgeball.currentLabel == "End") {
this.sludgeball.gotoAndPlay(1);
masterEnemyAttackTimer.stop();
if (masterEnemyAttackTimer.running == false)
{
attackStop = true;
this.parent.removeChild(this);
removeChild(sludgeball);
}
}
My problem is, on the first run, the masterAttack will attack the player wherever it is, then remove itself, which is good. Then the next time it runs, the masterAttack is not hitting the player. It's as if the globaltoLocal isn't working after the first run.
this.addChild(masterAttack);
var pt:Point = this.enemymagic.globalToLocal(new Point(Main.tileset[k].x, Main.tileset[k].y));
You add the masterAttack to this, but you got pt using enemymagic's globalToLocal
So change the line like this
var pt:Point = this.globalToLocal(new Point(Main.tileset[k].x, Main.tileset[k].y));

AS3 how do I control a movieclip in a peer to peer instance swf?

I've made a app using netconnection and netgroup in Flash CS6. I'm trying to build a simple 2-player multiplayer game. When 2 two players are connected I would like to hide a movieclip in one of the instances of the swf but not the other. How is that done?
It's a turn-based game so when player 1 takes his turn player 2 must not be able to click a button (so I want to hide it) and vice-versa.
I think it's working now. In the move function I added ok_mc.visible=false which hides the mc in the "local" instance and the put ok_mc.visible=true in the netstatus event. Like this
function drop(e:MouseEvent):void {
this.stage.removeEventListener(MouseEvent.MOUSE_MOVE, moveMe);
// Save the current movieclip position
var obj:Object = {};
obj.x = mc.x ;
obj.y = mc.y ;
obj.activePlayer=players[aktiv-1]
ok_mc.visible=false;
// Set the peerID to a group address suitable for use with the sendToNearest() method.
obj.sender = group.convertPeerIDToGroupAddress(nc.nearID);
obj.id = new Date().time;
// Sends a message to all members of a group.
group.post(obj);
}
function netStatus(event:NetStatusEvent):void{
switch(event.info.code){
case "NetGroup.Posting.Notify":
mc.x = event.info.message.x;
mc.y = event.info.message.y;
ok_mc.visible=true;
break;
}
}
It seems to work. Now I just have to figure out to show it at init in the first instance. Is there a way to count groupmembers and/or loop through them?