Показать сообщение отдельно
Старый 13.09.2014, 19:45
ntro123123 вне форума Посмотреть профиль Отправить личное сообщение для ntro123123 Найти все сообщения от ntro123123
  № 1  
Ответить с цитированием
ntro123123

Регистрация: May 2009
Сообщений: 47
По умолчанию MVC, ООП, AS3 учусь на примере 2D движка

Цели:
понять что такое MVC и ООП
научиться кодить на AS3

Решение:
написать скрипт/проект по следующему ТЗ:
Цитата:
Написать программу с применением ООП в MVC. Шарик (X, Y, масса, коэф. упругости, радиус и цвет(hex) указаны в data/set.txt) "пинается" курсором и падает на землю по физ. законам, вместе с отскоком от стены и земли.


Не реализовано в проекте:
отскок (вместо него костыль который обнуляет скорость, когда шарик касается "пол" сцены)

Много где костылей, много где не доделано. Основная задача разобраться с AS3, MVC.
Результат (+прикрепил весь проект as.rar):
mvc/Main.as
Код AS3:
package mvc
{
	import flash.display.Sprite;
	import mvc.*;
 
	public class Main extends Sprite
	{
		private var _model:Model;
		private var _view:Viewer;
		private var _controller:Controller;
 
		public function Main()
		{
			_model = new Model(stage); // я так понимаю с точки зрения MVC я сделал крупную ошибку передав всю сцену? см. 118-119 строки модели
 
			_view = new Viewer(_model);
			super.addChild(_view);
 
			_controller = new Controller(_view, _model);
		}
	}
}
mvc/Controller.as
Код AS3:
package mvc
{
	import flash.events.*;
	import flash.utils.Timer;
 
	public class Controller extends EventDispatcher
	{
		private var _model:Model;
		private var _view:Viewer;
 
		public function Controller(view:Viewer, model:Model)
		{
			_view = view;
			_model = model;
 
			_view.stage.getChildByName('root1').addEventListener(MouseEvent.CLICK, _model.getDataObj);  // так и не понял, почему root1 название? вроде везде mc_create
			_model.loadData.addEventListener(Event.COMPLETE, _model.createObj); // после загрузки txt файла с параметрами, вызываем метод создания шара
			_model.addEventListener('sharCreated', _view.addObj);
			_view.addEventListener('sharShowed', InitEvents);
		}
 
		private function InitEvents(e:Event):void
		{
			_model.currentShar.addEventListener(Event.ENTER_FRAME, _model.passivMove);
			_model.currentShar.Obj.addEventListener(MouseEvent.MOUSE_OVER, _model.mouseMove);
			var time:Timer=new Timer(50, 0); // каждые 50 мс вычисляем скорость мыши по текущим и предыдущим координатам
			time.addEventListener(TimerEvent.TIMER, _model.OnTimeCursorV);
			time.start();
		}
	}
}

