collision between a particle array and a box - actionscript-3

Im working on a school project and I need to get collision between an array of particles and a box, here is my current code:
for(var i : int = 0; i < particles.length; i++)
{
particles[i].update();
if(Particle.hitTestPoint(Square))
{
particle = particles.shift();
particle.destroy();
}
}
I get an error telling me that im trying to call an undefined method (hittestpoint) through a reference with static type class.
Any help would be greatly appreciated, thank!
Here is the code for the Particle.
package
{
import flash.display.*;
public class Particle
{
public var clip : DisplayObject;
public var xVel : Number = 0;
public var yVel : Number = 0;
public var drag : Number = 1;
public var gravity : Number = 0.0;
public var shrink : Number = 1;
public var fade : Number = 0;
public function Particle(symbolclass : Class, target : DisplayObjectContainer, xpos : Number, ypos : Number)
{
clip = new symbolclass();
target.addChild(clip);
clip.x= xpos;
clip.y= ypos;
}
public function update() : void
{
clip.x += xVel;
clip.y += yVel;
xVel *= drag;
yVel *= drag;
yVel+=gravity;
clip.scaleX *= shrink;
clip.scaleY *= shrink;
clip.alpha -= fade;
}
public function destroy() :void
{
clip.parent.removeChild(clip);
}
}
}
I used this tutorial for the particles, and my goal is to add collision to them

The Particle class must extend MovieClip to have the hitTestPoint method. Try changing the class to:
import flash.display.MovieClip;
public class Particle extends MovieClip
{
//code here
and import specific classes in your code (see MovieClip class as that's the one you are using and it's methods) for better results as good practice.

I'm not sure what particle refers to in that code since it's not defined in what you posted, but particles[i] is the particle you want to test.
Your Particle class doesn't have a hitTestPoint function- but it contains a DisplayObject that does. So with those two things in mind, you can call hit tests using particles[i].clip.hitTestPoint.
Next problem: you're trying to pass the class Square to the hitTest rather than an instance. And still, hitTestPoint takes a single point as its argument, not an object like what a square would represent. So you will probably want to use hitTestObject instead.

Edit: Updated my answer now that Particle code was posted.
Your Particle class doesn't define hitTestPoint. In addition to that, you are calling a static method which I don't think you want here... you want an instance method.
Make sure you define hitTestPoint in your Particle class. Then, instead of Particle.hitTestPoint, try particle.hitTestPoint (note upper case, which refers to the class is changed to lower-case which refers to the instance.
Try this:
for(var i : int = 0; i < particles.length; i++)
{
var particle:Particle = particles[i];
particles.update();
if(particle.hitTestPoint(Square))
{
particle = particles.shift();
particle.destroy();
}
}

Related

Why am I unable to access the methods of an object via is ObjectContainer

first of all, i'm not a native english speaker but, still, i'll try my best to be understandable and as clear as possible.
So, in my programming class, I need to make a Tile based game (like zelda, for exemple) with animate cc (flash). On a map, I want to make a dance floor with tiles that changes on the rhythm of a music. these tiles are movieclip with two frame, one white and one red.
This is how the tiles are generated:
private function createGrid(): void {
grid = new MovieClip();
addChild(grid);
for (var r: int = 0; r < nbRow; r++) {
for (var c: int = 0; c < nbCol; c++) {
var t: Tiles = new Tiles();
t.x = t.width * c;
t.y = t.height * r;
grid.addChild(t);
}
}
grid.x = 15; //center the grid on x
grid.y = 35; //center the grid on y
}
This is the Tiles Class :
package {
import flash.display.MovieClip;
import flash.events.*;
public class Tiles extends MovieClip {
private var rand:int;
public function Tiles() {
// constructor code
getTiles();
}
public function getTiles():void {
random();
setColor();
}
private function random() : void{
rand = Math.floor(Math.random()*100)+1;
}
private function setColor() : void{
if(rand<=30){
gotoAndStop(8); //red frame
}else{
gotoAndStop(7); //white frame
}
}
}
}
createGrid() place the tiles as soon as the map is placed on the stage and stock every tiles in the MovieClip grid. Now, I want the tiles to change randomly between red and white on the beat of a streamed music (and keep the ratio of 30% red tiles and 70% white tiles)
var s: Sound = new Sound();
var sc: SoundChannel;
s.load(new URLRequest("GameSong_mixdown.mp3"));
sc = s.play(0, 1000);
I know i need the leftpeek properties of my soundchannel to achieve that but,for now, I do my test with a button that trigger this function:
private function setTiles(e: Event): void {
// loop through all child element of a movieclip
for (var i: int = 0; i < grid.numChildren; i++) {
grid.getChildAt(i).getTiles();
}
}
Right now, the problem is : I'm unable to acces my Tiles method. I did a trace on grid,getChildAt(i), and saw all instances of my tiles in the console. So, i know for sure that every instances of my tiles are stored in grid. But, I don't know why, grid.getChildAt(i).getTiles(); doesn't work (and every other method from Tiles). The error message is: Call to a possibly udefined method getTiles through a reference with static type flash.display:DisplayObject
Does someone know what i'm doing wrong ?
ps: I translated all my class name, var name, etc from french to
english to make the code clearer.
Your mistake is that getChildAt(...) method has a return type of DisplayObject which is neither dynamic (will not let you access random properties) nor it have DisplayObject.getTiles() method.
All you need is to tell the program that this object is actually of Tiles class:
private function setTiles(e:Event):void
{
// loop through all child element of a movieclip
for (var i: int = 0; i < grid.numChildren; i++)
{
// Cast display objects to Tiles class.
var aTiles:Tiles = grid.getChildAt(i) as Tiles;
// Call the method.
aTiles.getTiles();
}
}

ActionScript classes reference

I have a class Square and a class Circle.
This my class Circle:
public class Circle extends MovieClip
{
var growthRate:Number = 2;
public function Circle()
{
addEventListener(Event.ENTER_FRAME, grow);
}
function grow(e :Event):void
{
e.target.width +=growthRate;
e.target.height +=growthRate;
}
}
I need to stop growing the circle inside a function from Shape.
public function Square() {
buttonMode = true;
addEventListener(MouseEvent.MOUSE_DOWN, down);
}
protected function down ( event: MouseEvent):void
{
//here i need to stop the circle
}
I don't know how to make a relation with the Circle class in order to stop the circle growing.
Thank you in advance.
I don't know how to make a relation with the Circle class in order to stop the circle growing.
That's because you cannot with the code you have right now. There's nothing in your class that's accessible from outside (public), that stops the growth. But there's not even something private in your class that does this. The functionality simply is not there.
So first of all, create the desired functionality. and make it available to public.
Here's how your Circle class could look like:
public class Circle extends Sprite
{
private var growthRate:Number = 2;
public function Circle()
{
// nothing here
// this is just to create a circle graphic, if you have artwork in your library symbol, you do not need this
graphics.beginFill(0xffffff * Math.random());
graphics.drawCircle(0, 0, 10 + 30 * Math.random());
graphics.endFill();
}
public function startGrowing(rate:Number = 0):void
{
if(rate != 0)
{
growthRate = rate;
}
addEventListener(Event.ENTER_FRAME, grow);
}
public function stopGrowing():void
{
removeEventListener(Event.ENTER_FRAME, grow);
}
private function grow(e:Event):void
{
width += growthRate;
height += growthRate;
}
}
Pay attention to
the constructor: I create a circle graphic there with code. As the comment says, if Circle is a class associated to a library symbol, you do not need this, because you already created the artwork in the symbol.
the super class: It's Sprite. This should be your default superclass. The only real reason to use MovieClip is if you have a timeline animation. It doesn't look like you have any of that from what you posted, so I recommend Sprite.
the two new public methods: startGrowing and stopGrowing, which do exactly what their names imply. startGrowing has an optional parameter to to start growing at a different growth rate.
the lack of e.target: which is unnecessary here.
A simple demo of that code looks like this:
var circle:Circle = new Circle();
circle.x = 200;
circle.y = 200;
addChild(circle);
circle.startGrowing();
//circle.startGrowing(1); // grow slowly
//circle.startGrowing(5); // grow fast
To stop the growth, stop listening for the ENTER_FRAME Event.
So far so good, now to your actual question:
how to make a relation with the Circle class
protected function down ( event: MouseEvent):void
{
//here i need to stop the circle
}
You think that you should make this connection in your Square class, but you are wrong about that. It's very bad practice to connect two classes this way. You want the classes to be as individual as possible.
Think about it like phones. Does your phone have a direct way to a specific other phone? No. It has the ability to connect to any phone, which makes it a lot more universally useful than a phone hard wired to another phone.
You make the connection outside both classes with events. That's like your phone making a call to the network with a number it wants to call. The network then figures out how to find the other phone with that number and how to establish the connection.
As a short interlude and so that we are on the same page about it, here's the Square class that I'm using:
public class Square extends Sprite
{
public function Square()
{
// nothing here
// this is just to create a circle graphic, if you have artwork in your library symbol, you do not need this
graphics.beginFill(0xffffff * Math.random());
graphics.drawRect(0, 0, 100, 100);
graphics.endFill();
}
}
As you can see, it only has a constructor in which I programmatically draw a rectangle. Again, if you have the desired artwork in your library symbol, there's no need for this. In that case, the constructor would be empty and in turn the entire class file would be empty. In this case, you do not even need a class file. Just associate the library symbol with the name. The Square is only a graphic asset without any code attached to it.
Here's a full fledged document class using both classes:
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var circle:Circle;
public function Main()
{
circle = new Circle();
circle.x = 200;
circle.y = 200;
addChild(circle);
circle.startGrowing(1);
var square:Square = new Square();
addChild(square);
square.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseDown(e:MouseEvent):void
{
circle.stopGrowing();
}
}
}
As you can see, the event listener is added in the document class and also the function that is executed when the event occurs is in Main.
Here's a variation of that without the square. This time you have to click on the circle to stop it growing:
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var circle:Circle;
public function Main()
{
circle = new Circle();
circle.x = 200;
circle.y = 200;
addChild(circle);
circle.startGrowing(1);
circle.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
}
private function onMouseDown(e:MouseEvent):void
{
circle.stopGrowing();
}
}
}
As you can see, making the connection outside both classes with events gives you a lot of flexibility to wire things up in a different way. Just like having a phone that connects to a network instead of another phone directly.

