Actionscript 3.0 - 追踪移动体的路径;

时间:2014-06-15 07:32:24

标签: actionscript-3 flash

我目前正在学习AS3.0。我正在尝试设计一个简单的两体行星模拟。我需要在屏幕上显示行星的路径。所以我的问题是,一旦我在每个定时器间隔有行星的更新x和y坐标,我该如何改变舞台的像素(x,y)的颜色,以便显示行星的路径?是否有一些形式stage.x = color?

的命令

谢谢!

2 个答案:

答案 0 :(得分:6)

我建议每次更新时使用BitmapData's draw()方法将行星渲染为像素。它基本上就像一个截图'您将其作为n参数传递的显示对象。如果传递对象变换,则位置/旋转/比例将可见(而不是从0,0绘制)。这样,您只会更新像素而不是连续创建新的显示对象。

这是一个基本的评论示例:

import flash.display.Sprite;
import flash.events.Event;

var trails:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,true,0x00000000);//create a transparent bitmap to draw the trails into
var trailsFade:ColorTransform = new ColorTransform(1,1,1,0.025,0,0,0,1);//color transform: keep rgb the same(1,1,1), set alpha to 0.025 out of 1.0
var background:Bitmap = addChild(new Bitmap(trails,PixelSnapping.AUTO,true)) as Bitmap;//add the trails pixels/bitmap data into a Bitmap/display object at the bottom of the display list

var dot:Sprite = addChild(new Sprite()) as Sprite;
dot.graphics.lineStyle(3);
dot.graphics.drawCircle(-4, -4, 8);

addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
    dot.x = mouseX;
    dot.y = mouseY;
    //draw trails of the dot
    trails.draw(dot,dot.transform.concatenatedMatrix,trailsFade);//draw the dot into the bitmap data using the dot's transformation (x,y, rotation, scale)
}

注意移动鼠标时的轨迹以及它们受(更新)速度的影响。

以下是使用多个对象的较长示例:

import flash.display.*;
import flash.events.Event;
import flash.geom.ColorTransform;

var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var trails:BitmapData = new BitmapData(w,h,true,0x00000000);//create a transparent bitmap to draw the trails into
var trailsFade:ColorTransform = new ColorTransform(1,1,1,0.025,0,0,0,0.1);//color transform: keep rgb the same(1,1,1), set alpha to 0.025 out of 1.0
var background:Bitmap = addChild(new Bitmap(trails,PixelSnapping.AUTO,true)) as Bitmap;//add the trails pixels/bitmap data into a Bitmap/display object at the bottom of the display list
var spheres:Sprite    = addChild(new Sprite()) as Sprite;//add a container for all the spheres (planets/moons/sun/etc.)

var mercuryPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;
var venusPivot:Sprite   = spheres.addChild(new Sprite()) as Sprite;
var earthPivot:Sprite   = spheres.addChild(new Sprite()) as Sprite;

var sun:Sprite     = spheres.addChild(getCircleSprite(69.5500 /4,0xFF9900)) as Sprite;
var mercury:Sprite = mercuryPivot.addChild(getCircleSprite(24.40 / 4,0xCECECE)) as Sprite;
var venus:Sprite   = venusPivot.addChild(getCircleSprite(60.52 / 4,0xFF2200)) as Sprite;
var earth:Sprite   = earthPivot.addChild(getCircleSprite(60.52 / 4,0x2233FE)) as Sprite;

mercury.x = 5791 / 40;
venus.x   = 10820 / 40;
earth.x   = 14960 / 40;
spheres.x = (w-spheres.width) * 0.5;
spheres.y = (h-spheres.height) * 0.5;

addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
    mercuryPivot.rotation += 0.5;
    venusPivot.rotation   += 0.25;
    earthPivot.rotation   += 0.12;
    //draw trails
    trails.draw(spheres,spheres.transform.concatenatedMatrix,trailsFade);
}


function getCircleSprite(radius:Number,color:int):Sprite{
    var circle:Sprite = new Sprite();
    circle.graphics.beginFill(color);
    circle.graphics.drawCircle(-radius * .5,-radius * .5,radius);//draw from centre
    circle.graphics.endFill();
    return circle;
}

请注意我们致电trails.draw(spheres,spheres.transform.concatenatedMatrix,trailsFade); 但如果您只想绘制trails.draw(earth,earth.transform.concatenatedMatrix,trailsFade);的踪迹,则可能是earth

trails

在上面的示例中,我只是嵌套精灵并使用rotation属性来保持简单。您可能希望使用一些三角函数来更新位置,因为行星可能没有完美的圆形轨道并且每次都会通过确切的位置。

