UV Scrolling in Starling

One of the things that really appealed to me about ND2D over the Starling Framework was the ability to scroll textures by manipulating their UV coordinates like this. Obviously this could come in pretty darned handy for space games, side scrollers, etc, etc.

Well, as it turns out, doing the same thing is also pretty easy in Starling using the Image object’s setTexCoords() method. Generally speaking, you loop through the four vertex points of the Image in question, get the coordinates of each vertex using getTexCoords() (which returns a Point instance), add a very small amount to the x and y properties of that point, then reset the coordinates of that vertex with setTexCoords() (which takes the vertex id and a Point).

Stealing assets like some mad pirate (the star fields from the ND2D example above and the ship from Lee Brimelow’s space game), I came up from this quick example here (around 430k with no preloader).

And the full source for the Starling bit (the magic taking place in updateStarfields() )…

/**
 *	Copyright (c) 2012 Devon O. Wolfgang
 *
 *	Permission is hereby granted, free of charge, to any person obtaining a copy
 *	of this software and associated documentation files (the "Software"), to deal
 *	in the Software without restriction, including without limitation the rights
 *	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *	copies of the Software, and to permit persons to whom the Software is
 *	furnished to do so, subject to the following conditions:
 *
 *	The above copyright notice and this permission notice shall be included in
 *	all copies or substantial portions of the Software.
 *
 *	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *	THE SOFTWARE.
 */

package  
{
	import flash.display.Bitmap;
	import flash.geom.Point;
	import starling.core.Starling;
	import starling.display.BlendMode;
	import starling.display.Image;
	import starling.display.Sprite;
	import starling.events.Event;
	import starling.events.TouchEvent;
	import starling.extensions.ParticleDesignerPS;
	import starling.textures.Texture;

	/**
	 * Quick example of scrolling UV coordinates in Starling Framework
	 * @author Devon O.
	 */
	public class STest extends Sprite
	{
		[Embed(source="../assets/starfield.jpg")]
		private static const SF1:Class;

		[Embed(source = "../assets/starfield.png")]
		private static const SF2:Class;

		[Embed(source = "../assets/ship.png")]
		private static const SHIP_IMG:Class;

		[Embed(source = "../assets/parts/particle.pex", mimeType = "application/octet-stream")]
		private static const CFG:Class;

		[Embed(source = "../assets/parts/texture.png")]
		private static const PART_IMG:Class;

		private static const SCREEN_WIDTH:int = 600;
		private static const SCREEN_HEIGHT:int = 600;	

		private var mMousePos:Point = new Point();
		private var mStarfield1:Image;
		private var mStarfield2:Image;
		private var mShip:Sprite;

		public function STest() 
		{	
			initStarfieldImages();
			initShip();
			initParticles();

			addEventListener(TouchEvent.TOUCH, onTouch);
			addEventListener(Event.ENTER_FRAME, onTick);
		}

		private function initStarfieldImages():void
		{
			var img:Bitmap;
			var tex:Texture;

			img = new SF1();
			tex = Texture.fromBitmap(img, true, true, .75);
			tex.repeat = true;
			mStarfield1 = new Image(tex)
			addChild(mStarfield1);

			img = new SF2();
			tex = Texture.fromBitmap(img, true, true, .75);
			tex.repeat = true;
			mStarfield2 = new Image(tex)
			mStarfield2.blendMode = BlendMode.SCREEN;
			addChild(mStarfield2);
		}

		private function initShip():void
		{
			mShip = new Sprite();
			var img:Image = Image.fromBitmap(new SHIP_IMG());
			img.x -= img.width * .5;
			img.y -= img.height * .5;
			mShip.addChild(img);
			mShip.x = SCREEN_WIDTH >> 1;
			mShip.y = SCREEN_HEIGHT >> 1;
			addChild(mShip);
		}

		private function initParticles():void
		{
			var exhaust:ParticleDesignerPS = new ParticleDesignerPS(new XML(new CFG()), Texture.fromBitmap(new PART_IMG()));
			exhaust.emitterX = -mShip.width >> 1;
			exhaust.emitterY = 0;
			mShip.addChild(exhaust);
			exhaust.start();
			Starling.juggler.add(exhaust);
		}

		private function onTouch(event:TouchEvent):void
		{
			mMousePos.x = event.getTouch(this).globalX - (SCREEN_WIDTH >> 1);
			mMousePos.y = event.getTouch(this).globalY - (SCREEN_HEIGHT >> 1);
		}

		private function onTick(event:Event):void
		{
			updateStarfields();
			updateShip();
		}

		private function updateStarfields():void
		{
			var p:Point;

			for (var i:int = 0; i < 4; i++) 			{ 				p = mStarfield1.getTexCoords(i); 				p.x += mMousePos.x * .00002; 				p.y += mMousePos.y * .00002; 				mStarfield1.setTexCoords(i, p); 				 				p = mStarfield2.getTexCoords(i); 				p.x += mMousePos.x * .00004; 				p.y += mMousePos.y * .00004; 				mStarfield2.setTexCoords(i, p); 			} 		} 		 		private function updateShip():void 		{ 			var dx:Number = (mMousePos.x + (SCREEN_WIDTH >> 1)  )	- mShip.x;
			var dy:Number = (mMousePos.y + (SCREEN_HEIGHT >> 1) )	- mShip.y;

			mShip.rotation = Math.atan2(dy, dx);
		}
	}
}
Date:
Category: