пятница, 23 октября 2009 г.

Flash actionscript 3 trim()


var str:String=" Privet ";
str=str.replace(/^\s+|\s+$/g, "");
trace (str) // output:Privet
//©Copyright by Sergey Kruk

среда, 23 сентября 2009 г.

Вселенная Away3d - Эпизод 7 : Планетарий

Давно хотел полетать в космосе, еще с журнала "Техника Молодежи" с космонавтом Пуховым (кто знает тот поймет). И вот смастерил на Away3d два планетария, первый - Солнце и Земля причем вторая является центром :) (Солнце - текстура и GlowFilter, Земля - две сферы одна непосредственно земля, вторая - облака которые крутятся вокруг земли и GlowFilter).

package {
import away3d.cameras.HoverCamera3D;
import away3d.containers.Scene3D;
import away3d.containers.View3D;
import away3d.core.utils.Cast;
import away3d.materials.BitmapMaterial;
import away3d.primitives.Sphere;

import com.adobe.viewsource.ViewSource;

import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.filters.GlowFilter;
import flash.geom.Point;

[SWF (width="800",height="600",frameRate="31",backgroundColor="0xafafaf")]

public class SolarSystem extends Sprite
{
[Embed (source="assets/sun_diffuse.jpg")]
private var sunDiffuseTxx:Class;
[Embed (source="assets/earth_diffuse.png")]
private var earthDiffuseTxx:Class;
[Embed (source="assets/earth_clouds_diffuse.png")]
private var earthCloudsDiffuseTxx:Class;
[Embed (source="assets/earthcloudmap.png")]
private var earthCloudsDiffuseTxx2:Class;
[Embed (source="assets/star_map_small.jpg")]
private var starsTxx:Class;


private var view:View3D;
private var camera:HoverCamera3D;

private var earth:Sphere;
private var sun:Sphere;
private var earthClouds:Sphere;

public function SolarSystem()
{
ViewSource.addMenuItem(this, "srcview/index.html");
init();
}

private function init():void
{
view=new View3D;
view.x=stage.stageWidth/2;
view.y=stage.stageHeight/2;
addChild(view);

var scene:Scene3D=new Scene3D;
view.scene=scene;


camera= new HoverCamera3D();
view.camera=camera;
camera.distance=1000;
camera.z=-400;
camera.targetpanangle = camera.panangle = 0;
camera.targettiltangle = camera.tiltangle = 0;
camera.zoom=4;
camera.focus=200;
camera.mintiltangle=-60
camera.maxtiltangle=60;
camera.hover()

earth=new Sphere({radius:150,segmentsW:16,segmentsH:16});
earth.material=new BitmapMaterial(Cast.bitmap(new earthDiffuseTxx));
earth.ownCanvas=true;
earth.filters=[new GlowFilter(0x00ddff,0.5,10,10,5)]
view.scene.addChild(earth);


earthClouds=new Sphere({radius:153,segmentsW:16,segmentsH:16});
earthClouds.material=new BitmapMaterial(Cast.bitmap(new earthCloudsDiffuseTxx2));
(earthClouds.material as BitmapMaterial).smooth=true;
view.scene.addChild(earthClouds);
earthClouds.addOnMouseUp(onEarthMouseUp);

sun = new Sphere({radius:50,x:0,y:0,z:600,segmentsH:16, segmentsW:16});
sun.material=new BitmapMaterial(Cast.bitmap(new sunDiffuseTxx));
sun.ownCanvas=true;
sun.filters=[new GlowFilter(0xffeeaa,0.7,15,15,10,3)]
view.scene.addChild(sun);
sun.addOnMouseUp(onSunMouseUp);

var stars:Sphere=new Sphere({radius:4000,segmentsW:9,segmentsH:9});
stars.scaleX = -1;
stars.material=new BitmapMaterial(Cast.bitmap(new starsTxx));
view.scene.addChild(stars);

addEventListener(Event.ENTER_FRAME,renderLoop);
stage.addEventListener(MouseEvent.MOUSE_DOWN,onMD);
stage.addEventListener(MouseEvent.MOUSE_UP,onMU);

}

private function onEarthMouseUp(e:*):void
{
camera.target=earth;
}

private function onSunMouseUp(e:*):void
{
camera.target=sun;
}

private var sunRadialAngle:Number=0;
private var sunRadialSpeed:Number=0.01;
private function renderLoop(e:*):void
{
earthClouds.rotationY+=0.15;

sunRadialAngle+=sunRadialSpeed;
sun.x=600*Math.cos(sunRadialAngle);
sun.z=600*Math.sin(sunRadialAngle);

camera.hover();
view.render();
}
private var prevMousePos:Point=new Point;
private var prevCameraAngles:Point=new Point;
private function onMD(e:*):void
{
prevMousePos.x=mouseX;
prevMousePos.y=mouseY;
prevCameraAngles.x=camera.targetpanangle;
prevCameraAngles.y=camera.targettiltangle;
addEventListener(Event.ENTER_FRAME,calculateCameraPosition)
}
private function onMU(e:*):void
{
removeEventListener(Event.ENTER_FRAME,calculateCameraPosition)
}
private function calculateCameraPosition(e:*):void
{
var camSpeed:Number=0.4;
camera.targetpanangle=(mouseX-prevMousePos.x)*camSpeed+prevCameraAngles.x;
camera.targettiltangle=(mouseY-prevMousePos.y)*camSpeed+prevCameraAngles.y;
}
}
}