<强>更新

考虑到这一点,如果你开始使用旧学校Graphics API可能对你很方便,但我们还不习惯使用像素。

它很容易上手:可以在flash播放器中显示的对象可以具有图形属性(请参阅Shape / Sprite / MovieClip类)。 (您可以使用显示对象,无论您是否可以将元素嵌入(DisplayObjectContainer)或不嵌入(DisplayObject),但这也是您可以查看的其他内容。)

这个graphics属性Sprites和MovieClip允许您使用简单的命令以编程方式绘制,例如:设置笔划(lineStyle()),填充(beginFill() / endFill() ),移动一个假想的笔&#39;没有绘制(moveTo),绘制一条线(lineTo),一个圆形,一个矩形,一个圆角矩形等等。它就在那里。

所以,最小的绘图程序看起来有点像这样:

import flash.events.MouseEvent;
import flash.events.Event;

var mousePressed:Boolean = false;//keep track if the mouse is pressed or not
graphics.lineStyle(1);//set the stroke to have a thickness of 1 (and the other parameters are defaults(color: black, transparency: 100% / 1.0, etc.))

stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler);//listend for mouse down
stage.addEventListener(MouseEvent.MOUSE_UP,mouseEventHandler);//...and mouse up changes
stage.addEventListener(Event.ENTER_FRAME,update);//update continuously

function mouseEventHandler(e:MouseEvent):void{
    mousePressed = (e.type == MouseEvent.MOUSE_DOWN);
    graphics.moveTo(mouseX,mouseY);//place the graphics 'pen' at this new location
}
function update(e:Event):void{
    if(mousePressed)  graphics.lineTo(mouseX,mouseY);//if the mouse is pressed, keep drawing a line to the current mouse location   
}

或更复杂的版本,您可以使用鼠标移动的速度来影响笔触粗细和透明度:

import flash.events.MouseEvent;
import flash.events.Event;
import flash.geom.Point;

var prevPos:Point = new Point();//previous mouse position
var currPos:Point = new Point();//current mouse position
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var mousePressed:Boolean = false;//keep track if the mouse is pressed or not
graphics.lineStyle(1);//set the stroke to have a thickness of 1 (and the other parameters are defaults(color: black, transparency: 100% / 1.0, etc.))
stage.doubleClickEnabled = true;

stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler);//listend for mouse down
stage.addEventListener(MouseEvent.MOUSE_UP,mouseEventHandler);//...and mouse up changes
stage.addEventListener(MouseEvent.DOUBLE_CLICK,function(e:MouseEvent):void{graphics.clear()});//double click to clear
stage.addEventListener(Event.ENTER_FRAME,update);//update continuously

function mouseEventHandler(e:MouseEvent):void{
    mousePressed = (e.type == MouseEvent.MOUSE_DOWN);
    graphics.moveTo(mouseX,mouseY);
}
function update(e:Event):void{
    //currPos.setTo(mouseX,mouseY);//this works for flash player 11 and above instead of setting x,y separately
    currPos.x = mouseX;
    currPos.y = mouseY;
    var mappedValue: Number = Point.distance(currPos,prevPos) / (w+h);//map the distance between points
    //prevPos.copyFrom(currPos);//this works for flash player 11 and above instead of setting x,y separately
    prevPos.x = mouseX;
    prevPos.y = mouseY;
    graphics.lineStyle(mappedValue * 100,0,1.0-(0.25+mappedValue));
    if(mousePressed)  graphics.lineTo(mouseX,mouseY);//if the mouse is pressed, keep drawing a line to the current mouse location   
}

所以回到行星路径的追踪,使用图形api,我之前的例子看起来像这样:

import flash.display.*;
import flash.events.Event;
import flash.geom.ColorTransform;
import flash.geom.Point;

var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var hasMoved:Boolean  = false;//has the graphics 'pen' been moved ?
var spheres:Sprite    = addChild(new Sprite()) as Sprite;//add a container for all the spheres (planets/moons/sun/etc.)

var earthPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;

var sun:Sprite     = spheres.addChild(getCircleSprite(69.5500 /4,0xFF9900)) as Sprite;
var earth:Sprite   = earthPivot.addChild(getCircleSprite(60.52 / 4,0x2233FE)) as Sprite;

earth.x   = 14960 / 40;
spheres.x = (w-spheres.width) * 0.5;
spheres.y = (h-spheres.height) * 0.5;

addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
    earthPivot.rotation   += 0.12;
    //draw trails
    drawTrail(earth,0x0000FF);
}

