Tag Archives: as3

Matrix Zoom and Pan

Actionscript:
  1. [SWF(width=600, height=600, frameRate=30)]
  2. var sw:Number = stage.stageWidth;
  3. var sh:Number = stage.stageHeight;
  4.  
  5. var s:Shape = Shape(addChild(new Shape()));
  6.  
  7. var scale:Number = 1;
  8. var scaleDest:Number = 1;
  9. var down:Boolean = false;
  10. var dx:Number = 0, dy:Number = 0, time:Number = 0;
  11.  
  12. buttonMode = true;
  13.  
  14. addInstructions();
  15. vectorTexture();
  16.  
  17. stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
  18. stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
  19. addEventListener(Event.ENTER_FRAME, onLoop);
  20.  
  21. function addInstructions():void{
  22.     var instruct:Sprite = Sprite(addChild(new Sprite()));
  23.     with (instruct.graphics) beginFill(0x666666), drawRect(0,0,270, 30);
  24.     instruct.x = instruct.y = 20;
  25.     var txt:TextField = TextField(instruct.addChild(new TextField()));
  26.     txt.defaultTextFormat = new TextFormat("Verdana", 11);
  27.     txt.x = txt.y = 5;
  28.     txt.selectable = false;
  29.     with (txt) textColor = 0xFFFFFF, autoSize = "left", text = "Click and hold to zoom, move mouse to pan";
  30. }
  31.  
  32. function vectorTexture():void{
  33.     var cols:Vector.<uint> = Vector.<uint>([0xFFFFFF, 0x000000]);
  34.     var rnd:Vector.<Number> = new Vector.<Number>(6, true);
  35.    
  36.     for(var i:int = 0 ; i<50; i++){
  37.         with(s.graphics){
  38.             lineStyle(Math.random() * 50 + 2, cols[int(Math.random()*cols.length)]);
  39.             drawCircle(Math.random() * sw, Math.random() * sh, 10 + Math.random() * Math.random() * 400);
  40.         }
  41.     }
  42.     s.graphics.lineStyle(20, 0xCCCCCC);
  43.     s.graphics.drawRect(0, 0,sw, sh);
  44. }
  45.  
  46. function onDown(evt:MouseEvent):void{ down = true; }
  47. function onUp(evt:MouseEvent):void{ down = false; }
  48. function onLoop(evt:Event):void {
  49.    if (down){
  50.      scaleDest *= 1.05;  
  51.      time = 0;
  52.    }else{
  53.      time++;
  54.      // zoom out after 30 iterations
  55.      if (time == 30){
  56.          scaleDest = 1;  
  57.      }
  58.    }
  59.    scale += (scaleDest - scale) / 4;
  60.    if (scale> 10) scale = scaleDest = 10;
  61.    
  62.    dx += (mouseX - dx) / 4;
  63.    dy += (mouseY - dy) / 4;
  64.    if (dx <0) dx = 0;
  65.    if (dy <0) dy = 0;
  66.    if (dx> sw) dx = sw;
  67.    if (dy> sh) dy = sh;
  68.    
  69.    // matrix zoom/pan
  70.    var m:Matrix = s.transform.matrix;
  71.    m.identity();
  72.    m.translate(-dx,-dy);
  73.    m.scale(scale, scale);
  74.    m.translate(dx,dy);
  75.    s.transform.matrix = m;
  76. }

I haven't been by the computer much these last two weeks - been traveling. Going back to nyc tomorrow so I'll go back to posting once a day.

This snippet uses a transformation matrix to zoom in and pan a Sprite instance. For demo purposes I filled the sprite with a few circles - but you'd likely be using this with a vector image of a map, a floor plan or some other graphic that warrants zooming and panning.

Back around flash 7 (I think) before the Matrix class was introduced we used to have to use MovieClip nesting to achieve this effect.


Have a look at the swf...


Posted in Graphics, matrix, motion | Also tagged , | Leave a comment

Distance Spring

