Alternativa3d 7 Flying carpet game Part 2 the terrain
Now if you followed the first part of the flying carpet tutorial you should have the first stage of the waving carpet. We now need to create the scene for the carpet to fly through and to do this i have decided to use the jiglib flash libraries to create terrain from height maps. A heightmap is an image usually made up of whites, greys and black and these represent different heights in 3d space. I created a basic tutorial on using the heightmaps jiglibflash and alternativa7 here. For this example i’m going to do something a little different and have actionscript create the heightmap for me. To do this i’m going to make use of the perlin noise function for bitmapdata.
var pmap:BitmapData = new BitmapData(500, 500);
var _seed:uint = Math.round(Math.random()*100);
pmap.perlinNoise(500,500, 6, _seed, true, false, 1, true);
As you can see in the code above its pretty easy to do and should create a bitmap looking like this. Now i actually want to have a flat piece of land at the beginning and end of this terrain so i’m going to create a new bitmapdata from this and add in the flat land which will just be a solid black. This way when i create multiple terrains i can join them seamlessly.
var pmap2:BitmapData = new BitmapData(500, 600,false,0x000000);
var rect:Rectangle = new Rectangle(0, 0, 500, 500);
var pt:Point = new Point(0, 50);
pmap2.copyPixels(pmap,rect,pt);
Here you can now see the 2 black areas which will be our flat land that we can connect together. Once we have our heightmap generated we can use the jiglibflash to create the terrain by using the following
terrain = physics.createTerrain(pmap2,MaterialTerrain, 500,600,40,11,11);
There are a few more steps to getting up and running with jiglibflash , if you are a little confused i suggest reading up on my previous post here which is a little more detailed or download the example files at the bottom of this post. Anyway now we have our terrain what i want to do is put this together with my carpet and have it move and update the terrain as we move. To do this i have setup 2 functions one called setupTerrain() and one called updateTerrain(). As you might expect the setupTerrain creates the initial section of terrain positions it and scales it to what is needed. Along with this is a variable called changeoverdistance which is used to increment every time a new piece of terrain is used.
package
{
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.Debug;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Object3DContainer;
import alternativa.engine3d.core.View;
import alternativa.engine3d.materials.FillMaterial;
import alternativa.engine3d.materials.TextureMaterial;
import alternativa.engine3d.containers.*;
import alternativa.engine3d.core.MipMapping;
import alternativa.engine3d.primitives.Sphere;
import alternativa.engine3d.primitives.Box;
import alternativa.engine3d.core.RayIntersectionData;
import alternativa.engine3d.core.MouseEvent3D;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.geom.Vector3D;
import jiglib.geometry.*;
import jiglib.physics.*;
import jiglib.math.*;
import net.glassesfactory.alt3dkit.jiglib.*;
import WavePlane;
import DesertSkyBox;
[SWF(backgroundColor="#000000", frameRate="100", width="800", height="600")]
public class test1 extends Sprite
{
[Embed(source="carpet.jpg")] static private const Carpet:Class;
[Embed(source="terraintex.jpg")] static private const Terraintex:Class;
private var rootContainer:Object3DContainer = new Object3DContainer();
private var terrainContainer:ConflictContainer = new ConflictContainer();
private var carpetContainer:Object3DContainer = new Object3DContainer();
private var camera:Camera3D;
private var terrain:JTerrain;
private var physics:GFAlternativa3DPhysics;
private var carpet:WavePlane;
private var MaterialCarpet:TextureMaterial;
private var MaterialTerrain:TextureMaterial;
private var sbox:DesertSkyBox;
private var changeoverdistance:int = 0;
private var pmap2:BitmapData;
public function test1():void
{
//setup stage
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
//setup textures
MaterialCarpet = new TextureMaterial(new Carpet().bitmapData,false,true,MipMapping.PER_PIXEL);
MaterialTerrain = new TextureMaterial(new Terraintex().bitmapData,false,true,MipMapping.PER_PIXEL);
//setup camera
camera = new Camera3D();
camera.view = new View(stage.stageWidth, stage.stageHeight);
addChild(camera.view);
addChild(camera.diagram);
camera.y = -65;
camera.z = 10;
camera.lookAt(0,0,0);
carpetContainer.addChild(camera);
//setup skybox
sbox = new DesertSkyBox(20000);
rootContainer.addChild(sbox);
//setup physics and terrain
physics = new GFAlternativa3DPhysics(terrainContainer, 8);
//setup initial terrain
setupTerrain();
//setup carpet
setupCarpet();
// Listeners
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(Event.RESIZE, onResize);
}
private function setupCarpet():void
{
carpetContainer.y = 60;
carpetContainer.rotationX = -90*Math.PI/180;
carpetContainer.rotationY = -180*Math.PI/180;
carpet = new WavePlane(2,40,60,1,36,true,true,true,MaterialCarpet,MaterialCarpet);
carpet.z = -20;
carpetContainer.addChild(carpet);
carpet.scaleX = carpet.scaleY = carpet.scaleZ = 0.5;
rootContainer.addChild(carpetContainer);
}
private function setupTerrain():void
{
createHeightMap();
terrain = physics.createTerrain(pmap2,MaterialTerrain, 500,600,40,11,11);
terrain.restitution = 1;
GFAlt3dTerrain(terrain.terrainMesh).rotationY = -180*Math.PI/180;
GFAlt3dTerrain(terrain.terrainMesh).scaleY = GFAlt3dTerrain(terrain.terrainMesh).scaleX = GFAlt3dTerrain(terrain.terrainMesh).scaleZ = 2;
changeoverdistance = 1;
rootContainer.addChild(terrainContainer);
}
private function createHeightMap():void
{
var pmap:BitmapData = new BitmapData(500, 500);
var _seed:uint = Math.round(Math.random()*100);
pmap.perlinNoise(500,500, 6, _seed, true, false, 1, true);
//copy to a new bitmapdata so we can have a flat area
//at the start and end so we can seamlessly join them
pmap2 = new BitmapData(500, 600,false,0x000000);
var rect:Rectangle = new Rectangle(0, 0, 500, 500);
var pt:Point = new Point(0, 50);
pmap2.copyPixels(pmap,rect,pt);
}
private function updateTerrain():void
{
//add more terrain as we progress forward
if(carpetContainer.z >= (changeoverdistance * 1200) - 1500)
{
terrain = physics.createTerrain(pmap2,MaterialTerrain, 500,600,40,11,11);
//GFAlt3dTerrain(terrain.terrainMesh).rotationX = -90*Math.PI/180;
GFAlt3dTerrain(terrain.terrainMesh).rotationY = -180*Math.PI/180;
GFAlt3dTerrain(terrain.terrainMesh).z = changeoverdistance * 1200;
GFAlt3dTerrain(terrain.terrainMesh).scaleY = GFAlt3dTerrain(terrain.terrainMesh).scaleX = GFAlt3dTerrain(terrain.terrainMesh).scaleZ = 2;
changeoverdistance++;
}
}
private function onEnterFrame(e:Event):void
{
//always move carpet forward
carpetContainer.z += 2;
//add new terrain if needed
updateTerrain();
//integrate jiglib physics
physics.engine.integrate(0.1);
//render
camera.render();
}
private function onResize(e:Event = null):void {
camera.view.width = stage.stageWidth;
camera.view.height = stage.stageHeight;
}
private function randRange(minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
}
}
To finish this off i have added a skybox around the whole scene so we have a better environment. I have used some sample skybox images from the website http://www.3delyvisions.com/skf1.htm
package
{
import alternativa.engine3d.objects.SkyBox;
import alternativa.engine3d.materials.TextureMaterial;
public class DesertSkyBox extends SkyBox
{
[Embed(source="backred2.jpg")] static private const backred:Class;
[Embed(source="frontred2.jpg")] static private const frontred:Class;
[Embed(source="leftred2.jpg")] static private const leftred:Class;
[Embed(source="rightred2.jpg")] static private const rightred:Class;
[Embed(source="topred2.jpg")] static private const topred:Class;
public function DesertSkyBox(size:Number):void
{
var left:TextureMaterial = new TextureMaterial(new leftred().bitmapData);
var right:TextureMaterial = new TextureMaterial(new rightred().bitmapData);
var back:TextureMaterial = new TextureMaterial(new backred().bitmapData);
var front:TextureMaterial = new TextureMaterial(new frontred().bitmapData);
//var bottom:TextureMaterial = new TextureMaterial(new backred().bitmapData);
var top:TextureMaterial = new TextureMaterial(new topred().bitmapData);
super(size, left, right, back, front, null, top, 0);
this.rotationX = -90*Math.PI/180;
}
}
}
Comments
Comments are currently closed