Посмотреть


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

package {
import away3d.cameras.TargetCamera3D;
import away3d.containers.Scene3D;
import away3d.containers.View3D;
import away3d.core.base.Object3D;
import away3d.core.math.Number3D;
import away3d.core.utils.Cast;
import away3d.events.MouseEvent3D;
import away3d.materials.BitmapMaterial;
import away3d.primitives.Sphere;

import com.adobe.viewsource.ViewSource;

import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;

[SWF (width="1000",height="600",frameRate="31",backgroundColor="0xafafaf")]

public class SolarSystem2 extends Sprite
{
[Embed (source="assets/starmap.png")]
private var starmap:Class

[Embed (source="assets/sunmap.jpg")]
private var sunmap:Class

[Embed (source="assets/mercurymap.jpg")]
private var mercurymap:Class

[Embed (source="assets/venusmap.jpg")]
private var venusmap:Class

[Embed (source="assets/earthmap.png")]
private var earthmap:Class

[Embed (source="assets/marsmap.jpg")]
private var marsmap:Class

[Embed (source="assets/jupitermap.jpg")]
private var jupitermap:Class

[Embed (source="assets/saturnmap.jpg")]
private var saturnmap:Class

[Embed (source="assets/uranusmap.jpg")]
private var uranmap:Class

[Embed (source="assets/neptunemap.jpg")]
private var neptunmap:Class

[Embed (source="assets/plutomap.jpg")]
private var plutonmap:Class

private var view:View3D;
private var camera:TargetCamera3D;
private var skybodies:Array=[]

public function SolarSystem2()
{
ViewSource.addMenuItem(this, "srcview/index.html");
initSpace();
initPlanets();
}

private function initSpace():void
{
view=new View3D;
view.x=stage.stageWidth/2;
view.y=stage.stageHeight/2;
addChild(view);

var scene:Scene3D=new Scene3D;
view.scene=scene;


camera= new TargetCamera3D();
view.camera=camera;
camera.z=-1000;
camera.zoom=2;
camera.focus=200;

// sky
var sky:Sphere=new Sphere({radius:70000});
sky.segmentsW=18;
sky.segmentsH=8;
sky.material=new BitmapMaterial(Cast.bitmap(new starmap));
sky.scaleX=-1;
view.scene.addChild(sky);

// render and interaction
addEventListener(Event.ENTER_FRAME,renderLoop);
stage.addEventListener(MouseEvent.MOUSE_DOWN,onMD);
stage.addEventListener(MouseEvent.MOUSE_UP,onMU);
}

private function initPlanets():void
{
var curr:SkyBody;
// sun
curr=new SkyBody(670,24,16,0,0,0);
curr.body.material=new BitmapMaterial(Cast.bitmap(new sunmap));
view.scene.addChild(curr.body);
skybodies.push(curr);

// mercury 88 days = 0.05 radians
curr=new SkyBody(10,12,12,0,710,0.05);
curr.body.material=new BitmapMaterial(Cast.bitmap(new mercurymap));
view.scene.addChild(curr.body);
skybodies.push(curr);

// venus 224 days
curr=new SkyBody(60,12,12,Math.random()*Math.PI*2,1080,0.05/3);
curr.body.material=new BitmapMaterial(Cast.bitmap(new venusmap));
view.scene.addChild(curr.body);
skybodies.push(curr);

// earth
curr=new SkyBody(70,12,12,Math.random()*Math.PI*2,1500,0.05/4);
curr.body.material=new BitmapMaterial(Cast.bitmap(new earthmap));
view.scene.addChild(curr.body);
skybodies.push(curr);

// mars
curr=new SkyBody(33,12,12,Math.random()*Math.PI*2,2280,0.05/8);
curr.body.material=new BitmapMaterial(Cast.bitmap(new marsmap));
view.scene.addChild(curr.body);
skybodies.push(curr);

// jupiter (real 770)
curr=new SkyBody(770,13,13,Math.random()*Math.PI*2,7780,0.05/4/12);
curr.body.material=new BitmapMaterial(Cast.bitmap(new jupitermap));
view.scene.addChild(curr.body);
skybodies.push(curr);

// saturn
curr=new SkyBody(603,12,12,Math.random()*Math.PI*2,14430,0.05/4/30);
curr.body.material=new BitmapMaterial(Cast.bitmap(new saturnmap));
view.scene.addChild(curr.body);
skybodies.push(curr);

// uran
curr=new SkyBody(250,12,12,Math.random()*Math.PI*2,28600,0.05/4/85);
curr.body.material=new BitmapMaterial(Cast.bitmap(new uranmap));
view.scene.addChild(curr.body);
skybodies.push(curr);

// neptun
curr=new SkyBody(240,12,12,Math.random()*Math.PI*2,45000,0.05/4/164);
curr.body.material=new BitmapMaterial(Cast.bitmap(new neptunmap));
view.scene.addChild(curr.body);
skybodies.push(curr);

// pluto
curr=new SkyBody(20,12,12,Math.random()*Math.PI*2,59000,0.05/4/249);
curr.body.material=new BitmapMaterial(Cast.bitmap(new plutonmap));
view.scene.addChild(curr.body);
skybodies.push(curr);

var i:int=skybodies.length
while(i--)
{
(skybodies[i] as SkyBody).body.addEventListener(MouseEvent3D.MOUSE_DOWN,onBodyMD);
(skybodies[i] as SkyBody).body.addEventListener(MouseEvent3D.MOUSE_UP,onBodyMU);
}
stage.addEventListener(MouseEvent.MOUSE_UP,onBodyMU);
camera.target=skybodies[0].body;
}

private function onBodyMD(e:MouseEvent3D):void
{
camera.target=e.target as Object3D;
}
private var lasTarget:Object3D;
private function onBodyMU(e:*):void
{
lasTarget=camera.target==null ? lasTarget : camera.target;
camera.target=null
}
private function renderLoop(e:*):void
{
var i:int=skybodies.length
while(i--)
{
(skybodies[i] as SkyBody).moveOnOrbit();
}
view.render();
}

private var prevMousePos:Point=new Point;
private var prevCameraAngleX:Number;

private function onMD(e:*):void
{
prevMousePos.x=mouseX;
prevMousePos.y=mouseY;
prevCameraAngleX=Math.atan2(camera.z,camera.x);
addEventListener(Event.ENTER_FRAME,calculateCameraPosition)
}
private function onMU(e:*):void
{
removeEventListener(Event.ENTER_FRAME,calculateCameraPosition)
}
private function calculateCameraPosition(e:*):void
{
var camSpeed:Number=0.04;
var currCameraAngleX:Number=prevCameraAngleX-(mouseX-prevMousePos.x)*camSpeed;
var targetBody:Sphere=camera.target as Sphere;
if (targetBody==null)
{
var r:int=Math.sqrt(lasTarget.x*lasTarget.x+lasTarget.z*lasTarget.z)*1.1;
camera.x=Math.cos(currCameraAngleX)*r;
camera.z=Math.sin(currCameraAngleX)*r;
camera.lookAt(new Number3D);

}
else
{
camera.x=targetBody.x+Math.cos(currCameraAngleX)*targetBody.radius*1.3;
camera.z=targetBody.z+Math.sin(currCameraAngleX)*targetBody.radius*1.3;
}
}

}
}


