Olá pessoal, estava me preparando para montar um novo tutorial sobre tile system, já estou a algum tempo uma atualização para a estruturação de cenários isométricos, mas eu pensei “por que não criar um cenário 3D tile?”

Clique na imagem para testar.
Gostou, este será o nosso produto final, pois bem vamos seguir com o tutorial.
Lógica:
A lógica é bem simples, usaremos 2 vetores diferentes, um deles será para mostrar qual será o tile que usaremos na posição e o outro vetor que indicara a altura. Criaremos os loops para percorrer o vetor e criar cubos num plano 3D. Como termos alguns cubos suspensos, completaremos os espaços vazios com cubos, e colocaremos uma função para rotacionar nosso Field.
Tiles:

Estes sãos os movieclips que usaremos no nosso arquivo .fla, todos eles com exceção do water são estáticos, não possuem nenhum freme alem do desenhado, já o water eu coloquei uma pequena movimentação para dar um efeito de água se movendo. Todos os movieclips estão com a propriedade linkage definidos.
Usaremos a classe MovieAssetMaterial para importarmos cada movieclip para um material diferente
public var matGrass:MovieAssetMaterial = new MovieAssetMaterial("grass");
public var matBase0:MovieAssetMaterial = new MovieAssetMaterial("base0");
public var matBase1:MovieAssetMaterial = new MovieAssetMaterial("base1");
public var matFlower:MovieAssetMaterial = new MovieAssetMaterial("flower");
public var matWater:MovieAssetMaterial = new MovieAssetMaterial("water", true);
Tiles x Materiais

Como vocês podem ver na imagem acima montaremos cubos para usarmos como tile, por enquanto vamos nos focar em criar as listas de materiais para as respectivas faces dos cubos.
public var w:MaterialsList = new MaterialsList(
{front: matWater, back: matWater, left: matWater,
right: matWater, top: matWater, bottom: matWater});
public var g:MaterialsList = new MaterialsList(
{front: matBase1, back: matBase1, left: matBase1,
right: matBase1, top: matGrass, bottom: matBase1});
public var f:MaterialsList = new MaterialsList(
{front: matBase1, back: matBase1, left: matBase1,
right: matBase1, top: matFlower, bottom: matBase1});
public var b:MaterialsList = new MaterialsList(
{front: matBase0, back: matBase0, left: matBase0,
right: matBase0, top: matBase0, bottom: matBase0});
Assim nosso Tile ficara formatado da seguinte forma.
public var arrayTile:Array = [
[w,w,w,w,w,w,w,w,w,w],
[w,w,w,g,g,g,g,w,w,w],
[w,g,g,g,g,g,f,w,w,w],
[w,f,g,f,g,g,g,g,w,w],
[w,g,g,g,f,g,g,g,w,w],
[w,w,g,g,w,g,g,g,w,w],
[w,w,w,g,g,f,g,g,w,w],
[w,w,w,g,g,g,g,w,w,w],
[w,w,f,g,g,f,w,w,w,w],
[w,w,w,w,w,w,w,w,w,w]];
Tile x Altura
Para não poluir o vetor de tile decidi usar um vetor separado para mostrar o posicionamento do bloco no plano R3.
public var arrayTileHeight:Array = [
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,2,2,3,0,0,0],
[0,3,2,0,1,1,2,0,0,0],
[0,2,1,1,1,1,2,0,0,0],
[0,0,1,1,1,1,1,0,0,0],
[0,0,0,1,1,0,0,0,0,0],
[0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0]];
Nós usaremos cada cubo com o tamanho 30x30x30 analogamente para subir um nível os blocos temos que multiplicarmos a posição demonstrada no vetor por 30.

