Iam trying to create a simple method in AS3 that adds 10 circles, each 30px in diameter in a column down the left-hand-side of the stage, so the first appears in the top-left corner and the last in the bottom-right. I would appreciate any help here. Thanks.
My current code follows: - It currently just returns 10 circles with no positioning.
package
{
import flash.display.*;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Circles extends MovieClip
{
private var timer:Timer = new Timer(100, 10);
public function Circles()
{
timer.addEventListener(TimerEvent.TIMER, createCircles);
timer.start();
}
private function createCircles(e:TimerEvent):void
{
var bcircle:MovieClip = new MovieClip();
var xpos:int = 0;
var ypos:int = 0;
bcircle.graphics.beginFill(0x0033CC);
bcircle.graphics.drawCircle(xpos,ypos,15);
bcircle.graphics.endFill();
bcircle.x = Math.random() * stage.stageWidth;
bcircle.y = Math.random() * stage.stageHeight;
addChild(bcircle);
}
}
}
bcircle.x = Math.random() * stage.stageWidth;
bcircle.y = Math.random() * stage.stageHeight;
These are the lines you want to be paying attention to as these lines control where each circle is placed when added to the stage.
Circle diameter = 30px, stage height (for example) = 400px.
30 goes into 400 13.33 times (400/30) so each circle needs to be spaced 13.3px further down than the last.
You can store a variable that counts how many circles are already on the stage and use it to multiply 13.3 to find the appropriate y value:
var i:int = 0;
private function createCircles(e:TimerEvent):void
{
var bcircle:MovieClip = new MovieClip();
var xpos:int = 0;
var ypos:int = 0;
bcircle.graphics.beginFill(0x0033CC);
bcircle.graphics.drawCircle(xpos,ypos,15);
bcircle.graphics.endFill();
bcircle.x = 0;
bcircle.y = (30 + 13.3) * i; // First circle placed at 0, Second placed at 43.3...
i++; // Increment i each time function is called
addChild(bcircle);
}
You can apply a similar method to then increment the x position of each circle once i reaches 10 (10 circles have been placed), use a trigger to detect this: if(i == 10)
This might help ...
package {
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Circles extends Sprite {
private const _circles:Array = []; // reusable container
private var _timer:Timer;
public function Circles() {
_timer = new Timer(1000, 10);
_timer.addEventListener(TimerEvent.TIMER, timer_timerHandler);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE, timer_timerCompleteHandler);
_timer.start();
}
private function createCircle():Sprite {
const sprite:Sprite = new Sprite();
drawCircleInGraphics(sprite.graphics);
addChild(sprite);
return sprite;
}
private function drawCircleInGraphics(graphics:Graphics, color:uint = 0x0033CC, radius:uint = 15):void {
graphics.beginFill(color);
graphics.drawCircle(0, 0, radius);
graphics.endFill();
}
private function createNewCircleAndPositionIt():void {
_circles[_circles.length] = createCircle();
if (_circles.length > 1) {
const last:Sprite = _circles[_circles.length - 1],
predecessor:Sprite = _circles[_circles.length - 2];
last.x = predecessor.x + 30;
last.y = predecessor.y + 30;
}
}
private function timer_timerHandler(event:TimerEvent):void {
createNewCircleAndPositionIt();
}
private function timer_timerCompleteHandler(event:TimerEvent):void {
_timer.removeEventListener(TimerEvent.TIMER, timer_timerHandler);
_timer.removeEventListener(TimerEvent.TIMER_COMPLETE, timer_timerCompleteHandler);
_timer = null;
}
}
}
Related
I'm trying to use vectors to make an enemy track a target (player's ship). However, I keep getting Error 1046. Any advice? The error occurs on the line containing the drawForceVector function in the Game.as file.
Here is my Game.as file code:
package{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Vector3D;
import flash.text.TextField;
public class Game extends MovieClip
{
public static var mouse :Vector3D = new Vector3D(100, 100);
public var boids :Vector.<Boid> = new Vector.<Boid>;
public var forces :Sprite;
public function Game() {
addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e :Event) :void {
var i :int, boid :Boid;
for (i = 0; i < 2; i++) {
boid = new Boid(stage.stageWidth * Math.random(), stage.stageHeight * Math.random(), 20 + Math.random() * 20);
addChild(boid);
boids.push(boid);
}
forces = new Sprite();
addChild(forces);
}
public function update():void {
var i :int;
forces.graphics.clear();
for (i = 0; i < boids.length; i++) {
boids[i].update();
drawForces(boids[i]);
}
}
private function drawForces(boid :Boid) :void {
var desired :Vector3D = boid.desired.clone();
var velocity :Vector3D = boid.velocity.clone();
var steering :Vector3D = boid.steering.clone();
velocity.normalize();
desired.normalize();
steering.normalize();
// Force vectors
drawForceVector(boid, velocity, 0x00FF00);
drawForceVector(boid, desired, 0x454545);
drawForceVector(boid, steering, 0x0000FF);
// Target
forces.graphics.lineStyle(1, 0x323232);
forces.graphics.beginFill(0x323232);
forces.graphics.drawCircle(mouse.x, mouse.y, 10);
forces.graphics.endFill();
}
private function drawForceVector(boid :Boid, force :Vector3D, color :uint, scale :Number = 100) :void { //ERROR OCCURS ON THIS LINE
forces.graphics.moveTo(boid.x + boid.width / 2, boid.y + boid.height / 2);
forces.graphics.lineStyle(2, color);
forces.graphics.lineTo(boid.x + force.x * scale, boid.y + force.y * scale);
}
}
}
Boid.as Code:
package {
import flash.display.MovieClip;
import flash.geom.Vector3D;
import flash.object.Vector3D;
public class Boid extends MovieClip
{
public static const MAX_FORCE :Number = 0.4;
public static const MAX_VELOCITY :Number = 3;
public var position :Vector3D;
public var velocity :Vector3D;
public var target :Vector3D;
public var desired :Vector3D;
public var steering :Vector3D;
public var mass :Number;
public function Boid(posX :Number, posY :Number, totalMass :Number = 20) {
position = new Vector3D(posX, posY);
velocity = new Vector3D(-1, -2);
target = new Vector3D(310, 240);
desired = new Vector3D(0, 0);
steering = new Vector3D(0, 0);
mass = totalMass;
truncate(velocity, MAX_VELOCITY);
x = position.x;
y = position.y;
graphics.beginFill(0xFF0000);
graphics.drawRect(0, 0, 20, 20);
graphics.endFill();
}
private function seek(target :Vector3D) :Vector3D {
var force :Vector3D;
desired = target.subtract(position);
desired.normalize();
desired.scaleBy(MAX_VELOCITY);
force = desired.subtract(velocity);
return force;
}
public function truncate(vector :Vector3D, max :Number) :void {
var i :Number;
i = max / vector.length;
i = i < 1.0 ? 1.0 : i;
vector.scaleBy(i);
}
public function update():void {
target = Game.mouse;
steering = seek(target);
truncate(steering, MAX_FORCE);
steering.scaleBy(1 / mass);
velocity = velocity.add(steering);
truncate(velocity, MAX_VELOCITY);
position = position.add(velocity);
x = position.x;
y = position.y;
}
}
}
Main.as Code:
package {
import flash.display.Sprite;
import flash.events.*;
[SWF(width = "600", height = "480")]
public class Main extends Sprite
{
private var game :Game = new Game();
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
stage.addEventListener(Event.ENTER_FRAME, enterFrame);
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
stage.frameRate = 30;
addChild(game);
}
private function mouseMove(e :MouseEvent) :void {
Game.mouse.x = e.stageX;
Game.mouse.y = e.stageY;
}
private function enterFrame(e :Event) :void {
game.update();
}
}
}
Thank you very much.
The target version of the player must be higher than the one you've got - Flash Player 9. As seen by the reference, it's said that Vector3D is included in: Runtime Versions: Flash Player 10, AIR 1.5. So basically you are building for so old Flash Player, that it still doesn't have this class inside it.
Simply change the target version to the latest possible one, and be sure it's higher than Flash Player 10. That will do the job! :)
I have been struggling with a as3 and flash game that i am trying to make. Everything looks fine, but still the bullet are stuck inside the cannon. When i use my mouse to shoot, instead of going out to a location, it just get stuck inside the cannon:
Got 3 as3 documents, and one flash document:
Ships.as
package{
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
public class Ship extends Sprite{
private var speed:int;
private var target:Point;
function Ship(){
speed=2+Math.random()*5;
//trace("Made a Ship!");
//set the target for the ships
target = new Point(Math.random()*500, Math.random()*500);
//target.x = Math.random()*500;
//target.y = Math.random()*500;
//addEventListener(Event.ENTER_FRAME, update);
}
function update(){
//Set the ships to point the target
var dx = target.x - x;
var dy = target.y - y;
var angle = Math.atan2(dy, dx)/Math.PI*180;
rotation = angle;
x=x+Math.cos(rotation/180*Math.PI)*speed;
y=y+Math.sin(rotation/180*Math.PI)*speed;
//New target
var hyp = Math.sqrt((dx*dx)+(dy*dy));
if(hyp < 5){
target.x = Math.random()*500;
target.y = Math.random()*500;
}
}
}
}
Game.as
package{
import flash.display.MovieClip;
import flash.events.Event;
public class Game extends MovieClip{
var ships:Array;
public function Game(){
trace("Made that game!");
addEventListener(Event.ENTER_FRAME, loop);
//set up the ship array
ships = new Array();
}
function loop(e:Event){
if(numChildren<10){
var s = new Ship();
addChild(s);
s.x = Math.random()*stage.stageWidth;
s.y = Math.random()*stage.stageHeight;
s.rotation = Math.random()*360;
//Add the ship to the list of ships
ships.push(s);
}
//Make a for loop to iterate through all the ship
for(var count=0; count<ships.length; count++){
ships[count].update();
//Add a new for loop to go through all the bullets
}
}
}
}
}
}
Turret.as
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Turret extends MovieClip{
//Properties goes here
var shotCooldown:int;
var bullets:Array;
const MAX_COOLDOWN = 10;
public function Turret(){
//Set the Shot Cooldown
shotCooldown = MAX_COOLDOWN;
bullets = new Array();
addEventListener(Event.ENTER_FRAME, update);
addEventListener(Event.ADDED_TO_STAGE, initialise);
}
function initialise(e:Event)
{
stage.addEventListener(MouseEvent.CLICK, fire);
}
function fire(m:MouseEvent)
{
//If we are allowed to shoot
if(shotCooldown<=0)
{
//Reset the Shot Cooldown
shotCooldown=MAX_COOLDOWN;
//Spawn a Bullet
var b = new Bullet();
b.rotation = rotation;
b.x = x;
b.y = y;
//Add the bullet to the list of bullets
bullets.push(b);
parent.addChild(b);
play();
}
}
function update(e:Event)
{
//Reduce the Shot Cooldown by 1
//shotCooldown=shotCooldown-1;
//shotCooldown-=1;
shotCooldown--;
if(parent != null)
{
var dx = parent.mouseX - x;
var dy = parent.mouseY - y;
var angle = Math.atan2(dy, dx) / Math.PI * 180;
rotation = angle;
}
}
}
}
They are stuck in place maybe because you are not moving them at all? If you are then please show me where. Try adding to the turret's enter frame event the following code:
for (var a:int = 0; bullets.length > a ; a++)
{
var temp:MovieClip;
temp = bullets[a] as Bullet;
var vel:Point = new Point();
vel.x = temp.target.x-temp.x;
vel.y = temp.target.y-temp.y;
vel.normalize(4);
temp.x += vel.x;
temp.y += vel.y;
}
And make an as file for the Bullet Class and add this:
package
{
import flash.geom.Point;
public class Bullet extends MovieClip
{
public var target:Point = new Point();
public function Bullet()
{
target.x = stage.mouseX;
target.y = stage.mouseY;
}
}
}
In Turret class bullets are added to the stage and array but doesn't have updated every frame like ships. See your own comment about updating bullets!
I'v got 2 classes. Simulating fluid. Both classes are pretty straight forward and short, but after 2 seconds of running, the simulation gets really slow, looks like a memory leak. But i can't see any leaks in this code.
Please let me know if you can figure out, why this is happening?
FluidLayer.as
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.display.IBitmapDrawable;
import flash.events.Event;
import flash.display.MovieClip;
public class FluidLayer extends MovieClip {
private var canvas:Sprite;
private var b:Bitmap;
private var blur:BlurFilter = new BlurFilter(20,20,3);
private var bmd1:BitmapData;
public function FluidLayer() {
canvas = new Sprite();
for(var i:int = 0;i < 600;i++){
var p:Particle = new Particle();
canvas.addChild(p);
p.x = stage.stageWidth * Math.random();
p.y = stage.stageHeight* Math.random();
p.initi(stage);
}
canvas.filters = new Array(blur);
addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void{
remove();
b = new Bitmap(makeFluid(canvas),"auto", true);
b.alpha = 0.7;
addChild(b);
}
private function makeFluid(o:Sprite):BitmapData{
bmd1 = new BitmapData(stage.stageWidth, stage.stageHeight, true);
bmd1.draw(o,null,null,null,null,true);
bmd1.threshold(bmd1, bmd1.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false);
return bmd1;
}
private function remove():void{
if(numChildren > 1)
removeChildAt(1);
if(bmd1){
bmd1.dispose();
bmd1 = null;
}
}
}}
Particle.as
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
public class Particle extends MovieClip {
private var speedX:int;
private var speedY:int;
private var _s:Stage;
public function Particle() {
this.graphics.beginFill(0x00CCFF);
this.graphics.drawCircle(0,0,Math.random() * 30);
speedX = Math.random() * 10 - 5;
speedY = Math.random() * 10 - 5;
this.addEventListener(Event.ADDED_TO_STAGE, initi);
}
public function initi(s:Stage):void{
this._s = s;
addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void{
this.x += Math.random()*speedX;
this.y += Math.random()*speedY;
if(this.x > _s.stageWidth || this.y > _s.stageHeight){
//this.x = Math.random()*_s.stageWidth;
//this.y = Math.random()*_s.stageHeight;
removeEventListener(Event.ENTER_FRAME, render);
this.parent.removeChild(this);
}
}
}}
You must call bmd1.dispose(); before reinstantiating it or it will not release the bitmap from memory.
Edit:
After looking through your code very carefully, optimizing it, and cleaning up some things, I have come to the conclusion that your simulation is no longer running slower and slower.
The problem was that the way you would calculate the particle's x and y speed. Essentially it would diminish in speed until stopping all together. On top of the massive high quality blur you have placed and the lack of freeing bitmaps, your movie would appear and actually slow to a crawl.
Here is your code I have modified. I benchmarked it and it didn't peak above 10% cpu or 40k memory after 15 minutes.
Particle.as
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
public class Particle extends MovieClip {
private var speedX:int;
private var speedY:int;
private var deleted:Boolean = false;
public function Particle() {
this.graphics.beginFill(0x00CCFF);
this.graphics.drawCircle(0,0,Math.random() * 30);
//The max prevents particle speed from rounding to zero.
speedX = Math.ceil(Math.random() * 10 - 5);
speedY = Math.ceil(Math.random() * 10 - 5);
}
public function render():void{
//It originally appeared to be slowing down. In-fact, it was.
x += Math.random() * speedX;
y += Math.random() * speedY;
deleted = (x > FluidLayer.w || y > FluidLayer.h);
//Comment this below if you want particles to be removed once they go out of bounds.
if(deleted) {
x = Math.random() * FluidLayer.w;
y = Math.random() * FluidLayer.h;
deleted = false;
}
}
public function isDeleted():Boolean {
return deleted;
}
}
}
FluidLayer.as
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.display.IBitmapDrawable;
import flash.events.Event;
import flash.display.MovieClip;
public class FluidLayer extends MovieClip {
private var canvas:Sprite;
private var bitmap:Bitmap;
private var bitmapData:BitmapData;
private var particleArray:Array = new Array();
public static const w:uint = 550;
public static const h:uint = 400;
public function FluidLayer() {
addEventListener(Event.ADDED_TO_STAGE, initialize);
}
//By only one event handler to render, we prevent the overhead of 599 bubbling events.
private function render(e:Event):void {
for each(var p:Particle in particleArray) {
p.render();
//uncomment below if you want particles to become removed when they navigate out of bounds.
//if(p.isDeleted()) {
//canvas.removeChild(p);
//particleArray.splice(particleArray.indexOf(p),1);
//}
}
bitmapData.fillRect(bitmapData.rect, 0); //clear the bitmapdata
bitmapData.draw(canvas,null,null,null,null,true);
bitmapData.threshold(bitmapData, bitmapData.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false);
}
//We call initialize once the fluid layer has been added to stage
//or else stage values will be null.
private function initialize(e:Event):void {
canvas = new Sprite();
//You DEFINITELY want to lower the blur amount here.
//This is what is ultimately slowing your SWF down to a crawl.
//canvas.filters = new Array(new BlurFilter(20,20,1));
for(var i:uint = 0; i < 600; i++) {
var p:Particle = new Particle();
p.x = Math.random() * w;
p.y = Math.random() * h;
canvas.addChild(p);
particleArray.push(p);
}
//The bitmap and bitmapData only need to be initialized once
bitmapData = new BitmapData(w, h, true);
bitmap = new Bitmap(bitmapData, "auto", true);
bitmap.alpha = 0.7;
addChild(bitmap);
addEventListener(Event.ENTER_FRAME, render);
}
}
}
The original slowdown appears to be the blur filter on the canvas. (Comment the filter out to see proof)
The automatic creation of bitmaps by flash (CacheAsBitmap & Bitmap Filter buffers) to render the filter is likely causing the memory leak and this could be due the constantly changing dimension of canvas, due to the particles movement.
Try adding this line after creating canvas for a quick fix:
canvas.scrollRect = new Rectangle(0,0,stage.stageWidth,stage.stageHeight);
By limiting the size of the canvas with the scrollRect we are stopping this reallocation.
However the fluid no longer goes to the edges of the stage. This could be worked around in the draw and bitmap allocation routines, increasing dimensions and offsetting, i'll let you have a go at that but its connected partially to the blur filter amount.
I'd suggest adapting these idea with the very good ideas in Andreas' code.
So i put together a solution for my question with the help of Andreas and adamh.
Andreas - showed me that i forgot to dispose the bitmapdata (really nice spot!)
Adamh - told me to define scrollrect on the canvas (Upped the performance a lot!)
But what did it in the end and made the performance fluid, was a simple mistake from my side. I noticed in the particle.as > render(), that i was only checking if the particle was out of bounds on 2 sides (facepalm), stupid mistake. When i changed the render function to check the remaining 2 sides, it fixed the performance issue.
Sorry for the stupid question :) and thanks again to Andreas and adamh
the final classes:
FluidLayer.as
package {
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.display.BitmapData;
import flash.filters.BlurFilter;
import flash.display.Bitmap;
import flash.geom.Point;
import flash.geom.ColorTransform;
import flash.display.IBitmapDrawable;
import flash.events.Event;
import flash.display.MovieClip;
import flash.geom.Rectangle;
public class FluidLayer extends MovieClip {
private var canvas:Sprite;
private var b:Bitmap;
private var blur:BlurFilter = new BlurFilter(20,20,3);
private var bmd1:BitmapData;
public function FluidLayer() {
canvas = new Sprite();
canvas.scrollRect = new Rectangle(0,0,1010,550);
for(var i:int = 0;i < 600;i++){
var p:Particle = new Particle();
canvas.addChild(p);
p.x = stage.stageWidth * Math.random();
p.y = stage.stageHeight* Math.random();
p.initi(stage);
}
canvas.filters = new Array(blur);
addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void{
remove();
b = new Bitmap(makeFluid(canvas),"auto", true);
b.alpha = 0.7;
addChild(b);
}
private function makeFluid(o:Sprite):BitmapData{
bmd1 = new BitmapData(stage.stageWidth, stage.stageHeight, true);
bmd1.draw(o,null,null,null,null,true);
bmd1.threshold(bmd1, bmd1.rect, new Point(0,0), ">", 0XFF2b2b2b, 0x55FFFF, 0xFFFFFF, false);
return bmd1;
}
private function remove():void{
if(numChildren > 1)
removeChildAt(1);
if(bmd1){
bmd1.dispose();
bmd1 = null;
}
}}}
Particle.as
package {
import flash.display.MovieClip;
import flash.events.Event;
import flash.display.Stage;
public class Particle extends MovieClip {
private var speedX:int;
private var speedY:int;
private var _s:Stage;
public function Particle() {
this.graphics.beginFill(0x00CCFF);
this.graphics.drawCircle(0,0,Math.random() * 30);
speedX = Math.random() * 10 - 5;
speedY = Math.random() * 10 - 5;
this.addEventListener(Event.ADDED_TO_STAGE, initi);
}
public function initi(s:Stage):void{
this._s = s;
addEventListener(Event.ENTER_FRAME, render);
}
private function render(e:Event):void{
this.x += Math.random()*speedX;
this.y += Math.random()*speedY;
if(this.x > _s.stageWidth || this.y > _s.stageHeight || this.x < 0 && this.y < 0){
this.x = Math.random()*_s.stageWidth;
this.y = Math.random()*_s.stageHeight;
//removeEventListener(Event.ENTER_FRAME, render);
//this.parent.removeChild(this);
}
}
}}
This question is related to ActionScript 3.0 and Flash CS6
I am trying to make an object shake a bit in a certain for some seconds. I made it a "movieclip" and made this code:
import flash.events.TimerEvent;
var Machine_mc:Array = new Array();
var fl_machineshaking:Timer = new Timer(1000, 10);
fl_machineshaking.addEventListener (TimerEvent.TIMER, fl_shakemachine);
fl_machineshaking.start ();
function fl_shakemachine (event:TimerEvent):void {
for (var i = 0; i < 20; i++) {
Machine.x += Math.random() * 6 - 4;
Machine.y += Math.random() * 6 - 4;
}
}
When testing the movie I get multiple errors looking exactly like this one:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Historieoppgave_fla::MainTimeline/fl_shakemachine()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
Also, the object doesnt shake, but it moves steadily upwards to the left a bit every tick.
To the point:
I wish to know how I stop the script after the object is not in the stage/scene anymore and also how to make it shake around, as I do not see what is wrong with my script, please help, thank you ^_^
AStupidNube brought up a great point about the original position. So adding that to shaking that should be a back and forth motion, so don't rely on random values that may or may not get you what you want. Shaking also has a dampening effect over time, so try something like this:
Link to working code
• http://wonderfl.net/c/eB1E - Event.ENTER_FRAME based
• http://wonderfl.net/c/hJJl - Timer Based
• http://wonderfl.net/c/chYC - Event.ENTER_FRAME based with extra randomness
**1 to 20 shaking items Timer Based code - see link above for ENTER_FRAME code••
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.text.TextField;
import flash.utils.Timer;
public class testing extends Sprite {
private var shakeButton:Sprite;
private var graphic:Sprite;
private var shakerPos:Array;
private var shakers:Array;
private var numShakers:int = 20;
private var dir:int = 1;
private var displacement:Number = 10;
private var shakeTimer:Timer;
public function testing() {
this.shakers = new Array();
this.shakerPos = new Array();
this.addEventListener(Event.ADDED_TO_STAGE, this.init);
}
private function init(e:Event):void {
this.stage.frameRate = 30;
this.shakeTimer = new Timer(33, 20);
this.shakeTimer.addEventListener(TimerEvent.TIMER, this.shake);
this.graphics.beginFill(0x333333);
this.graphics.drawRect(0,0,this.stage.stageWidth, this.stage.stageHeight);
this.graphics.endFill();
this.createShakers();
this.shakeButton = this.createSpriteButton("Shake ");
this.addChild(this.shakeButton);
this.shakeButton.x = 10;
this.shakeButton.y = 10;
this.shakeButton.addEventListener(MouseEvent.CLICK, this.shakeCallback);
}
private function createSpriteButton(btnName:String):Sprite {
var sBtn:Sprite = new Sprite();
sBtn.name = btnName;
sBtn.graphics.beginFill(0xFFFFFF);
sBtn.graphics.drawRoundRect(0,0,80,20,5);
var sBtnTF:TextField = new TextField();
sBtn.addChild(sBtnTF);
sBtnTF.text = btnName;
sBtnTF.x = 5;
sBtnTF.y = 3;
sBtnTF.selectable = false;
sBtn.alpha = .5;
sBtn.addEventListener(MouseEvent.MOUSE_OVER, function(e:Event):void { sBtn.alpha = 1 });
sBtn.addEventListener(MouseEvent.MOUSE_OUT, function(e:Event):void { sBtn.alpha = .5 });
return sBtn;
}
private function createShakers():void {
var graphic:Sprite;
for(var i:int = 0;i < this.numShakers;i++) {
graphic = new Sprite();
this.addChild(graphic);
graphic.graphics.beginFill(0xFFFFFF);
graphic.graphics.drawRect(0,0,10,10);
graphic.graphics.endFill();
// add a 30 pixel margin for the graphic
graphic.x = (this.stage.stageWidth-60)*Math.random()+30;
graphic.y = (this.stage.stageWidth-60)*Math.random()+30;
this.shakers[i] = graphic;
this.shakerPos[i] = new Point(graphic.x, graphic.y);
}
}
private function shakeCallback(e:Event):void {
this.shakeTimer.reset();
this.shakeTimer.start();
}
private function shake(e:TimerEvent):void {
this.dir *= -1;
var dampening:Number = (20 - e.target.currentCount)/20;
for(var i:int = 0;i < this.numShakers;i++) {
this.shakers[i].x = this.shakerPos[i].x + Math.random()*10*dir*dampening;
this.shakers[i].y = this.shakerPos[i].y + Math.random()*10*dir*dampening;
}
}
}
}
Now this is a linear dampening, you can adjust as you see fit by squaring or cubing the values.
You have to remember the original start position and calculate the shake effect from that point. This is my shake effect for MovieClips. It dynamically adds 3 variables (startPosition, shakeTime, maxShakeAmount) to it. If you use classes, you would add them to your clips.
import flash.display.MovieClip;
import flash.geom.Point;
function shake(mc:MovieClip, frames:int = 10, maxShakeAmount:int = 30) : void
{
if (!mc._shakeTime || mc._shakeTime <= 0)
{
mc.startPosition = new Point(mc.x, mc.y);
mc._shakeTime = frames;
mc._maxShakeAmount = maxShakeAmount;
mc.addEventListener(Event.ENTER_FRAME, handleShakeEnterFrame);
}
else
{
mc.startPosition = new Point(mc.x, mc.y);
mc._shakeTime += frames;
mc._maxShakeAmount = maxShakeAmount;
}
}
function handleShakeEnterFrame(event:Event):void
{
var mc:MovieClip = MovieClip(event.currentTarget);
var shakeAmount:Number = Math.min(mc._maxShakeAmount, mc._shakeTime);
mc.x = mc.startPosition.x + (-shakeAmount / 2 + Math.random() * shakeAmount);
mc.y = mc.startPosition.y + (-shakeAmount / 2 + Math.random() * shakeAmount);
mc._shakeTime--;
if (mc._shakeTime <= 0)
{
mc._shakeTime = 0;
mc.removeEventListener(Event.ENTER_FRAME, handleShakeEnterFrame);
}
}
You can use it like this:
// shake for 100 frames, with max distance of 15px
this.shake(myMc, 100, 15);
BTW: In Flash, you should enable 'permit debugging' in your 'publish settings' to have more detailed errors. This also gives back the line numbers where your code is breaking.
update:
Code now with time / maximum distance separated.
Here is a forked version of the chosen answer, but is a bit more flexible in that it allows you to set the frequency as well. It's also based on time as opposed to frames so you can think in terms of time(ms) as opposed to frames when setting the duration and interval.
The usage is similar to the chosen answer :
shake (clipToShake, durationInMilliseconds, frequencyInMilliseconds, maxShakeRange);
This is just an example of what I meant by using a TimerEvent as opposed to a ENTER_FRAME. It also doesn't require adding dynamic variables to the MovieClips you are shaking to track time, shakeAmount, and starting position.
public function shake(shakeClip:MovieClip, duration:Number = 3000, frequency:Number = 30, distance:Number = 30):void
{
var shakes:int = duration / frequency;
var shakeTimer:Timer = new Timer(frequency, shakes);
var startX:Number = shakeClip.x;
var startY:Number = shakeClip.y;
var shakeUpdate:Function = function(e:TimerEvent):void
{
shakeClip.x = startX + ( -distance / 2 + Math.random() * distance);
shakeClip.y = startY + ( -distance / 2 + Math.random() * distance);
}
var shakeComplete:Function = function(e:TimerEvent):void
{
shakeClip.x = startX;
shakeClip.y = startY;
e.target.removeEventListener(TimerEvent.TIMER, shakeUpdate);
e.target.removeEventListener(TimerEvent.TIMER_COMPLETE, shakeComplete);
}
shakeTimer.addEventListener(TimerEvent.TIMER, shakeUpdate);
shakeTimer.addEventListener(TimerEvent.TIMER_COMPLETE, shakeComplete);
shakeTimer.start();
}
-4 <= Math.random() * 6 - 4 < 2
You add this offset to Machine.x 20 times, so chances for moving to the left is greater, than to the right.
It seems that you looking for something like this:
for each (var currentMachine:MovieClip in Machine_mc)
{
currentMachine.x += Math.random() * 6 - 3;
currentMachine.y += Math.random() * 6 - 3;
}
I'm in the midst of creating a Bumptop styled selection tool. Right now I got as far as creating the tool itself (which actually works pretty good) and spreading some random square items on the stage. This is the class that creates the selection tool :
package com.reyco1.medusa.selectiontool
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
public class SelectionBase extends Sprite
{
private var points:Array = [];
public function SelectionBase()
{
super();
addEventListener(Event.ADDED_TO_STAGE, initialize);
}
private function initialize(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, initialize);
points.push(new Point(mouseX, mouseY)); stage.addEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
}
private function handleMouseMove(e:MouseEvent):void
{
graphics.clear();
graphics.beginFill(0x33CCFF, .5);
graphics.drawCircle(0, 0, 20);
graphics.endFill();
graphics.moveTo(0, 0);
graphics.lineStyle(1.5, 0x33CCFF, .5);
graphics.lineTo(mouseX, mouseY);
points.push(new Point(mouseX, mouseY));
graphics.beginFill(0x33CCFF, .1);
graphics.moveTo(points[0].x, points[0].y);
for (var i:uint = 1; i < points.length; i++)
{
graphics.lineTo(points[i].x, points[i].y);
}
graphics.lineTo(points[0].x, points[0].y);
graphics.endFill();
dispatchEvent(new Event("UPDATE"));
}
public function clear():void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
graphics.clear();
}
}
}
And this is the document class that implements it :
package
{
import com.reyco1.medusa.selectiontool.SelectionBase;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.display.StageAlign;
import flash.display.StageQuality;
import flash.display.StageScaleMode;
[SWF(width = '1024', height = '768', backgroundColor = '0x000000')]
public class SelectionToolPrototype extends Sprite
{
private var selectionTool:SelectionBase;
public function SelectionToolPrototype()
{
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.quality = StageQuality.MEDIUM;
stage.addEventListener(MouseEvent.MOUSE_DOWN, handleDown);
stage.addEventListener(MouseEvent.MOUSE_UP, handleUp);
placeShapesRandomly();
}
private function placeShapesRandomly():void
{
for(var a:Number = 0; a<25; a++)
{
var s:Sprite = new Sprite();
s.graphics.beginFill(Math.random() * 0xCCCCCC);
s.graphics.drawRect(0, 0, 50, 50);
s.graphics.endFill();
s.x = Math.floor(Math.random() * 900 - 40) + 40;
s.y = Math.floor(Math.random() * 700 - 40) + 40;
s.rotation = Math.floor(Math.random() * 360 - 40) + 40;
s.buttonMode = true;
addChild(s);
}
}
private function handleUp(e:MouseEvent):void
{
selectionTool.removeEventListener("UPDATE", handleToolUpdate);
removeChild(selectionTool);
selectionTool = null;
}
private function handleDown(e:MouseEvent):void
{
selectionTool = new SelectionBase();
selectionTool.addEventListener("UPDATE", handleToolUpdate);
selectionTool.x = mouseX;
selectionTool.y = mouseY;
addChild(selectionTool);
}
private function handleToolUpdate(e:Event):void
{
// logic to determin if items are within selection goes here
}
}
}
I've tried using collision detection by means of BitmapData and even using collision libraries like CDK but I cant get anything to work. Anybody have an idea what I should use in the handleToolUpdate(e:MouseEvent); ? Thanks!
Update:
I'll break it down. Basically I am trying to create a prototype of the BumpTop Lasso or Selection tool.
I need help in finding out which objects either collide or have a point within the bounds of the drawn lasso.
I have upload what I have so far to my server here : http://labs.reyco1.com/bumptop/SelectionToolPrototype.html. You can see the source by right clicking and selecting "View Source".
Like I said in my earlier post, I tried using Bitmapdata collision testing and even tried using the Collision Detection Kit to no avail. Thanks in advance.
Loop through the display object you are attaching your random sprites to, and using for each, check their value of hitTestObject against your selectionTool instance.
Here are the Adobe docs for hitTestObject():
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#hitTestObject%28%29