Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   actionscript и физика (http://www.flasher.ru/forum/showthread.php?t=167921)

inozemcev 14.09.2011 14:27

actionscript и физика
 
Ребята помогите разобраться с физикой и реализовать задачу пересечения двух векторов.

Задача при пересечении дух векторов - вектора мяча и вектора стены - получить новый вектор мяча.

Сам ориентировался на данную статью. Смог разобраться в терминологии, смог найти точку пересечения, но построить новый вектор не получается. К автору топика уже не обратится. статья старая.

В статье используется ationscript 1 Поэтому сделал несколько отличный код, ввел понятия VectorDara VectorView

Код AS3:

public class VectorData 
{
        private var _start:Point;
        private var _end:Point;
        private var _delta:Point;
 
        private var _ort:Point;
 
        private var _normal_l:VectorData;
        private var _normal_r:VectorData;
 
        public static const END_POINT:Boolean = true;
        public static const DELTA_POINT:Boolean = false;
 
        public function VectorData(start:Point, endOrDelta:Point, type:Boolean = END_POINT) 
        {
                _start = start;
                if (type)
                {
                        _end = endOrDelta;
                        _delta = new Point (_end.x - _start.x, _end.y - _start.y);
                } else {
                        _delta = endOrDelta;
                        _end = new Point (_start.x + _delta.x, _start.y + _delta.y);
                }
        }
 
        public function get start () :Point
        {
                return _start;
        }
 
        public function get delta () :Point
        {
                return _delta;
        }
 
        public function get end () :Point
        {
                return _end;
        }
 
        public function get length () :Number
        {
                return Math.sqrt (delta.x * delta.x + delta.y * delta.y);
        }
 
        public function get ort () :Point
        {
                if (!_ort)
                {
                        _ort = new Point (delta.x / length, delta.y / length);
                }
                return _ort;
        }
 
        public function get rad () :Number
        {
                return Math.atan2 (ort.y, ort.x);
        }
 
        public function get gradus () :Number
        {
                return rad * 180 / Math.PI;
        }
 
        public function get normal_l () :VectorData
        {
                if (!_normal_l)
                {
                        _normal_l = new VectorData(start,new Point (-delta.y, delta.x), VectorData.DELTA_POINT);
                }
                return _normal_l;
        }
 
        public function get normal_r () :VectorData
        {
                if (!_normal_r)
                {
                        _normal_r = new VectorData(start,new Point (delta.y, - delta.x), VectorData.DELTA_POINT);
                }
                return _normal_r;
        }
 
        public static function add (vector1:VectorData, vector2:VectorData) :VectorData
        {
                var newDelta:Point = new Point (vector1.delta.x + vector2.delta.x, vector1.delta.y + vector2.delta.y);
                var newVector:VectorData = new VectorData (vector1.start, newDelta, false);
                return newVector;
        }
 
        public static function cosA (vector1:VectorData, vector2:VectorData) :Number
        {
                return (vector1.ort.x * vector2.ort.x + vector1.ort.y * vector2.ort.y);
        }
 
        public static function scalar (vector1:VectorData, vector2:VectorData) :Number
        {
                return (vector1.length * vector2.length * VectorData.cosA (vector1, vector2))
        }
 
        public static function proection (vector:VectorData, scalarDot:int ) :Point
        {
                var newDelta:Point = new Point (vector.ort.x * scalarDot / vector.length, vector.ort.y * scalarDot / vector.length);
                return newDelta;
        }
 
        public static function intersection (vector1:VectorData, vector2:VectorData) :Point
        {
                var delta3:Point = new Point (vector2.start.x - vector1.start.x, vector2.start.y-vector1.start.y);
                var vector3:VectorData = new VectorData (vector1.start, delta3, DELTA_POINT);
 
                var t:Number = scalarNV (vector3, vector2) / scalarNV (vector1, vector2);
                return new Point (vector1.start.x + vector1.delta.x * t, vector1.start.y + vector1.delta.y * t);
        }
 
        public static function scalarNV (vector1:VectorData, vector2:VectorData) :int
        {
                return vector1.delta.x * vector2.delta.y - vector1.delta.y* vector2.delta.x;
        }
 
        public static function dot (vector1:VectorData, vector2:VectorData) :int
        {
                return vector1.delta.x * vector2.delta.x + vector1.delta.y * vector2.delta.y;
        }
 
}


И собственно главный класс Main
Код AS3:

public class Main extends Sprite 
        {
                private var start:Point;
                private var vectorDatas:Array = [];
 
                public function Main():void
                {
                        if (stage) init();
                        else addEventListener(Event.ADDED_TO_STAGE, init);
                }
 
                private function init(e:Event = null):void
                {
                        removeEventListener(Event.ADDED_TO_STAGE, init);
                        // entry point
 
                        stage.addEventListener (MouseEvent.CLICK, onClick);
                }
 
                private function onClick (event:MouseEvent) :void
                {
                        if (numChildren == 3)
                        {
                                vectorDatas = [];
                                while (numChildren) removeChildAt (0);
                                start = null;
                        }
 
                        var end:Point = new Point (event.stageX, event.stageY);
                        if (start)
                        {
                                var vectorData:VectorData = new VectorData (start, end);
                                //trace ('Vector length : ' + vectorData.length);
 
                                vectorDatas.push(vectorData);
 
                                var vectorView:VectorView = new VectorView (vectorData);
                                addChild (vectorView);
 
                                vectorView.draw ();
                                start = null;
                        } else {
                                start = end;
                        }
 
 
                        if (numChildren == 2)
                        {
 
 
                                vectorData = makeBounce (vectorDatas[0], vectorDatas[1]);
                                vectorView = new VectorView (vectorData);
                                vectorView.draw (1, 0xCCCC00, 1);
                                addChild (vectorView);
                        }
                }
 
                private function makeBounce (vector1:VectorData, vector2:VectorData) :VectorData
                {
                        var iPoint:Point = VectorData.intersection (vector1, vector2);
 
                        var dot_v1_v2:int = VectorData.dot (vector1, vector2);
                        var dot_v1_v2_left:int = VectorData.dot (vector1, vector2.normal_l);
 
                        var proectionV2:Point = VectorData.proection (vector2, dot_v1_v2);
                        var proectionV2left:Point = VectorData.proection (vector2, dot_v1_v2_left);
 
                        proectionV2left.x *= -1;
                        proectionV2left.y *= -1;
 
                        var newVectorDelta:Point = new Point(proectionV2.x + proectionV2left.x, proectionV2.y + proectionV2left.y);
                        var newVector:VectorData = new VectorData (iPoint, newVectorDelta, VectorData.DELTA_POINT);
                        return newVector;
                }
 
                /*
                private function createVector (start:Point, endOrDelta:Point, color:int, type:Boolean = VectorData.END_POINT) :VectorView
                {
                        var vectorData:VectorData = new VectorData (start, endOrDelta, type);
                        var vectorView:VectorView = new VectorView (vectorData);
                        vectorView.draw (1, color, 1);
                        return vectorView;
                }
                */

        }


TanaTiX 14.09.2011 15:02

Поищи в сети Д. Когнер. Физика для разработчиков компьютерных игр. Примеры там правда на С++. Но понимание принципов обеспечит. А правильный код появится если еще и доке поковыряться.

botbot 14.09.2011 15:25

Код стрёмный. Проще возьми готовый физический движёк, их куча есть. Box2D например, самый популярный. Ну а если надо разобраться самому детально - курс линейной алгебры, для начала.
Например, то что ты называешь вектором на самом деле отрезок из двух точек, т.е. 4 числа. А вектор, это всего 2 числа. Вот для примера тебе код вектора с дижка glaze, у меня он под рукой как раз:
Код AS3:

// glaze - 2D rigid body dynamics & game engine
// Copyright (c) 2010, Richard Jewson
//
// This project also contains work derived from the Chipmunk & APE physics engines. 
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//  this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//  this list of conditions and the following disclaimer in the documentation
//  and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
package org.rje.glaze.engine.math {
 
        import flash.geom.Point;
 
        /**
        * 2D Vector class (linked list enabled)
        * Used hold the x,y values of a vector.  Contains many util functions that are often
        * inlined for performance reasons.
        */

        public class Vector2D {
 
                /**
                * X Axis component of this vector
                */

                public var x:Number;
 
                /**
                * Y Axis component of this vector
                */

                public var y:Number;
 
                /**
                * Linked list pointer.
                */

                public var next:Vector2D;
 
                /**
                * Arbitary flag.  Used by the Enhanced collision detector to find contact points in 1 pass.
                */

                public var flag:Boolean;
 
                public function Vector2D(px:Number = 0, py:Number = 0) {
                        x = px;
                        y = py;
                }
 
                public function clone():Vector2D {
                        return new Vector2D(this.x,this.y);
                }
 
                public function setTo(px:Number, py:Number):void {
                        x = px;
                        y = py;
                }
 
                public function copy(v:Vector2D):void {
                        x = v.x;
                        y = v.y;
                }
 
                public function dot(v:Vector2D):Number {
                        return x * v.x + y * v.y;
                }
 
                public function cross(v:Vector2D):Number {
                        return x * v.y - y * v.x;
                }
 
                public function plus(v:Vector2D):Vector2D {
                        return new Vector2D(x + v.x, y + v.y);
                }
 
                public function plusEquals(v:Vector2D):Vector2D {
                        x += v.x;
                        y += v.y;
                        return this;
                }
 
                public function minus(v:Vector2D):Vector2D {
                        return new Vector2D(x - v.x, y - v.y);   
                }
 
                public function minusEquals(v:Vector2D):Vector2D {
                        x -= v.x;
                        y -= v.y;
                        return this;
                }
 
                public function mult(s:Number):Vector2D {
                        return new Vector2D(x * s, y * s);
                }
 
                public function multEquals(s:Number):Vector2D {
                        x *= s;
                        y *= s;
                        return this;
                }
 
                public function times(v:Vector2D):Vector2D {
                        return new Vector2D(x * v.x, y * v.y);
                }
 
                public function timesEquals(v:Vector2D):Vector2D {
                        x *= v.x;
                        y *= v.y;
                        return this;
                }
 
                public function div(s:Number):Vector2D {
                        if (s == 0) s = 0.0001;
                        return new Vector2D( x / s , y / s );
                }
 
                public function divEquals(s:Number):Vector2D {
                        if (s == 0) s = 0.0001;
                        x /= s;
                        y /= s;
                        return this;
                }
 
                public function magnitude():Number {
                        return Math.sqrt(x * x + y * y);
                }
 
                public function distance(v:Vector2D):Number {
                        var delta:Vector2D = this.minus(v);
                        return delta.magnitude();
                }
 
                public function normalize():Vector2D {
                        var m:Number = magnitude();
                        if (m == 0) m = 0.0001;
                        return mult(1 / m);
                }
 
                public function normalizeEquals():Vector2D {
                        var m:Number = magnitude();
                        if (m == 0) m = 0.0001;
                        return multEquals(1 / m);
                }               
 
                public function leftHandNormal():Vector2D {
                        return new Vector2D(this.y,-this.x);
                }
 
                public function rightHandNormal():Vector2D {
                        return new Vector2D(-this.y,this.x);
                }
 
                public function clampMax( max:Number ):Vector2D {
                        var l:Number = magnitude();
                        if (l>max) {
                                multEquals(max/l);
                        }
                        return this;
                }
 
                public function abs():Vector2D {
                        return new Vector2D( (this.x < 0) ? -this.x : this.x, (this.y < 0) ? -this.y : this.y);
                }
 
                public function interpEquals( blend:Number , v:Vector2D ):Vector2D {
                        this.x = this.x + blend * (v.x - this.x);
                        this.y = this.y + blend * (v.y - this.y);
                        return this;
                }
 
                public function projectOnto( v:Vector2D ):Vector2D {
                        var dp:Number = this.dot(v);
                        var f:Number  = dp / ( v.x*v.x + v.y*v.y );
                        return new Vector2D( f*v.x , f*v.y);
                }
 
                public function angle( v:Vector2D ):Number {
                        return Math.atan2( this.cross(v), this.dot(v) );
                }
 
                public static function forAngle( a:Number ):Vector2D {
                        return new Vector2D(Math.cos(a), Math.sin(a));
                }
 
                public function forAngleEquals( a:Number ):void {
                        this.x = Math.cos(a);
                        this.y = Math.sin(a);
                }
 
                public function rotateByVector(v:Vector2D):Vector2D {
                return new Vector2D(this.x * v.x - this.y * v.y, this.x * v.y + this.y * v.x);
            }
 
                public function rotate(angle:Number):Vector2D {
                        var a:Number = angle * Math.PI / 180;
                        var cos:Number = Math.cos(a);
                        var sin:Number = Math.sin(a);
                        return new Vector2D( (cos*x) - (sin*y) , (cos*y) + (sin*x) );
                }
 
                public function rotateAbout( angle:Number , point:Vector2D ):Vector2D {                       
                        var d:Vector2D = this.minus(point).rotate(angle);
                        this.x = point.x + d.x;
                        this.y = point.y + d.y;
                        return this;
                }
 
                public function rotateEquals(angle:Number):Vector2D {
                        var a:Number = angle * Math.PI / 180;
                        //var a:Number = angle;
                        var cos:Number = Math.cos(a);
                        var sin:Number = Math.sin(a);
                        var rx:Number  = (cos*x) - (sin*y);
                        var ry:Number  = (cos*y) + (sin*x);
                        this.x = rx;
                        this.y = ry;
                        return this;
                }
 
                public static function createVectorArray( len:int ):Array {
                        var vectorArray:Array = new Array();
                        for (var i:int = 0; i < len; i++) {
                                vectorArray[i] = new Vector2D(0, 0);
                        }
                        return vectorArray;
                }
 
                public function equalsZero():Boolean {
                        return this.x == this.y == 0;
                }
 
                public function toPoint():Point {
                        return new Point(x,y);
                }
 
                public function toString():String {
                        return (x + ":" + y);
                }
 
                public static function fromString( str:String ):Vector2D {
                        if (str==null)
                                return null;
                        var vectorParts:Array = str.split(":");
                        if ((vectorParts==null)||(vectorParts.length!=2))
                                return null;
                        var xVal:Number = parseFloat( vectorParts[0] );
                        var yVal:Number = parseFloat( vectorParts[1] );
                        if ( (isNaN(xVal)) || (isNaN(yVal)) )
                                return null;
                        return new Vector2D( xVal , yVal  );
                }
 
                public static const zeroVect:Vector2D = new Vector2D(0, 0);
 
        }
}

Это - вектор в чистом виде.

inozemcev 14.09.2011 16:20

Код AS3:

public function dot(v:Vector2D):Number
 {
        return x * v.x + y * v.y;
}
 
public function cross(v:Vector2D):Number
 {
        return x * v.y - y * v.x;
}

Можете прояснить, что возвращают эти функции

willis83 14.09.2011 16:32

странно, я вот не понимаю почему вектор это одна точка? Вектор же направленный, т.е. это или пара точек или точка и угол(для 2D пространства). Просто не пойму тогда разницу между точкой и вектором2Д.
Как вектором можно задать направление если это точка?

TanaTiX 14.09.2011 16:33

Если удобно считать вектор состоящим из 2х точек, добавьте одну сами. Координаты у нее будет всегда в точке (0; 0). А вообще не нужно путать отрезок с направлением.

botbot 14.09.2011 16:44

Цитата:

Сообщение от willis83 (Сообщение 1031434)
странно, я вот не понимаю почему вектор это одна точка? Вектор же направленный, т.е. это или пара точек или точка и угол(для 2D пространства). Просто не пойму тогда разницу между точкой и вектором2Д.
Как вектором можно задать направление если это точка?

Просто высокий уровень абстракции. Грубо говоря, отделяют мух от котлет. Да, по описанию вектор и есть точка, только в векторном пространстве. Вектор должен задавать направление и длину. А для их задания в двумерном пространстве хватает двух чисел, остальное - лишнее, частные случаи. Начало вектора всегда считается (0, 0), как уже написали. Это сделано, чтобы его можно было "приложить" к любому месту. Например, к объекту в точке (3,4) или у объекту в точке (4, 6). Понимаете разницу?

inozemcev 14.09.2011 16:49

Цитата:

Сообщение от willis83 (Сообщение 1031434)
странно, я вот не понимаю почему вектор это одна точка? Вектор же направленный, т.е. это или пара точек или точка и угол(для 2D пространства). Просто не пойму тогда разницу между точкой и вектором2Д.
Как вектором можно задать направление если это точка?

Я так понимаю вектор в физических движках задается дельтой, то есть разницей между конечными и начальными координатами X и Y, в этом случае начальной точкой всегда будет (0,0). И имея некую точку в пространстве, к ней можно применить вектор тем самым получим отрезок, из начальной и конечной точек.

Добавлено через 1 минуту
Так давайте без отсылок к какой либо литературе постараемся решить эту задачу на месте! Есть два вектора, если нужно описать их только одной точкой - то это свойство delta. Я могу вычислить угол между ними, могу найти нормализованные вектора (с длинной равной 1), могу вычислить их длину, могу построить нормали, могу найти точку где пересекаются прямые. Осталось немного )

botbot 14.09.2011 16:51

Цитата:

Сообщение от inozemcev (Сообщение 1031428)
Код AS3:

public function dot(v:Vector2D):Number
 {
        return x * v.x + y * v.y;
}
 
public function cross(v:Vector2D):Number
 {
        return x * v.y - y * v.x;
}

Можете прояснить, что возвращают эти функции

Честно говоря незнаю, второе похоже на векторное произведение, а первое - оператор "точка", видимо. В общем это математические операции над векторами, нужны для всяких там приложений сил и определений пересечений.

Добавлено через 59 секунд
Цитата:

Сообщение от inozemcev (Сообщение 1031439)
Я так понимаю вектор в физических движках задается дельтой, то есть разницей между конечными и начальными координатами X и Y, в этом случае начальной точкой всегда будет (0,0). И имея некую точку в пространстве, к ней можно применить вектор тем самым получим отрезок, из начальной и конечной точек.

Добавлено через 1 минуту
Так давайте без отсылок к какой либо литературе постараемся решить эту задачу на месте!

Что решать, вы уже дали правильный ответ.

inozemcev 14.09.2011 17:02

Я имел ввиду задачу пересечения двух векторов и построение нового вектора


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

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