Flash as3 Var movieClip duplicates - actionscript-3

Having multiple movieclips being able to move around on a grid, once dragging it, it seems to duplicate and the 'original' remains in place.
What causes it to duplicate in my code?
import flash.display.MovieClip
[SWF(width = 1300, height = 1000)]
var tileSize: int = 100;
var cols: int = stage.stageWidth / tileSize;
var rows: int = stage.stageHeight / tileSize;
var grid: Sprite = Sprite(addChild(new Sprite()));
grid.graphics.lineStyle(0, 0x000000, 0);
var i: int = 0;
for (i = 1; i < cols; i++) {
var posX: Number = i * tileSize
grid.graphics.moveTo(posX, 0);
grid.graphics.lineTo(posX, stage.stageHeight);
}
for (i = 1; i < rows; i++) {
var posY: Number = i * tileSize
grid.graphics.moveTo(0, posY);
grid.graphics.lineTo(stage.stageWidth, posY);
var ball: the_ball = new the_ball();
addChild(ball);
ball.x = tileSize * 5;
ball.y = tileSize * 5;
ball.buttonMode = true;
ball.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
function onDown(evt: MouseEvent): void {
addEventListener(Event.ENTER_FRAME, onRunSnapping);
}
function onRunSnapping(evt: Event): void {
ball.x = Math.round(mouseX / tileSize) * tileSize;
ball.y = Math.round(mouseY / tileSize) * tileSize;
}
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
function onUp(evt: MouseEvent): void {
removeEventListener(Event.ENTER_FRAME, onRunSnapping);
}
}

It's not duplicating, there are just many movieclips stacked on top of each other.
You add a new ball for each row you add on the exact same position.
I dont know how you want the balls to be distributed, but try to replace
ball.y = tileSize * 5; with ball.y = posY; to see what im talking about.

Related

AS3 animate dynamically created movie clips with ENTER_FRAME

I have some code which loads a movie clip from the library, reproduces it and spreads it around the stage in different sizes, positions and rotations. What I can't figure out is how to then animate each one with an ENTER_FRAME event listener - So maybe I can also animate the scale, position and rotations? Any help greatly appreciated. Thanks.
for (var i = 0; i < 20; i++ )
{
//Generate Item from library
var MovieClip_mc:mcMovieClip = new mcMovieClip();
addChild(MovieClip_mc);
//Size
var RandomSize = (Math.random() * 0.5) + 0.5;
MovieClip_mc.scaleX = RandomSize;
MovieClip_mc.scaleY = RandomSize;
//Rotation
var RandomRotation:Number = Math.floor(Math.random()*360);
MovieClip_mc.rotation = RandomRotation;
//Position
MovieClip_mc.x = Math.floor(Math.random() * CanvasWidth);
MovieClip_mc.y = Math.floor(Math.random() * CanvasHeight);
}
For performance benefits, it is better to do it using one ENTER_FRAME handler. The handler can be located in your main class and update each mcMovieClip's properties by calling certain methods declared in the mcMovieClip class. Below is a simple example.
Main class
var mcs:Array = [];
for(var i:int = 0; i < 1; i++)
{
mcs.push(new mcMovieClip());
addChild(mcs[i]);
}
addEventListener(Event.ENTER_FRAME, updateTime);
function updateTime(e:Event):void
{
for(var j:int = 0; j < mcs.length; j++)
{
mcs[j].updatePosition(Math.random() * stage.stageWidth,
Math.random() * stage.stageHeight);
mcs[j].updateRotation(Math.random() * 360);
mcs[j].updateSize(Math.random());
}
}
mcMovieClip class
function updateSize(size:Number):void
{
this.scaleX = this.scaleY = size;
}
function updateRotation(rot:Number):void
{
this.rotation = rot;
}
function updatePosition(newX:Number, newY:Number):void
{
this.x = newX;
this.y = newY;
}
You don't actually need to do that from the outside. You can animate it with its own script in the first frame, so each instance will be animated:
addEventListener(Event.ENTER_FRAME, onFrame);
function onFrame(e:Event):void
{
// Math.random() - 0.5 will produce a random value from -0.5 to 0.5
x += Math.random() - 0.5;
y += Math.random() - 0.5;
scaleX += (Math.random() - 0.5) / 10;
scaleY = scaleX;
rotation += (Math.random() - 0.5) * 5;
}

Adding another Movie Clip into another Frame