AS 3.0 Dynamic Instance Names

Hi i made a custom class where i would like to create x instances of a movieclip. But the following doesn't work:
package {
import flash.display.MovieClip;
public class CustomClass extends MovieClip {
public function CustomClass(amount:uint) {
var Collector:Array = new Array();
//Add and position Tiles to stage.
for (var i:uint = 1; i <= amount; i++){
var newMovieClip:MovieClip = new MovieClip;
newMovieClip.y = amount * 10;
Collector.push(newMovieClip);
}
addChild(Collector);
}
}
}
I would like to position them on the timeline with
var customClass_mc:CustomClass = new CustomClass(10);
addChild(customClass_mc);
//try to trace the x position of one of the instances.
trace(customClass_mc.Collector[5].x);
I keep getting the error: Scene 1, Layer 'Layer 1', Frame 1, Line 5 1119: Access of possibly undefined property Collector through a reference with static type CustomClass.
Firstly, you need to declare Collector as public:
public var Collector:Array = new Array();
Your Collector is an array, not a display object, and so it can't be added to the display tree. Instead you would push each newMovieClip onto the display of Custom class and position them inside your for loop. Then you don't need the collector at all, because you can target the movieclips using getChildAt():
trace(customClass_mc.getChildAt(5).x);
I found another answer myself which i think is even better!
You don't need the container at all.
when you use the following
package {
import flash.display.MovieClip;
public class CustomClass extends MovieClip {
public function CustomClass(amount:uint) {
//Add and position Tiles to stage.
for (var i:uint = 1; i <= amount; i++){
var newMovieClip:MovieClip = new MovieClip;
newMovieClip.y = amount * 10;
newMovieClip.name = "clip"+i;
addChild(newMovieClip);
}
}
}
}
No i can acces the movieclips by using:
var customClass_mc:CustomClass = new CustomClass(10);
addChild(customClass_mc);
//try to trace the x position of the fifth instance.
trace(customClass_mc.getChildByName("child5").y);
The variable 'Collector' is only available inside the constructor the way you have it. Collector has to be made public to be accessible from outside the timeline. The best thing to do would be to make a public getter method to access this. So something like:
import flash.display.MovieClip;
public class CustomClass extends MovieClip {
private var Collector:Array = new Array();
public function get Collector():Array
{
return Collector;
}
public function CustomClass(amount:uint) {
//Add and position Tiles to stage.
for (var i:uint = 1; i <= amount; i++){
var newMovieClip:MovieClip = new MovieClip;
newMovieClip.y = amount * 10;
Collector.push(newMovieClip);
}
addChild(Collector);
}
}

Actionscript: Am I deleting this class instance correctly?

