Actionscript 3.0 - 追踪移动体的路径; [英] Actionscript 3.0 - tracing the path of a moving body ;

查看:161
本文介绍了Actionscript 3.0 - 追踪移动体的路径;的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



谢谢!

解决方案

div>

我推荐使用可能对你很方便,如果你开始使用,还不习惯像素播放。 b
$ b

很容易上手:可以在Flash Player中显示的对象可以具有图形属性(请参阅Shape / Sprite / MovieClip类)。 (你可以有显示对象,你不能绘制到你是否可以将元素嵌入(DisplayObjectContainer)或不(DisplayObject),但是你也可以看看其他的东西)。

这个属性Sprites和MovieClip允许你使用简单的命令来绘制程序,比如:设置一个笔画( lineStyle() ),填充( beginFill() / endFill()), ( moveTo ),绘制一条线( lineTo ),一个圆形,一个矩形,一个圆形矩形,等等。这是所有的。

因此,一个最小的绘图程序看起来有点像这样:

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

var mousePressed:Boolean = false; //跟踪鼠标是否被按下
graphics.lineStyle(1); //设置笔划厚度为1其他参数是默认值(颜色:黑色,透明度:100%/ 1.0等))

stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler); //调用鼠标
stage.addEventListener(MouseEvent.MOUSE_UP,mouseEventHandler); // ...和鼠标变化
stage.addEventListener(Event.ENTER_FRAME,更新); //不断更新

function mouseEventHandler e:MouseEvent):void {
mousePressed =(e.type == MouseEvent.MOUSE_DOWN);
graphics.moveTo(mouseX,mouseY); //将图形笔放置在这个新位置

函数更新(e:Event):void {
if( mouseP)graphics.lineTo(mouseX,mouseY); //如果鼠标被按下,继续画一条线到当前的鼠标位置
}

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

  import flash.events.MouseEvent; 
import flash.events.Event;
导入flash.geom.Point;
$ b $ var prevPos:Point = new Point(); //上一个鼠标位置
var currPos:Point = new Point(); //当前鼠标位置
var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var mousePressed:Boolean = false; //跟踪鼠标是否被按下
graphics.lineStyle(1); //设置笔划厚度为1(其他参数为默认值(颜色:黑色,透明度:100%/ 1.0等))
stage.doubleClickEnabled = true;

stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseEventHandler); //调用鼠标
stage.addEventListener(MouseEvent.MOUSE_UP,mouseEventHandler); // ...鼠标变化
stage.addEventListener(MouseEvent.DOUBLE_CLICK,function(e:MouseEvent):void {graphics.clear()}); //双击清除
stage.addEventListener(Event.ENTER_FRAME,update); / /不断更新

函数mouseEventHandler(e:MouseEvent):void {
mousePressed =(e.type == MouseEvent.MOUSE_DOWN);
graphics.moveTo(mouseX,mouseY);

function update(e:Event):void {
//currPos.setTo(mouseX,mouseY);//这个适用于flash player 11及以上版本,而不是设置x,y分别为
currPos.x = mouseX;
currPos.y = mouseY;
var mappedValue:Number = Point.distance(currPos,prevPos)/(w + h); //映射点之间的距离
//prevPos.copyFrom(currPos); //这个适用于flash播放器11及以上,而不是分别设置x,y
prevPos.x = mouseX;
prevPos.y = mouseY;
graphics.lineStyle(mappedValue * 100,0,1.0-(0.25 + mappedValue));
if(mousePressed)graphics.lineTo(mouseX,mouseY); //如果鼠标被按下,继续画一条线到当前的鼠标位置
}



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

  import flash.display。*; 
import flash.events.Event;
import flash.geom.ColorTransform;
导入flash.geom.Point;

var w:Number = stage.stageWidth;
var h:Number = stage.stageHeight;
var hasMoved:Boolean = false; //图形笔被移动了?
var spheres:Sprite = addChild(new Sprite())as Sprite; //为所有球体添加一个容器(planets / moons / sun / etc)

var earthPivot:Sprite = spheres.addChild(新的Sprite())为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;
//绘制轨迹
drawTrail(earth,0x0000FF);


函数drawTrail(s:Sprite,color:int){
var globalPos:Point = s.localToGlobal(new Point()); //将局部位置(它可能已经被嵌套了几次)到全局/舞台坐标系
if(!hasMoved){//如果图形笔没有被移动(仍然在0,0),这只会发生一次:第一次绘制鼠标位置
graphics.moveTo(globalPos.x,globalPos.y); //将其移动到我们将要绘制的位置
hasMoved = true; //并确保我们已经标记了上面已经完成
}
graphics.lineStyle(1,color);
graphics.lineTo(globalPos.x,globalPos.y);


函数getCircleSprite(radius:Number,color:int):Sprite {
var circle:Sprite = new Sprite();
circle.graphics.beginFill(color);
circle.graphics.drawCircle(-radius * .5,-radius * .5,radius); //从中心绘制
circle.graphics.endFill();
返回圆;
}



另外,为了您在动画中的灵感,你可以看看一些,Erik Natzke,Joshua Davis等。

I'm learning AS3.0 currently. I am trying to design a simple two body planet simulation. I need to show the paths of the planets on the screen. So my question is, once I have the updated x and y coordinates for the planets at each Timer interval, how do I change the color of the pixel (x,y) of the stage so that it shows the path of the planets? Is there some command of the form stage.x = color?

Thanks!

解决方案

I recommend using BitmapData's draw() method to render your planets as pixels each time you update them. It basically works like a 'screenshot' of the display object you pass it as n argument. If you pass the objects transformation, the position/rotation/scale will be visible (as opposed to drawing from 0,0). This way, you will only be updating pixels instead of continuously creating new display objects.

Here's a basic commented example:

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)
}

Notice the trails when you move the mouse and how they are affected by the (update) speed.

Here's a longer example using multiple objects:

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;
}

Notice we call trails.draw(spheres,spheres.transform.concatenatedMatrix,trailsFade); but it could be trails.draw(earth,earth.transform.concatenatedMatrix,trailsFade); if you only want to draw the trails of earth.

In the example above I'm just nesting sprites and using the rotation property to keep things simple. You might want to use a bit of trigonometry to update positions because planets will probably not have perfectly circular orbits and pass through the exact location every single time.

Update

Thinking about this more, using the old school Graphics API might be handy for you if you get started and haven't got used to playing with pixels yet.

It's easy to get started with: objects that can be displayed in flash player can have a graphics property (see the Shape/Sprite/MovieClip classes). (You can have display object that you can't draw into whether you can nest elements into (DisplayObjectContainer) or not(DisplayObject), but that's a whole other thing for you too look into).

This graphics property Sprites and MovieClip has allows you to draw programmatically using simply commands such as: setting a stroke(lineStyle()), a fill (beginFill()/endFill()), moving an imaginary 'pen' without drawing (moveTo), drawing a line (lineTo), a circle, a rectangle, a rounded rectangle, etc. It's all there.

So, a minimal drawing program would look a bit like this:

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   
}

or a more complex version where you use the speed of the mouse movement to influence the stroke thickness and transparency:

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   
}

So going back to the tracing of a planet path, using the graphics api, my previous example would look like so:

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;
}

From my experience, using this older drawing API can get slow if you have a lot of lines on stage. I say older because it might actually be 15 years old now. Flash Player 10 introduced a newer drawing API. You can read on it on the Adobe Devnet but I warmly recommend Senocular's Flash Player 10 Drawing API Tutorial and his slides and example code from Flash Camp

Back to pixels: it's not that hard. You use the BitmapData class to manipulate pixels and use a Bitmap instance so you can add those pixels on stage. Here's a minimal drawing program:

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 ?
}

want to make trippy patterns, sure thing, have a play:

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
}

So, back to the trails example:

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;
}

Which looks like this:

Not sure if it's what you want though, but pixels are fun to use and pretty fast too. With a bit of math you can do some minimal 3D as well.

Also, for your inspiration on drawing in actionscript, you can have a look at some of Keith Peters', Erik Natzke, Joshua Davis, etc.

这篇关于Actionscript 3.0 - 追踪移动体的路径;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