mvc/Model.as
Код AS3:
package mvc
{
	import flash.events.*;
	import objects.Shar;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	import flash.events.EventDispatcher;
	import flash.display.Stage;
 
	public class Model extends EventDispatcher
	{
		public var currentShar:Shar;
		public var loadData:URLLoader=new URLLoader();
		private var stage:Stage;
 
		private const CURSOR_WEIGHT:Number=5; //масса шарика
		private var g:Number; // сила тяжесть
		private var stageWidth:uint;
		private var stageHeight:uint;
 
		private var cursorV:Number=0; // сохраненная скорость мыши в момент столкновения
		private var cursorCurrentV:Number=0; // текущая(мгновенная) скорость мыши
		private var cursorLastX:Number;
		private var cursorLastY:Number;
		private var lastLocalX:Number=0;
		private var lastLocalY:Number=0;
 
		public function Model(stage:Stage)
		{
			this.stage=stage; // я так понимаю с точки зрения MVC я сделал крупную ошибку передав всю сцену? см. 118-119 строки
 
			this.g=10/stage.frameRate; // сила тяжесть
			this.stageWidth=stage.stageWidth;
			this.stageHeight=stage.stageHeight;
			this.cursorLastX=stageWidth/2;
			this.cursorLastY=stageHeight/2;
		}
 
		public function getDataObj(e:Event):void
		{
			e.target.stage.getChildByName('root1').removeEventListener(MouseEvent.CLICK, getDataObj);
			//e.target.stage.removeChild(e.target.stage.getChildByName('root1')); // удаление кнопки, почемуто если удалить кнопку, то все перестает работать
			loadData.load(new URLRequest('data/set.txt')); // считали параметры шара из файла
		}
 
		public function createObj(e:Event = null):void
		{
			var arr:Array=new Array();
			arr=loadData.data.split(';');
			currentShar=new Shar({ // создали экземпляр шара по параметрам из файла (класс objects/Shar.as)
					X:arr[0],
					Y:arr[1],
					M:arr[2],
					E:arr[3],
					R:arr[4],
					C:arr[5]
				});
			dispatchEvent(new Event('sharCreated'));
		}
 
		public function passivMove(e:Event):void
		{
			var shar:Object=e.target;
 
 
			// сохраненная скорость мыши при столкновении постепенно уменьшается до 0
 
			if(this.cursorV>0) 
				this.cursorV-=g;
			else if(this.cursorV<0)
				this.cursorV=0;
 
			var Fc:Number=this.CURSOR_WEIGHT*this.cursorV; // вычислить вектор столкновения мыши с шариком (если мышь не сталкивалась тоthis.cursorV=0 и вектор=0)
			var XFc:Number=(lastLocalX/shar.R)*Fc;
			var YFc:Number=(-lastLocalY/shar.R)*Fc;
 
 
			var Fs:Number=shar.M*shar.V; // вычисляем mg
			var XFs:Number=0*Fs; // знаю что бессмысленно умножать на 0, но с точки зрения физики так понятней, сейчас разговор идет исключительно про MVC и ООП
			var YFs:Number=1*Fs;
 
 
			var Nx:Number=XFs+XFc; // вычисляем новый результирующий вектор
			var Ny:Number=YFs+YFc;
 
			shar.direc=Math.atan2(Ny, -Nx); // вычисляем новый угол движения шара
			shar.A=Math.sqrt(Ny*Ny+Nx*Nx)*0.05; // вычисляем скалярную величину нового векутор (0.05 - коэф. ибо без него слишком быстро меняеться)
			shar.V+=shar.A; // изменяем скорость шарика
 
			shar.X+=shar.V*Math.cos(shar.direc); // изменяем координаты, лучше делать через _viewer.updateObj ?
			shar.Y+=shar.V*Math.sin(shar.direc); // изменяем координаты, лучше делать через _viewer.updateObj ?
 
 
			// далее идут вычисления границу сцены и предотвращения ухода за них шара
 
			if(shar.Y+shar.R>=stageHeight)
			{
				shar.Y=stageHeight-shar.R;
				shar.V=0; // сбрасываем скорость на 0, когда шар упал вниз сцены, правильнее будет делать отскок от сцены за счет изменения shar.direc
			}
			if(shar.Y-shar.R<=0)
			{
				shar.Y=shar.R;
				shar.V=0; // если уперся в потолок, тоже сбрасываем скорость на 0, в идеале опять же сделать отскок
			}
			if(shar.X+shar.R>=stageWidth)
			{
				shar.X=stageWidth-shar.R;
			}
			if(shar.X-shar.R<=0)
			{
				shar.X=shar.R;
			}
		}
 
		public function OnTimeCursorV(e:TimerEvent):void
		{
			var dX:Number=Math.abs(stage.mouseX-cursorLastX); // через таймер же не предать stage.mouseX, он нужен для вычисления скорости мышки за счет измерения изменения координат курсора
			var dY:Number=Math.abs(stage.mouseY-cursorLastY);
			this.cursorCurrentV=Math.sqrt(dX*dX+dY*dY); // мгновенная скорость см. 127 строку
			this.cursorLastX=stage.mouseX;
			this.cursorLastY=stage.mouseY;
		}	
 
		public function mouseMove(e:MouseEvent):void
		{
			this.cursorV=this.cursorCurrentV; // мгновенная становиться текущуй скоростью, и используеться в расчетах именно она в момент сталкнвовения с мыщью
			this.lastLocalX=e.localX; // сохраняем координаты мыши для вычисления вектора силы мыши
			this.lastLocalY=e.localY;
		}
	}
}
mvc/Viewer.as
Код AS3:
package mvc
{
	import flash.display.Sprite;
	import flash.events.*;
	import objects.Shar;
 
 
	public class Viewer extends Sprite
	{
		private var _model:Model;
 
		public function Viewer(model:Model)
		{
			_model=model;
		}
 
		public function addObj(e:Event):void
		{
			addChild(e.target.currentShar.Obj);
			dispatchEvent(new Event('sharShowed'));
		}
 
		public function updateObj(x:Number, y:Number) // пожалуй, этим должен заниматься вьювер, но как туда предать параметры через контроллер? Или можно передать ссылку на сам вьювер?
		{
			_model.currentShar.X=x;
			_model.currentShar.Y=y;
		}
	}
}
objects/Shar.as
Код AS3:
package objects
{
	import flash.display.Sprite;
 
	public class Shar extends Sprite
	{
		private var _obj:Sprite=new Sprite();
		private var _X:Number;
		private var _Y:Number;
		private var _M:Number;
		private var _E:Number;
		private var _R:uint;
		private var _C:uint;
		private var _V:Number=1;
		private var _A:Number;
		private var _direc:Number=1.5*Math.PI;
 
		public function Shar(param:Object)
		{
			this.M=param.M;
			this.E=param.E;
			this.C=param.C;
			this.Obj.graphics.drawCircle(0, 0, param.R);
			this.R=param.R;
			this.X=param.X;
			this.Y=param.Y;
		}
 
		public function get Obj():Object
		{
			return this._obj;
		}
 
		public function set X(X:Number):void
		{
			_X=X;
			this.Obj.x=X;
		}
 
		public function get X():Number
		{
			return _X;
		}	
 
		public function set Y(Y:Number):void
		{
			_Y=Y;
			this.Obj.y=Y;
		}
 
		public function get Y():Number
		{
			return _Y;
		}	
 
		public function set R(r:uint):void
		{
			_R=r;
			this.Obj.width=r*2;
			this.Obj.height=r*2;
		}
 
		public function get R():uint
		{
			return _R;
		}
 
		public function set C(c:uint):void
		{
			_C=c;
			this.Obj.graphics.beginFill(c);
		}
 
		public function get C():uint
		{
			return _C;
		}	
 
		public function set E(e:Number):void
		{
			_E=e;
		}
 
		public function get E():Number
		{
			return _E;
		}
 
		public function set M(m:Number):void
		{
			_M=m;
		}
 
		public function get M():Number
		{
			return _M;
		}
 
		public function set V(v:Number):void
		{
			_V=v;
		}
 
		public function get V():Number
		{
			return _V;
		}
 
		public function set A(a:Number):void
		{
			_A=a;
		}
 
		public function get A():Number
		{
			return _A;
		}
 
		public function set direc(d:Number):void
		{
			_direc=d;
		}
 
		public function get direc():Number
		{
			return _direc;
		}
	}
}
(упс, спойлер не пашет)

Вопросы:
как все поняли в AS я новичок, хотел бы, чтобы меня тыкнули носом в мои ошибки (все, кроме физики объекта), и услышать как бы вы реализовали с точки зрения MVC данный проект, какие есть направления MVC и т.п.

P. S. "движка" громко сказано =)