Посмотреть

вторник, 22 сентября 2009 г.

Ошибки 5003 & 5005

Возникают от нехватки памяти в среде Flash CS4. Создание системной переменной среды
JAVA_TOOL_OPTIONS со значением -Xmx512M решает проблему.

суббота, 19 сентября 2009 г.

Вселенная Away3d - Эпизод 6 : Материалы

С материалами все оказалось достаточно просто. В Away3d существует несколько типов материалов. По оказываемому "воздействию" на конечное отображение трехмерной модели, материалы можно поделить на Color, Wire и Bitmap материалы. Color материал, такой материал который просто окрашивает модель в определенный цвет. Wire материал который дополнительно отображает ребра модели. Bitmap материал - по-сути картинка натянутая на модель. Также эти же материал можно поделить в зависимости от их реакции на источник света в сцене - по их подсветке и их затенению. В Away3d две модели затенения и соответственно засветления :) - Flat и Phong. Flat - простая модель затенения (меньше ест процессорного времени), затенение рассчитывается как величина отклонения нормали меша (mesh) от вектора направление которого от источника света к модели. Phong модель - это Flat затенение со сглаженными световым переходам между мешами.

Я сделал небольшой проектик - в центре сфера и сбоку источник света, по клику на сферу назначается на материал - какой именно материал видно из приведенного ниже кода:

