Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Волшебное превращение float в NaN, и как это ловить? (haxe) (http://www.flasher.ru/forum/showthread.php?t=142069)

drnet_ua 12.07.2010 10:23

Волшебное превращение float в NaN, и как это ловить? (haxe)
 
Решил поигратся с АС3, до этого был только АС1-2 на таймлайне в FlashIDE в виде АктивХ оболочки на Делфи(опыта лет 8, всякие презентации, слайдшоу, автораны и тд в ассортименте)

Изучив с чем сейчас можно работать остановился на Haxe+FlashDevelop

Для первой задачи выбрал тему про сталкивающиеся 2д шары.

вроде все красиво... но есть 2 проблеммы и 1 вопрос:

1) мне кажется что шары "дергаются", перепрыгивают из 1 места поля в другое и тд, ведут себя странно вобщем. Пока их мало все красиво
это происходит именно в куске кода расчета столкновений

2) через некоторое время, иногда почти сразу, иногда секунд 15-30+ происходит ситуация, после которой VoloX, VeloY получает значение NaN, после чего все вычисляемые от них параметры также уходят в НаН :( и шар залипает в 0,0 превращаяесь в "черную дыру" :(((

Собственно вопрос, как в Нахе такие ситуации ловить?
т.е. я догадываюсь в чем проблемма в общем виде, но как-то привык что у меня рантайм-еррор выскакивает при неадекватных опперациях типа корня из отрицательного числа.

для удобства весь проект архивом

собственно Код:

BallObject:
Код AS3:

package ;
import flash.display.GradientType;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.Lib;
 
class BallObject extends Sprite
{
        public var Radius:Float;
        public var Color:UInt;
        public var VeloX:Float;
        public var VeloY:Float;
        public var minTop:UInt;
        public var maxBottom:UInt;
        public var minLeft:UInt;
        public var maxRight:UInt;
 
        public function MoveBall()
        {
 
                this.x += VeloX;
                this.y += VeloY;
 
                //wall collisions
                //left
                if (this.x < minLeft) {
                        VeloX = -VeloX;
                        this.x = minLeft;
                } else
                //right
                if (this.x > maxRight) {
                        VeloX = -VeloX;
                        this.x = maxRight;
                }
                //top
                if (this.y < minTop) {
                        VeloY = -VeloY;
                        this.y = minTop;
                } else
                //bottom
                if (this.y > maxBottom) {
                        VeloY = -VeloY;
                        this.y = maxBottom;
                }
 
 
        }
 
 
        private function Render()
 
        {
 
                var m = new Matrix();
        m.createGradientBox(Radius, Radius, 0, -Radius, -Radius);
        graphics.beginGradientFill(GradientType.RADIAL, [0xFFFFFF, Color], [1,1], [0, 0xFF], m);
                graphics.drawCircle(0, 0, Radius);
                graphics.endFill();                       
        }
 
        public function new(StartX,StartY,newRadius,VelX,VelY,newColor,stageHeight,stageWidth)
        {
                super();
                this.x = StartX;
                this.y = StartY;
                Radius = newRadius;
                minLeft = Math.round(Radius)+5;
                maxRight = Math.round(stageWidth - Radius)-5;
                minTop = Math.round(Radius)+5;
                maxBottom = Math.round(stageHeight - Radius)-5;
 
 
                Color = newColor;
                VeloX = VelX;
                VeloY = VelY;                                               
                Render();       
        }
 
}

и

BallManager:

Код AS3:

package ;
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.events.Event;
import flash.geom.Point;
import flash.Lib;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
 
class BallManager extends MovieClip
 
 
 
{
 
        var myStage:MovieClip;
        var balls:Array<BallObject>;
        var wrongCollisions:UInt;
        var rightCollisions:UInt;
        var totalCollisions:UInt;
        //var gui:MyGui;
 
public function BallCollideEx(ball1:BallObject,ball2:BallObject) {
 
                totalCollisions++;
 
                //localize
                var ed:Float = 1;
                var x1:Float = ball1.x; var y1:Float = ball1.y;
                var x2:Float = ball2.x; var y2:Float = ball2.y;
                var vX1:Float = ball1.VeloX; var vY1:Float = ball1.VeloY;
                var vX2:Float = ball2.VeloX; var vY2:Float = ball2.VeloY;
                var r1:Float = ball1.Radius; var r2:Float = ball2.Radius;
                var mass1:Float = 1;
                var mass2:Float = 1;
 
 
                // flashback to collision time
                var dx:Float =  x2 - x1;
                var dy:Float =  y2 - y1;
                var d:Float = Math.sqrt(dx * dx + dy * dy);
 
                if (d < (r1 + r2)) {
                // right collision
                rightCollisions++;
 
                var vp1:Float = vX1 * dx / d + vY1 * dy / d;
                var vp2:Float = vX2 * dx / d + vY2 * dy / d;
 
                var dt:Float = (r1 + r2 - d) / (vp1 - vp2);
 
                // balls collision coordinates;
                x1 -= vX1 * dt;                y1 -= vY1 * dt;
                x2 -= vX2 * dt;                y2 -= vY2 * dt;
 
                // collision
                var dx:Float =  x2 - x1;
                var dy:Float =  y2 - y1;
                var d:Float = Math.sqrt(dx * dx + dy * dy);
 
                // Unit vector in the direction of the collision
                var aX:Float = dx / d;
                var aY:Float = dy / d;
 
                // Projection of the velocities in these axes
                var vA1:Float = (vX1 * aX + vY1 * aY);        var vB1:Float = ( -vX1 * aY + vY1 * aX);
                var vA2:Float = (vX2 * aX + vY2 * aY);        var vB2:Float = ( -vX2 * aY + vY2 * aX);
 
                // New velocities in these axes (after collision): ed<=1,  for elastic collision ed=1
                var vAP1:Float = vA1 + (1 + ed) * (vA2 - vA1) / (1 + mass1 / mass2);
                var vAP2:Float = vA2 + (1 + ed) * (vA1 - vA2) / (1 + mass2 / mass1);
 
                // Undo the projections
                vX1 = vAP1 * aX - vB1 * aY; vY1 = vAP1 * aY + vB1 * aX;
                vX2 = vAP2 * aX - vB2 * aY; vY2 = vAP2 * aY + vB2 * aX;
 
                // move time forward
                x1 += vX1 * dt;                y1 += vY1 * dt;
                x2 += vX2 * dt;                y2 += vY2 * dt;
 
                // restore variables
                ball1.x = x1; ball1.y = y1;
                ball1.VeloX = vX1; ball1.VeloY = vY1;
                ball2.x = x2; ball2.y = y2;
                ball2.VeloX = vX2; ball2.VeloY = vY2;
 
        } else {
                //no collision detected
                wrongCollisions++;
                }
 
}
 
 
public function AddRandomBall(maxHeight,maxWidth):BallObject
        {
                var ColorArray:Array<Int> = [Math.round(Math.random() * 255), Math.round(Math.random() * 255), Math.round(Math.random() * 255)];
                //ColorArray[Math.round(Math.random() * 3)] = 255;
                var Color = ColorArray[2] + ColorArray[1] * 0xff + ColorArray[2] * 0xffff;
 
                var Radius = Math.random() * 5 + 5;
 
                var Angle = Math.random() * 360;
                var Speed = Math.random() * 5 + 1;
                var VeloX = Math.sin(Angle) * Speed;
                var VeloY = Math.cos(Angle) * Speed;               
 
                var BallX = Radius+ Math.random() * (maxWidth-Radius*2);
                var BallY = Radius + Math.random() * (maxHeight-Radius*2);               
 
                return new BallObject(BallX,BallY,Radius,VeloX,VeloY,Color,maxHeight,maxWidth);
 
        }
 
        public function bruteCollide() {
                for (i in 0...balls.length-1) {                       
                        for (j in 0...balls.length-1) {
                                        if (i != j) { BallCollideEx(balls[i], balls[j]);                }
                                        }
                                        }
        }
 
        public function xSortCollide() {
 
                        balls.sort(function (ball1:BallObject, ball2:BallObject):Int return Math.round(ball1.x - ball2.x) );
                        var rad:Float;
                        var xDist:Float;
                        for (i in 0...balls.length - 2) {                                               
                                for (j in i + 1...balls.length - 1) {
                                        rad = balls[j].Radius + balls[i].Radius;
                                        xDist = Math.abs(balls[j].x - balls[i].x);
                                        if (xDist < rad) { BallCollideEx(balls[i], balls[j]); }
                                        else { break; }
 
                                                }
                                        }
                }
public function moveBalls(e:Event) {
 
        var mode:UInt;
        //mode = gui.modeSwitch.mode;
        mode = 1;
        rightCollisions = 0;
        wrongCollisions = 0;
        totalCollisions = 0;
 
        var cur:Float = Lib.getTimer();       
 
        for (i in 0...balls.length - 1) { balls[i].MoveBall(); }
 
        switch (mode) {
 
                        case 0: bruteCollide();
                        case 1: xSortCollide();
 
                        }
 
 
 
        var Elapsed = Lib.getTimer() - cur;
        /*gui.fpsField.text = 'Elapsed: ' + Elapsed + 'ms';
        gui.totalCollisionsField.text = 'Всего проверок: ' + totalCollisions;
        gui.rightCollisionsField.text = 'Правильных столкновений: ' + rightCollisions;
        gui.wrongCollisionsField.text = 'Ложных проверок: ' + wrongCollisions;
        gui.wasteField.text = 'Эффективность: ' + Math.floor(10000*rightCollisions / wrongCollisions)/100 + '%';*/

        }
 
 
        public function new(dst:MovieClip)
        {
        super();
        myStage = dst;
 
        myStage.addChild(this);
        myStage.stage.frameRate = 60;
 
        //maxballs
        var MaxBalls = 350;
        balls = new Array<BallObject>();
 
                for (i in 0...MaxBalls) {
                balls.push(AddRandomBall(dst.stage.stageHeight, dst.stage.stageWidth));
                myStage.addChild(balls[i]);
        }
 
        //gui = new MyGui();
        //myStage.addChild(gui);
        //gui.x = dst.stage.stageWidth - gui.width;
        //gui.y = 0;
 
 
        this.addEventListener(Event.ENTER_FRAME, moveBalls);
 
}
}

и Main
Код AS3:

package ;
 
import flash.display.DisplayObject;
import flash.display.MovieClip;
import flash.Lib;
 
class Main
{
 
        private var Manager: BallManager;
 
        public function new() {
 
 
 
        Manager = new BallManager(Lib.current);
 
        }
        static function main()
        {
        new Main();
        }
 
}


i.o. 12.07.2010 11:07

Цитата:

как это ловить?
ну наверное проверять с помощью isNaN() в "интимных" местах.


Откуда они вообще берутся? Вот возьмем скажем:
Код AS3:

                var d:Float = Math.sqrt(dx * dx + dy * dy);
 
                // Unit vector in the direction of the collision
                var aX:Float = dx / d;
                var aY:Float = dy / d;
 
                // Projection of the velocities in these axes
                var vA1:Float = (vX1 * aX + vY1 * aY);        var vB1:Float = ( -vX1 * aY + vY1 * aX);
                var vA2:Float = (vX2 * aX + vY2 * aY);        var vB2:Float = ( -vX2 * aY + vY2 * aX);

Если d окажется ноликом, то NaN'ом станет:
aX и aY - деление на ноль
vA1, vA2, vB1, vB2 - потому что используют aX или aY, т.е NaN. А при операциях с NaN'ом получается в итоге NaN.

И в коде у вас много лишних объявлений локальных переменных. и еще попадаются переобъявления одних и тех же.


Часовой пояс GMT +4, время: 10:37.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.