LogoLogo
  • Home
  • Projects
  • About
  • Contact

Rockin and Rollin with the JiglibFlash Terrain

Devon O. · March 16, 2010 · Actionscript, Flash · 8 comments
6

Finally got the chance to play around with the new JiglibFlash height map terrain, today, and have to say I am very impressed!

The first thing I noticed missing, though, was the ability to update the terrain in order to use animated height maps. I tried deleting then creating a new terrain inside a rendering event handler. This actually worked better than it sounds like it might. At least for a very short time. Going this route, within less than a minute, the frame rate dropped from around 58 to around 15 and the memory usage was well over 400 and climbing steadily to an inevitable crash. I knew an update function was needed for any animation.

Before I dig into the nerd stuff, have a look at what I’m talking about. Double click the example below to see an animated JTerrain instance in action (double click on it a second time to stop the animation and save a bit of processor power). And this is just using perlin noise. You could also use sound data (mp3 or microphone), video data, etc. etc (giving myself some ideas and goosebumps just thinking about it).

Get Adobe Flash player

If you’d like to try this out yourself, here’s the changes I made to a few of the jiglib core classes (for Papervision3D only, so far). In ITerrain.as add just a simple function update():void to the interface methods.

In JTerrain, you’ll need to add a quick update method

C#
1
2
3
public function update():void {
    _terrain.update();
}

The tricky part comes in pv3dTerrain.as. First you’ll need to add some private variables to keep a few things persistent:

C#
1
2
3
4
private var _map:BitmapData;
private var _d:Number;
private var _w:Number;
private var _maxHH:Number;

In the constructor, you’ll actually want to set those vars:

C#
1
2
3
4
5
// set for updating
_map = terrainHeightMap;
_d = depth;
_w = width;
_maxHH = maxHeight;

In the build terrain method, you’ll want to change these 2 lines:

C#
1
2
var vertices :Array  = this.geometry.vertices;
var faces    :Array  = this.geometry.faces    ;

to:

C#
1
2
var vertices :Array  = this.geometry.vertices    = [];
var faces    :Array  = this.geometry.faces        = [];

in order to create the vertices and faces arrays from scratch every time this method is called.

Finally, still in the pv3dTerrain.as file, you’ll need to add an update method that calls the buildTerrain method using our stored variables like so:

C#
1
2
3
public function update():void {
    buildTerrain(_w, _d, _maxHH, _map);
}

Now, keep in mind that doing this may add to a bit more memory consumption when not using animated terrains, as a reference to your bitmapdata is now stored within your terrain instance (but you always destroy bitmapdata when through with it, right?), plus, who knows, it may just break something down the road, so I’d recommend keeping a back up of the original files if you give this a try.