Com isso acabamos criando espaços vagos.para resolvermos isso criaremos um loop que criará blocos do tipo base da altura 0 ate a altura definida.
Criando Tiles
A diferença dos tiles que vimos em R2 para o R3 é que alteramos a propriedades x e z com os loops ao invés de (x,y) a propriedade y utilizamos para altura.
public function Objetos () {
for (var i = 0; i < arrayTile.length; i++) {
for (var j = 0; j < arrayTile[0].length; j++) {
//Criando blocos extras na altura
if (arrayTileHeight[i][j]>0) {
for (var k=0; k< arrayTileHeight[i][j]; k++){
var obCubeb:Cube = new Cube(b,30,30,30);
cena.addChild (obCubeb);
obCubeb.x = i * 30 -150;
obCubeb.z = j * 30 -150;
obCubeb.y = k * 30;
}
}
//Criando bloco Tile
var obCube:Cube = new Cube(arrayTile[i][j],30,30,30);
cena.addChild (obCube);
obCube.x = i * 30 -150;
obCube.z = j * 30 -150;
obCube.y = arrayTileHeight[i][j] * 30;
}
}
addEventListener (Event.ENTER_FRAME,Loop,false, 0, true);
}
Código extra: Movimentando a câmera
Para fazer a movimentação da câmera utilizei a seguinte lógica, criei um objeto do tipo plano no centro de nosso cenário, e travei a câmera nele com o método.
obcamera.lookAt (centro);
Assim independente o posicionamento do x, y e z da câmera, ele sempre terá como foco o centro do mapa. Agora podemos movimentar o x e z da câmera para circular o cenário que ele nunca mudara seu foco.
A cada frame colocaremos as propriedades x e z somarem um valor, valor este que estará armazenado em um vetor. Se sempre somarmos valores nossa câmera sempre se afastará, com as possibilidades definidas em um vetor podemos manipular para ele alem de somar subtrair também para trazer a câmera de voltar.
Código Completo
Arquivo main.as
package {
//flash
import flash.display.MovieClip;
import flash.events.*;
//Papervision
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.objects.primitives.Cube;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.render.BasicRenderEngine;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.view.Viewport3D;
import org.papervision3d.materials.MovieAssetMaterial;
import org.papervision3d.materials.utils.MaterialsList;
public class main extends MovieClip {
//papervision
public var cena:Scene3D;
public var viewport:Viewport3D;
public var camera:Camera3D;
public var renderer:BasicRenderEngine;
public var centro:Plane;
//material
public var matGrass:MovieAssetMaterial = new MovieAssetMaterial("grass");
public var matBase0:MovieAssetMaterial = new MovieAssetMaterial("base0");
public var matBase1:MovieAssetMaterial = new MovieAssetMaterial("base1");
public var matFlower:MovieAssetMaterial = new MovieAssetMaterial("flower");
public var matWater:MovieAssetMaterial = new MovieAssetMaterial("water", true);
public var w:MaterialsList = new MaterialsList(
{front: matWater, back: matWater, left: matWater,
right: matWater, top: matWater, bottom: matWater});
public var g:MaterialsList = new MaterialsList(
{front: matBase1, back: matBase1, left: matBase1,
right: matBase1, top: matGrass, bottom: matBase1});
public var f:MaterialsList = new MaterialsList(
{front: matBase1, back: matBase1, left: matBase1,
right: matBase1, top: matFlower, bottom: matBase1});
public var b:MaterialsList = new MaterialsList(
{front: matBase0, back: matBase0, left: matBase0,
right: matBase0, top: matBase0, bottom: matBase0});
//tiles
public var arrayTile:Array = [
[w,w,w,w,w,w,w,w,w,w],
[w,w,w,g,g,g,g,w,w,w],
[w,g,g,g,g,g,f,w,w,w],
[w,f,g,f,g,g,g,g,w,w],
[w,g,g,g,f,g,g,g,w,w],
[w,w,g,g,w,g,g,g,w,w],
[w,w,w,g,g,f,g,g,w,w],
[w,w,w,g,g,g,g,w,w,w],
[w,w,f,g,g,f,w,w,w,w],
[w,w,w,w,w,w,w,w,w,w]];
public var arrayTileHeight:Array = [
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,2,2,3,0,0,0],
[0,3,2,0,1,1,2,0,0,0],
[0,2,1,1,1,1,2,0,0,0],
[0,0,1,1,1,1,1,0,0,0],
[0,0,0,1,1,0,0,0,0,0],
[0,0,0,0,1,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0]];
//Camera
public var cam:int = 0
public var a:int = 0;
public var arrayCam:Array = [[-45,0],[0,-45],[45,-0],[0,45]];
public function main () {
Set ();
Objetos ();
}
public function Set ():void {
viewport = new Viewport3D(400,300,true,false,true,true);
addChild (viewport);
cena = new Scene3D ;
renderer = new BasicRenderEngine ;
camera = new Camera3D ;
camera.focus = 100;
camera.zoom = 10;
camera.x = 650;
camera.z = 450;
camera.y = 700;
centro = new Plane();
centro.y = 0;
centro.z = 0;
centro.x = 0;
}
public function Objetos ():void {
for (var i = 0; i < arrayTile.length; i++) {
for (var j = 0; j < arrayTile[0].length; j++) {
//Criando blocos extras na altura
if (arrayTileHeight[i][j]>0) {
for (var k=0; k< arrayTileHeight[i][j]; k++){
var obCubeb:Cube = new Cube(b,30,30,30);
cena.addChild (obCubeb);
obCubeb.x = i * 30 -150;
obCubeb.z = j * 30 -150;
obCubeb.y = k * 30;
}
}
//Criando bloco Tile
var obCube:Cube = new Cube(arrayTile[i][j],30,30,30);
cena.addChild (obCube);
obCube.x = i * 30 -150;
obCube.z = j * 30 -150;
obCube.y = arrayTileHeight[i][j] * 30;
}
}
addEventListener (Event.ENTER_FRAME,Loop,false, 0, true);
}
public function Loop (e:Event):void {
a++ ;
rotaionCamera (camera,arrayCam[cam][0],arrayCam[cam][1])
if (a % 30 == 0){
nextCamera()
}
renderer.renderScene (cena,camera,viewport);
}
public function nextCamera():void{
cam= cam+1
if (cam>=4){
cam = 0
}else if (cam<=-1){
cam = 3
}
}
public function rotaionCamera (obcamera:Camera3D,newx,newz):void {
obcamera.x+= newx;
obcamera.z+= newz;
obcamera.lookAt (centro);
}
}
}
Obs: Lembrando que estamos fazendo um aplicativo utilizando as classes do papervision, não podemos esquecer-nos de importalas.