I am attempting to add a new movie clip into the next frame of my shooter game.
I am using Actionscript 3.0
To give a basis of what I need help with for my assessment. When the score =50, switch to the next frame. And this is where I would like to add a new type of movie clip for the user to shoot!
Here is the code I have so far.
FRAME 1
//Tate's open screen
stop(); //makes the screen wait for events
paraBtn.addEventListener(MouseEvent.CLICK, playClicked); //this line is making your button an mouse click event
function playClicked(evt: MouseEvent): void { // now we are calling the event from this function and telling it to go to the next frame we labelled play
gotoAndStop("frame2");
// All rights of this music goes towards the makers of the game "Risk of Rain" which was made by Hapoo Games
}
FRAME 2 (Where the game actually starts)
stop();
// This plays the sound when left click is used
var spitSound: Sound = new Sound();
spitSound.load(new URLRequest("gunSound.mp3"));
//This plays the gameover sound when your lives reach 0
var overSound: Sound = new Sound();
overSound.load(new URLRequest("Gameover.mp3"));
//This plays the sound when you are hit
var etSound: Sound = new Sound();
etSound.load(new URLRequest("Urgh.mp3"));
//This sets the lives and points.
stage.addEventListener(MouseEvent.MOUSE_MOVE, aimTurret);
var points: Number = 0;
var lives: Number = 3;
var target: MovieClip;
var _health: uint = 100;
initialiseCursor();
//This variable stops the multiple errors with the move objects and bullets and range to stop compiling.
var Gameover: Boolean = false;
//This aims the turrent to where you mouse is on the screen
function aimTurret(evt: Event): void {
if (Gameover == false) {
gun.rotation = getAngle(gun.x, gun.y, mouseX, mouseY);
var distance: Number = getDistance(gun.x, gun.y, mouseX, mouseY);
var adjDistance: Number = distance / 12 - 7;
}
}
function getAngle(x1: Number, y1: Number, x2: Number, y2: Number): Number {
var radians: Number = Math.atan2(y2 - y1, x2 - x1);
return rad2deg(radians);
}
function getDistance(x1: Number, y1: Number, x2: Number, y2: Number): Number {
var dx: Number = x2 - x1;
var dy: Number = y2 - y1;
return Math.sqrt(dx * dx + dy * dy);
}
function rad2deg(rad: Number): Number {
return rad * (180 / Math.PI);
}
//Starts lives and shows text next to the numbers
function initialiseCursor(): void {
Mouse.hide();
target = new Target();
target.x = mouseX;
target.y = mouseY;
target.mouseEnabled = false;
addChild(target);
stage.addEventListener(MouseEvent.MOUSE_MOVE, targetMove);
stage.addEventListener(MouseEvent.MOUSE_DOWN, targetDown);
stage.addEventListener(MouseEvent.MOUSE_UP, targetUp);
livesdisplay.text = String(lives) + " Lives Left";
pointsdisplay.text = String(points) + " Points";
}
function targetMove(evt: MouseEvent): void {
target.x = this.mouseX;
target.y = this.mouseY;
}
function targetDown(evt: MouseEvent): void {
target.gotoAndStop(2);
}
function targetUp(evt: MouseEvent): void {
target.gotoAndStop(1);
}
//Starts bullets and speed of bullets, also addding new arrays for baddies
var gunLength: uint = 90;
var bullets: Array = new Array();
var bulletSpeed: uint = 20;
var baddies: Array = new Array();
stage.addEventListener(MouseEvent.MOUSE_DOWN, fireGun);
function fireGun(evt: MouseEvent) {
if (Gameover == false) {
var bullet: Bullet = new Bullet();
bullet.rotation = gun.rotation;
bullet.x = gun.x + Math.cos(deg2rad(gun.rotation)) * gunLength;
bullet.y = gun.y + Math.sin(deg2rad(gun.rotation)) * gunLength;
addChild(bullet);
bullets.push(bullet);
spitSound.play();
}
}
function deg2rad(deg: Number): Number {
return deg * (Math.PI / 180);
}
stage.addEventListener(Event.ENTER_FRAME, moveObjects);
function moveObjects(evt: Event): void {
if (Gameover == false) {
moveBullets();
moveBaddies();
}
}
function moveBullets(): void {
for (var i: int = 0; i < bullets.length; i++) {
var dx = Math.cos(deg2rad(bullets[i].rotation)) * bulletSpeed;
var dy = Math.sin(deg2rad(bullets[i].rotation)) * bulletSpeed;
bullets[i].x += dx;
bullets[i].y += dy;
if (bullets[i].x < -bullets[i].width || bullets[i].x > stage.stageWidth + bullets[i].width || bullets[i].y < -bullets[i].width || bullets[i].y > stage.stageHeight + bullets[i].width) {
removeChild(bullets[i]);
bullets.splice(i, 1);
}
}
}
// This is the start of the timer
var timer: Timer = new Timer(1000);
timer.addEventListener(TimerEvent.TIMER, addBaddie);
timer.start();
// Adding army men on a timer and only from the top side
function addBaddie(evt: TimerEvent): void {
var baddie: Baddie = new Baddie();
var side: Number = Math.ceil(Math.random() * 1);
if (side == 1) {
baddie.x = Math.random() * stage.stageWidth;
baddie.y = -baddie.height;
}
baddie.angle = getAngle(baddie.x, baddie.y, gun.x, gun.y);
baddie.speed = 7;
addChild(baddie);
baddies.push(baddie);
}
function moveBaddies(): void {
for (var i: int = 0; i < baddies.length; i++) {
var dx = Math.cos(deg2rad(baddies[i].angle)) * baddies[i].speed;
var dy = Math.sin(deg2rad(baddies[i].angle)) * baddies[i].speed;
baddies[i].x += dx;
baddies[i].y += dy;
if (baddies[i].hitTestPoint(gun.x, gun.y, true)) {
removeChild(baddies[i]);
baddies.splice(i, 1);
loseLife();
//If baddie was removed then we don’t check for bullet hits
} else {
checkForHit(baddies[i]);
}
}
}
function checkForHit(baddie: Baddie): void {
for (var i: int = 0; i < bullets.length; i++) {
if (baddie.hitTestPoint(bullets[i].x, bullets[i].y, true)) {
removeChild(baddie);
points++;
if (points == 50) {
gotoAndStop("frame3")
}
pointsdisplay.text = String(points) + " Points";
baddies.splice(baddies.indexOf(baddie), 1);
}
}
}
// Keeping track of lost lives and when hitting 0 doing to frame four, also displaying "Lose life!"
function loseLife(): void {
etSound.play();
lives--;
if (lives == 0) {
Gameover = true;
overSound.play();
gotoAndStop("frame4")
}
livesdisplay.text = String(lives) + " Lives Left";
trace("Lose Life!");
}
FRAME 3 (This is where I need help, to add another movie clip) (I have made one for the frame named, "BaddieRed" With the Linkage being "Baddiered"
stop();
// The code from frame2 carries over and works the same in this frame
FRAME 4 (This is the screen where it's gameover)
stop();
timer.stop();
// User need to close by pressing the close button
//And restart the game manually
Is this what you're trying to achieve? Something like...
function addBaddie(evt: TimerEvent): void
{
var baddie : MovieClip;
if (points < 50) { var bad1: Baddie = new Baddie(); baddie = bad1; }
if (points >= 50) { var bad2 : Baddiered = new Baddiered(); baddie = bad2; }
var side: Number = Math.ceil(Math.random() * 1);
if (side == 1)
{
baddie.x = Math.random() * stage.stageWidth;
baddie.y -= baddie.height;
}
baddie.angle = getAngle(baddie.x, baddie.y, gun.x, gun.y);
baddie.speed = 7;
addChild(baddie);
baddies.push(baddie);
}

AS3 - Creating rectangle with mouse

I want to make a top down strategy game in as3, and I want the user to be able to mark multiple movieclips with the mouse, like in operating systems where ju press the mouse button down and then drag the mouse, and it will create a rectangle. How do you do that in as3?
stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
var sp : Sprite = new Sprite();
var p1 : Point = new Point();
var p2 : Point = new Point();
function onDown(e:MouseEvent) : void {
p1.x = mouseX;
p1.y = mouseY;
addEventListener(Event.ENTER_FRAME, onMove);
}
function onMove(e:Event) : void {
p2.x = mouseX;
p2.y = mouseY;
draw();
}
function onUp(e:MouseEvent) : void {
removeEventListener(Event.ENTER_FRAME, onMove);
stage.removeChild(sp);
}
function draw() : void {
sp.graphics.clear();
p2.x = p2.x - p1.x;
p2.y = p2.y - p1.y;
sp.graphics.lineStyle(1, 0x0000FF);
sp.graphics.beginFill(0xC2C2C2, 0.2);
sp.graphics.drawRect(p1.x, p1.y, p2.x, p2.y);
stage.addChild(sp);
}
Hope this helps...
You can do like that (copy and paste the following code into your Actions panel):
var s:Shape = new Shape();
s.graphics.beginFill(0xC2C2C2, 0.2);
s.graphics.lineStyle(0, 0x666666);
s.graphics.drawRect(0, 0, 100, 100);
function mouseDownHandler(e:MouseEvent):void {
addChild(s);
s.x = e.stageX;
s.y = e.stageY;
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
function enterFrameHandler(e:Event):void {
s.scaleX = (mouseX - s.x) / 100;
s.scaleY = (mouseY - s.y) / 100;
}
function mouseUpHandler(e:MouseEvent):void {
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
removeChild(s);
}
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
It's nice to have a simple selection box, but how about some selectable objects?
Have a look at what I've got, it's quite simple, and most of the code is for the visuals.
// Add 100 green circles.
var objects:Vector.<Sprite> = new Vector.<Sprite>();
for(var i:int = 0; i < 100; ++i){
var object:Sprite = new Sprite();
object.x = Math.random() * stage.stageWidth;
object.y = Math.random() * stage.stageHeight;
object.graphics.lineStyle(2, 0x00FF00);
object.graphics.beginFill(0x00FF00, 0.5);
object.graphics.drawCircle(0,0,15);
object.graphics.endFill();
objects.push(object);
addChild(object);
}
// Main variables we'll be using.
var startPos:Point = new Point();
var selection:Rectangle = new Rectangle();
var isSelecting:Boolean = false;
// Mouse listeners.
stage.addEventListener(MouseEvent.MOUSE_DOWN, mDown);
stage.addEventListener(MouseEvent.MOUSE_UP, mUp);
function mDown(e:MouseEvent):void {
startPos.x = stage.mouseX;
startPos.y = stage.mouseY;
isSelecting = true;
}
function mUp(e:MouseEvent):void {
isSelecting = false;
}
// Main loop; check if we're intersecting with any of the sprites; if so render them yellow.
stage.addEventListener(Event.ENTER_FRAME, loop);
function loop(e:Event):void {
graphics.clear();
if(isSelecting) {
selection = new Rectangle(startPos.x, startPos.y, stage.mouseX - startPos.x, stage.mouseY - startPos.y);
normalize(selection);
graphics.lineStyle(2, 0xFF0000);
graphics.beginFill(0xFF0000, 0.5);
graphics.drawRect(selection.x, selection.y, selection.width, selection.height);
graphics.endFill();
for (var j:int = 0; j < objects.length; ++j) {
var object:Sprite = objects[j];
if(selection.intersects(object.getBounds(this))){
object.graphics.clear();
object.graphics.lineStyle(2, 0xFFCC00);
object.graphics.beginFill(0xFFCC00, 0.5);
object.graphics.drawCircle(0,0,15);
object.graphics.endFill();
}
}
}
}
// Intersection requires positive values.
function normalize(rect:Rectangle):void {
if (rect.width < 0) {
rect.width = -rect.width;
rect.x -= rect.width;
}
if (rect.height < 0) {
rect.height = -rect.height;
rect.y -= rect.height;
}
}

Tracking an animated ball

In this project I am trying to track a ball. If the balls color is grey I want it to be surrounded with a square. My Problem is that there is only a ball being tracked. I would like all the grey balls to tracked.
Would really appreciate if someone can help me out.
Here is the code(Ball and Box are called from an external class):
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
[SWF(frameRate='31')]
public class Main extends Sprite
{
private var balls:Array;
private var directions:Array = [new Point(-1,-1),new Point(0,-1),new Point(1,-1),
new Point(-1,0),new Point(1,0),
new Point(-1,1),new Point(0,1),new Point(1,1)
];
private var ballNum: Number = 10;
private var ball:Ball;
private var ball2:Ball;
private var box:Box;
private var ay:Number = 5;
private var gravity:Number = 6;
private var bounce:Number = -0.9;
public function Main()
{
init();
}
private function init():void
{
balls = new Array();
for(var i:Number = 0; i < ballNum; i++)
{
ball = new Ball(Math.random() * 30);
ball.x = Math.random() * stage.stageWidth;
ball.y = Math.random() * stage.stageHeight;
ball.direction = directions[Math.floor(Math.random()*directions.length)];
addChild(ball);
balls.push(ball);
}
box = new Box();
addChild(box);
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void
{
for(var i:int = 0; i < balls.length; i++)
{
balls[i].x += balls[i].direction.x;
balls[i].y += balls[i].direction.y;
}
if(ball.color == 0xcccccc)
{
box.x = ball.x - box.width / 2;
box.y = ball.y - box.height / 2;
}
}
}
}
You have only one box and one box can have only one x and y after onEnterFrame function ends.
try something like this:
for (var i: int = 0; i < balls.length; i++) {
balls[i].x += balls[i].direction.x;
balls[i].y += balls[i].direction.y;
if (balls[i].color == 0xcccccc) {
box[i].x = balls[i].x - box[i].width / 2;
box[i].y = balls[i].y - box[i].height / 2;
//OR balls[i].box.visible=true;
}
}
You need to put your check for color in the for loop to check all your balls:
for (var i: int = 0; i < balls.length; i++) {
balls[i].x += balls[i].direction.x;
balls[i].y += balls[i].direction.y;
if (balls[i].color == 0xcccccc) {
box.x = balls[i].x - box.width / 2;
box.y = balls[i].y - box.height / 2;
}
}

Collision-based springing

I have placed one large ball, "centerBall", in the center of the stage. Then I added in a
bunch of smaller ones, giving them random sizes and velocities. These will move with basic motion code and bounce off the walls. On each frame, did a distance-based collision check between each moving ball and the center ball. If I got a collision, I've calculated an offset spring target based on the angle between the two balls and the minimum distance.
There is still one problem: some of the smaller balls bypass "centerBall" boundaries and then bounce off. You can see that in the attached image. Why is happening this?
Here is the code:
import flash.display.Sprite;
import flash.events.Event;
public class Bubbles extends Sprite
{
private var balls:Array;
private var numBalls:Number = 10;
private var centerBall:Ball;
private var bounce:Number = -1;
private var spring:Number = 0.2;
public function Bubbles()
{
init();
}
private function init():void
{
balls = new Array();
centerBall = new Ball(100, 0xcccccc);
addChild(centerBall);
centerBall.x = stage.stageWidth / 2;
centerBall.y = stage.stageHeight / 2;
for(var i:uint = 0; i < numBalls; i++)
{
var ball:Ball = new Ball(Math.random() * 40 + 5, Math.random() * 0xffffff);
ball.x = Math.random() * stage.stageWidth;
ball.y = Math.random() * stage.stageHeight;
ball.vx = Math.random() * 6 - 3;
ball.vy = Math.random() * 6 - 3;
addChild(ball);
balls.push(ball);
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void
{
for(var i:uint = 0; i < numBalls; i++)
{
var ball:Ball = balls[i];
move(ball);
var dx:Number = ball.x - centerBall.x;
var dy:Number = ball.y - centerBall.y;
var dist:Number = Math.sqrt(dx * dx + dy * dy);
var minDist:Number = ball.radius + centerBall.radius;
if(dist < minDist)
{
var angle:Number = Math.atan2(dy, dx);
var targetX:Number = centerBall.x + Math.cos(angle) * minDist;
var targetY:Number = centerBall.y + Math.sin(angle) * minDist;
ball.vx += (targetX - ball.x) * spring;
ball.vy += (targetY - ball.y) * spring;
}
}
}
private function move(ball:Ball):void
{
ball.x += ball.vx;
ball.y += ball.vy;
if(ball.x + ball.radius > stage.stageWidth)
{
ball.x = stage.stageWidth - ball.radius;
ball.vx *= bounce;
}
else if(ball.x - ball.radius < 0)
{
ball.x = ball.radius;
ball.vx *= bounce;
}
if(ball.y + ball.radius > stage.stageHeight)
{
ball.y = stage.stageHeight - ball.radius;
ball.vy *= bounce;
}
else if(ball.y - ball.radius < 0)
{
ball.y = ball.radius;
ball.vy *= bounce;
}
}
}
Click here to see the pic
The problem you have is that you are doing collision detection based on them frames and not the positions.
You need to check where it is now and where it was last frame so you can keep track of its movements. This is why it goes through your center ball because you check in the current frame for a collision.
Here is a link to a time based collision detection of circles.
Timed based collision
Hope this helps ; )