Actionscript - Make movieclip move towards another movieclip - actionscript-3

Hi guys I'm trying to make a FPS game, I'd like some help to get a 'baddie' movieclip to randomly spawn off stage and move towards the 'Player' movieclip, I'd also like it to allow several instances of that movieclip to be on the stage at the same time and to increase the amount of them over time i.e 1 extra 'Baddie' per 30 seconds.
I can also post my current code if needed?
Thanks in advanced.
Code
I need 10 rep to post more than two links so I've put the links into one.
I put my code on to PasteBin to minimise the post.
Links to my code

For movement, add an ENTER_FRAME Event to baddie that moves right if the enemy is on the left, left if right, down if up, up if down, etc:
baddie.addEventListener(Event.ENTER_FRAME, moveTowardsPlayer);
function moveTowardsPlayer(e:Event):void
{
var speed = 5;
if(e.currentTarget.x > char.x)
{
e.currentTarget.x -= speed;
}else
{
if(e.currentTarget.x < char.x)
{
e.currentTarget.x += speed;
}else
{
//...so on...
}
}
}
Also, you can make a timer with a delay of how much milliseconds you want to spawn (30,000 for 30 seconds) an enemy, and if you want multiple enemies, you can add the Event to all of them through an Array loop:
for(var i = 0; i < enemyArray.length; i++)
{
var baddie:Baddie = new Baddie; addChild(baddie);
enemyArray.push(baddie);
//...so on...
}
Also, Math.random() could be used for a random location of the enemy, like enemy.x = Math.random() * widthMax and enemy.y = Math.random() * heightMax

Related

How to define the position of a movieclip in relation to that of another of movieclip