Okay by deleting correctly I mean am I actually getting rid of the instance or is it just not being drawn anymore? I should mention that I'm trying to delete the instance from within its own class, that is it deletes itself. It 'works' in that the square it draws no longer appears on the screen but again I'm not sure if it's really gone or just not being drawn. Anyway here's the class:
package
{
import flash.display.*;
import flash.events.*;
public class OBJECT_bullet_1 extends Sprite
{
public var X:int = 0; public var Y:int = 0;
public var Y_SPEED:int = 5;
public var DEPTH:int = 9;
public var CONTAINER:Sprite = new Sprite();
public function CREATE(CONTAINER:Sprite,X:int,Y:int):void
{
this.CONTAINER = CONTAINER;
CONTAINER.stage.addEventListener(Event.ENTER_FRAME,STEP);
this.X = X; this.Y = Y;
DRAW();
}
public function STEP(event:Event):void
{
this.graphics.clear();
Y -= Y_SPEED;
if (Y < 20) {Y = 300; CONTAINER.removeChild(this); CONTAINER.stage.removeEventListener(Event.ENTER_FRAME,STEP); CONTAINER.(delete this); CONTAINER = null; return;}
DRAW();
}
public function DRAW():void
{
this.graphics.beginFill(0xCCCC00,1);
this.graphics.drawRect(X - 2,Y - 2,4,4);
this.graphics.endFill();
CONTAINER.addChild(this);
}
}
}
The part I'm concerned about is in the STEP function when it checks to see if Y < 20. You'll notice that it does several things afterwords. Am I deleting it correctly? If so is there anything I am doing to delete it that I don't need to?
Yes to both questions. To ensure an object is deleted, all you have to do is remove all references to it. The child reference and event callback are the only ones the above code is aware of, and you have taken care to remove them both. Nullifying your own container reference is unnecessary, as is whatever you think CONTAINER.(delete this) does.
There are some other significant problems with your supplied code. I made some improvements and heavily commented all changes to explain why I made them.
// You should avoid using the default package. Using the default package
// can make it difficult later on if you start having naming conflicts.
package com.stackoverflow.example {
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.utils.getTimer;
// Class names are spelled in CamelCase by convention. Also, note
// that "Object" has a special meaning in AS3 so you should avoid
// using it to refer to anything else. I used here "Entity" instead.
public class EntityBullet1 extends Sprite {
// ALLCAPS when used are reserved for static const names.
// A good use of static consts is to store "magic numbers".
public static const DEFAULT_COLOR:uint = 0xCCCC00;
public static const DEFAULT_SPEED_X:Number = 0;
public static const DEFAULT_SPEED_Y:Number = -100;
public static const DEFAULT_SIZE:Number = 4;
// I'm calculating the time between frames for smoother movement.
public var lastTime:int;
public var color:uint = DEFAULT_COLOR;
public var size:int = DEFAULT_SIZE;
// Instead of separate x and y vars, you can use the Point class.
public var pos:Point;
public var speed:Point;
// Instead of a "create" method do all creation inside the constructor!
public function EntityBullet1(x:Number = 0, y:Number = 0) {
pos = new Point(x, y);
speed = new Point(DEFAULT_SPEED_X, DEFAULT_SPEED_Y);
// You don't need the parent container to access the ENTER_FRAME
// event. Every DisplayObject has its own. Much simpler.
addEventListener(Event.ENTER_FRAME, firstStep);
}
public function draw():void {
// Keep all drawing inside the draw function. Previously,
// clear() was being called inside the step method.
graphics.clear();
graphics.beginFill(color);
graphics.drawRect(pos.x - size/2, pos.y - size/2, size, size);
graphics.endFill();
}
// On the first frame, the field "lastTime" is still uninitialized.
// This method initializes it to the current time and hands off
// future events to the proper step() method.
public function firstStep(event:Event):void {
removeEventListener(Event.ENTER_FRAME, firstStep);
addEventListener(Event.ENTER_FRAME, step);
lastTime = getTimer();
step(event);
}
public function step(event:Event):void {
// To move at a fixed rate regardless of how fast the framerate is,
// you need to calculate the time delta.
var cur:int = getTimer();
var delta:Number = (cur - lastTime) / 1000.0;
lastTime = cur;
// Position equals velocity times time.
pos.x += speed.x * delta;
pos.y += speed.y * delta;
draw();
// Note that all DisplayObjects already have references to their
// parent containers called "parent"!
if (pos.y < 20) {
if (parent != null) parent.removeChild(this);
removeEventListener(Event.ENTER_FRAME, step);
}
}
}
}

How can I use Action Script 3.0 to make random placed Symbols fly by?