function drawTrail(s:Sprite,color:int) {
    var globalPos:Point = s.localToGlobal(new Point());//convert the local position of the sprite (it might have been nested several times) to the global/stage coordinate system
    if(!hasMoved){//if the graphics 'pen' wasn't moved (is still at 0,0), this will happen only once: the 1st time you draw the mouse position
        graphics.moveTo(globalPos.x,globalPos.y);//move it to where we're about to draw first
        hasMoved = true;//and make sure we've marked that the above was done
    }
    graphics.lineStyle(1,color);
    graphics.lineTo(globalPos.x,globalPos.y);
}

function getCircleSprite(radius:Number,color:int):Sprite{
    var circle:Sprite = new Sprite();
    circle.graphics.beginFill(color);
    circle.graphics.drawCircle(-radius * .5,-radius * .5,radius);//draw from centre
    circle.graphics.endFill();
    return circle;
}

trails with graphics api

根据我的经验,如果你在舞台上有很多行,使用这个旧的绘图API可能会变慢。我说年纪大了,因为现在可能已经15岁了。 Flash Player 10引入了更新的绘图API。您可以在Adobe Devnet上阅读,但我热烈推荐Senocular's Flash Player 10 Drawing API Tutorial和他的slides and example code from Flash Camp

回到像素:它并不那么难。您使用BitmapData类来操作像素并使用Bitmap实例,以便您可以在舞台上添加这些像素。这是一个最小的绘图程序:

var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0xFFFFFF);//setup pixels
addChild(new Bitmap(canvas));//add them to the stage
addEventListener(Event.ENTER_FRAME,update);//setup continuous updates
function update(e:Event):void{
    canvas.setPixel(int(mouseX),int(mouseY),0x990000);//pretty easy, right ?
}

想制作一个有趣的模式,肯定的是,有一个游戏:

var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight,false,0xFFFFFF);//setup pixels
addChild(new Bitmap(canvas));//add them to the stage
addEventListener(Event.ENTER_FRAME,update);//setup continuous updates
function update(e:Event):void{
    canvas.lock();//when updating multiple pixels or making multiple pixel operations
    canvas.perlinNoise(mouseX,mouseY,mouseX/stage.stageWidth * 8,getTimer(),false,true);
    canvas.unlock();//when you're done changing pixels, commit the changes
}

所以,回到小道示例:

var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var canvas:BitmapData = new BitmapData(w,h,false,0xFFFFFF);
addChild(new Bitmap(canvas));
var spheres:Sprite    = addChild(new Sprite()) as Sprite;//add a container for all the spheres (planets/moons/sun/etc.)

var earthPivot:Sprite = spheres.addChild(new Sprite()) as Sprite;

var sun:Sprite     = spheres.addChild(getCircleSprite(69.5500 /4,0xFF9900)) as Sprite;
var earth:Sprite   = earthPivot.addChild(getCircleSprite(60.52 / 4,0x2233FE)) as Sprite;

earth.x   = 14960 / 40;
spheres.x = (w-spheres.width) * 0.5;
spheres.y = (h-spheres.height) * 0.5;

addEventListener(Event.ENTER_FRAME,update);
function update(e:Event):void{
    earthPivot.rotation   += 0.12;
    //draw trails
    drawTrail(earth,0x0000FF,canvas);
}

function drawTrail(s:Sprite,color:int,image:BitmapData) {
    var globalPos:Point = s.localToGlobal(new Point());//convert the local position of the sprite (it might have been nested several times) to the global/stage coordinate system
    image.setPixel(int(globalPos.x),int(globalPos.y),color);//colour a pixel at a set position
}

function getCircleSprite(radius:Number,color:int):Sprite{
    var circle:Sprite = new Sprite();
    circle.graphics.beginFill(color);
    circle.graphics.drawCircle(-radius * .5,-radius * .5,radius);//draw from centre
    circle.graphics.endFill();
    return circle;
}

看起来像这样: trails with pixels

不确定它是否是您想要的,但像素使用起来很有趣,也非常快。 通过一些数学运算,你也可以做一些minimal 3D

另外,对于你在动作中绘画的灵感,你可以看一些Keith Peters',Erik Natzke,Joshua Davis等等。

答案 1 :(得分:0)

不,没有这样的命令,但你总是可以创建一个非常简单的Sprite对象并将其添加到相应位置的舞台上。类似的东西:

var dot:Sprite = new Sprite();
dot.graphics.beginFill(0xCCCCCC);
dot.graphics.drawRect(-1, -1, 2, 2);
dot.graphics.endFill();

dot.x = x;
dot.y = y;
addChild(dot);