Этот урок научит вас создавать шар с возможностью его вращения. Вставляем данный код в панель AS3.0
Code
/* В этой части урока, мы рисуем частично открытую сферу. Мы руководствуемся те ми же принципами, как в предыдущих частях. Главная разница в том, что вместо набора вершин и граней, мы используем двумерный массив вершин, tilesArray. Каждый элемент, tilesArray[i][j], представляет вершину. Каждой вершине (за исключением, когда i или j максимальны) соответствует грань чьи вершины - tilesArray[i][j], tilesArray[i+1][j], tilesArray[i][j+1], tilesArray[i+1][j+1]. Таким образом, достаточно помнить лиш массив вершин. Каждой грани соответствует i,j вершины. i и j находятся в области с 0 до фиксированного целого числа ,хранящегося в переменной nMesh. Для параметрических поверхностей, x=x(t,s), y=y(t,s), z=z(t,s), i и j соответствуют последовательным значениям параметров t и s. Ниже я прокомментировал только новые части кода. */ var fLen:Number=2000; var spBoard:Sprite=new Sprite(); this.addChild(spBoard); spBoard.x=200; spBoard.y=190; var shBack:Shape=new Shape(); spBoard.addChild(shBack); drawBack(); var shCube:Shape=new Shape(); spBoard.addChild(shCube); var doRotate:Boolean=false; var prevX:Number; var prevY:Number; var curTheta:Number=-10; var curPhi:Number=60; /* Значение tilesArray хранится в nMesh. Мы выбираем 30 к 30 которого обычно достаточно , чтобы создать гладкую поверхность. */ var nMesh:Number=30; //Массив вершын. var tilesArray:Array=[]; //Логическая переменная, которая блокирует окраску после выполнения renderView var firstRun:Boolean=true; /* Следующий массив запоминает цвета для наших граней. */ var tilesColors:Array=[]; function drawBack():void { shBack.graphics.lineStyle(1,0x000000); shBack.graphics.beginFill(0x000000); shBack.graphics.drawRect(-160,-160,320,320); shBack.graphics.endFill(); } /* setTilesArray определяет вершины для нашей грани. RenderView функция подобна прежней из прошлого урока. */ setTilesArray(); renderView(curTheta,curPhi); /* В setTilesArray мы определяем вершины, которые соответствуют параметрической сфера с радиусом 90. i и j служат типовыми значениями для параметров.i изменяется в пределах от 0 до 7/4*pi, чтобы оставить отверстие в сфере, j - от 0 до пи. (Конечно i и j соответствуют параметризации сферы сферической тета координат и phi.) */ function setTilesArray():void { var i:int; var j:int; var istep:Number; var jstep:Number; istep=(7/4)*Math.PI/nMesh; jstep=Math.PI/nMesh; for (i=0; i<=nMesh; i++) { tilesArray[i]=[]; for (j=0; j<=nMesh; j++) { tilesArray[i][j]=[90*Math.cos(istep*i)*Math.sin(jstep*j),90*Math.sin(istep*i)*Math.sin(jstep*j),90*Math.cos(jstep*j)]; } } } /* Изменения в renderView функции соответствуют тому факту, что tilesArray двумерен также как и dispArray. Поэтомув каждом цыкле присудствует два индекса i и j . distArray отслеживает расстояния от зрителя всех nMesh*nMesh середин. Каждый элемент distArray - форма [dist,i,j]. После сортировки distArray, мы знаем, какие грани соотвецтвующих i,j - сзади,а какие спереди. После выполнения renderView ,переменная firstRun устанавливается к false,таким образом назначение цветов происходит однажды. */ function renderView(t:Number,p:Number):void { var i:int; var j:int; var n:int; var distArray=[]; var dispArray=[]; var tilesNewArray=[]; var midPoint:Array=[]; var dist:Number; var depLen:Number; var coloFactor=1.2; t=t*Math.PI/180; p=p*Math.PI/180; shCube.graphics.clear(); for (i=0; i<=nMesh; i++) { tilesNewArray[i]=[]; for (j=0; j<=nMesh; j++) { tilesNewArray[i][j]=pointNewView(tilesArray[i][j],t,p); } } for (i=0; i<nMesh; i++) { if (firstRun) { tilesColors[i]=[]; } for (j=0; j<nMesh; j++) { midPoint[0]=(tilesNewArray[i][j][0]+tilesNewArray[i+1][j][0]+tilesNewArray[i][j+1][0]+tilesNewArray[i+1][j+1][0])/4; midPoint[1]=(tilesNewArray[i][j][1]+tilesNewArray[i+1][j][1]+tilesNewArray[i][j+1][1]+tilesNewArray[i+1][j+1][1])/4; midPoint[2]=(tilesNewArray[i][j][2]+tilesNewArray[i+1][j][2]+tilesNewArray[i][j+1][2]+tilesNewArray[i+1][j+1][2])/4; dist=Math.sqrt(Math.pow(fLen-midPoint[0],2)+Math.pow(midPoint[1],2)+Math.pow(midPoint[2],2)); distArray.push([dist,i,j]); if (firstRun) { tilesColors[i][j]=combineRGB((2*coloFactor*midPoint[2]+100)*0.8+70,(2*coloFactor*midPoint[1]+100)*0.8+70,(2*coloFactor*midPoint[0]+100)*0.8+70); } } } distArray.sort(byDist); for (i=0; i<=nMesh; i++) { dispArray[i]=[]; for (j=0; j<=nMesh; j++) { dispArray[i][j]=[fLen/(fLen-tilesNewArray[i][j][0])*tilesNewArray[i][j][1],-fLen/(fLen-tilesNewArray[i][j][0])*tilesNewArray[i][j][2]]; } } depLen=distArray.length; shCube.graphics.lineStyle(1,0x333333); for (n=0; n<depLen; n++) { i=distArray[n][1]; j=distArray[n][2]; shCube.graphics.moveTo(dispArray[i][j][0],dispArray[i][j][1]); shCube.graphics.beginFill(tilesColors[i][j],1.0); shCube.graphics.lineTo(dispArray[i][j+1][0],dispArray[i][j+1][1]); shCube.graphics.lineTo(dispArray[i+1][j+1][0],dispArray[i+1][j+1][1]); shCube.graphics.lineTo(dispArray[i+1][j][0],dispArray[i+1][j][1]); shCube.graphics.lineTo(dispArray[i][j][0],dispArray[i][j][1]); shCube.graphics.endFill(); } firstRun=false; } function byDist(v:Array,w:Array):Number { if (v[0]>w[0]) { return -1; } else if (v[0]<w[0]) { return 1; } else { return 0; } } function pointNewView(v:Array,theta:Number,phi:Number):Array { var newCoords:Array=[]; newCoords[0]=v[0]*Math.cos(theta)*Math.sin(phi)+v[1]*Math.sin(theta)*Math.sin(phi)+v[2]*Math.cos(phi); newCoords[1]=-v[0]*Math.sin(theta)+v[1]*Math.cos(theta); newCoords[2]=-v[0]*Math.cos(theta)*Math.cos(phi)-v[1]*Math.sin(theta)*Math.cos(phi)+v[2]*Math.sin(phi); return newCoords; } /* функция combineRGB - очень удобная вспомогательная функция который позволяет нам легко связывать цвета во Flash в терминах из их красного цвета, зелени, и голубых компонентов. Эта удачная функция , использующая поразрядное перемещение - предналежит Джою Лотт. */ function combineRGB(red:Number,green:Number,blue:Number):Number { var RGB:Number; if (red>255) { red=255; } if (green>255) { green=255; } if (blue>255) { blue=255; } if (red<0) { red=0; } if (green<0) { green=0; } if (blue<0) { blue=0; } RGB=(red<<16) | (green<<8) | blue; return RGB; } spBoard.addEventListener(MouseEvent.ROLL_OUT,boardOut); spBoard.addEventListener(MouseEvent.MOUSE_MOVE,boardMove); spBoard.addEventListener(MouseEvent.MOUSE_DOWN,boardDown); spBoard.addEventListener(MouseEvent.MOUSE_UP,boardUp); function boardOut(e:MouseEvent):void { doRotate=false; } function boardDown(e:MouseEvent):void { prevX=spBoard.mouseX; prevY=spBoard.mouseY; doRotate=true; } function boardUp(e:MouseEvent):void { doRotate=false; } function boardMove(e:MouseEvent):void { var locX:Number=prevX; var locY:Number=prevY; if (doRotate) { prevX=spBoard.mouseX; prevY=spBoard.mouseY; curTheta+=(prevX-locX); curPhi+=(prevY-locY); renderView(curTheta,curPhi); e.updateAfterEvent(); } }