I'm trying to make a simple animation with Flash CS4 and Action Script 3.0 to make a number of Symbols fly by from right to left constantly. What I want is that once a symbol has reached the end of the screen it is destroyed and another one is placed at the start position.
I intend to give each symbol a random speed and create a random symbol each time one is 'destroyed'. Any clues where I can start?
As you seem new to flash as a platform I would think writing classes shouldn't be your first port of call when learning ActionScript. Definitely just play about on the timeline for now and learn the basics. As very simple solution to this, I would suggest creating a MovieClip in the library with a class name like 'MyBall'... then paste this onto the first frame of the main timeline et voila.
// Create some variables to store data
var numberOfBalls : int = 20;
var myBalls : Array = [];
var xVelocities : Array = [];
var maxXVelocitySpeed : Number = 5;
var minXVelocitySpeed : Number = 2;
// Add your orginal balls to the stage
for (var i : int = 0; i < numberOfBalls; i++)
{
var myBall : MyBall = new MyBall();
myBall.x = -(Math.random() * stage.stageWidth);
myBall.y = Math.random() * stage.stageHeight;
var xVelocity : Number = minXVelocitySpeed + (Math.random() * (maxXVelocitySpeed - minXVelocitySpeed));
myBalls.push(myBall);
xVelocities.push(xVelocity);
addChild(myBall);
}
// Add a listener for enter frame events
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
//Run this code on every frame to move the balls and reposition them if they are off the stage
function enterFrameHandler(event : Event) : void
{
for each( var myBall : MyBall in myBalls)
{
var ballIndex : int = myBalls.indexOf(myBall);
myBall.x += xVelocity[ballIndex];
if (myBall.x > stage.stageWidth)
{
myBall.x = -(Math.random() * stage.stageWidth);
myBall.y = Math.random() * stage.stageHeight;
}
}
}
First, turn your symbols into MovieClips. Then create a base class MySymbol.as for your symbols, something like:
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.geom.Point;
public class MySymbol extends MovieClip
{
public var speed:Number; // Pixels moved per frame
public function MySymbol(speed:Number, startPosition:Point)
{
this.speed = speed;
this.addEventListener(Event.ENTER_FRAME, update);
this.x = startPosition.x;
this.y = startPosition.y;
}
private function update():void
{
this.x -= this.speed;
if (this.x < 0 - this.width) { // We're at the left edge
this.removeEventListener(Event.ENTER_FRAME, update);
this.dispatchEvent(new Event(Event.COMPLETE));
}
}
}
}
Then make sure your movie clips are exported for AS3 (the "linkage" option on the item in the library). Make the class name for each item unique (e.g. MySymbol1, MySymbol2), and set the base class to MySymbol.
Your document class might look something like this:
package {
import flash.display.MovieClip;
import flash.events.Event;
import MySymbol; // Not strictly needed
public class DocumentClass extends flash.display.MovieClip
{
private static var SYMBOLS:Array = new Array(MySymbol1, MySymbol2);
public function DocumentClass()
{
// Create five symbols:
for (var i:int = 0; i < 5; i++) {
makeSymbol();
}
}
private function makeSymbol():void
{
// Pick a random symbol from the array:
var symType:Class = SYMBOLS[Math.random() * SYMBOLS.length];
// Construct the new symbol:
var loc:Point = new Point(stage.stageWidth, Math.random() * stage.stageHeight);
var sym:MySymbol = new symType(1 + Math.random() * 30, loc);
// Listen for the object hitting the left edge:
sym.addEventListener(Event.COMPLETE, remakeObject);
this.addChild(sym);
}
private function remakeObject(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, remakeObject);
this.removeChild(e.target);
// Replace the dead symbol:
makeSymbol();
}
}
}
It is a lot more efficient if instead of destroying and re-creating an object that flies off-stage you re-use the existing one and move it back to the right. But this is an optimization you can implement later, if things become slow.
Note that all the code above is UNTESTED and I have not coded AS3 in a while, so there's likely at least a few bugs in it. Hopefully it will serve as a good enough starting point.
Define a Circle (symbol) class that extends Sprite/Shape and has a velocity variable
Draw a circle (or whatever) with a random color
Math.floor(Math.random() * 0xffffff)
Assign a random value to velocity
minVelocity + Math.floor(Math.random() * velocityRange)
Create a start() method inside the Circle class that registers an enter frame handler
Increment this.y inside the enter frame handler, and dispatch a 'recycleMe' event if y is more than the max value.
Create N instances of Circle, addChild them, and call their start() methods.
listen to 'recycleMe' events on each of them, and reset the value of y from the handler.
Here's a few prompts to get you started.
MovieClips have an x and y property. If you were to add to these numbers over time you would see the MovieClip move along the x and/or y axis of the stage. Look into doing this using the Event.ENTER_FRAME which will allow you to change the values every time the screen is going to update.
Your stage will have a given width (a stageWidth property). You probably want to monitor when your MovieClip's x property is greater than the width of your stage. If it is remove (removeChild) it and add a new one (addChild) and place it back at the start x/y position.