In any case, when done, you can create the example above with the script below:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
package {
 
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Point;
    import flash.geom.Vector3D;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
 
    import jiglib.geometry.JSphere;
    import jiglib.geometry.JTerrain;
    import jiglib.plugin.papervision3d.Papervision3DPhysics;
    import jiglib.plugin.papervision3d.Pv3dMesh;
 
    import net.hires.debug.Stats;
 
    import org.papervision3d.cameras.Camera3D;
    import org.papervision3d.lights.PointLight3D;
    import org.papervision3d.materials.shadematerials.PhongMaterial;
    import org.papervision3d.objects.DisplayObject3D;
    import org.papervision3d.objects.primitives.Sphere;
    import org.papervision3d.render.BasicRenderEngine;
    import org.papervision3d.scenes.Scene3D;
    import org.papervision3d.view.Viewport3D;
 
    /**
     * Animated JiglibFlash terrain example
     * @author Devon O.
     */
 
    [SWF(width='550', height='400', backgroundColor='#000000', frameRate='60')]
    public class Main extends Sprite {
 
        public static const NUM_BALLS:int = 5;
 
        private var _scene:Scene3D;
        private var _cam:Camera3D;
        private var _light:PointLight3D;
        private var _view:Viewport3D;
        private var _eng:BasicRenderEngine;
 
        private var _lightAngle:Number = 0;
 
        private var _terrain:JTerrain;
        private var _terrainMap:BitmapData;
        private var _offsetPoint:Point;
        private var _seed:int;
 
        private var _physics:Papervision3DPhysics;
 
        private var _balls:Vector. = new Vector.(NUM_BALLS, true);
 
        private var _appSeen:Boolean = false;
        private var _noApp:Sprite;
 
        public function Main():void {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
 
        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
 
            init3D();
            initPhysics();
            initScene();
 
            addChild(new Stats());
 
            _noApp = createNoApp();
            addChild(_noApp);
 
            stage.doubleClickEnabled = true;
            stage.addEventListener(MouseEvent.DOUBLE_CLICK, startStop);
        }
 
        private function startStop(event:MouseEvent):void {
            if (_appSeen) {
                stopRendering();
                addChild(_noApp);
            } else {
                startRendering();
                if (contains(_noApp)) removeChild(_noApp);
            }
            _appSeen = !_appSeen;
        }
 
        private function createNoApp():Sprite {
            var s:Sprite = new Sprite();
            s.mouseEnabled = false;
            s.graphics.beginFill(0x000000);
            s.graphics.drawRect(0, 0, 550, 400);
            s.graphics.endFill();
            var tf:TextField = new TextField();
            tf.defaultTextFormat = new TextFormat("_sans", 12, 0xFFFFFF);
            tf.selectable = false;
            tf.mouseEnabled = false;
            tf.autoSize = TextFieldAutoSize.LEFT;
            tf.text = "Double Click to Start.";
            tf.x = Math.round(550 * .5 - tf.width * .5);
            tf.y = Math.round(400 * .5 - tf.height * .5);
            s.addChild(tf);
            return s;
        }
 
        private function init3D():void {
            _view = new Viewport3D(stage.stageWidth, stage.stageHeight);
            addChild(_view);
 
            _cam = new Camera3D();
            _cam.z = -500;
            _cam.y = 400;
 
            _light = new PointLight3D();
            _light.y = 500;
 
            _cam.target = new DisplayObject3D();
 
            _scene = new Scene3D();
            _eng = new BasicRenderEngine();
        }
 
        private function initPhysics():void {
            _physics = new Papervision3DPhysics(_scene, 8);
        }
 
        private function initScene():void {
            // terrain stuff
            var tmat:PhongMaterial = new PhongMaterial(_light, 0x000077, 0x000000, 0);
            _terrainMap = new BitmapData(100, 100, false);
            _seed = int(Math.random() * 10000);
            _offsetPoint = new Point();
 
            _terrain = _physics.createTerrain(_terrainMap, tmat, 600, 600, 200, 9, 9);
 
            // just so you can see the bitmapdata creating the terrain
            var bmp:Bitmap = new Bitmap(_terrainMap);
            bmp.y = 300;
            addChild(bmp);
 
            // add the balls to the mix
            var bmat:PhongMaterial = new PhongMaterial(_light, 0xFF00FF, 0x000000, 0);
            for (var i:int = 0; i < NUM_BALLS; i++) {
                var ball:Sphere = new Sphere(bmat, 30);
                _scene.addChild(ball);
 
                // keep balls in front of terrain at all times with line below
                //_view.getChildLayer(ball).layerIndex = (i+1);
 
                var jball:JSphere = new JSphere(new Pv3dMesh(ball), 30);
                jball.moveTo(new Vector3D(0, i * 200, 0));
                _balls[i] = jball;
                _physics.addBody(jball);
            }
        }
 
        private function startRendering():void {
            addEventListener(Event.ENTER_FRAME, render);
        }
 
        private function stopRendering():void {
            removeEventListener(Event.ENTER_FRAME, render);
        }
 
        private function render(event:Event):void {
            // wrinkle up then update the terrain
            _offsetPoint.x += 1;
            _offsetPoint.y -= 1;
            _terrainMap.perlinNoise(50, 50, 1, _seed, true, false, 7, true, [_offsetPoint]);
 
            _terrain.update();
 
            // orbit the light around
            _light.z = Math.sin(_lightAngle) * 200;
            _light.x = Math.cos(_lightAngle) * 200;
            _lightAngle += 0.05;
 
            // ease the camera back and forth according to mouse pos
            var ratio:Number = ((stage.mouseX / stage.stageWidth) - .5) * 2;
            _cam.x += ((ratio * 500) - _cam.x) * .1;
 
            // check on the family jewels
            var i:int = NUM_BALLS;
            while (i--) {
                var jball:JSphere = _balls[i];
                if ((jball.z < -300) || (jball.z > 300) || (jball.x < -300) || (jball.x > 300)) jball.moveTo(new Vector3D(0, 400, 0));
            }
 
            // render it all
            _physics.engine.integrate(0.2);
            _eng.renderScene(_scene, _cam, _view);
        }
    }
}

Next up – a little ragdoll action… Woot!

  Facebook   Pinterest   Twitter   Google+
jiglibflashphysicsterrain
  • Save/Retrieve ByteArrays to/from Database via AMFPHP
    May 07, 2009 · 10 comments
    4754
    3
    Read more
  • An Ending and a Beginning
    December 31, 2007 · 4 comments
    1792
    3
    Read more
  • Santabot: A Unity3D Flash Game
    December 26, 2011 · 4 comments
    2714
    13
    Read more
8 Comments:
  1. Nice work… (as always).

    longerlife · March 16, 2010
  2. Thanks, LL…

    Devon O. · March 19, 2010
  3. Thank you so much, I’ve been looking for a way to update the terrain for a few weeks now. You the man!

    SteenMSU · March 24, 2010
  4. No – YOU the man.. :)
    You really from MSU? Went to UofM, myself.. many many moons ago, that is…
    Have fun with the terrain, but a word of warning, seems more than 8 or so horizontal/vertical segments and it no longer seems to work so well (see the post after this)..

    Devon O. · March 24, 2010
  5. Ha ha, what a small world. I just finished my Masters at MSU in December. Thanks for the heads up :)

    SteenMSU · March 24, 2010
  6. Very helpful! I was working on something similar where I needed regular updates to the JTerrain and MAN, the memory was going through the roof! Your solution was exactly what I needed.

    Patrick · May 03, 2010
  7. Thanks again Devon! Here’s my terrain painting experiment that greatly benefited from your post: http://blog.ironandroid.com/?p=23. Wouldn’t mind a comment if you had the time. Download the source and have fun.

    Patrick · May 15, 2010

Leave a Comment! Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Devon O. Wolfgang

AIR | Unity3D | AR/VR

Unity Certified Developer

Technical Reviewer of “The Essential Guide to Flash CS4 AIR Development” and “Starling Game Development Essentials”

Reviewer of “The Starling Handbook”

Unity Engineer at Touch Press.

Categories
  • Actionscript (95)
  • AIR (16)
  • Flash (99)
  • Games (7)
  • Liberty (13)
  • Life (53)
  • Shaders (20)
  • Unity3D (21)
Recent Comments
  • MainDepth on Unity Ripple or Shock Wave Effect
  • Devon O. on Unity Ripple or Shock Wave Effect
  • Feral_Pug on Unity Ripple or Shock Wave Effect
  • bavvireal on Unity3D Endless Runner Part I – Curved Worlds
  • Danielius Vargonas on Custom Post Processing with the LWRP
Archives
  • December 2020 (1)
  • December 2019 (1)
  • September 2019 (1)
  • February 2019 (2)
  • December 2018 (1)
  • July 2018 (1)
  • June 2018 (1)
  • May 2018 (2)
  • January 2018 (1)
  • December 2017 (2)
  • October 2017 (1)
  • September 2017 (2)
  • January 2017 (1)
  • July 2016 (1)
  • December 2015 (2)
  • March 2015 (1)
  • September 2014 (1)
  • January 2014 (1)
  • August 2013 (1)
  • July 2013 (1)
  • May 2013 (1)
  • March 2013 (2)
  • December 2012 (1)
  • November 2012 (1)
  • September 2012 (3)
  • June 2012 (2)
  • May 2012 (1)
  • April 2012 (1)
  • December 2011 (2)
  • October 2011 (3)
  • September 2011 (1)
  • August 2011 (1)
  • July 2011 (1)
  • May 2011 (2)
  • April 2011 (2)
  • March 2011 (1)
  • February 2011 (1)
  • January 2011 (2)
  • December 2010 (3)
  • October 2010 (5)
  • September 2010 (1)
  • July 2010 (2)
  • May 2010 (5)
  • April 2010 (2)
  • March 2010 (7)
  • February 2010 (5)
  • January 2010 (5)
  • December 2009 (3)
  • November 2009 (1)
  • October 2009 (5)
  • September 2009 (5)
  • August 2009 (1)
  • July 2009 (1)
  • June 2009 (2)
  • May 2009 (6)
  • April 2009 (4)
  • March 2009 (2)
  • February 2009 (4)
  • January 2009 (1)
  • December 2008 (5)
  • November 2008 (2)
  • September 2008 (1)
  • August 2008 (6)
  • July 2008 (6)
  • June 2008 (9)
  • May 2008 (4)
  • April 2008 (3)
  • March 2008 (4)
  • February 2008 (9)
  • January 2008 (7)
  • December 2007 (6)
Copyright © 2021 Devon O. Wolfgang