package {
import away3d.containers.*;
import away3d.core.utils.Cast;
import away3d.lights.DirectionalLight3D;
import away3d.materials.*;
import away3d.primitives.Sphere;

import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;

[SWF (width="600",height="600",frameRate="31",backgroundColor="0xececec")]
public class away3d_prj05_materials extends Sprite
{
[Embed (source="assets/earthmap.png")]
private var bitmapTexture:Class;
[Embed (source="assets/earthnightmap.png")]
private var bitmapTexture2:Class;
[Embed (source="assets/earthnormalmapz.png")]
private var bitmapNZ:Class;
private var view:View3D;
private var sphere:Sphere;
private var matIndex:int=-1;
private var matlib:Array;

public function away3d_prj05_materials()
{
initMatlib();

view=new View3D;
view.x=stage.stageWidth*0.5;
view.y=stage.stageHeight*0.5;
addChild(view);
view.camera.z=-500;

var scene:Scene3D=new Scene3D;
view.scene=scene;

var m:PhongColorMaterial
m=new PhongColorMaterial(0xff0000);
m.shininess=100;
m.specular=0.7;

sphere=new Sphere;
sphere.segmentsW=20;
sphere.segmentsH=10;
scene.addChild(sphere);
assignNextMaterial();

var light:DirectionalLight3D=new DirectionalLight3D;
light.x = 200;
light.z = -100;
light.y = 300;
light.color = 0xFFFFFF;
light.ambient = 0.5;
light.diffuse = 0.7;
scene.addChild(light);

this.addEventListener(Event.ENTER_FRAME,renderLoop);
this.stage.addEventListener(MouseEvent.MOUSE_WHEEL,onMW);
this.stage.addEventListener(MouseEvent.CLICK,onSphereMD);
}
private function renderLoop(e:*=null):void
{
sphere.rotationY+=-(mouseX-stage.stageWidth*0.5)/50
sphere.rotationX+=(mouseY-stage.stageHeight*0.5)/50
view.render();
}
private function initMatlib():void
{
matlib=[];

var curr:WireColorMaterial;
curr=new WireColorMaterial;
curr.color=0xff0000;
curr.wirecolor=0;
matlib.push(curr);

var curr1:PhongColorMaterial;
curr1=new PhongColorMaterial({});
curr1.color=0xff0000;
matlib.push(curr1);

var curr2:BitmapMaterial=new BitmapMaterial(Cast.bitmap(new bitmapTexture));
curr2.smooth=true;
matlib.push(curr2);

var curr21:WhiteShadingBitmapMaterial=new WhiteShadingBitmapMaterial(Cast.bitmap(new bitmapTexture));
curr21.diffuse_brightness=1
matlib.push(curr21);

var curr3:PhongBitmapMaterial=new PhongBitmapMaterial(Cast.bitmap(new bitmapTexture));
matlib.push(curr3);

var curr4:EnviroBitmapMaterial=new EnviroBitmapMaterial(Cast.bitmap(new bitmapTexture),Cast.bitmap(new bitmapTexture2));
curr4.reflectiveness=0.3
matlib.push(curr4);

var curr5:Dot3BitmapMaterial=new Dot3BitmapMaterial(Cast.bitmap(new bitmapTexture),Cast.bitmap(new bitmapNZ));
matlib.push(curr5);

}
private function onMW(e:MouseEvent):void
{
view.camera.z+=e.delta*10;
}
private function onSphereMD(e:*):void
{
assignNextMaterial();
}
private function assignNextMaterial():void
{
matIndex++;
matIndex=matIndex == matlib.length ? 0 : matIndex;
sphere.material=matlib[matIndex];
}
}
}


