我是 ActionScript 3.0 的新手。我在http://www.senocular.com/flash/tutorials/as3withmxmlc/尝试了一个教程。演示程序动画一个球并允许它被拖动。
编写的程序有问题。当您将鼠标拖到舞台外并释放鼠标按钮时,小球不会获得 MOUSE_UP 事件。因此,代码永远不会调用 stopDrag()。我在 stackoverflow 上搜索了建议,其中一个建议是用舞台和球听 MOUSE_UP 并添加一些处理它的逻辑。
我添加了一些代码来做到这一点。我还按照编写的程序重构了程序,因为它非常杂乱无章。这是我现在拥有的:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
public class BallToss extends Sprite {
private var ball:TossableBall;
// mouse position at last call to trackMouseMvt()
private var lastMousePos:Point = new Point();
// delta mouse movement from frame L-1 to frame L, where L is last frame
private var lastDeltaMouse:Point = new Point();
public function BallToss() {
var stageBounds:Rectangle = new Rectangle(0, 0, stage.stageWidth,
stage.stageHeight);
ball = new TossableBall(50, stageBounds);
ball.x = stageBounds.width/2;
ball.y = stageBounds.height/2;
addChild(ball);
ball.addEventListener(MouseEvent.MOUSE_DOWN, grabBall);
// however I order the next two calls to addEventListener(), it seems
// that the ball's MOUSE_UP gets handled before the stage's MOUSE_UP
stage.addEventListener(MouseEvent.MOUSE_UP, handleStageMouseUp);
ball.addEventListener(MouseEvent.MOUSE_UP, releaseBall);
// initialize 'lastMousePos' and set up 'trackMouseMvt' to be called on
// every frame
lastMousePos = new Point(mouseX, mouseY);
ball.addEventListener(Event.ENTER_FRAME, trackMouseMvt);
}
private function grabBall(evt:MouseEvent):void {
trace("in grabBall");
// set ball 'glideVector' to (0,0) so it will stop moving
ball.setGlideVector(new Point(0,0));
ball.startDrag();
}
private function releaseBall(evt:MouseEvent):void {
trace("in releaseBall");
ball.stopDrag();
// set up the ball to glide at the rate of 'lastDeltaMouse'
ball.setGlideVector(lastDeltaMouse);
}
private function trackMouseMvt(evt:Event):void {
var currMouse:Point = new Point(mouseX, mouseY);
lastDeltaMouse = currMouse.subtract(lastMousePos);
lastMousePos = currMouse;
}
private function handleStageMouseUp(evt:Event):void {
trace("in handleStageMouseUp");
ball.stopDrag();
var stageBounds:Rectangle = new Rectangle(0, 0, stage.stageWidth,
stage.stageHeight);
if (ball.x > stageBounds.right - 0.5)
ball.x = stageBounds.right - 0.5;
else if (ball.x < 0)
ball.x = 0;
if (ball.y > stageBounds.bottom - 0.5)
ball.y = stageBounds.bottom - 0.5;
else if (ball.y < 0)
ball.y = 0;
}
}
}
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
import flash.geom.Rectangle;
class TossableBall extends Sprite {
private var stageBounds:Rectangle;
private var glideVector:Point = new Point();
private var friction:Number = .95;
public function TossableBall(size:Number, stageBoundsIn:Rectangle) {
stageBounds = stageBoundsIn;
graphics.lineStyle(1);
graphics.beginFill(0xFF8000);
graphics.drawCircle(0, 0, size/2);
addEventListener(Event.ENTER_FRAME, glide);
}
public function setGlideVector(glideVectorIn:Point):void {
glideVector = glideVectorIn;
}
private function glide(evt:Event):void {
x += glideVector.x;
y += glideVector.y;
var shapeBounds:Rectangle = getBounds(parent);
if (shapeBounds.left < stageBounds.left) {
glideVector.x = Math.abs(glideVector.x);
} else if (shapeBounds.right > stageBounds.right) {
glideVector.x = -Math.abs(glideVector.x);
}
if (shapeBounds.top < stageBounds.top) {
glideVector.y = Math.abs(glideVector.y);
} else if (shapeBounds.bottom > stageBounds.bottom) {
glideVector.y = -Math.abs(glideVector.y);
}
glideVector.x *= friction;
glideVector.y *= friction;
}
}
我不太喜欢这段代码。问题归结为无法在一个地方检测到所有病例。我想写这样的东西:
if (..ball and stage both got MOUSE_UP..) {
..handle it..;
else if (..only stage got MOUSE_UP..) {
..handle it..;
}
这个逻辑会让我写出更万无一失、更简单的案例处理和更清晰的逻辑。从目前的情况来看,这种组织代码的方式会产生很多复杂的行为。
事件监听模型似乎无法做到这一点。对事件的反应必须单独发生,还是必须发生?有没有办法检测“队列中”的事件?
或者,我可以避免使用 startDrag(),即避免使球 Sprite 可拖动,并且只让舞台监听 MOUSE_UP,然后自己处理所有拖动逻辑。这也可以让我更好地处理当用户拖出舞台时我希望球放置在哪里等问题。我想知道这是否总体上更好。