Actionscript:
  1. [SWF(backgroundColor=0x222222, width=500, height=500)]
  2. var hsw:Number = stage.stageWidth / 2;
  3. var hsh:Number = stage.stageHeight / 2;
  4. var pointNum:int = 800
  5. var points3D:Vector.<Number> = new Vector.<Number>();
  6. var points3Dout:Vector.<Number> = new Vector.<Number>();
  7. var points2D:Vector.<Number> = new Vector.<Number>();
  8. var uvts:Vector.<Number> = new Vector.<Number>();
  9. var sorted:Array = [];
  10. var pnt:Point = new Point();
  11. var m:Matrix3D = new Matrix3D();
  12. var v:Vector3D = new Vector3D();
  13. for (var i:int = 0; i<pointNum; i++){
  14.     v.y = i * 0.7 - 300
  15.     var t =Math.random()*6.28;
  16.     v.x = 200 * Math.cos(i * 2 * Math.PI / 180);
  17.     v.z = 200 * Math.sin(i * 2 * Math.PI / 180);
  18.     v = m.transformVector(v);
  19.     points3D.push(v.x, v.y, v.z);
  20.     points2D.push(0,0);
  21.     uvts.push(0,0,0);
  22.     sorted.push(new Vector3D());
  23. }
  24. points3D.fixed = true;
  25. points2D.fixed = true;
  26. uvts.fixed = true;
  27. var p:PerspectiveProjection = new PerspectiveProjection();
  28. var proj:Matrix3D = p.toMatrix3D();
  29. var dx:Number = 0, dy:Number = 0;
  30. addEventListener(Event.ENTER_FRAME, onLoop);
  31. function onLoop(evt:Event):void {
  32.     var i:int, j:int;
  33.     dx += (mouseX - dx) / 4;
  34.     dy += (mouseY - dy) / 4;
  35.     m.identity();
  36.     m.appendRotation(getTimer() / 4, Vector3D.Y_AXIS);
  37.     m.transformVectors(points3D, points3Dout);
  38.    
  39.     m.identity();
  40.     m.appendRotation(dx, Vector3D.Z_AXIS);
  41.     m.appendRotation(dy, Vector3D.X_AXIS);
  42.     m.appendTranslation(0, 0, 1000);
  43.     m.append(proj);
  44.     Utils3D.projectVectors(m, points3Dout, points2D, uvts);
  45.     for (i = 0, j = 0; i<points2D.length; i+=2, j++){
  46.         sorted[j].x = points2D[i] + hsw;
  47.         sorted[j].y = points2D[i + 1] + hsh;
  48.         sorted[j].z = uvts[j * 3 + 2];
  49.     }
  50.     sorted.sortOn("z", Array.NUMERIC);
  51.     graphics.clear();
  52.     for(i = 0; i<sorted.length; i++){
  53.         var zpos:Number = sorted[i].z * 10000;
  54.         var c:int = zpos * 14;
  55.         graphics.beginFill(c <<16 | c <<8 | c);
  56.         graphics.drawCircle(sorted[i].x, sorted[i].y, zpos);
  57.         graphics.endFill();
  58.     }
  59. }

A variation on some recent posts... this snippet draws a rotating spring made up of 800 particles...

Have a look at the swf...


Posted in 3D, Graphics, Vector | Also tagged , | 3 Comments

QuickBox2D create() Method

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2. import Box2D.Common.Math.*;
  3. import Box2D.Collision.Shapes.*;
  4.  
  5. [SWF(width = 600, height = 600, backgroundColor = 0x000000, frameRate=60)]
  6.  
  7. var sim:QuickBox2D = new QuickBox2D(this);
  8.  
  9. sim.setDefault({fillColor:0x990000, lineColor:0xFFCC00});
  10. sim.createStageWalls();
  11.  
  12. var shapeTypes:Array = ["circle", "box", "poly"];
  13. var pnts:Array = [-1, 0, -0.5, -1, 0.5, -1, 1, 0, 0,0.5, -1, 0];
  14. var poly:Array=[];
  15. for (var i:int = 0; i<20; i++){
  16.     var xp:Number = 3 + Math.random()*15;
  17.     var yp:Number = 3 + Math.random()*15;
  18.     var w:Number = 0.2 + Math.random() * 2;
  19.     var h:Number = 0.2 + Math.random() * 2;
  20.     var r:Number = 0.2 + Math.random();
  21.     var ang:Number = Math.random() * Math.PI * 2;
  22.     var index:Number = int(Math.random()*shapeTypes.length);
  23.     var s:Number = 0.3 + Math.random()*0.7;
  24.     for (var j:int = 0; j<pnts.length; j++){
  25.          poly[j] = pnts[j] * s;
  26.     }
  27.     sim.setDefault({fillColor:int(Math.random()*255) <<16, lineColor:0xFFCC00});
  28.     sim.create(shapeTypes[index], {x:xp, y:yp, width:w, height:h, angle:ang, radius:r, points:poly, wireframe:false})
  29. }
  30.  
  31. sim.start();
  32. sim.mouseDrag();

Was showing someone QuickBox2D today and created this demo after showing them a few other posts. After writing this, I realized I hadn't posted about the QuickBox2D.create() method. Which is what addBox(), addRect(), addJoint() etc.. use internally. It takes a string for the type of QuickObject you'd like to create along with the standard params Object. Note that depending on the QuickObject type certain params will simply be ignored - for example radius is ignored when the type is "box" etc...


Have a look at the swf...

Posted in Box2D, QuickBox2D | Also tagged , , | 1 Comment

QuickBox2D groupIndex Platforms

Actionscript:
  1. import com.actionsnippet.qbox.*;
  2. import Box2D.Common.Math.*;
  3. import Box2D.Collision.Shapes.*;
  4.  
  5. [SWF(width = 800, height = 600, backgroundColor = 0x000000)]
  6.  
  7. var sim:QuickBox2D = new QuickBox2D(this);
  8.  
  9. sim.createStageWalls();
  10.  
  11. var boxNum:int = 8;
  12. var boxes:Array = [];
  13. var xp:Number, yp:Number, w:Number;
  14. for (var i:int = 0; i<boxNum; i++){
  15.     xp = 3 + Math.random() * 10;
  16.     yp = 4 + i * 2;
  17.     w = 2 + Math.random() * 3;
  18.     boxes.push(sim.addBox({x: xp, y: yp, width: w, height: 0.5, density:0, groupIndex:-1, fillColor:0xFF6532}));
  19. }
  20.  
  21. var char:QuickObject = sim.addBox({x:2, y:18, width:1, height:2, allowSleep:false, groupIndex:-1, fillColor:0x0099CC});
  22.  
  23. sim.start();
  24.  
  25. var charVel:b2Vec2;
  26. var charVelAng:Number;
  27.  
  28. addEventListener(Event.ENTER_FRAME, onLoop);
  29. function onLoop(evt:Event):void {
  30.      
  31.     charVel = char.body.GetLinearVelocity();
  32.     charVelAng =  char.body.GetAngularVelocity();
  33.     var filter:b2FilterData;
  34.    
  35.     if (key[Keyboard.RIGHT]){
  36.         charVel.x += 1
  37.         char.body.SetLinearVelocity(charVel);
  38.         charVelAng += 1;
  39.         char.body.SetAngularVelocity(charVelAng);
  40.     }
  41.     if (key[Keyboard.LEFT]){
  42.         charVel.x -=1;
  43.         char.body.SetLinearVelocity(charVel);
  44.         charVelAng -= 1;
  45.         char.body.SetAngularVelocity(charVelAng);
  46.     }
  47.     if (key[Keyboard.UP] && sim.w.GetContactCount()> 0){
  48.          charVel.y = -10;
  49.          trace(charVel.y);
  50.          char.body.SetLinearVelocity(charVel);
  51.          charVelAng *= 0.8;
  52.          char.body.SetAngularVelocity(charVelAng);
  53.     }
  54.     for (var i:int = 0; i<boxes.length; i++){
  55.         var rect:Rectangle = char.userData.getRect(this);
  56.         if (rect.bottom / 30 <boxes[i].y){
  57.             filter = boxes[i].shape.GetFilterData();
  58.             filter.groupIndex = 1;
  59.             boxes[i].shape.SetFilterData(filter);
  60.         }else{
  61.             filter = boxes[i].shape.GetFilterData();
  62.             if (filter.groupIndex != -1){
  63.                 filter.groupIndex = -1;
  64.                 boxes[i].shape.SetFilterData(filter);
  65.             }
  66.         }
  67.     }
  68. }
  69.  
  70. var key:Object = new Object();
  71. stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed);
  72. stage.addEventListener(KeyboardEvent.KEY_UP, onKeyReleased);
  73. function onKeyPressed(evt:KeyboardEvent):void{ key[evt.keyCode] = true; }
  74. function onKeyReleased(evt:KeyboardEvent):void{ key[evt.keyCode] = false; }

NOTE: This requires the QuickBox2D mini-library

This snippet shows how to use groupIndex to create simple platforms for a character to jump on. A few people have asked me about this so I figured I'd post about it. It works by altering the groupIndex of each platform based on the characters position - if the character is below a platform, both the character and the platform have groupIndex -1 (meaning they will not collide). As soon as the character is above a platform, the platforms groupIndex is set to 1 (allowing the character to walk on the platform despite having just passed through it.


Have a look at the swf...


It's also worth noting that I'm using b2World.GetContactCount() to make sure it's ok to jump... if there were more going on in the demo you'd need to check a specific contact point(s), but since the only collision that could happen involves the character this works nicely...

Posted in Box2D, QuickBox2D | Also tagged , , , | 10 Comments