I am trying to make a movieclip follow a custom mouse pointer (which is a movieclip) but always stay at a defined postion (in terms of coordinates), a distance away from the mouse pointer on easing to where the mouse pointer is. Below is the code:
import flash.display.MovieClip;
import flash.events.Event;
Mouse.hide();
var mouseCounter:int = 0;
var mouseDelay:int = 5;// how many frames the mouse must stay still before the follow code is run.
var speed:Number = 5;
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
stage.addEventListener(Event.ENTER_FRAME,follow);
// set counter back to zero whenever the mouse is moved.
function mouseMove(e:MouseEvent):void
{
wand.x = stage.mouseX;
wand.y = stage.mouseY;
e.updateAfterEvent();
mouseCounter = 0;
}
function follow(e:Event):void
{
// increment the counter each frame
mouseCounter++;
// now run the follow block if the mouse has been still for enough frames.
if (mouseCounter >= mouseDelay)
{
orb_mc.x -= (orb_mc.x - mouseX) / speed;
orb_mc.y -= (orb_mc.y - mouseY) / speed;
orb_mc.x = mouseX + 46.5;
orb_mc.y = mouseY +50.95;
}
}
The last two lines of codes (26 & 27), is what I used to define the orb_mc's position in relation to the custom mouse pointer which is "wand" however it seems to have resulted in the ease movement of the orb been hampered, so dont know if the positioning code I used is wrong
function follow(e:Event):void
{
// increment the counter each frame
mouseCounter++;
// now run the follow block if the mouse has been still for enough frames.
if (mouseCounter >= mouseDelay)
{
// Do this:
orb_mc.x -= (orb_mc.x - mouseX + 46.5) / speed;
orb_mc.y -= (orb_mc.y - mouseY + 50.95) / speed;
// OR this:
//orb_mc.x = orb_mc.x - (orb_mc.x - mouseX + 46.5) / speed;
//orb_mc.y = orb_mc.y - (orb_mc.y - mouseY + 50.95) / speed;
// but not both.
}
}
You see, once you use one of the increment assignment operators (-=,+=,/=,*=), immediately following that by a regular assignment operator will obviously override any value it had before. You understand that actionscript gets "read" by the computer (this is probably the wrong verbiage but you get my drift) and it reads each block (an area inside a curly brace set { }) from top to bottom. So the very first time that your follow method is called, it is doing 4 things, in order:
increment the counter
evaluate if mouseCounter >= mouseDelay
increments orb_mc x/y coords
assigns orb_mc x/y coords to final destination
It is doing this on the very first time the follow block is read. This is why both acceptable bits of code in my answer do 2 things:
they increment the x/y coords (don't set them to a final value)
they change based on a variable factor (speed)
Glad it's working!

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.

Sounds still playing in another frame

Hey I am still getting some unwanted sound effects still playing in another frame, for example when I click my left mouse button which is also my jump button it will play the jump sound as well as playing the collect coins sound wierdly even though i remove each child from the stage when going to the game over screen.
Now im a bit unfamiliar with the sound channel so if its needed to be used please be kind and explain :)
In Frame 1:
var myMusic1:Sound = new Game_Over_Noise();
var myMusic2:Sound = new Jump_Noise();
var myMusic3:Sound = new Coin_Noise();
var myMusic4:Sound = new Power_Up_Noise();
var myMusic5:Sound = new Theme();
var channel:SoundChannel = myMusic5.play();
In Frame 8, Game Screen:
function doJump(evt:MouseEvent):void
{
if(!isJumping) //If the player is jumping.
{
jumpPower = 30; //Jump power is equal to 30.
isJumping = true; //isJumping variable is also equal to true.
var channel:SoundChannel = myMusic2.play(); //Play sound effect.
}
}
function update(evt:Event):void
{
if(isJumping) //If the player is jumping.
{
MainChar.y -= jumpPower; //Subtract the value of jumpPower from the player's y co-ordinate.
jumpPower -= 2; //Decrease the value of jumppower by 2.
}
if(MainChar.y + gravity < ground) //If the value of the player's Y co-ordinate and gravity is less than ground.
MainChar.y += gravity; //Then add the value of gravity to the player's Y co-ordinates.
else //else
{
MainChar.y = ground; //The players Y co-ordinate is equal to ground.
isJumping = false; //Make isJumping equal to false.
}
}
in Frame 5, Game Over Screen:
SoundMixer.stopAll();
Now this stops the theme music and not the sound effects, now i actually dont mind the theme tune playing all the time but i would like ALL sound effects (game sounds) to only play in the game.
I know my coding isnt the best and efficient but its easily readible to me, I appreciate the help! :D
Looks to me like you need to remove your event listeners (they're active even when something is off-stage).

How to check if objects position is greater than an array of objects AS3

Hey everyone so I'm trying to figure out how to check if one movie Clips x position which is called ball is greater than an array of objects x position which is called car. So I have an array setup with the car the car's main timeline consist of 4 frames that holds the same movie Clip just different sizes on each frame to make the game harder.
So what I want to do is check whenever the ball has jumped over the current car then add plus one to the score. But I am having trouble trying to figure this out. Here is what I have so far:
In my Enter Frame Game Loop I have the Function checkAddPoints:
private function gameLoop(e:Event):void
{
checkBunnyHitObstacles();
checkAddPoints();
}
Then The function:
private function checkAddPoints():void
{
for (var i:int = 0; i < aCarArray.length; i++)
{
var currentCar:car = aCarArray[i];
if (ball.x > currentCar.x)
{
nScore ++;
updateCurrentScore();
}
}
}
So I am getting the current car in the loop and trying to check if the ball has jumped over it. I thought the most logical thing to do was to check if the ball x position was greater than the car x position then it would work. But it just adds a endless amount of numbers and not just one like I want.
Does anyone know what i need to do?
UPDATE: This seems to work haven't had any errors yet
if (currentcar.x - 15 < ball.x && currentCar.x + 15 > ball.x)
{
trace("AddPoint Success");
nScore++;
updateCurrentScore();
}
Storing flag aboud award status in the car should help in your task. If you add flag to the car, let's say car.isAwarded, by default isAwarded is false, you will be able award only once for every car:
private function checkAddPoints():void {
var i:uint, len:uint = aCarArray.length, currentCar:car;
for (i; i < len; ++i) {
currentCar = aCarArray[i];
//Award only once
if (!currentCar.isAwarded && ball.x > currentCar.x) {
nScore++;
currentCar.isAwarded = true;
updateCurrentScore();
}
}
}

Enemy move randomly

To make things quick, I have an arrangement of tiles that a player and an enemy are on.
public static var floor1:Array = new Array(7);
floor1[0] = [0,1,1,1,1,1,0];
floor1[1] = [1,1,1,1,1,1,1];
floor1[2] = [1,1,1,0,1,1,1];
floor1[3] = [1,1,0,0,0,1,1];
floor1[4] = [1,1,1,0,1,1,1];
floor1[5] = [1,1,1,1,1,1,1];
floor1[6] = [0,1,1,1,1,1,0];
public function Main()
{
var tilew:int = 60;
var tileh:int = 60;
for (var i:int=0; i<floor1.length; i++)
{
for (var u:int=0; u<floor1[i].length; u++)
{
var cell:MovieClip = new Tile();
cell.gotoAndStop(floor1[i][u]);
cell.x = ((u-i)*tileh);
cell.y = ((u+i)*tilew/2);
addChild(cell);
cell.addEventListener(MouseEvent.ROLL_OVER, mouseover);
cell.addEventListener(MouseEvent.ROLL_OUT, mouseout);
cell.addEventListener(MouseEvent.CLICK, mouseclick);
cell.addEventListener(Event.ENTER_FRAME, beginfloor1);
}
}
var player:Player = new Player();
addChild(player);
player.mouseEnabled = false;
player.x = 5 * (tileh);
player.y = 5 * (tilew/2);
var enemy:Enemy = new Enemy();
addChild(enemy);
enemy.mouseEnabled = false;
enemy.x = 9 * (tileh);
enemy.y = 9 * (tileh/2);
My goal is to have the enemy move randomly on tiles in his range. What I did was create a square graphic called enemyVisionArea that checks which tile is hitting the enemy, which is basically surrounding tiles.
I have a timer function that tells the enemy to move every 5 seconds if the player isn't near him and if he's next to an available tile.
function timerenemy (event:TimerEvent){
if (enemy.enemyVisionArea.hitTestObject(enemyMover) && !player.visionPoint.hitTestObject(enemyMover.tileMiddle))
{
enemy.x = (enemyMover.x)+55;
enemy.y = (enemyMover.y)+20;
trace("moved");
}
}
enemyMover is a variable that I made equal to the tile objects.
function beginfloor1(event:Event)
{
enemyMover = event.currentTarget as Tile;
}
It just stays where it is. I'm just want to have the enemy move on its own on any tile that its enemyVisionArea is hitTesting a nearby tile. The beginfloor1 function doesn't seem to be working. Is there any way I can declare enemyMover = event.currentTarget as Tile and have the enemy move on a random tile that its enemyVisionArea is hitTesting?
If this is confusing, I can post the full code.
You are assigning 49 enterframe listeners which are called in sequence, and they ALL change one single variable to the cell they are attached to. Of course, the last tile is what's always assigned.
I expect that you want an enemy to check if there's a tile available for it to move to. You are essentially checking for one tile which is enemyMover - how do you determine what's that tile? You have to check all available tiles that are around the enemy, make a list of them and select one out of that list that's not the current tile, then move the enemy there.
So, first you need a complete tileset to be addressable from somewhere. The best way will be to declare a class-wide var tileset:Array and fill it where you make new tiles. Drop the Event.ENTER_FRAME listener from the code there, as it's useless. Then, in your timerevent that's for the enemy you do check all of the tileset if they are within your enemy's vision area (you use hitTestObject, I'd use clear distance grid-wise or coordinate-wise - it's a whole lot faster), if so, you add them to the TEMPORARY array you create within that function. Of course, if your enemy is at the currently processed cell, you ignore it - you have to move your enemy, not make him stand in place. Then, select (somehow, it's up to you) what cell your enemy should move to, and execute a move. Yes, if you want your enemy to move randomly, select a cell at random by its index via Math.floor(Math.random()*selectedcells.length).