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

use*_*511 0 flash actionscript-3

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

谢谢!

Geo*_*nza 6

我建议每次更新时使用BitmapData的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)
}
Run Code Online (Sandbox Code Playgroud)

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

这是使用多个对象的更长示例:

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;
}
Run Code Online (Sandbox Code Playgroud)

请注意我们打电话,trails.draw(spheres,spheres.transform.concatenatedMatrix,trailsFade);trails.draw(earth,earth.transform.concatenatedMatrix,trailsFade);如果你只是想画出它的踪迹earth.

步道

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

更新

考虑到这一点,如果你开始使用旧的学校Graphics API可能对你很方便,而且还不习惯使用像素.

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

graphics属性Sprites和MovieClip允许您使用简单的命令进行编程绘制,例如:设置笔触(lineStyle()),填充(beginFill()/ endFill()),移动虚构的"笔"而不绘制(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   
}
Run Code Online (Sandbox Code Playgroud)

或更复杂的版本,您使用鼠标移动的速度来影响笔划的厚度和透明度:

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   
}
Run Code Online (Sandbox Code Playgroud)

所以回到行星路径的追踪,使用图形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;
}
Run Code Online (Sandbox Code Playgroud)

带有图形API的小径

根据我的经验,如果你在舞台上有很多台线,使用这个旧的绘图API可能会变慢.我说年纪大了,因为现在可能已经15岁了.Flash Player 10引入了更新的绘图API.你可以在Adobe Devnet上阅读,但我热烈推荐Senocular的Flash Player 10绘图API教程和他的幻灯片以及来自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 ?
}
Run Code Online (Sandbox Code Playgroud)

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

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
}
Run Code Online (Sandbox Code Playgroud)

所以,回到小道示例:

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;
}
Run Code Online (Sandbox Code Playgroud)

看起来像这样: 带像素的小径

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

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