Olá pessoal, para lhes ser sincero eu não pretendia fazer uma continuação tão cedo para o papervison tile, mas eu me empolguei muito ao escrever o tutorial anterior, e decidi criar uma continuação. Prestem atenção no flash a seguir.

Este foi o ultimo passo do nosso tutorial tile sytem, pois bem, a primeira meta do nosso tutorial papervision tile será replicar esta aplicação para o 3d. Agora veja como ficará o projeto final deste tutorial de hoje.

Sobre:
Poderemos utilizar o mesmo arquivo fla que construímos no tutorial anterior, mas eu não irei utilizar o mesmo arquivo main, pois desta vez adicionaremos alguns conceitos de POO (Programação Orientada a Objetos) em nosso tutorial.
Nosso tutorial será constituído pelos seguintes arquivos:
- ppv_tile.fla: Este arquivo não tem mistério nenhum, é o mesmo que utilizamos no tutorial anterior.
- Tile3D.as: Este arquivo será a classe modelo para cada bloco, ele será responsável por desenhar o cubo, manipular as propriedades de coordenadas tile, ground e wall, que nos dirá se o tile desenhado permitir caminhar sobre ele e se ele funcionará como uma parede que impedirá a passagem quando o player estiver no mesmo nível.
- Player.as: Esta classe além de desenhar nosso player no cenário e manipular coordenadas, ela também contará com o método de mover o player pelo cenário.
- main.as: Nosso arquivo principal, será responsável por montar nosso ambiente 3d, adicionar o player no cenário e manipular o teclado para movimentar o player.
Obs: Não podemos esquecer-nos de referenciar a biblioteca do papervision.
Diretórios:
Neste tutorial utilizaremos o conceito de pacotes, e as classes não estarão no mesmo diretório que o arquivo fla, veja a imagem como será organizado nosso diretório.
Como funcionará o código.
No nosso arquivo main.as criaremos 3 vetores, um para informar os materiais, outro para informar a altura que cada tile irá ficar e um terceiro que terá o mesmo comprimento dos outros, mas utilizaremos ele para armazenar objetos da classe Tile3D para podermos ter uma fácil manipulação de dados usando coordenadas tile.
Em nosso loop de criação de tiles instanciaremos cada posicionamento do veto tiles[i][j] pra se comportarem como um novo objeto do tipo Tile3D.
Nossa classe Tile3D será uma classe estendida da classe Cube do papervision, a diferença que nossa herança vai precisar de parâmetros adicionais como tamanho do cubo, posicionamento x,z,y no tile.
No decorrer do loop definiremos a propriedade wall e ground de acordo com os vetores especificadores de altura e material, utilizaremos os métodos da classe.
Ao termino do loop instanciaremos o objeto player do tipo Player
A classe Player receberá como parâmetros: o tamanho do tile, e posicionamento x,z e y como parâmetro opcional.
Para mover o player pelo cenário invocaremos o método move da classe Player, que recebe como parâmetros: direcionamento Z, direcionamento X e o vetor com os objetos de tile.
Lógica das classes Tile3D e Player:
Criar um cubo com os parâmetros passados pelo construtor de Tile3D e Player. Logo em seguida repassar os parâmetros para classe mãe Cubo. Não permitiremos o usuário alterar os atributos diretamente, pois para alterarmos precisaremos de uma validação, por isso estaremos utilizando os atributos do tipo privado, a validação será da seguinte maneira: O usuário informara qual será o tile que ele quer posicionar o cubo, o método automaticamente modificará o atributo que armazena o posicionamento no tile e calculará a posição física dele no plano 3d (x,z,y).
Lógica Get/Set:
Vamos supor que o atributo no qual armazenaremos o posicionamento do tileX esta definido como public. Ao fazermos “Player.tileX = 2;” modificaremos o nosso atributo para 2, mas com isso o nosso Player não se moveu para a posição 2. Este problema é solucionado utilizando a lógica get/set. Um método Get para recupera um valor (x = Player.tileX) e um método set para modifica um valor (Player.tileX = 2). Como não podemos ter atributos com o mesmo nome que os métodos utilizaremos “_nome” quando for atributo e “get nome ou set nome” para função.
private var _tileX:int;
private function gotoTile(n:int):Number{ return _cubeW * n; } public function set tileX(n:int):void { _tileX = n; x = gotoTile(n); } public function get tileX():int { _tileX = Math.floor(x /_tileWidth); return _tileX; }
Eu sei que a teoria pode estar meio confusa para alguns mas prometo que montarei um tutorial mais detalhado sobre Orientação a Objetos para vocês poderem refazerem este tutorial dizer. “Uhmmm então é isso.”
Move Player
Nosso método move na classe Player funcionará da seguinte forma, ele receberá parametros de adição para x,z e um vetor. se passarmos como parametro (0,1,vetor) estaremos informando que queremos que o player mova 0 na escala X e +1 na escala Z. Mas antes de mover verificamos se o bloco no qual nosso player está querendo se mover é permitido andar sobre ele (ground = true) e também se não existe um bloco do tipo parede atrapalhando (wall = false), só depois de verificarmos se é permitido andar que movimentamos nosso player.
public function move(dirx:int,dirz:int,arrayObj:Array):void { var nextTileX:Number = tileX + dirx; var nextTileZ:Number = tileZ + dirz; if (arrayObj[nextTileX][nextTileZ]!= "undefined" && !(arrayObj[nextTileX][nextTileZ].wall) && arrayObj[nextTileX][nextTileZ].ground){ if ((dirx == 1) || (dirx == -1) || (dirz == 1) || (dirz == -1)) { tileX = nextTileX; tileZ = nextTileZ; } } }
Códigos:
Segue abaixo o código referente as arguivos: Tile3D.as, Player.as, main.as. Lembrando que o nome dos arquivos precisam ser exatamente estes respeitando letra maiuscula e minuscula, o mesmo vale para as pastas que os arquivo serão alocados.
- Tile3D.as
package org.tile3d{ import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.primitives.Cube;
public class Tile3D extends Cube { private var _wall:Boolean; private var _ground:Boolean = true; private var _tileX:int; private var _tileY:int; private var _tileZ:int; private var _cubeW:Number;
public function Tile3D(matList:MaterialsList,_cubeW:Number=20,_tileX:Number=1,_tileZ:Number=1,_tileY:Number=1) { super(matList,_cubeW,_cubeW,_cubeW); this._cubeW = _cubeW; tileX = _tileX; tileZ = _tileZ; tileY = _tileY; } private function gotoTile(n:int):Number{ return _cubeW * n; } //Get e Set: Modificando os valores dos atributos privados public function set tileX(n:int):void { _tileX = n; x = gotoTile(n); } public function get tileX():int { return _tileX; } public function set tileY(n:int):void { _tileY = n; y = gotoTile(n); } public function get tileY():int { return _tileY; } public function set tileZ(n:int):void { _tileZ = n; z = gotoTile(n); } public function get tileZ():int { return _tileZ; } //Permite que o objeto seja usada como chão public function set ground(valor:Boolean):void { _ground = valor; } public function get ground():Boolean { return _ground; } //Transforma o objeto em uma parede public function set wall(valor:Boolean):void { _wall = valor; } public function get wall():Boolean { return _wall; } }
}
- Player.as
package org{ import org.papervision3d.objects.primitives.Cube; import org.papervision3d.materials.MovieAssetMaterial; import org.papervision3d.materials.utils.MaterialsList;
public class Player extends Cube { private var _tileX:int; private var _tileY:int; private var _tileZ:int; private var _tileWidth:Number; private var matP:MovieAssetMaterial = new MovieAssetMaterial("playermat1"); private var p:MaterialsList = new MaterialsList({all: matP});
public function Player(_tileWidth:Number=20,_tileX:Number=1,_tileZ:Number=1,_tileY:Number=1) { super(p,15,15,15); this._tileWidth = _tileWidth; tileX = _tileX; tileZ = _tileZ; tileY = _tileY; } public function move(dirx:int,dirz:int,arrayObj:Array):void { var nextTileX:Number = tileX + dirx; var nextTileZ:Number = tileZ + dirz; if (arrayObj[nextTileX][nextTileZ]!= "undefined" && !(arrayObj[nextTileX][nextTileZ].wall) && arrayObj[nextTileX][nextTileZ].ground){ if ((dirx == 1) || (dirx == -1) || (dirz == 1) || (dirz == -1)) { tileX = nextTileX; tileZ = nextTileZ; } } } private function gotoTile(n:int):Number{ return _tileWidth * n+(_tileWidth-15)/2; } //Get e Set: Modificando os valores dos atributos privados public function set tileX(n:int):void { _tileX = n; x = gotoTile(n); } public function get tileX():int { _tileX = Math.floor(x /_tileWidth); return _tileX; } public function set tileY(n:int):void { _tileY = n; y = gotoTile(n); } public function get tileY():int { _tileY = Math.floor(y/_tileWidth); return _tileY; } public function set tileZ(n:int):void { _tileZ = n; z = gotoTile(n); } public function get tileZ():int { _tileZ = Math.floor(z/_tileWidth); return _tileZ; } }
}
- main.as
package { //flash import flash.display.MovieClip; import flash.events.*; import org.tile3d.*; import org.Player;
//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( {all: matBase0}); //tiles public var arrayTile:Array =[ [w, w, w, w, w, w, w, w, w, w, w, w, w, w, w], [w, g, g, g, g, g, f, g, w, w, w, w, w, w, w], [w, g, g, f, g, g, g, g, g, w, g, g, f, w, w], [w, g, g, g, g, f, g, g, g, w, g, g, g, w, w], [w, w, g, g, g, g, g, g, g, f, f, g, g, w, w], [w, w, g, g, g, g, g, g, g, f, g, g, w, w, w], [w, g, g, g, g, g, g, g, g, g, g, w, w, w, w], [w, g, g, g, f, w, g, f, g, g, w, w, w, w, w], [w, w, g, g, w, w, g, g, g, w, w, w, w, w, w], [w, 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,1,0,0,0,0,0,0,0,0], [0,0,0,1,0,0,0,0,0,0,0,0,1,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,1,1,0,0,0,0], [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,1,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,0,0,0,0,0,0,0,0,0,0,0,0]];
public var tiles: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,0,0,0,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,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,1,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,1,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,0,0,0,0,0,0,0,0,0,0]];
//Player public var player:Player; //Outros public var tileWidth:Number = 20;
public function main () {
Set (); Objetos ();
} public function Set ():void {
viewport = new Viewport3D(400,300,true,false,true,true); addChild (viewport); setChildIndex (viewport,1); cena = new Scene3D ; renderer = new BasicRenderEngine ; camera = new Camera3D ; camera.focus = 100; camera.zoom = 10; camera.x = 650; camera.z = 450; camera.y = 700;
} 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 tiles[i][j] = new Tile3D(arrayTile[i][j],tileWidth,i,j,arrayTileHeight[i][j]); if (arrayTileHeight[i][j]>0) { tiles[i][j].wall=true; for (var k=0; k<arrayTileHeight[i][j];k++){ var tilesBlock=new Tile3D(b,tileWidth,i,j,k); cena.addChild (tilesBlock); } } if (arrayTile[i][j] == w){ tiles[i][j].ground=false; } //Criando bloco Tile cena.addChild (tiles[i][j]); } } //Player player = new Player(20,1,1); cena.addChild (player);
stage.addEventListener (KeyboardEvent.KEY_UP, onKeyUpEvent,false,0,true); addEventListener (Event.ENTER_FRAME,Loop,false, 0, true);
} public function Loop (e:Event):void { camera.lookAt (player); renderer.renderScene (cena,camera,viewport);
} public function movePlayer(ob:Cube,dir:String,code:int) { if (code==37){ player.move(0,-1,tiles); }else if (code==39){ player.move(0,1,tiles); }else if (code==38){ player.move(-1,0,tiles); }else if (code==40){ player.move(1,0,tiles); } } public function onKeyUpEvent (event:KeyboardEvent ):void { var Code:Number=event.keyCode; if (Code==37 ||Code==38 ||Code==40 ||Code==39 ) { movePlayer (player,null,Code); } } } }