Управление: левый клик - смена материала, крутить колесико - приближение/отдаление. Сорцы доступны по правому клику мыши.

понедельник, 14 сентября 2009 г.

Вселенная Away3d - Эпизод 5 : Первые шаги в трехмерном мире

В этой статье будет показан пример прототипа игры, в которой игрок сможет перемещаться по виртуальному миру. Создаем actionscript проект away3d_prj03_moving ( настраиваем под 10й флешплеер, подключаем Away3dLite), со следущим содержимым:

package
{
import away3dlite.containers.*;
import away3dlite.materials.*;
import away3dlite.primitives.*;
import flash.display.Sprite;
import flash.events.*;
import flash.ui.Keyboard;

// Первый раз пишу комментарии к коду на русском языке :)
// Опции компиляции SWF
[SWF (width="800",height="400",frameRate="31",backgroundColor="0xffffff")]
public class away3d_prj03_moving extends Sprite
{
// константы для пересчета углов из градусов в радианы и обратно
private var g2r:Number=Math.PI/180;
private var r2g:Number=180/Math.PI;
// основной вьюпорт
private var view:View3D;
// флажки регистраторы заданного движения через клавиатуру
// пока клавиша нажата происходит движение
private var dirLeftRight:int=0;
private var dirForwardBack:int=0;
private var dirUpDown:int=0;
// углы поворота по горизонтали и по вертикали (поворот осуществляется перемещением мыши)
private var yaw_angle:Number;
private var pitch_angle:Number;
// временные переменные
private var dz:int;
private var dx:int;
private var dy:int;

public function away3d_prj03_moving()
{
// создание мира и установка наблюдателя
view= new View3D;
addChild(view);
view.x=400;
view.y=200;
view.camera.y=-200;
view.camera.z=-1000;
var scene:Scene3D=new Scene3D;
view.scene=scene

// небо
// задание материала
var m:WireColorMaterial
m=new WireColorMaterial;
m.color=0xbbbbff;
var skybox:Skybox6=new Skybox6;
skybox.material=m;
scene.addChild(skybox)
// земля
m=new WireColorMaterial;
m.color=0x555500;
var plane:Plane=new Plane;
plane.material=m;
plane.width=2000;
plane.height=2000;
plane.segmentsW=20;
plane.segmentsH=20;
scene.addChild(plane);
// здания (случайное генерирование)
var i:int;
var t:int;
var box:Cube6;
for (i=0;i<20;i++)
{
for (t=0;t<20;t++)
{
if (Math.random()>.95)
{
// вот здесь возводим здание
box=new Cube6;
box.width=100;
box.height=int(Math.random()*200+100);
box.depth=100;
box.y=-box.height*.5+2;
box.x=-1000+t*100;
box.z=-1000+i*100;
scene.addChild(box);
}
}
}
// регистрация клавиатуры и мыши
stage.addEventListener(KeyboardEvent.KEY_DOWN,onKD);
stage.addEventListener(KeyboardEvent.KEY_UP,onKU);
this.addEventListener(MouseEvent.MOUSE_MOVE,omMM);
// запуск движка на отрисовку каждыйй кадр
this.addEventListener(Event.ENTER_FRAME,renderLoop);
}
// высчитывание текущих углов поворота наблюдателя
private function omMM(e:MouseEvent):void
{
yaw_angle=5*(mouseX-400)/400;
pitch_angle=45*(mouseY-200)/200;
}
// обработка клавиатуры на нажатие
private function onKD(e:KeyboardEvent):void
{
if (e.shiftKey)
{
if (e.keyCode==Keyboard.UP)
{
dirUpDown=-1;
}
else
if (e.keyCode==Keyboard.DOWN)
{
dirUpDown=1;
}
}
else
{
if (e.keyCode==Keyboard.LEFT)
{
dirLeftRight=-1;
}
else
if (e.keyCode==Keyboard.RIGHT)
{
dirLeftRight=1;

}
else
if (e.keyCode==Keyboard.UP)
{
dirForwardBack=-1;
}
else
if (e.keyCode==Keyboard.DOWN)
{
dirForwardBack=1;
}
}
}
// обработка клавиатуры на отжатие (просто сброс в ноль соотв флажков)
private function onKU(e:KeyboardEvent):void
{
if (e.keyCode==Keyboard.LEFT)
{
dirLeftRight=0;
}
else
if (e.keyCode==Keyboard.RIGHT)
{
dirLeftRight=0;
}
else
if (e.keyCode==Keyboard.UP)
{
dirForwardBack=0;
dirUpDown=0;
}
else
if (e.keyCode==Keyboard.DOWN)
{
dirForwardBack=0;
dirUpDown=0;
}
}
// непосредственно рендеринг
private function renderLoop(e:*=null):void
{
// поворот камеры
view.camera.rotationY+=yaw_angle;
view.camera.rotationX=-pitch_angle;
// обсчет приращений скорости в зависимости от горизонтального угла поворота
// при движении вперед
dz=-Math.cos(view.camera.rotationY*g2r)*10*dirForwardBack;
dx=-Math.sin(view.camera.rotationY*g2r)*10*dirForwardBack;
// при движениях вбок (стрейфе)
dz+=-Math.cos((view.camera.rotationY-90)*g2r)*10*dirLeftRight;
dx+=-Math.sin((view.camera.rotationY-90)*g2r)*10*dirLeftRight;
// перемещение в горизонтальной плоскости
view.camera.z+=dz;
view.camera.x+=dx;
// обсчет изменения вертикального положения если наблюдатель не стоит на месте
// от вертикального угла - насколько высоко голова смотри в небо или под ноги :)
if (dirForwardBack!=0)
{
dy=Math.sin(view.camera.rotationX*g2r)*10*dirForwardBack;
view.camera.y+=dy;
}
// визуализация
view.render();
}
}
}



Работающий пример

Скачать исходники
Комментарии к коду, я думаю, достаточно полно объясняют как происходит построение и управление. Если что непонятно - пишите комменты, я либо отвечу там, либо дополню статью.

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

Согласитесь, пример простой, но уже позволяет его применить для полноценной игры. Но наш мир выглядит совсем уж просто, не хватает красоты :) , поэтому в следующей статье я затрону использование текстур , битовых изображений, которые можно "натягивать" на трехмерные объекты.