logo
468x60-2-495


  • Home
  • Privacy Policy
  • About
search
top
Aug 18, 2011 Posted on Aug 18, 2011 in Hints and Tips | 10 comments

PhotoDune – Envato Photo Marketplace

It’s been almost five years since we launched Envato, the company behind this site and many others, and in that time we’ve built eight digital marketplaces for everything from WordPress Themes to Background Music. With our fifth birthday coming up this weekend, we’re excited to announce the beta launch of our ninth marketplace: PhotoDune for royalty free stock photos.

Connects to Other Envato Marketplaces

Like all our marketplaces, this one allows you to use your regular Envato Marketplace account and cash to make purchases. It also has the same familiar interface that you are used to with some new upgrades to search and browsing to cater to the photo market!

If you haven’t got an account yet, you can sign up here.

High Quality, Affordable Prices

Prices for a regular license on photos go from $1 to $9 depending on the size of photo you are buying. That’s incredibly affordable, and what’s more, the level of quality you’ll find on PhotoDune is extremely high. Check out our Top Sellers, or a few of my favourite images below:








Selling on PhotoDune

If you are a photographer interested in selling with PhotoDune, be sure to check out leading industry blog Microstock Diaries’ write up Envato Enters Microstock with PhotoDune and visit PhotoDune to Get Started Selling Your Work.

The Future of the Envato Marketplaces

With our ninth marketplace out, on the eve of our fifth birthday, and with our millionth member milestone in sight for later this year, you might be wondering what’s in store for the Envato Marketplaces?

Over the years we’ve had thousands of authors generate a whole lot of earnings through these sites, with the first one set to break into our million dollar Power Elite group fairly shortly. This community of authors has only gotten stronger and stronger and has become the bedrock of our marketplaces.

Ultimately our mission is always to serve our community, both of authors and buyers. We’re doing this by creating what we hope will be the largest set of creative marketplaces online. Despite having nine marketplaces out, there is a list just as long of new frontiers to explore! There are after all plenty of other things people want to sell!

With each passing year the momentum and community size swells, and this means the marketplaces become ever more effective ways to sell your content. We’ve upped our rates three times in the past so that we can offer our authors a good return on their work, and just as importantly, we offer a happy and vibrant community life to go with it.

So I hope that whether you are a buyer or an author you find PhotoDune useful, and that in years to come we’ll be rocking the photographer success stories from our newest marketplace!



View full post on Activetuts+

banner ad

10 Responses to “PhotoDune – Envato Photo Marketplace”

  1. Dru Kepple says:
    August 18, 2011 at 11:32 pm

    One of the more common questions I see on forums and get from colleagues is how to debug Error 1009, also known as the “Null Object Reference Error.” Or, as I call it, the “Annoying Mosquito Error From Hell.” It crops up a lot, and unfortunately the error itself does not contain much information about the source of the error. In this quick tip, we’ll take a look at some steps you can take to track down this mosquito and squash it good.


    Introduction

    This piece is the first followup to the more general “Fixing Bugs in AS3” tutorial. If you wish to better understand some of the techniques in this tip, you may wish to read that in full first.


    Step 1: Understand the Error

    It’s too bad that Adobe doesn’t (or can’t) provide more information about the root of this error. First of all, it’s rather obtusely worded (much like all of their errors, but this more so than most):

    TypeError: Error #1009: Cannot access a property or method of a null object reference

    Let’s try to put this in everyday terms. Error 1009 means that you’ve tried to do something with a variable that you assume has a value, but really does not. Flash doesn’t like that. You wouldn’t like it either; imagine you had a glass that you assumed was full of the tasty beverage of your choice, but really was empty. You grab the glass, expecting a refreshing swig, but you feel the disappointing weight of an empty glass instead. That’s your own personal Error 1009.

    In ActionScript, if you do this:

    
    
    var s:String;
    trace(s.toUpperCase());
    

    Flash will bum hard (a technical term for “produce an error”) when you run the code. The variable s may have been declared, but its value is null (we never set the value, just declared the variable), so calling the toUpperCase method on it is troublesome.

    To be clear, because s is declared as a String, the compiler takes no issue with the code: there is a variable called s, it’s a String, and toUpperCase is a valid method to call on Strings. The error we get is a run-time error, which means we only get it when we run the SWF. Only when the logic is performed do we now get to see how this turns out.


    Step 2: Permit Debugging

    As with any run-time error, sometimes it’s pretty easy to tell what’s going on without any extra information. But other times it’s helpful to narrow this down further. At this point, try turning on “Permit Debugging.” When this is enabled, you get errors that also give you line numbers. Alternatively, you may be able to “Debug Movie” by pressing Command-Shift-Return / Control-Shift-Enter.

    To do so, see the general debugging tips article, “Fixing Bugs in AS3”

    Sometimes this is enough. Knowing the specific line might be all the information you needed. If not, we’ll dig a little deeper in the next step.

    Our dear editor, Michael James Williams, encapsulated the point of this step in a limerick, which I’m happy to present to you now with his kind permission:

    AS3 error one-oh-oh-nine
    Is never a very good sign.
    No need for concern,
    Hit Ctrl-Shift-Return
    And it’ll pinpoint the cause (well, the line).


    Step 3: Start Tracing

    If you’ve located the offending line but are still unsure what’s going on, pick apart the line. Take every variable in that line and trace them out prior to the error.

    Because the error comes when accessing a property or calling a method on a null variable, to cover your bases you should trace any variables and properties that are immediately followed by a dot. For example, take this line of code:

    
    
    myArray.push(someSprite.stage.align.toLowerCase());
    

    Admittedly, that’s a rather contrived piece of code that I can’t imagine a practical use for, but you should identify four total possible null values that are being accessed with the dot:

    • myArray: we are calling the push method on this variable
    • someSprite: we are accessing the stage property
    • stage: we are accessing the align property
    • align: we are calling the toLowerCase method

    So your debugging code might look like this:

    
    
    trace("myArray: ", myArray);
    trace("someSprite: ", someSprite);
    trace("someSprite.stage: ", someSprite.stage);
    trace("someSprite.stage.align: ", someSprite.stage.align);
    

    Order is important; if someSprite is the null object, but you test for someSprite.stage.align before testing for someSprite, you end up with less definitive results.

    Now, common sense also plays into this. In my example, if stage exists, then align will most assuredly have a value; the Stage always has an align setting, even if it’s the default value.

    Typically, you’ll see something like the following:

    
    
    myArray: [...stuff in the array...]
    someSprite: [object Sprite]
    someSprite.stage: null
    Error #1009: ...
    

    Which should clue you in that the stage property is null, and now you can go about fixing it.


    Step 4: Finding a Solution

    The easiest solution is to wrap up the offending statement in an “if” block, and only run the block if the variable in question is not null. So, assuming that in our previous example, it was in fact stage that was null, we could do something like this:

    
    
    if (someSprite.stage) {
        myArray.push(someSprite.stage.align.toLowerCase());
    }
    

    This test — if (someSprite.stage) — will return true if there is a value (regardless of the value), and false if it’s null. In general this notation works; you can always use if (someSprite.stage != null) if you prefer. Numbers present a slightly different situation, though. If the Number has a value of 0, then technically it has a value, but testing if (someNumberThatEqualsZero) will evaluate to false. For Numbers you can use the isNaN() function to determine if a valid numeric value is stored in a given variable.

    At any rate, this technique is a simple way to sidestep the error. If the variable we want to perform an operation on is not set, then don’t do the operation. If there is no tasty beverage in our glass, don’t pick up the glass. Simple enough.

    But that approach is only feasible if the logic is optional. If the logic is required, then perhaps you can provide a default value to the questionable variable before the error-ing operation. For example, if myArray has the potential to be null, but it’s imperative that it’s not, we can do this:

    
    
    if (!myArray) {
        myArray = [];
    }
    myArray.push(someSprite.stage.align.toLowerCase());
    

    This will first check to see if the array is null. If it is, initialize it to an empty array (an empty array is a valid value. It may be empty, but it’s an array, and not null) before running the contrived line of code. If it’s not null, skip straight to the contrived line of code. In real-life terms, if our glass is empty, then fill it with a tasty beverage before picking it up.

    In addition, if myArray is an instance property of the class in which this line of code is running, you can pretty safely ensure a valid value by initializing your properties when the object initializes.

    What if the logic is required, but the variable in question is not so readily under our control? For example, what if our contrived line of code is required, but the questionable variable is someSprite.stage? We can’t just set the stage property; that’s controlled internally to DisplayObject and is read-only to us mere mortals. Then you may need to get crafty, and read the next step.


    Step 5: Dealing with a null stage

    There are probably an infinite number of scenarios where a given variable or property could be null. Obviously, I can’t cover them all in a Quick Tip. There is one specific situation, however, that crops up again and again.

    Let’s say you write some code that looks like this:

    
    
    public class QuickSprite extends Sprite {
        public function QuickSprite() {
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
        }
        private function onMove(e:MouseEvent):void {
            var color:ColorTransform = new ColorTransform();
            color.color = stage.mouseX / stage.stageWidth * 0xFFFFFF;
            this.transform.colorTransform = color;
        }
    }
    

    Another contrived bit of code (which might induce seizures — consider yourself warned), but basically the idea is that you have a Sprite subclass and you set this as the class for a clip on the stage, using the Flash IDE.

    However, you decide you want to work with these QuickSprites programmatically. So you try this:

    
    
    var qs:QuickSprite = new QuickSprite();
    addChild(qs);
    

    And you get the accursed Error 1009. Why? Because in the QuickSprite constructor, you access the stage property (inherited from DisplayObject). When the object is created entirely with code, it is not on the stage at the point that that line of code runs, meaning stage is null and you get the error. The QuickSprite gets added the very next line, but it’s not soon enough. If the instance is created by dragging a symbol out of the library and onto the stage, then there’s a little bit of magic at work behind the scenes that ensure that the instance is on the stage (that is, the stage property is set) during the constructor.

    So here’s what you do: you test for the existence of a value for stage. Depending on the result, you can either run the set up code right away, or set up a different event listener for when the QuickSprite does get added to the stage. Something like this:

    
    
    public function QuickSprite() {
        if (stage) {
            init();
        } else {
            this.addEventListener(Event.ADDED_TO_STAGE, init);
        }
    }
    private function init(e:Event=null) {
        this.removeEventListener(Event.ADDED_TO_STAGE, init);
        stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
    }
    

    If we move the stage line to a different function, and only call that function when we have a stage, then we’re set. If stage exists from the start, go ahead and run init() right away. If not, we’ll use init() as an event listener function for ADDED_TO_STAGE, at which point we will have a stage value and can run the code. Now we can use the class for either connecting to IDE Sprite or completely programmatically.

    This works well in document classes, too. When you run a SWF by itself, the document class has immediate access to stage. If you load that SWF into another SWF, though, the code in the document class’s initialization stack gets executed before the loaded SWF is added to the display. A similar stage-checking trick will allow you to work with the SWF as both a standalone piece and as a SWF loaded into a containing SWF.


    That Is All

    Thanks for reading this Quick Tip! I hope you are enlightened a bit about how Error 1009 occurs, and how you can debug it. Stay tuned for more Quick Tips on other common errors.


  2. Collis says:
    August 19, 2011 at 12:07 am

    It’s been almost five years since we launched Envato, the company behind this site and many others, and in that time we’ve built eight digital marketplaces for everything from WordPress Themes to Background Music. With our fifth birthday coming up this weekend, we’re excited to announce the beta launch of our ninth marketplace: PhotoDune for royalty free stock photos.

    Connects to Other Envato Marketplaces

    Like all our marketplaces, this one allows you to use your regular Envato Marketplace account and cash to make purchases. It also has the same familiar interface that you are used to with some new upgrades to search and browsing to cater to the photo market!

    If you haven’t got an account yet, you can sign up here.

    High Quality, Affordable Prices

    Prices for a regular license on photos go from $1 to $9 depending on the size of photo you are buying. That’s incredibly affordable, and what’s more, the level of quality you’ll find on PhotoDune is extremely high. Check out our Top Sellers, or a few of my favourite images below:








    Selling on PhotoDune

    If you are a photographer interested in selling with PhotoDune, be sure to check out leading industry blog Microstock Diaries’ write up Envato Enters Microstock with PhotoDune and visit PhotoDune to Get Started Selling Your Work.

    The Future of the Envato Marketplaces

    With our ninth marketplace out, on the eve of our fifth birthday, and with our millionth member milestone in sight for later this year, you might be wondering what’s in store for the Envato Marketplaces?

    Over the years we’ve had thousands of authors generate a whole lot of earnings through these sites, with the first one set to break into our million dollar Power Elite group fairly shortly. This community of authors has only gotten stronger and stronger and has become the bedrock of our marketplaces.

    Ultimately our mission is always to serve our community, both of authors and buyers. We’re doing this by creating what we hope will be the largest set of creative marketplaces online. Despite having nine marketplaces out, there is a list just as long of new frontiers to explore! There are after all plenty of other things people want to sell!

    With each passing year the momentum and community size swells, and this means the marketplaces become ever more effective ways to sell your content. We’ve upped our rates three times in the past so that we can offer our authors a good return on their work, and just as importantly, we offer a happy and vibrant community life to go with it.

    So I hope that whether you are a buyer or an author you find PhotoDune useful, and that in years to come we’ll be rocking the photographer success stories from our newest marketplace!


  3. Activetuts+ Editor says:
    August 19, 2011 at 12:48 am

    It’s time for another excellent Active Premium tutorial exclusively available to Premium members. In this tutorial, you’ll learn how to create a Pong game that can be controlled by moving your hands, and a picture gallery that can be navigated in the style of Minority Report — all in the browser’s Flash Player with no drivers required, if you’re on the Mac.


    Preview

    Let’s take a look at what we will be working towards. First, a Pong game where each paddle is controlled by a player’s hand:

    Second, an image gallery with gesture control, in the style of Minority Report:

    Zoom is two hands on one image and then you expand them away from each other.

    Rotate is two hands on an image, one going up and the other going down.


    Will It Work for Me?

    You’ll need a Kinect, of course! Assuming you have that, if you’re on a Mac, it’s very easy to get this working; no drivers are required. On Windows it’s a little more fiddly: you’ll need to install some drivers, and the libraries to make Flash recognise the Kinect are still in beta and not as polished as the Mac versions.


    Active Premium Membership

    Activetuts+ Premium Membership

    We run a Premium membership system which costs $9 a month (or $22 for 3 months!) which periodically gives members access to extra tutorials, like this one! You’ll also get access to Psd Premium, Vector Premium, Audio Premium, Net Premium, Ae Premium, Cg Premium and Photo Premium too. If you’re a Premium member, you can log in and download the tutorial. If you’re not a member, you can of course join today!

    Also, don’t forget to follow @envatoactive on twitter and grab the Activetuts+ RSS Feed to stay up to date with the latest tutorials and articles.


  4. Daniel Branicki says:
    August 19, 2011 at 1:11 am

    At the end of the first part of this series, we had just created a new shader, which will allow us to hide part of the main character’s sprite when it is part-way concealed by a portal. In this part, we’ll put that to use as we create a portal prototype.


    Final Result Preview

    Let’s take a look at the final result we will be working towards, across the whole of this multi-part tutorial:

    Please view the full post to see the Unity content.

    Hit the number keys 1-8 to try different levels. The aim is to get the little yellow Roly character to the designated end point, using portal mechanics. The demo shows off a few of the different mechanics we’ll introduce.

    It’s going to take us a while to get to that point, though! In this second part of the tutorial, we’ll start work on adding the actual portal objects. Click here to see what we’ll have built by the end of this part.


    Step 1: Create a Portal

    It’s time to create an early portal prototype. Here’s a texture we’ll use to build it.

    Texture for the portal.

    It’s very small, but we will stretch so the portal will look OK. Create a sprite the way you did before, but this time instead of selecting Pixel Perfect, select only Auto Resize. Then change the height of the sprite to 128 and width to 12. Also, you may assign Tiles Material to it.

    Portal sprite settings.
    Portal sprite.

    Now add Box Collider to our portal. Do it the same way we did before, but this time let’s check Is Trigger, because we don’t want our collider to be solid, we want the ball to be able to go through it. Also remember to set it’s z size to 30, so all objects on the ground can detect the collision with it.

    Collider is a trigger.

    The next thing to do is to create a script and name it Portal. This will be the script we attach to the portal, it will store portal related data, such as a linear equation of an axis, its height and what kind of portal does it lead to. Of course you should place this script in the Game Scripts folder.


    Step 2: Set the Portal’s Height

    First thing we need to do is to clean up the script. Change the class’s name to Portal and delete comments.

    
    
    using UnityEngine;
    using System.Collections;
    
    public class Portal : MonoBehaviour
    {
    	void Start ()
    	{
    
    	}
    
    	void Update ()
    	{
    
    	}
    }
    

    First thing that we need to know is height of the portal. We don’t really want to force using sprite’s height as portal’s height, because that will force a correlation between them. What we can use, is our collider’s height, because it can be changed without any visual influence. We need to create a variable that will hold the height for us.

    
    
    using UnityEngine;
    using System.Collections;
    
    public class Portal : MonoBehaviour
    {
    	private float height = 0.0f;
    

    Before we set our height, let’s create a variable that will hold a reference to our PackedSprite component. Since it’s not a unity class, we can’t simply use packedSprite, because it’s not existant. First thing we need to do is to create the variable that we will assign our PackedSprite component to.

    
    
    private float height = 0.0f;
    private PackedSprite sprite;
    

    To assign the reference, we need to use GetComponent() function. It will find the any component we need thats attached to our object, and return a reference to it.

    
    
    void Start ()
    {
    	sprite = GetComponent<PackedSprite>();
    

    Now we can set our height.

    
    
    void Start ()
    {
    	sprite = GetComponent<PackedSprite>();
    
    	height = ((BoxCollider)collider).size.y*transform.localScale.y;
    }
    

    Notice that first we need to cast our collider to BoxCollider. That’s because BoxCollider is a specific collider, and the collider reference points only to the class our BoxCollider inherits from. Notice that we can acces size only if we have a reference to BoxCollider, that’s why we need to cast. Of course we need to multiply the height by the scale of our object, because even when we scale the object, the size of the box collider remains the same.

    Now, how do we figure out the axis the portal goes through? We need to have two points, one at the bottom and second at the top of the portal. If we’ve got that, we can easly figure out portal’s parameters.


    Step 3: Calculate the Portal’s Vertices

    Let’s calculate top and bottom vertices now. There is a usefull Bounds class in collider, that has the data on the volume of our collider in the world space, but we won’t use it, because it would be a bit tricky to calculate the top and bottom vertices using the volume of our object. Instead, let’s first create vertices as if there was no rotation applied to our portal, and then rotate them by the same amount the portal is rotated.

    How do we calculate vertices?

    Let’s start from creating two Vector3s.

    
    
    private float height = 0.0f;
    private PackedSprite sprite;
    private Vector3 top;
    private Vector3 bottom;
    

    Let’s take care of the top vertex first. If we’ve got that, then we can easly calculate the bottom because it’s basically a mirror image of the top.

    
    
    height = ((BoxCollider)collider).size.y*transform.localScale.y;
    top = new Vector3(transform.position.x, transform.position.y + height, transform.position.z);
    

    We simply set the top to the top of our unrotated portal. Now, if portal is rotated we need to rotate it by the same amount around the center. That means we need a function that will rotate a point around another point by the angle we want, and return the rotated result.

    
    
    public Vector2 RotatePoint(Vector3 basePoint, Vector3 sourcePoint, float rotationAngle)
    {
    	float s = Mathf.Sin(rotationAngle*Mathf.Deg2Rad);
    	float c = Mathf.Cos(rotationAngle*Mathf.Deg2Rad);
    
    	// translate point back to origin
    	sourcePoint.x -= basePoint.x;
    	sourcePoint.y -= basePoint.y;
    
    	// rotate point
    	float xnew = sourcePoint.x * c - sourcePoint.y * s;
    	float ynew = sourcePoint.x * s + sourcePoint.y * c;
    
    	// translate point back:
    	sourcePoint.x = xnew + basePoint.x;
    	sourcePoint.y = ynew + basePoint.y;
    
    	return sourcePoint;
    }
    

    You must have met with this kind of function many times now. Since rotating around the center of the coordinate system is much simpler than rotating around a specific point, that’s why we first offset both points (the point we rotate and the point we rotate around) by the point we rotate around. This way, the point we rotate around is at the center of the coordinate system, so we can simply rotate around it the simple way, remembering that later we need to move back our point by the same amount we did offset it earlier. To calculate the Sin and Cos of our angle we need to use our Mathf class again. We also need to remember that both functions take radians as the input, so we need to multiply them by Mathf.Deg2Rad constant. Having all that, it’s very simple to use rotation around the origin formula. Again, after we use it we need to move the returned point back by the same amount we moved it in the first place.

    Now let’s rotate our top vertex.

    
    
    height = ((BoxCollider)collider).size.y*transform.localScale.y;
    top = new Vector3(transform.position.x, transform.position.y + height/2.0f, transform.position.z);
    top = RotatePoint(transform.position, top, transform.eulerAngles.z);
    

    As you can see, to get the angles of our portal we need to access transform.eulerAngles. Of course since we work in 2D, we only allow rotation around the z axis. Since bottom is a mirror image of the top, it is equal to the transform.position minus the distance between the top and transform.position.

    
    
    height = ((BoxCollider)collider).size.y*transform.localScale.y;
    top = new Vector3(transform.position.x, transform.position.y + height/2.0f, transform.position.z);
    top = RotatePoint(transform.position, top, transform.eulerAngles.z);
    bottom = transform.position - (top - transform.position);
    

    And that’s it, we’ve got our vertices.


    Step 4: Calculate the Portal’s Factors, Part 3

    Let’s create additional variables that will hold our equation’s factor.

    
    
    private float height = 0.0f;
    private PackedSprite sprite;
    private Vector3 top;
    private Vector3 bottom;
    
    [HideInInspector]
    public float a;
    [HideInInspector]
    public float b;
    

    As you can see, the new varriables are public. That’s because we may want to access them from other scripts, technically we should make them private and then provide functions that return their values, but that’s a lot of hassle for a one-man project. We set those variables in script, so we don’t want to expose them in the inspector, that’s why before declaring each of variables we need to put [HideInInspector] attribute. You can read more on attributes at this unity docs page. Now we can calculate our factors. If you played with the shader, you should have noticed that we can use it well only if _A + _B is equal to 1. That’s because texture UVs are from 0 to 1, and if the sum of the factors is higher than 1.0, then the scale is too big to handle for our _Cutoff, which ranges only from -1 to 1. That’s why we need the factors to sum up to 1. First things first, let’s calculate the first factor, a. It simply dictates how fast does the slope rise in the y axis. If the a factor is really high, and in comparison the b factor is very low, then you may be sure that the slope will be very steep. When the situation is reversed, the slope will be very flat instead. First Step NaNwould be to set the factors so they represent the slope nicely, we already calculated top and bottom vertices, and we know that the segment they create is part of the line we want to have an equation of. That will do.

    
    
    bottom = transform.position - (top - transform.position);
    
    b = top.x - bottom.x;
    a = bottom.y - top.y;
    

    Now let’s go on with the translation. I explained that we need the sum of first two factors to be one, but that isn’t entirely true. Because factors can be positive and negative values, they just can’t always be equal to one. It’s their absolute values that always must be equal to one in our case. Let’s translate the a factor first.

    
    
    bottom = transform.position - (top - transform.position);
    
    b = top.x - bottom.x;
    a = bottom.y - top.y;
    
    a = a / (Mathf.Abs(a) + Mathf.Abs(b));
    

    It’s very simple, we just see what part is a of a sum of both factors. Now to figure out the second factor. We should use the very same way to do that, but our a has already been translated, therefore it’s no longer usable for this method. We need to create a temporary variable that will hold the value of a, before it’s translated.

    
    
    bottom = transform.position - (top - transform.position);
    
    b = top.x - bottom.x;
    a = bottom.y - top.y;
    
    float tmpA = a;
    a = a / (Mathf.Abs(a) + Mathf.Abs(b));
    

    And now we can calculate our b, using tmpA instead of already translated a.

    
    
    float tmpA = a;
    a = a / (Mathf.Abs(a) + Mathf.Abs(b));
    b = b / (Mathf.Abs(tmpA) + Mathf.Abs(b));
    

    Step 5: Going Through Portal

    Now it’s the time to create a class which will automatically cut off part of the sprite according to it’s distance to portal, rotation and so on. We’ll first get it to work for non-rotated sprites, and then extend its capabilities. For ease of testing, let’s make our ball Kinematic for now. It will be easier to move it around in the scene window. The Is Kinematic checkbox is in the rigidbody component.

    Check for the body to be kinematic.

    Now let’s create a script for the objects which can use portals. Again, clean it up and let’s start working on it right away.

    
    
    using UnityEngine;
    using System.Collections;
    
    public class Portalable : MonoBehaviour
    {
    	void Start ()
    	{
    	}
    
    	void Update ()
    	{
    	}
    }
    

    Now let’s create our cutoff variable. Let’s call it gCutoff.

    
    
    public class Portalable : MonoBehaviour
    {
    	private float gCutoff = 0.0f;
    

    Of course we’ll also need a reference to our sprite.

    
    
    private float gCutoff = 0.0f;
    private PackedSprite sprite;
    
    void Start ()
    {
    	sprite = GetComponent<PackedSprite>();
    

    Another reference we will need, is to the portal our sprite currently goes through.

    
    
    private float gCutoff = 0.0f;
    private PackedSprite sprite;
    private Portal portal;
    

    We can set this reference when our sprite collides with the portal. How do we know it does? It’s pretty simple, there’s a callback called OnTriggerEnter(), which is called whenever our objects enters a trigger. Since our portal object has a collider that is a trigger, we can use this function. But how do we know that we entered the portal object, not some other object that also has a trigger collider? That’s also very simple, we just need to check whether the object we entered has a Portal script component attached to it.

    
    
    void OnTriggerEnter(Collider other)
    {
    }
    

    The function takes Collider other as its argument, it is a reference to the collider we intersected with. Now let’s check whether it has a Portal script attached or not. If it does, let’s set our portal to it, if it doesn’t let’s simply return, because in this script we will be handling only intersections with portals. Intersections with other objects will be the job of other scripts.

    
    
    void OnTriggerEnter(Collider other)
    {
    	if (other.GetComponent<Portal>() != null)
    		portal = other.GetComponent<Portal>();
    	else
    		return;
    }
    

    Now let’s create our SetCutoff() function. It should automatically set the amount of sprite it needs to cut. For that, we need to know what is our distance from the portal, or rather, what is our distance from the portal’s axis.

    
    
    void SetCutoff()
    {
    	if (portal == null)
    		return;
    }
    

    In case we try to SetCutoff() when we are not even intersecting with a portal, we simply ignore the request. Now to calculate our gCutoff, we need the distance mentioned earlier. The best place to create a function which returns it seems to be the Portal class, so let’s go back to the Portal script.


    Step 6: Calculate the Distance

    To start off, we need to get a formula that will help us calculate the linear equation. We’ve got the factors and the point we need to go through, so this won’t be hard at all. Keep in mind that our original axis equation is Ax + By = C throughout this step. Here’s the formula I found, y = a*(x - x0) + y0. The x0, y0 are the coordinates of the point we want the axis to go through. It assumes that our b factor is equal to 1, but that’s not a problem at all. We need to find the C factor, so by messing with equation a bit we’ll get that C = a*x0 + y0. Of course the a from this formula isn’t the same us our a from portal axis, because the a from the formula is a factor when b is equal to 1. Taking that into consideration, we can simply calculate that the formula’s a factor is equal to a/b, where a and b are our portal’s factors. Now we can calculate the c factor. First, let’s create a variable for it.

    
    
    [HideInInspector]
    public float a;
    [HideInInspector]
    public float b;
    [HideInInspector]
    public float c;
    

    And now calculate it.

    
    
    a = a / (Mathf.Abs(a) + Mathf.Abs(b));
    b = b / (Mathf.Abs(tmpA) + Mathf.Abs(b));
    c = a/b*transform.position.x + transform.position.y;
    

    And that’s it. Now let’s create our Dist() function, it will return the distance from the point to our portal’s axis.

    
    
    public float Dist(Vector3 p)
    {
    }
    

    To calculate the distance we need to use Mathf.Abs(Ax + By + C)/Mathf.Sqrt(A*A + B*B) formula, but we need to tweak it here and there so it’s adequate to our original equation, because this formula assumes that Ax + Bx + C = 0. If we go with a directional linear equation, like the one we just used, we need to make B factor be equal to 1. Then, the A will be equal to a/b, because it’s the same a we used with the previous formula. This way, our factors for the distance formula will be: A = a/b, B = 1.0 and C = c. That’s it, now we only need to use the formula.

    
    
    public float Dist(Vector3 p)
    {
    	return (a/b*p.x + p.y - c)/Mathf.Sqrt((a/b)*(a/b) + 1.0f);
    }
    

    Notice that we skipped the Math.Abs(), so it may give us a negative distance result. We did it because we want the distance to help us differentiate from which side of the portal the object enters. It will be essential later on, because the object going through portal must exit another portal through adequate side, for example, if we’ve got green and red sides and if the object enters through the green one, it should exit from the green one too. Another thing we need to be careful of is division by zero. In our case, if the b factor is equal to 0, then the division by zero will occur, because c factor is equal to a/b. To prevent returning a wrong distance in this case, we need to handle this case separately.

    
    
    public float Dist(Vector3 p)
    {
    	if (b == 0.0f)
    		return (p.x - transform.position.x);
    	else
    		return (a/b*p.x + p.y - c)/Mathf.Sqrt((a/b)*(a/b) + 1.0f);
    }
    

    b is equal to zero only if the portal is completely unrotated, or rotated by 180 degrees. The distance in these cases will be equal to the difference in position on the x axis. Again, we don’t want to use Mathf.Abs() here, because we want to differentiate between the portal’s sides.


    Step 7: Going Through Portal Part 2

    Now since we’ve got our distance, it’s time to test the function out. Let’s go back to our Portalable script, and use it to calculate the gCutoff. First, let’s save the distance to a variable named dist.

    
    
    void SetCutoff()
    {
    	if (portal == null)
    		return;
    
    	float dist = portal.Dist(transform.position);
    }
    

    Now let’s make our dist appear in our console

    
    
    void SetCutoff()
    {
    	if (portal == null)
    		return;
    
    	float dist = portal.Dist(transform.position);
    	Debug.Log(dist);
    }
    

    Now we need to call the SetCutoff() function so the Debug.Log(dist) will be executed. We will do so in the Update() function.

    
    
    void Update ()
    {
    	SetCutoff();
    }
    

    Let’s go back to the editor and hit play. In the debug console we’ll be able to see the distance from the portal’s axis. You can rotate the portal around to test whether other stuff we calculated is also correct. If the distance appears to be correct, we can move on with our function. Remember that our sprite need a Portalable script attached, and portal needs Portal script attached to it. Also, the reference to the portal is set upon an intersection with it, so first we need to move our sprite to intersect with the portal.

    Debug console in action.
    The distance to line appears to be correct.

    It works. You can use Debug.Log() whenever you want to check if something works or not. If you know it’s not working and want to know why, I recommend using classic debugging. Now you can delete the Debug.Log(dist) line.

    Now we need to know how much of a sprite should we need to cut off along the portal’s axis.

    How do we calculate how much of a sprite needs to be invisble.

    As you can see, in this case the issue isn’t very difficult to solve, partly because we’ve got our signed distance. In the first case, where the smaller part of a sprite is invisible, we can see that the pink length, the one we need to calculate is equal to half of the green length minus the blue length, the distance between our sprite and the portal. In the second case, it’s pretty much the same but instead of substracting the distance, we add it up. Our distance is signed, that means we can simply add the distance in both cases, because then in the first case it will add a negative value, which is the same as substracting, and in the second case it will add a positive value. Of course we will need to be careful to not do the both sides the wrong way, that is substracting when we need to add and adding when we need to substract, because it depends from which side does our sprite start out. We’ll take care of it soon enough. Now for the more general case.

    How do we calculate how much of a sprite needs to be invisble at various portal angles.

    As you can see, it looks like we need to calculate here things the same way, but there appears another issue. This time, the length of the sprite isn’t equal to simple width of the sprite, this time it’s a diagonal. You can imagine that this length will be different, and it depends on how the portal is rotated. Fortunately, the calculations of the right length is not that hard. We need to use projections. Metanet has a good, interactive basic geometry appendix, so if you have no idea how do we use projections, you should check it out.


    Step 8: Going Through Portal Part 3

    The first thing we need to do is to create a unit vector that will represent our portal’s axis. Here’s a little catch, we don’t really need our unit vector to reasemble the portal’s axis, we just need it to project our sprite’s diagonal on it and get the length of the projected vector. Since we don’t really want to use the world-space diagonal of our sprite, we also don’t want to use accurate portal’s axis. That’s why we should simply use absolute values of our portal’s factors instead of real values. If we wouldn’t do that, the projected length would be messed up more or less, depending on what kind of axis would we throw our diagonal on.

    
    
    void SetCutoff()
    {
    	if (portal == null)
    		return;
    
    	float dist = portal.Dist(transform.position);
    
    	Vector2 dir = new Vector2(Mathf.Abs(portal.a), Mathf.Abs(portal.b));
    }
    

    Now we want to convert our dir into a unit vector

    
    
    Vector2 dir = new Vector2(Mathf.Abs(portal.a), Mathf.Abs(portal.b));
    dir.Normalize();
    

    Now let’s create a vector that will represent the size of our sprite.

    
    
    Vector2 dir = new Vector2(Mathf.Abs(portal.a), Mathf.Abs(portal.b));
    dir.Normalize();
    
    Vector2 size = new Vector2(sprite.width, sprite.height);
    

    And finally, it’s time to project our size vector onto the unit vector. Of course, before we do that, we need to do is to create the projection vector.

    
    
    Vector2 dir = new Vector2(Mathf.Abs(portal.a), Mathf.Abs(portal.b));
    dir.Normalize();
    
    Vector2 size = new Vector2(sprite.width, sprite.height);
    Vector2 proj = new Vector2();
    

    And now apply the formula to calculate it.

    
    
    Vector2 proj = new Vector2();
    
    proj.x = Vector2.Dot(size, dir)*dir.x;
    proj.y = Vector2.Dot(size, dir)*dir.y;
    

    And that’s it, we’ve got our projection. Now we need to calculate our gCutoff, and we’re done!

    
    
    Vector2 proj = new Vector2();
    
    proj.x = Vector2.Dot(size, dir)*dir.x;
    proj.y = Vector2.Dot(size, dir)*dir.y;
    
    gCutoff = dist/proj.magnitude + 0.5f;
    

    We just calculate it the way I explained before. We don’t need additional conditionals because our dist can carry a negative value. All in all, it sums up to this, it’s just a question of how much of the sprite is between its center and the portal. Then of course we need to cut additional half, so we cut along the portal’s axis, not somewhere else.


    Step 9: Get the UVs

    We still need to do a couple of things before we can see any interesting results. We need to calculate the minimum and maximum cutoff value. You know that the texture coordinates range from 0 to 1. What we calculated in the previous step, is the amount of the cutoff we need to apply to a single frame, not the whole texture, in which many frames can sit. That’s why we need to calculate where on the texture should we start cutting the frame, and where we finish doing so. First of all, we need UVs of our current frame, and that’s the first thing we should do, get them. Let’s not continue the previous function, because it already finished doing what was it supposed to do, let’s create another and call it UpdateCutoff.

    
    
    void UpdateCutoff()
    {
    }
    

    Now let’s create a Rect that will hold our sprite’s UVs.

    
    
    void UpdateCutoff()
    {
    	Rect uvs = new Rect();
    }
    

    We need to set it to the current animation frame UVs or if we’re not playing any animation, to static frame UVs.

    
    
    void UpdateCutoff()
    {
    	Rect uvs = new Rect();
    
    	if (sprite.GetCurAnim() != null)
    		uvs = sprite.GetCurAnim().GetCurrentFrame().uvs;
    	else
    		uvs = sprite.DefaultFrame.uvs;
    }
    

    As you can imagine, GetCurAnim() returns a null if no animation is played, and the UVAnimation class when we do play any. To get current frame we need to call GetCurrentFrame() function, and from the frame we can access uvs. When we don’t play anything we need to access our sprite’s DefaultFrame, and then we can get uvs from it.


    Step 10: Going Through Portal Part 4

    Now let’s create the variables that will hold our extreme cutoff values.

    
    
    void UpdateCutoff()
    {
    	Rect uvs = new Rect();
    
    	if (sprite.GetCurAnim() != null)
    		uvs = sprite.GetCurAnim().GetCurrentFrame().uvs;
    	else
    		uvs = sprite.DefaultFrame.uvs;
    
    	float cutoffMin, cutoffMax;
    }
    

    First, let’s study how are we going to calculate those extremes. Let’s go with an example.

    Texture for our example.

    In this example our sprite is currently displaying the fourth frame and it’s going through portal. We need to know how much of cutoff to apply if we want to cut the texture up to the point where it touches the frame but doesn’t cut anything and to the point that it ideally cuts the whole frame and doesn’t cut any more of the texture.

    Where does the axis intersect with the frame quad on the texture.

    As you can see, we simply need to find where the given portal axis would intersect with our sprite’s UVs. There’s a catch here, depending on how the portal axis looks, we need to know where it intersect with different UVs. In this example the axis would first intersect with the bottom-left UV, and the last one it would touch would be the top-right. Now let’s see another example, where portal axis looks a bit differently.

    Different axis.

    As you can see, this time when we start cutting the frame, the texture is cut up to the top-left UV of our frame. When it finishes cutting the whole frame, it’s at the bottom-right UV.

    Those are the only options we have, so we need two cases to prepare. First one, when the extremes will be the bottom-left and top-right UVs, and the second one when the extremes will be the bottom-right and top-left UVs. So how will our condition look? We need to visualise what kind of angles will result with which extreme points.

    Different portal lines.

    Portal’s rotation will help us to make a good condition. As you may have noticed, the extremes are bottom-right and top-left when angles range from 90 to 180 and from 270 to 360. The other cases have bottom-left and top-right extremes. Let’s start creating our condition. Of course using the angle values doesn’t seem a very good idea, portal could be at angle equal to 1000 or more. That’s why we should use trigonometric functions. As you know, the Tan() function returns negative values only for the 2nd and 4th quarters of the coordinate system. That’s exactly when we need to calculate the bottom-left and top-right extremes.

    
    
    float cutoffMin, cutoffMax;
    
    if (Mathf.Tan(Mathf.Deg2Rad*portal.transform.eulerAngles.z) < 0.0f)
    {
    }
    else
    {
    }
    

    Always remember to use Mathf.Deg2Rad constant when you’re using trigonometric functions and deal with euler angles. Alright, so how do we calculate the cutoffMin? It’s pretty simple, since the cutoff is basically a C factor in a linear equation, we know that it is equal to x*A + y*B. That’s because our equation is in this form: x*A + y*B = C. If we want to calculate the cutoffMin, that mean we need to substitute the x with the first extreme’s x value and y with first extereme’s y value.

    Before we’ll get right to the meat, here’s a quick reminder how the UVs positions work. Here’s how UVs on the texture look like.

    UVs on the texture.

    Notice that the top is actually 0, and the bottom is 1. The lower the point on the texture, the higher y value it has. Now let’s see how does it look if we’re dealing with a frame, not a whole texture.

    Frame's UVs.

    As you can see, it’s pretty similar. The only difference is we don’t deal with whole texture but rather with a specific quad in the texture.


    Step 11: Going Through Portal Part 5

    Now we can calculate our minCutoff.

    
    
    if (Mathf.Tan(Mathf.Deg2Rad*portal.transform.eulerAngles.z) < 0.0f)
    {
    	cutoffMin = uvs.xMin*portal.a + (uvs.yMin + uvs.height)*portal.b;
    }
    else
    {
    }
    

    As you can see, we simply use our linear equation to see where does our line intersects with the point we specified. We’re going to do the same to calculate cutoffMax, but this time we’re going to substitute the last extreme.

    
    
    if (Mathf.Tan(Mathf.Deg2Rad*portal.transform.eulerAngles.z) < 0.0f)
    {
    	cutoffMin = uvs.xMin*portal.a + (uvs.yMin + uvs.height)*portal.b;
    	cutoffMax = (uvs.xMin + uvs.width)*portal.a + (uvs.yMin)*portal.b;
    }
    else
    {
    }
    

    For the second case, where the extremes are different we simply substitute those different extreme’s into our equation

    
    
    if (Mathf.Tan(Mathf.Deg2Rad*portal.transform.eulerAngles.z) < 0.0f)
    {
    	cutoffMin = uvs.xMin*portal.a + (uvs.yMin + uvs.height)*portal.b;
    	cutoffMax = (uvs.xMin + uvs.width)*portal.a + (uvs.yMin)*portal.b;
    }
    else
    {
    	cutoffMin = (uvs.xMin + uvs.width)*portal.a + (uvs.yMin + uvs.height)*portal.b;
    	cutoffMax = uvs.xMin*portal.a + uvs.yMin*portal.b;
    }
    

    And that’s it. We need to do only one more thing to see the results. We need to submit the values we have to the shader, so it can work correctly.


    Step 12: Feed the Shader

    As you probably remember, the shader we created had a few specific Properties, the linear equation’s factors. How do we set those? It’s very simple, we only need to use our Renderer component to access the material we are currently using. Once we have that, we can change any properties that are defined in the shader which our material uses. Here’s how we do it.

    
    
    renderer.material.SetFloat("_A", portal.a);
    renderer.material.SetFloat("_B", portal.b);
    

    One other thing you should be aware of. If we tweak the material in the way we just did, the unity will automatically copy it for the object that modified the properties. If it didn’t do that, then two sprites would use the very same material, and they would both tweak it to their custom needs resulting in one sprite’s shader properties being overwritten by another. Just a note that you don’t actually have to worry about this because it’s handled automatically.

    Now we need to submit our _Cutoff property to the shader. How to calculate that? Well, we’ve got our extreme cutoff values, and also we know how much of a sprite we need to cutoff, because that’s what gCutoff represents. So for example, if we want to cutoff half of the sprite, what would have to be the value of _Cutoff? Of course it would have to be the number exactly inbetween of cutoffMin and cutoffMax. If we wouldn’t want to cut the sprite at all, we would want the _Cutoff to be equal to cutoffMin, and if we wanted to cut the whole sprite then we would need _Cutoff to be equal to cutoffMax. We basically need to use linear interpolation here.

    
    
    renderer.material.SetFloat("_A", portal.a);
    renderer.material.SetFloat("_B", portal.b);
    
    renderer.material.SetFloat("_Cutoff", Mathf.Lerp(cutoffMin, cutoffMax, gCutoff));
    

    Mathf.Lerp() simply finds the number between cutoffMin and cutoffMax, basing on the step, which in our case is gCutoff. The Step NaNindicates the distance between two extreme values. So for example, if we use a Mathf.Lerp() on the values 25 and 50 with the Step NaNequal to 0.5, then the returned value will be equal to 37.5, exactly in between the two given numbers.

    Let's not forget to call our function after we set the gCutoff.

    
    
    	gCutoff = dist/proj.magnitude + 0.5f;
    
    	UpdateCutoff();
    }
    

    Step 13: Going Through Portal Part 6

    Let's test out our portal now.

    Cutoff seems to work well.

    Looks pretty good behind the thick portal. Let's move our sprite in front of it so we can see if the cutoff is as accurate as it should be.

    Cutoff works well!

    It looks alright. Since our code is angle dependant, we should check if everything's alright for different angles too.

    Example of cutoff working very well.

    It looks like everything works just fine. Of course we're far from finishing the portals, but that's one huge Step NaNforward. Note that for now we only let the green side of the portal to be the 'visible side', for now we shouldn't really care which side is visible or not, but we'll have to do so later on. From now on, we'll try to make a rotated sprites work with our shader.


    Step 14: Rotated Sprites

    First, let's visualize how do we need to cut our texture if the sprite is rotated. A few sketches will surely help with that.

    How do we need to cut the texture depending on sprite rotations.

    As you can see, there's some kind of pattern here. If you haven't noticed it by looking at this sketch, another picture one should make everything clear.

    -45 degrees for the portal results with the same cutoff as 45 degrees for the portal.

    The portal's rotation is equal to -45 euler angles. As you can see, the most interesting thing now is that the portal at -45 degrees cuts off the same part of sprite as the second case from the previous image. Now, let's consider yet another example.

    Another example how to cut the rotated sprite's texture.

    As you can see, if we want to properly display rotated sprite, we need to cut the texture as if the portal angle would be equal to portal's z euler angles minus sprite's z euler angles.


    Step 15: Factors Class

    We want many objects to be able to use one portal, that's why we can't calculate the factor's for a specific sprite's rotation. Every sprite will need to keep its own, custom portal factors that are adequate to its rotation. It would be a good idea to gather all specific factors in one class for clarity. Let's start from creating a new class inside of Portal script. Let's name it Factors.

    
    
    public class Portal : MonoBehaviour
    {
    	public class Factors
    	{
    	}
    

    Why do we create a class instead of a struct? Because classes are passed on as references, and that seems much more efficient than copying the whole struct. We need all data specific for the portal's rotation, that means we also need to include top and bottom vertices besides a, b, c factors.

    
    
    public class Factors
    {
    	public Vector3 top = new Vector3();
    	public Vector3 bottom = new Vector3();
    
    	public float a = 0.0f;
    	public float b = 0.0f;
    	public float c = 0.0f;
    }
    

    It will also be useful to have the rotation in a separate variable so we won't have to calculate it every time.

    
    
    public class Factors
    {
    	public Vector3 top = new Vector3();
    	public Vector3 bottom = new Vector3();
    
    	public float a = 0.0f;
    	public float b = 0.0f;
    	public float c = 0.0f;
    
    	public float rot = 0.0f;
    }
    

    Now let's substitute all of our loose factors in the class with one Factors instance.

    
    
    public class Factors
    {
    	public Vector3 top = new Vector3();
    	public Vector3 bottom = new Vector3();
    
    	public float a = 0.0f;
    	public float b = 0.0f;
    	public float c = 0.0f;
    
    	public float rot = 0.0f;
    }
    
    private float height = 0.0f;
    private PackedSprite sprite;
    public Factors facs = new Factors();
    
    void Start ()
    {
    

    Now we need to edit our Start() function, so it calculates the variables inside facs, instead of old, deleted variables.

    
    
    void Start ()
    {
    	sprite = GetComponent<PackedSprite>();
    	height = ((BoxCollider)collider).size.y*transform.localScale.y;	
    
    	facs.top = new Vector3(transform.position.x, transform.position.y + height/2.0f, transform.position.z);
    	facs.top = RotatePoint(transform.position, facs.top, transform.eulerAngles.z);
    	facs.bottom = transform.position - (facs.top - transform.position);
    
    	facs.b = facs.top.x - facs.bottom.x;
    	facs.a = facs.bottom.y - facs.top.y;
    
    	float tmpA = facs.a;
    	facs.a = facs.a / (Mathf.Abs(facs.a) + Mathf.Abs(facs.b));
    	facs.b = facs.b / (Mathf.Abs(tmpA) + Mathf.Abs(facs.b));
    	facs.c = facs.a/facs.b*transform.position.x + transform.position.y;
    }
    

    Step 16: Return New Factors

    Now let's create another function. This one will calculate the factors for rotated sprite. It will return an instance of Factors, containing all the factors that sprite may need. Also, we need to know what is the sprite's rotation, so the function must have one argument. Let's call the function CalcFacs().

    
    
    public Factors CalcFacs(float angle)
    {
    }
    

    The first thing we want to do is to create our return Factors.

    
    
    public Factors CalcFacs(float angle)
    {
    	Factors f = new Factors();
    }
    

    Now let's calculate the rotation according to the formula we thought up earlier.

    
    
    public Factors CalcFacs(float angle)
    {
    	Factors f = new Factors();
    	f.rot = transform.eulerAngles.z - angle;
    }
    

    It's portal rotation minus sprite rotation. Now let's calculate the rest of the factors, we can simply copy-paste it from the Start() function and then substitute transform.eulerAngles.z with f.rot. We would also need to substitute facs with the Factors we're going to return, that is f.

    
    
    public Factors CalcFacs(float angle)
    {
    	Factors f = new Factors();
    	f.rot = transform.eulerAngles.z - angle;
    
    	f.top = new Vector3(transform.position.x, transform.position.y + height/2.0f, transform.position.z);
    	f.top = RotatePoint(transform.position, f.top, f.rot);
    	f.bottom = transform.position - (f.top - transform.position);
    
    	f.b = f.top.x - f.bottom.x;
    	f.a = f.bottom.y - f.top.y;
    
    	float tmpA = f.a;
    	f.a = f.a / (Mathf.Abs(f.a) + Mathf.Abs(f.b));
    	f.b = f.b / (Mathf.Abs(tmpA) + Mathf.Abs(f.b));
    	f.c = f.a/f.b*transform.position.x + transform.position.y;
    }
    

    And now we can return our f, so the Portalable object will be able to use it.

    
    
    public Factors CalcFacs(float angle)
    {
    	Factors f = new Factors();
    	f.rot = transform.eulerAngles.z - angle;
    
    	f.top = new Vector3(transform.position.x, transform.position.y + height/2.0f, transform.position.z);
    	f.top = RotatePoint(transform.position, f.top, f.rot);
    	f.bottom = transform.position - (f.top - transform.position);
    
    	f.b = f.top.x - f.bottom.x;
    	f.a = f.bottom.y - f.top.y;
    
    	float tmpA = f.a;
    	f.a = f.a / (Mathf.Abs(f.a) + Mathf.Abs(f.b));
    	f.b = f.b / (Mathf.Abs(tmpA) + Mathf.Abs(f.b));
    	f.c = f.b/f.a*transform.position.x + transform.position.y;
    
    	return f;
    }
    

    Don't forget to adjust our Dist() function, so it uses our facs class.

    
    
    public float Dist(Vector3 p)
    {
    	if (facs.b == 0.0f)
    		return (p.x - transform.position.x);
    	else
    		return (facs.a/facs.b*p.x + p.y - facs.c)/Mathf.Sqrt((facs.a/facs.b)*(facs.a/facs.b) + 1.0f);
    }
    

    That's it, now we need to edit appropiately our Portalable script.


    Step 17: Edit Portalable Script

    First thing we should do is to define a Factors instance in our class.

    
    
    public class Portalable : MonoBehaviour
    {
    	private float gCutoff = 0.0f;
    	private PackedSprite sprite;
    	public Portal portal;
    
    	private Portal.Factors facs;
    

    Now let's calculate appropiate factors. Good place to do that is our SetCutoff() function.

    
    
    void SetCutoff()
    {
    	if (portal == null)
    		return;
    
    	facs = portal.CalcFacs(transform.eulerAngles.z);
    

    We also need to change our dir. It needs to use our own factors now.

    
    
    void SetCutoff()
    {
    	if (portal == null)
    		return;
    
    	facs = portal.CalcFacs(transform.eulerAngles.z);
    
    	float dist = portal.Dist(transform.position);
    
    	Vector2 dir = new Vector2(Mathf.Abs(facs.a), Mathf.Abs(facs.b));
    	dir.Normalize();
    
    	Vector2 size = new Vector2(sprite.width, sprite.height);
    	Vector2 proj = new Vector2();
    
    	proj.x = Vector2.Dot(size, dir)*dir.x;
    	proj.y = Vector2.Dot(size, dir)*dir.y;
    
    	gCutoff = dist/proj.magnitude + 0.5f;
    
    	UpdateCutoff();
    }
    

    Finally, let's update our UpdateCutoff() function. Again, instead of portal's factors, we need to use the ones calculated for our angle. We also need to use our calculated rotation instead of portal.transform.eulerAngles.z.

    
    
    void UpdateCutoff()
    {
    	Rect uvs = new Rect();
    
    	if (sprite.GetCurAnim() != null)
    		uvs = sprite.GetCurAnim().GetCurrentFrame().uvs;
    	else
    		uvs = sprite.DefaultFrame.uvs;
    
    	float cutoffMin, cutoffMax;
    
    	if (Mathf.Tan(Mathf.Deg2Rad*facs.rot) < 0.0f)
    	{
    		cutoffMin = uvs.xMin*facs.a + (uvs.yMin + uvs.height)*facs.b;
    		cutoffMax = (uvs.xMin + uvs.width)*facs.a + (uvs.yMin)*facs.b;
    	}
    	else
    	{
    		cutoffMin = (uvs.xMin + uvs.width)*facs.a + (uvs.yMin + uvs.height)*facs.b;
    		cutoffMax = uvs.xMin*facs.a + uvs.yMin*facs.b;
    	}
    
    	renderer.material.SetFloat("_A", facs.a);
    	renderer.material.SetFloat("_B", facs.b);
    
    	renderer.material.SetFloat("_Cutoff", Mathf.Lerp(cutoffMin, cutoffMax, gCutoff));
    }
    

    Now we should test our rotations. You can play with the angle of the sprite at the runtime, because it's updating the factors all the time, but the portal does intitialization only at the beginning, so rotating it won't change much, you'll have to restart the game.

    Badly cut texture.

    As you can see, the rotations doesn't work too good, but the issue doesn't seem too complicated to fix. As you can notice when you move the rotated sprite, the cutoff simply progresses in the wrong direction. To change the direction our cutoff progresses, we need to swap cutoffMin and cutoffMax variables. So why does it happen, why our extremes are calculated incorrectly? Remember when I said that we will need to be careful so the sign of our distance isn't exactly the opposite of what it neds to be? This is the time we needed to be careful of it. So instead of swapping the cutoffMin with cutoffMax we could multiply our calculated dist by -1, and the result would be the same.

    Axis's factors make it go from the wrong side we want.

    We cutoff the texture from the different side we should. So when do we do so wrongly? When our facs.rot is in 3rd or 4th quarters and if the portal is in its 1st or 2nd quarter or when our facs.rot is in 1st or 2nd and our portal is in 3rd or 4th quarter.

    
    
    if ((Mathf.Sin(Mathf.Deg2Rad*facs.rot) < 0.0f != Mathf.Sin(Mathf.Deg2Rad*portal.transform.eulerAngles.z) < 0.0f)
    	&& (Mathf.Sin(Mathf.Deg2Rad*facs.rot) < 0.0f || Mathf.Sin(Mathf.Deg2Rad*portal.transform.eulerAngles.z) < 0.0f))
    {
    }
    
    renderer.material.SetFloat("_A", facs.a);
    renderer.material.SetFloat("_B", facs.b);
    

    As you can see, we used hand-mande exclusive or statement here. The idea is, we need to swap the extremes either when Mathf.Sin(Mathf.Deg2Rad*facs.rot) < 0.0f or Mathf.Sin(Mathf.Deg2Rad*portal.transform.eulerAngles.z) < 0.0f, but if both of them are true, they would need to be swapped twice and that we result with nothing changed so why should we do it in the first place? We shouldn't. When both are false, we don't want to swap anything. For swapping we'll use a temoporary variable.

    
    
    if ((Mathf.Sin(Mathf.Deg2Rad*facs.rot) < 0.0f != Mathf.Sin(Mathf.Deg2Rad*portal.transform.eulerAngles.z) < 0.0f)
    	&& (Mathf.Sin(Mathf.Deg2Rad*facs.rot) < 0.0f || Mathf.Sin(Mathf.Deg2Rad*portal.transform.eulerAngles.z) < 0.0f))
    {
    	float tmp = cutoffMin;
    	cutoffMin = cutoffMax;
    	cutoffMax = tmp;
    }
    

    And that's it. We can now test whether the cutoff is calculated properly even for rotated sprites.

    Texture is cut well for rotated sprites.

    Step 18: Adjust Visibility

    For now our sprite is visible on the green side of the portal and it's invisible on the red one. Let's get a bit of control over where the sprite is visible and where it's not. Let's say we want the sprite to be always visible as it enters the portal, and then if it crosses the portal axis, it disappears. So no matter if we start from the red side or the green side, the sprite should be visible as it enters it. The first question that need to be asked is, how do we reverse the current order? That's pretty simple, if all we want is to be visible on the red side instead of the green one, we need to make the portal's factors into their opposites. Of course we need to change only a and b factors, because c is a kind of an offset and have no share in shaping the axis.

    
    
    void SetCutoff()
    {
    	if (portal == null)
    		return;
    
    	facs = portal.CalcFacs(transform.eulerAngles.z);
    	facs.a *= -1.0f;
    	facs.b *= -1.0f;
    

    Let's check if it really works.

    Sprite is visible on the other side of the portal.

    As you can see, now the sprite is visible on the red side of the portal, proves that making the factors into their opposites works. Now we need to think how should we manage those sides. One variable should be enough, it could indicate whether we are on one side of the portal, or another. How do we differentiate between the sides? Remember that our Dist() function can return the distance with a sign, depending on which side of an axis is our sprite on. That's all we need. Delete the test lines in which we multiply the factors and let's get to work.


    Step 19: Handle Stepping Out of Portal

    Before we do anything else, let's create a OnTriggerExit() callback. This function is called when we finished intersecting with a trigger. When our sprite finishes intersecting with our current portal, we need it no more so we can delete the reference to it.

    
    
    void OnTriggerExit(Collider other)
    {
    }
    

    If we finished intersecting with a trigger and yet our portal reference is equal to null that means we couldn't have stepped out of the portal, but from some other trigger that we don't care in this script. If that's the case, let's simply return.

    
    
    void OnTriggerExit(Collider other)
    {
    	if (portal == null)
    		return;
    }
    

    If we have our portal reference set, but it is not equal to the Portal component attached to the trigger we Step NaNout of, that means that either the trigger doesn't have a Portal script component attached and it is equal to null, or it has a Portal component, but it's not the portal our sprite is currently using, though that's very unlikely. If any of those happens, we also need not to handle the case and therefore may safely return.

    
    
    void OnTriggerExit(Collider other)
    {
    	if (portal == null)
    		return;
    
    	if (other.GetComponent<Portal>() != portal)
    		return;
    }
    

    Finally, if we exit our portal, we simply set the portal reference to null, because we don't need it anymore.

    
    
    void OnTriggerExit(Collider other)
    {
    	if (portal == null)
    		return;
    
    	if (other.GetComponent<Portal>() != portal)
    		return;
    
    	portal = null;
    }
    

    Step 20: Handle Visible Sides

    Let's create our variable which will hold the info on which side are we. Let's call it side.

    
    
    public class Portalable : MonoBehaviour
    {
    	private float gCutoff = 0.0f;
    	private PackedSprite sprite;
    	public Portal portal;
    
    	private Portal.Factors facs;
    	public float side = 1.0f;
    

    Now let's set our side variable. The place to do that is in OnTriggerEnter() function, because we want to set the side from which sprite enters the portal. Now how do we know which side is which? Well, we've got a useful info from our distance from portal. We know that if we are above the portal axis, our distance is positive, and if we are below it, it's negative. Of course we can't speak about above and below when our axis is completely vertical, but this applies to all other cases. If you play with the portal a bit, rotating it from 0 to 180 degrees, you'll notice that the red side is always on the top. When the rotation ranges from 180 to 360 degrees, the green side is always on top. That's the info we will use to differentiate the green side and the red side. So, if our distance is positive and the portal's angle ranges from 0 to 180, we know that we are on the red side. The same applied if the situation is reversed, our distance is negative and the portal's angle ranges from 180 to 360. In other cases, we enter from the green side so we don't have to multiply our factors by -1. First thing we need to do is to calculate the distance.

    
    
    void OnTriggerEnter(Collider other)
    {
    	if (other.GetComponent<Portal>() != null)
    		portal = other.GetComponent<Portal>();
    	else
    		return;
    
    	float dist = portal.Dist(transform.position);
    }
    

    Now we need to create a condition and then multiply our side by -1.

    
    
    void OnTriggerEnter(Collider other)
    {
    	if (other.GetComponent<Portal>() != null)
    		portal = other.GetComponent<Portal>();
    	else
    		return;
    
    	float dist = portal.Dist(transform.position);
    
    	if ((Mathf.Sin(Mathf.Deg2Rad*portal.transform.eulerAngles.z) >= 0.0f && portal.Dist(transform.position) >= 0.0f)
    		|| (Mathf.Sin(Mathf.Deg2Rad*portal.transform.eulerAngles.z) < 0.0f && portal.Dist(transform.position) < 0.0f))
    		side *= -1.0f;
    }
    

    Note that we multiply instead of assigning -1. That's for the case when we would like to start invisible or other special cases. If we wanted to start invisible now, would simply need to set the initial side to -1, and then the multiplying would do the rest of the work for us. Finally, we need to multiply our factors with the side, so the changes may take place.

    
    
    void SetCutoff()
    {
    	if (portal == null)
    		return;
    
    	facs = portal.CalcFacs(transform.eulerAngles.z);
    	facs.a *= side;
    	facs.b *= side;
    

    We also should reset the side to 1 when we finish intersecting with the portal. That's because we're only multiplying i

  5. Michael James Williams says:
    August 19, 2011 at 1:50 am

    For the digital creators among us, there are a couple of FITC sponsored events on the near horizon that we thought you’d like to hear about. Also, for those thinking of attending, we thought a bit of a discount would serve as a little icing on the cake.


    This post was originally published on Envato Notes.

    RIA Unleashed 2011

    RIA Unleashed brings together guests and speakers from New England and throughout North America. This popular, low-cost event is accessible to every budget, and last year’s event was a super success.

    This 2 day event packs in one full day of workshops, and one full day of presentations. Enjoy the over 20 presentations and 10 workshops with presenters that have been hand-picked for their skill and talent.

    RIA Unleashed runs from October 27-28 2011 in exciting Waltham MA – just east of Boston. For more details head over to the RIA Unleashed website.

    SCREENS 2011

    If mobile development is your thing, you won’t want to miss out on SCREENS. SCREENS is now completely dedicated to mobile, tablet and set top box development. It is one of the only events in the world designed for developers of all platforms of screen content.

    SCREENS includes 2 full days of presentations, plus one optional day of pre-conference workshops. The conference will include all the mobile tech from iOS, Android, HTML5 and JQuery Mobile, HP/WebOS, AIR, FLEX, Windows Phone, as well as the marketing and business of apps.

    The conference runs from November 14-15 2011 in beautiful Toronto, Ontario. For more information hit up the SCREENS website.

    Save 10% Off Your Tickets

    FITC was gracious enough to extend us some savings on their events. Just use the discount code ‘envato‘ when you sign up to receive a 10% discount!


  6. Michael James Williams says:
    August 19, 2011 at 2:12 am

    Moving items to top and bottom of the display list can be very useful when developing games and applications. Learn to easily manage depth using this QuickTip.


    Final Result Preview

    Let’s take a look at the final result we will be working towards:

    Click an icon to select it and bring it to the top of the display list, then use the two buttons to move it lower in the hierarchy.


    Step 1: Brief Overview

    Using ActionScript 3 we’ll learn how to manage top, bottom and intermediate levels of depth.


    Step 2: Set Up Your Flash File

    Launch Flash and create a new Flash Document, set the stage size to 320x200px and the frame rate to 24fps.


    Step 3: Interface

    This is the interface we’ll be using, a series of buttons in stage that will activate the depth change.

    Convert the characters to Button and name the Tuts+ logos like this: nt, at, pt. For the other buttons the instance names are bottomB and oneB.


    Step 4: ActionScript

    Create a new ActionScript Class (Cmd+N), save the file as Main.as and write the following lines, please read the comments in the code to fully understand the class behavior.

    
    
    package
    {
    	import flash.display.Sprite;
    	import flash.events.MouseEvent;
    	import flash.filters.GlowFilter;
    
    	public final class Main extends Sprite
    	{
    		private var lastItem:Sprite; //stores the last clicked sprite
    		private var glow:GlowFilter = new GlowFilter(0xFF9900);// a glow filter to highlight the last item
    
    		public final function Main():void
    		{
    			lastItem = nt; //the top item at start
    			addListeners();
    		}
    
    		private final function addListeners():void
    		{
    			at.addEventListener(MouseEvent.MOUSE_DOWN, up);
    			pt.addEventListener(MouseEvent.MOUSE_DOWN, up);
    			nt.addEventListener(MouseEvent.MOUSE_DOWN, up);
    
    			oneB.addEventListener(MouseEvent.MOUSE_UP, downOne);
    			bottomB.addEventListener(MouseEvent.MOUSE_UP, bottom);
    		}
    
    		private final function up(e:MouseEvent):void
    		{
    			lastItem.filters = []; //remove last filter if any
    			lastItem = e.target as Sprite; //stopre last clicked item
    			lastItem.filters = [glow]; //apply filter
    			setChildIndex(lastItem, numChildren - 1);//get next highest depth
    		}
    
    		private final function downOne(e:MouseEvent):void
    		{
    			if(getChildIndex(lastItem) != 0)//prevent out of bounds
    			{
    				setChildIndex(lastItem, getChildIndex(lastItem) - 1);//down one level
    			}
    		}
    
    		private final function bottom(e:MouseEvent):void
    		{
    			setChildIndex(lastItem, 0);//bottom
    		}
    	}
    }
    

    Step 5: Document Class

    Add the class name to the Class field in the Publish section of the Properties panel to associate the FLA with the Main document class.


    Conclusion

    Use what you learned in this QuickTip in your games and applications!

    I hope you liked this Quick Tip, thank you for reading!


  7. Daniel Apt says:
    August 19, 2011 at 2:53 am

    Ever wanted to make a manageable and beautiful photo viewer app? In this tutorial, I’ll show you how to design and code a nifty Polaroid photo viewer, focusing on the design and tweening.


    Final Result Preview

    Let’s take a look at the final result we will be working towards:


    Section 1: Organization

    In this section we’ll discuss our folder structure, also we’ll acquire our stock imagery.


    Step 1: Creating Our Folders

    First let’s create a folder in which our project will be located. We’ll name it “Polaroid Viewer”.

    Afterwards just copy this folder structure:

    The folder structure which we'll use in our tutorial

    Step 2: Understanding Our Folder Structure

    When creating very visual projects, it’s very important to first really know what you want to design. Inside the Design folder I always have my visual concepts and also in the Design folder I edit the images I’ll need for a project.

    After I’ve finished working on my concept I proceed to making a working product, I do this inside the Project folder. Inside the Project folder is the very known bin, lib and src folder structure:

    • bin: Everything which is being exported and is needed to launch the final product, including data assets.
    • lib: Our Flash documents.
    • src: All our code, our own classes, as well as other frameworks.

    Step 3: Acquire Stock Imagery

    Now that we’ve created our folders, let’s proceed to the images. In this tutorial we’ll need at least two images:

    • A polaroid frame
    • A picture of a wooden floor

    You’ll need a Stock Xchange account to download these images, if you don’t yet have one, you should sign up! It’s a website filled with free stock imagery!

    Click the links to download the images, afterwards save or move them to our Design folder.

    Also we’ll need images to place inside the polaroid frames. Here’s a list of images which I’ve used, but feel free to use your own images.

    • Image #1
    • Image #2
    • Image #3

    Section 2: Design

    In this section we’re going to edit our stock images. After doing so, we’ll import these images inside our Flash document, which we’ll create later.

    We’re going to edit our images with Photoshop, I’ll be using CS5, however you can always use older versions. If you’re not so confident in your Photoshop skills, you can download the images which I’ve already edited. Just download the source files from this tutorial, and you can find the images inside the Edited Images folder.


    Step 4: Preparing Our Wooden Floor

    In the final example all our polaroid pictures lie on a wooden floor. We’re now going to create this background.

    Create a New Document in Photoshop with the dimensions 600x600px.

    Add the wooden texture image to the document. Scale it so you’re pleased with the final result.

    Our background has been scaled down.

    I’ve also added a Gradient Map, setting the colors to black and white.

    Add a gradient map to our background

    Lastly I’ve changed the gradient map’s transition to 80%. To do so, click on one of the lower arrows, and afterwards click on the dot in the middle of the gradient. Drag this dot to 80%.

    Editing the Gradient Map

    And voila! We’ve created our wooden background! Save it as a Photoshop Document (.psd) in our Design folder, and name it Background.psd.

    Our background which we'll use in our project

    Step 5: Preparing the Polaroid Frame

    We want to place our own images inside the polaroid frame. We must do two things, we’ll first need to remove the polaroid frame from its (white) background, and also we’ll need to cut the “photo” part away.

    To do this, we’ll first create a new 600x600px Photoshop document. Paste the polaroid picture inside the document, scale it down till it fits.

    The polaroid frame image has been opened in Photoshop

    Why do we scale the image down? Because we’re creating a 600x600px Flash document, and it’s unnecessary to have and load a huge image if we won’t even scale it larger than 600 px.


    Step 6: Isolating the Polaroid Frame

    Select the pen tool (P) and click around the polaroid frame’s outer edge. When working with the Pen tool, be sure to set the Pen tool in its Paths mode.

    Set the Pen Tool to paths mode.

    Press Control + Enter (Windows) or Cmd + Enter (Mac) to select your current path.

    Select with the pen tool the outer area of the polaroid picture

    With your path selected click on the “Add Layer Mask” button. We’ve now isolated the polaroid from its background!

    Add a layer mask to the polaroid

    Step 7: Cutting the Photo Part Away From the Polaroid Frame

    This step is very similar to Design Step 4. Again select the pen tool, and click around the inner area of the polaroid’s frame. Afterwards select the current path with Ctrl + Enter/Cmd + Enter.

    Select with the pen tool the inner area of the polaroid picture

    Now Alt-click on the mask in the Layers Panel. You’re now editing the mask directly.

    Editing the Layer Mask of our polaroid picture

    Select the Marquee tool (M). Right-click your selection and select Fill > Black.

    Alt-click again on the mask icon, to return back to our “normal” Layer view. We’ve successfully edited our mask and now our polaroid is ready for use. Let’s save the image as a Photoshop document (.psd), I’ve named my document Polaroid.psd.

    The polaroid picture has been edited

    Section 3: Flash

    In this section we’re (finally) going to use Flash. We’re going to set our Flash document to use the folder bin for exporting, and the folder src for our code. Time to open Flash!


    Step 8: Creating Our Flash Document

    Create a new Flash Document (ActionScript 3.0) with Flash Professional. Set the dimensions to 600x600px and the framerate to 24 fps. Set the Document Class to Main. Also change the background to black (#000000). Save it as “Polaroid.fla”, inside the lib folder.


    Step 9: Changing Our Publish Settings

    Afterwards go to File > Publish Settings, change Polaroid.swf to ../bin/Polaroid.swf, you can uncheck the HTML option. Now everything we export (only a SWF) will be in the bin folder. Do not close the Publish Settings window.

    Change our publish settings of our Flash Document

    Step 10: Changing Our Source Path

    Click the Flash tab. Afterwards click on the Settings button next to Script: ActionScript 3.0.

    Now we can change the source path. You’ll see a folder icon with the text “.”, change that to “../src”.

    Flash will use the src folder for all its classes.

    Change the ActionScript settings of our Flash Document

    Step 11: Importing Our Graphics to Flash

    It’s now time to start importing our graphics in to our Flash Document. If you had any trouble with the images, you can always download the source files from this tutorial at the top. There’ll be a folder named “Edited Images”, inside there’ll be the edited images which you can use.

    Create a new Flash Document (ActionScript 3.0) with Flash Professional. Set the dimensions to 600x600px and the framerate to 24 fps. Also change the background to black (#000000).

    We’ve saved our images as .psd files because they work so greatly with other Adobe products, like Flash. After creating our document, select File > Import to Library and select Polaroid.psd and Background.psd. After doing so our library looks like this:

    We've imported our assets in to our Flash Document's library

    Step 12: Creating Our Background Sprite

    Drag Background.psd from the Library to our stage, afterwards convert it to a movie clip. Name it Background, and check the box “Export for ActionScript”. Set the base class to flash.display.Sprite. After doing so, you can remove the background again from the stage.

    Convert the background to a symbol

    Why did I set Background’s base class to Sprite instead of the default base class MovieClip? Because the only difference between a MovieClip and a Sprite is that MovieClips can contain multiple frames, and Sprites cannot. We don’t need multiple frames for our Background, so let’s set the base class of Background to Sprite.


    Step 13: Creating and Our Polaroid Movie Clip

    Just like we did with our background, drag polaroid.psd from the Libary to our stage. Convert it to a movie clip and name it Polaroid, again check the Export for ActionScript box. Set the base class to flash.display.Sprite.


    Step 14: Creating Our Polaroid’s Layers

    Our Polaroid is still on the stage, double-click it, so we can edit it. So far Polaroid only has one layer, rename this layer to Polaroid Frame.

    Create two new Layers, naming them Mask and Image Holder.

    The layers inside the symbol Polaroid

    Step 15: Creating the Image Holder

    Our Polaroid will contain an image, this image must be displayed somewhere, this will be done in a movie clip named “Image Holder”.

    Draw a rectangle of approximately the size as the “photo area” of the polaroid, do this in the Image Holder layer. It doesn’t matter which color the rectangle will be. After creating this rectangle, convert it to a movie clip, name it “Image Holder”.

    Give Image Holder an instance name of imageHolder.


    Step 16: Adding a Mask to the Image Holder

    Image Holder will contain the images which we will load. Sometimes these images are too big — take for example a 400x100px image; this image is much too wide, and its edges would extend out of the polaroid. We want to prevent this. Therefore we must hide all imagery which extends outside of the Image Holder’s area.

    To do this, we must create a mask. A mask tells a layer which part should be displayed, and which part should be hidden.

    If we want every image to be displayed inside Image Holder, without any edges protruding, we should set the mask’s size to the same dimensions as Image Holder itself.

    Copy Image Holder, and paste it in place with Ctrl + Shift + V (Windows) / Cmd + Shift + V (Mac) on the layer Mask. Afterwards break the copied Image Holder with Ctrl + B (Windows) / Cmd + B (Mac).

    Lastly we must tell our Mask layer that it is a Mask. Right-click on the layer Mask and select the option Mask.


    Section 4: Code

    It’s time to start coding, if you had any trouble with the Flash Section, you can just copy the folder Flash Section Completed. Inside that folder is everything you need to start following these steps.


    Step 17: Creating an XML File

    To load our images, we’ll use an XML file. The XML file will tell our product where the images are located.

    Open a text editor and type the following:

    
    
    <images>
    	<image>
    		<file>IMAGE_1.jpg</file>
    	</image>
    	<image>
    		<file>IMAGE_2.jpg</file>
    	</image>
    	<image>
    		<file>IMAGE_3.jpg</file>
    	</image>
    </images>
    

    You should change IMAGE_1.jpg, IMAGE_2.jpg, etc. to real filenames, which refer to images located inside the bin folder. If you don’t have any images, download the images that I mentioned in Step 3.

    Save this XML file as images.xml, inside the bin folder.


    Step 18: Which Classes Do We Need?

    Before we start coding, it’s important to know which tasks our project must do:

    • We must load our images from an XML file.
    • We must display these images inside a Polaroid.
    • We must prevent other Polaroids from zooming in when we are already zoomed in on a Polaroid.

    To code all these functionalities in one class would make that class extremely complex, it’s better to seperate each task to a different class.

    • ImageLoader: Will load the XML file and pass the images to PolaroidHolder.
    • PolaroidHolder: When it receives the images, it will create a Polaroid for every image, so it also makes sure that only one Polaroid is zoomed in at a time.
    • Polaroid: The image will be displayed inside this class.

    Step 19: Creating Our Main Class

    The Main class is the class which Polaroid.fla calls when it gets initiated.

    Create a new ActionScript file and name it “Main.as”, save it inside the src folder. The Main class looks as follows.

    
    
    package {
    
    	import flash.display.MovieClip;
    
    	public class Main extends MovieClip {
    
    		public function Main():void {
    
    		}
    	}
    }
    

    It’s so empty because we first need to create our other classes, while we’re busy we’re going to keep on adding code to the Main class.


    Step 20: Explaining Absolute and Relative File Paths

    In this project we’re loading several assets: an xml file and various images. We can use relative file paths or absolute paths. Let me explain the difference with an example; we have the following folder structure:

    An imaginary folder setup, we're using this example to understand the difference between absolute and relative file paths

    Loader.swf must load image1.jpg. From its current position Loader.swf must “open” the images directory and load image1.jpg. We tell Loader.swf to load images/image1.jpg. This type of loading is called relative file path loading, because the url is relative to Loader.swf’s current position.

    So how do you load image1.jpg, regardless of where Loader.swf is located? This is done with absolute file path loading. The file path starts from the upper core, from the root. If it’s on a computer, its root is a hard drive. We’re deploying our project online, so the root would be the site server.


    Step 21: Why We Need Absolute File Paths

    When our project is done, we’d like to deploy it. Most probably it would be embedded inside an HTML page. There’s one small problem. If Loader.swf wants to load, it will load from its current location, from the location of the HTML page. We don’t want this, and therefore we must use absolute file path loading.

    Now comes the biggest problem, we won’t know the location of the HTML file. We need to find the absolute path to the .swf file, and edit that path so we can load our imagery.

    We can get the absolute path to the .swf file with root.loaderInfo.url.

    It’s time to create our ImageLoader class.


    Step 22: Creating Our ImageLoader Class

    Create a new ActionScript file and name it ImageLoader.as, save it inside the .src folder. The class looks like this, it has been thoroughly commented:

    
    
    package  {
    	//import the classes we need
    	import flash.net.URLLoader;
    	import flash.net.URLRequest;
    	import flash.events.Event;
    	import flash.display.Loader;
    	import flash.display.Bitmap;
    	import flash.display.Sprite;
    
    	public class ImageLoader extends Sprite{
    		//will load our xml
    		private var xmlLoader:URLLoader = new URLLoader();
    
    		//stores the xml
    		private var xml:XML;
    
    		//a list of file paths to the images
    		private var imageFileList:XMLList;
    
    		//the path to the .swf file
    		private var swfPath:String;
    
    		//the project folder path (where the folders bin, src and lib are located)
    		private var projectPath:String;
    
    		//we must know the title of our project, so we can edit the .swf url to get our projectPath
    		private var projectTitle:String;
    
    		//we need to count how many images we've already loaded
    		private var count:uint = 0;
    
    		//we must store the images, the images are Bitmaps
    		public var images:Vector.<Bitmap> = new Vector.<Bitmap>;
    
    		public function ImageLoader(_projectTitle:String) {
    			//we must know when ImageLoader has been added, then we can figure out what the root's url is
    			addEventListener(Event.ADDED, whenAdded);
    
    			//store the project's title
    			projectTitle = _projectTitle;
    
    			//when imageLoader is done with loading, call xmlLoaded
    			xmlLoader.addEventListener(Event.COMPLETE, xmlLoaded);
    		}
    
    		private function whenAdded(event:Event):void {
    			//store the swf path
    			swfPath = root.loaderInfo.url;
    
    			//get our projectPath
    			projectPath = swfPath.substr(0, swfPath.length - projectTitle.length);
    		}
    
    		//this function will load the images from an xml, and store the images
    		public function load(url:String):void {
    			//load the xml, which we'll need to load the images
    			xmlLoader.load(new URLRequest(projectPath + url));
    		}
    
    		private function xmlLoaded(event:Event):void {
    			//store the xml, which xmlLoader has loaded
    			xml = new XML(event.target.data);
    
    			//store all the file links in an XMLList
    			imageFileList = new XMLList(xml.image.file);
    
    			//now that we have the file information, we can load the images
    			loadImages();
    		}
    
    		private function loadImages():void {
    			for each (var imageFile:String in imageFileList){
    				//create
    				var imageLoader:Loader = new Loader();
    				//whenever an image has been loaded, call imageLoaded
    				imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded, false, 0, true);
    				imageLoader.load(new URLRequest(projectPath + imageFile));
    			}
    		}
    
    		private function imageLoaded(event:Event):void {
    			//we're counting how many images we've already loaded, we've just loaded (another) one
    			count++;
    
    			//get the image Bitmap
    			var image:Bitmap = Bitmap(event.target.loader.content);
    
    			//store the image in our images Vector
    			images.push(image);
    
    			//if this is the last image we needed to load
    			if(count == imageFileList.length()){
    				//we're done, dispatch an event
    				dispatchEvent(new Event('imagesLoaded'));
    			}
    
    			//--cleanup
    			//unload the loader
    			event.target.loader.unload();
    		}
    
    		public function cleanUp():void {
    			xmlLoader.data = null;
    			xmlLoader = null;
    			xml = null;
    			imageFileList = null;
    			count = 0;
    			images = null;
    		}
    	}
    
    }
    

    Step 23: Improving Our Main Class

    Now that we have our ImageLoader class, we can improve our Main class.

    
    
    package {
    
    	import flash.display.MovieClip;
    	import flash.events.Event;
    
    	public class Main extends MovieClip {
    		//a custom class we've made which will load all images from an xml file as Bitmaps
    		private var imageLoader:ImageLoader;
    
    		//this class will hold and display all our Polaroids
    		private var polaroidHolder:PolaroidHolder;
    
    		public function Main():void {
    			//load our images, give imageLoader the name of the .swf file, so it can load using absolute paths
    			imageLoader = new ImageLoader('Polaroid.swf');
    			addChild(imageLoader);
    			imageLoader.addEventListener('imagesLoaded', displayImages, false, 0, true);
    			imageLoader.load('pictures.xml');
    		}
    
    		private function displayImages(event:Event):void {
    			//we've loaded all our images
    			polaroidHolder = new PolaroidHolder(imageLoader.images);
    			addChild(polaroidHolder);
    
    			//also clean up the imageLoader
    			imageLoader.cleanUp();
    			imageLoader = null;
    		}
    	}
    }
    

    Step 24: Creating Our PolaroidHolder Class

    The PolaroidHolder will receive the images as a Vector. After receiving the images, it will create a Polaroid for each image. Let’s create our PolaroidHolder class:

    
    
    package {
    	import flash.display.MovieClip;
    	import flash.display.Bitmap;
    	import flash.events.MouseEvent;
    
    	public class PolaroidHolder extends MovieClip {
    
    		//this vector will hold all our Polaroids
    		public var polaroids:Vector.<Polaroid>  = new Vector.<Polaroid>;
    		//with this variable we no
    		private var zoomedIn:Boolean;
    		//the Polaroid we're zoomed in on
    		private var currentPolaroid:Polaroid;
    
    		public function PolaroidHolder(images:Vector.<Bitmap>) {
    			// constructor code
    			for each (var image:Bitmap in images) {
    				//create a new Polaroid
    				var polaroid:Polaroid = new Polaroid(image);
    
    				//position and rotate it
    				polaroid.x = Math.random() * 200 + 100;
    				polaroid.y = Math.random() * 200;
    				polaroid.rotation = Math.random() * 60 - 30;
    
    				//add a clicking eventListener
    				polaroid.addEventListener(MouseEvent.CLICK, onPolaroidClick);
    				addChild(polaroid);
    
    				//add it to the polaroids vector
    				polaroids.push(polaroid);
    			}
    		}
    
    		private function onPolaroidClick(event:MouseEvent):void {
    			//there's been a click on a Polaroid!
    			if (currentPolaroid == null) {
    				//no currentPolaroid has been set, we're zooming in
    				//set the clicked Polaroid as the current Polaroid
    				currentPolaroid = event.currentTarget as Polaroid;
    
    				//mute all other Polaroids (the ones which aren't zoomed in)
    				for each (var polaroid:Polaroid in polaroids) {
    					if (polaroid != currentPolaroid) {
    						polaroid.mute();
    					}
    				}
    			} else {
    				//check if the click was on the current polaroid
    				if (event.currentTarget == currentPolaroid) {
    					//the same polaroid has been clicked (again), time to zoom out
    
    					//unmute all other Polaroids, they can respond again to events
    					for each (var polaroid:Polaroid in polaroids) {
    						if (polaroid != currentPolaroid) {
    							polaroid.unmute();
    						}
    					}
    
    					//now we're not zoomed in, so we don't have a current polaroid
    					currentPolaroid = null;
    				}
    			}
    		}
    
    	}
    
    }

    In lines 50 and 62, we call the functions mute() and unmute(). Mute makes the Polaroid numb to all events, it won’t respond to mouse overs, or clicks. This is precisely what we want when we’re zoomed in. We don’t want other Polaroids to do anything. After we’re zooming out, we want the Polaroids to respond to events; by calling unmute, the Polaroids will respond again to mouse overs and clicks.


    Step 25: Creating Our Polaroid Class

    Now it’s time to create our most interesting class, our Polaroid class! For this class we’ll need the popular tweening library tweener. Download it, and save the library inside the src folder (see this guide for more details).

    
    
    package {
    	import flash.display.MovieClip;
    	import flash.events.MouseEvent;
    
    	import caurina.transitions.*;
    	import caurina.transitions.properties.*;
    	import flash.display.Bitmap;
    	import flash.events.Event;
    
    	public class Polaroid extends MovieClip {
    
    		//the scale at which the Polaroid is zoomed in
    		private static const ZOOMED_IN_SCALE:Number = 1;
    		//the scale at which the Polaroid is zoomed out
    		private static const ZOOMED_OUT_SCALE:Number = .6;
    
    		//the max height an image can be
    		private var IMAGE_MAX_HEIGHT:Number;
    		//the max width an image can be
    		private var IMAGE_MAX_WIDTH:Number;
    
    		//we must scale the loaded images, remember the scale
    		private var scale:Number;
    
    		//when we zoom out, we zoom out back to the Polaroid's original position and rotation
    		//the Polaroid's original x coordinate.
    		private var origX:Number;
    		//we also need the original y coordinate
    		private var origY:Number;
    		//store the Polaroid's original rotation
    		private var origRotation:Number;
    		//when this Boolean becomes true, the Polaroid will not respond to mouse events
    		private var muted:Boolean;
    		//we need to know if the Polaroid has been clicked
    		public var clicked:Boolean;
    
    		public function Polaroid(image:Bitmap) {
    			//make the Polaroid a button
    			buttonMode = true;
    
    			//the maximum dimensions for an image are limited by the dimensions of imageHolder
    			IMAGE_MAX_HEIGHT = imageHolder.height;
    			IMAGE_MAX_WIDTH = imageHolder.width;
    
    			//scale the Polaroid down
    			scaleX = ZOOMED_OUT_SCALE;
    			scaleY = ZOOMED_OUT_SCALE;
    
    			//we'll need to resize the image to make it fit
    			//first check if it is a portrait or landscape
    			if (image.width > image.height) {
    				//it is a landscape
    				//the scale is limited by the image's height
    				scale = IMAGE_MAX_HEIGHT / image.height;
    			} else {
    				//it is a portrait
    				//the scale is limited by the image's width
    				scale = IMAGE_MAX_WIDTH / image.width;
    			}
    
    			//scale the image
    			image.scaleX = scale;
    			image.scaleY = scale;
    
    			//add the scaled image
    			imageHolder.addChild(image);
    
    			//add event listeners to the Polaroid;
    			addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
    			addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
    			addEventListener(MouseEvent.CLICK, onClick);
    			addEventListener(Event.ADDED, whenAdded);
    		}
    
    		public function mute():void {
    			//calling this function will make the Polaroid not respond to events
    			buttonMode = false;
    			muted = true;
    		}
    
    		public function unmute():void {
    			//calling this function will make the Polaroid respond to events
    			buttonMode = true;
    			muted = false;
    		}
    
    		private function whenAdded(event:Event):void {
    			//store the Polaroid's original coordinates and rotation
    			origX = x;
    			origY = y;
    			origRotation = rotation;
    
    			//we won't need this event listener anymore, remove it
    			removeEventListener(Event.ADDED, whenAdded);
    		}
    
    		private function onMouseOver(event:MouseEvent):void {
    			//only respond if the Polaroid has not been muted
    			if (! muted) {
    				//only respond if the Polaroid has not been clicked, clicked Polaroids should not respond to mouse overs.
    				if (! clicked) {
    					//move the polaroid to the front
    					parent.setChildIndex(this, parent.numChildren - 1);
    					//move and turn the polaroid in a random direction
    					Tweener.addTween(this, {x: origX + Math.random() * 30 - 15, y: origY + Math.random() * 30 -15, rotation:origRotation + Math.random() * 20 - 10, time:1});
    				}
    			}
    		}
    
    		private function onMouseOut(event:MouseEvent):void {
    			//only respond if the Polaroid has not been muted
    			if (! muted) {
    				//only respond if the Polaroid has not been clicked
    				if (! clicked) {
    					//move the polaroid back to it's original position and rotation
    					Tweener.addTween(this, {x: origX, y:origY, rotation:origRotation, time:1});
    				}
    			}
    		}
    
    		private function onClick(event:MouseEvent):void {
    			//only respond if the Polaroid has not been muted
    			if (! muted) {
    				//if it hasn't been clicked before
    				if (! clicked) {
    					//we've been clicked, let's make that true
    					clicked = true;
    
    					//we're zooming in, let's dispatch an event (Main will pick this up)
    					dispatchEvent(new Event('zoomIn'));
    
    					//zoom the Polaroid in to the center of the stage
    					Tweener.addTween(this, {x:stage.stageWidth/2 - width/2, y:stage.stageHeight/2 - height/2, rotation:0, scaleX:ZOOMED_IN_SCALE, scaleY:ZOOMED_IN_SCALE, time: 1});
    				} else {
    					//we've already been clicked, so make clicked false
    					clicked = false;
    
    					//we're zooming out, let's dispatch an event (Main will pick this up)
    					dispatchEvent(new Event('zoomOut'));
    
    					//zoom the polaroid out, back to its original position
    					Tweener.addTween(this, {x: origX, y:origY, rotation:origRotation, scaleX: ZOOMED_OUT_SCALE, scaleY:ZOOMED_OUT_SCALE, time:1});
    				}
    			}
    		}
    	}
    }
    

    Step 26: Adding Our PolaroidHolder to Our Main Class

    Make the changes as seen in the code below.

    
    
    package {
    
    	import flash.display.MovieClip;
    
    	public class Main extends MovieClip {
    
    		//a custom class we've made which will load all images from an xml file as Bitmaps
    		private var imageLoader:ImageLoader;
    
    		private var polaroidHolder:PolaroidHolder;
    
    		public function Main():void {
    			//load our imagges
    			imageLoader = new ImageLoader();
    			imageLoader.addEventListener('imagesLoaded', displayImages, false, 0, true);
    			imageLoader.load('pictures.xml');
    		}
    
    		private function displayImages(event:Event):void {
    			//we've loaded all our images
    			polaroidHolder = new PolaroidHolder(imageLoader.polaroids);
    			addChild(polaroidHolder);
    
    			//also clean up the imageLoader
    			imageLoader.cleanUp();
    			imageLoader = null;
    		}
    	}
    }
    

    Step 27: The Result So Far

    It seems to work, but it’s not very interesting. When zooming in, the user is not “pulled in”, our product is not immersive enough. What we need is a background! By chance we created one in Step 4. Time to add our background!


    Step 28: Adding Our Background

    We had exported our background with the class Background.

    Not only will we add Background as a child of Main, we’ll also make Background darken when we’re zoomed in, and lighten when we’re zoomed out. How do we do this? Whenever a Polaroid is clicked, it dispatches a custom event, zoomIn or zoomOut. We can trace this event, just add event listeners to our Main class, they’ll pick up the zoomIn and zoomOut events, and whenever they’re picked up, we can tell our Background to lighten or darken:

    
    
    package {
    
    	import flash.display.MovieClip;
    	import flash.events.Event;
    
    	import caurina.transitions.*;
    	import caurina.transitions.properties.*;
    
    	public class Main extends MovieClip {
    
    		//a custom class we've made which will load all images from an xml file as Bitmaps
    		private var imageLoader:ImageLoader;
    
    		//this class will display all our Polaroids, by receiving a Vector of Bitmaps
    		private var polaroidHolder:PolaroidHolder;
    
    		//the wooden background, bg is an abbrivation for background
    		private var bg:Background
    
    		public function Main():void {
    			//load our images
    			imageLoader = new ImageLoader('Polaroid.swf');
    			imageLoader.addEventListener('imagesLoaded', displayImages, false, 0, true);
    			addChild(imageLoader);
    			imageLoader.load('pictures.xml');
    
    			//add our bg as a child
    			bg = new Background();
    			addChild(bg);
    
    			//add event listener, so we know when we're zoomed in or out
    			//3rd parameter of addEventListener is true, so we can capture the event, when it "bubbles" up from the Polaroid
    			addEventListener('zoomIn', onZoomIn, true);
    			addEventListener('zoomOut', onZoomOut, true);
    		}
    
    		private function displayImages(event:Event):void {
    			//we've loaded all our images
    			polaroidHolder = new PolaroidHolder(imageLoader.images);
    			addChild(polaroidHolder);
    
    			//also clean up the imageLoader
    			imageLoader.cleanUp();
    			imageLoader = null;
    		}
    
    		private function onZoomIn(event:Event):void {
    			//upon zooming in, we'll darken the bg
    			Tweener.addTween(bg, {alpha:.6, time:1});
    		}
    
    		private function onZoomOut(event:Event):void {
    			//upon zooming out, we'll lighten the bg
    			Tweener.addTween(bg, {alpha:1, time:1});
    		}
    	}
    }
    

    Step 29: Looking Back

    Tada! We’re done, this was quite a tutorial! I hope you guys had fun following this tutorial, and also learnt something from it. Why not play around with the code? You could try adding text fields and somehow display the title of the image. Or use several types of Polaroids. Thanks, and feel free to comment if you have any questions or comments. Keep an eye out for my next tutorial!


  8. Michael James Williams says:
    August 19, 2011 at 3:31 am

    I’m neither an artist nor an animator, and yet I was able to lip-sync an audio track in next to no time, all thanks to SmartMouth by Justin Putney. This Flash Professional extension really impressed me with how quickly it was able to automate an otherwise extremely tedious task. Read on to see how it can make animating your cutscenes so much easier.


    First Impressions

    SmartMouth comes in a standard MXP package, like most Flash Professional extensions, so it was a snap to install: I just double-clicked the MXP and followed the on-screen instructions. (It’d be the same for any version of Flash from CS3 upwards, though for CS3 itself you must have installed the Extension Manager.)

    Once I installed it and restarted Flash, I could access the main panel via Commands | Lip Sync with SmartMouth:

    SmartMouth main panel

    The Help document can be brought up by clicking the question mark button; this does a great job of explaining the separate elements of the panel, but — call me biased — I felt it could also have used a brief tutorial walking me through how to use the tool. Still, there’s a detailed tutorial over on the Adobe Developer Connection, and the process is pretty simple anyway:

    First, I imported a sound track (I picked this public domain reading of one of Aesop’s Fables, from LibriVox), put it on its own layer, and set its Sync to Stream.

    Next, I created a new layer for the mouth to go on. Like I said, I’m not an artist, but fortunately we have a free Lip Sync Assets pack in the Activetuts+ archives, so I downloaded and imported that. I dragged and dropped each symbol onto a frame in my MouthShapes layer.

    Then I re-opened the SmartMouth panel; it had taken a guess at the layers I wanted to use for audio and animation, so all I had to do was choose the shapes that corresponded to each phoneme:

    SmartMouth main panel -- populated

    As you can see, it picked a Start Frame and an End Frame for me, so all I had to do was click Tell me, SmartMouth. This kicks off the audio analyzer, which plays the whole audio track through (visualizing it as it goes):

    SmartMouth Audio Analyzer

    After that, there’s a brief wait while it adds the keyframes for each mouth sound. I picked a 45 second sound file, which took up about a thousand frames (at 24fps), and SmartMouth figured out which mouth sounds went where — and actually placed the keyframes — within twenty seconds:

    SmartMouth modifies the timeline

    All I had to do then was remove the original mouth shapes from the timeline, and add a “grin” to the end (okay, technically that last one was optional). Check out the results for yourself:

    Click to start the audio and animation.

    I’m impressed!


    Room for Improvement

    I did come across a couple of bugs while using SmartMouth. When I entered my registration key, the “Success” dialog got stuck in a loop, and kept reappearing no matter how many times I hit OK. Then, later, I tried deleting all the mouth frames which SmartMouth had placed and running it again; this made it run a lot slower, and in fact it took longer than the 60 second time limit Flash imposes, making it crash without finishing its job.

    Still, neither bug was a big problem, since SmartMouth has a kind of “emergency exit”: right-click the main panel and click EXIT, and it’ll shut down, putting you back in control. Plus, if the audio is too long, you can work in chunks of a few hundred frames at a time by changing the Start and End Frame options.

    I mentioned, the Help docs are well-written — but I would have liked to see tool tips on the various buttons within the panel. It’s not immediately obvious what the buttons next to End Frame are for, nor what Mode or Limit To actually do, without reading up on them. Even “Tell me, SmartMouth” doesn’t suggest a command that will automatically place symbols in the timeline. But these are just nitpicks; once you’ve used the options, you’ll know what they do.

    My one major gripe was that, even though I placed the mouth shape symbols in different places around the stage, SmartMouth aligned them all when syncing to the audio (I think the mouth shape for the letter O is out of place in the SWF demo above). However, this proved to be my mistake: if I’d created a new symbol on the MouthShapes layer, and placed the individual mouth symbols inside that symbol, SmartMouth would have preserved my positionings.


    My Verdict

    After Ian finished Animating the Envato Community Podcast, he told me that a tool like SmartMouth would have saved him a lot of time and tedium. (Actually, he used rather more excited terms than that.) I can see why.

    In that video, there were several different people talking in turn, so there were different mouths that needed to be animated. SmartMouth doesn’t have an interface for doing this specifically, but it would be pretty simple to use it for that. Either:

    • separate the speakers’ voices into separate tracks on separate layers and run SmartMouth once per track,
    • use the Start and End Frame boxes to isolate the section of the track corresponding to one character at a time, or
    • run it once for each character and simply delete the frames that don’t match the character who’s talking.

    Although SmarthMouth’s most instantly impressive feature is its ability to put the mouth symbols on the stage in sync with the vocal track, this isn’t strictly necessary. If you prefer, you can tell SmartMouth just to create a new layer with labels corresponding to each phoneme in the vocals, so you can put the graphics in manually without having to keep scrubbing the timeline to see what sound you’re supposed to be imitating. This would be useful for frame-by-frame animation, or a scene with a lot of motion.

    It’s also possible to make SmartMouth export the phoneme data to an XML file; this could then be used in another platform, like Unity, or even loaded into a SWF with AS3 so that you could animate a custom avatar’s mouth dynamically. (From what I hear, Justin is working on a version of the tool specifically for that purpose.)

    Overall, I highly recommend SmartMouth if you need to do any lip-syncing in Flash. The basic functionality it amazing by itself, and the extra features push it over the edge.

    SmartMouth is available for purchase at the Ajar Productions website; prices start at $49.99 for a single seat, with discounts if multiple seats are bought at once.


  9. Daniel Branicki says:
    August 19, 2011 at 3:54 am

    In this tutorial (part free, part Premium), you’ll learn how to create a 2D puzzle game in Unity which uses a Portal-style game mechanic to teleport objects across the level. In this first part, we’ll lay out the main concepts of the game, put some graphics together, and get the basic (portal-less) physics working.


    Final Result Preview

    Let’s take a look at the final result we will be working towards, across the whole of this multi-part tutorial:

    Please view the full post to see the Unity content.

    Hit the number keys 1-8 to try different levels. The aim is to get the little yellow Roly character to the designated end point, using portal mechanics. The demo shows off a few of the different mechanics we’ll introduce.

    It’s going to take us a while to get to that point, though! In this first part of the tutorial, we’ll make a good start.

    Important Note: This project does make use of a few commercial Unity plugins: Sprite Manager 2 and Vectrosity. Also, while the first two parts of the tutorial are free to read, the third and fourth will be available exclusively to our Premium members.


    Step 1: Project Overview

    When creating your game you never want to jump right away into the code, first, you need an idea.

    Some people like to simply start doodling whatever they have on mind, some take a couple of random words and make a concept of the game based on thoughts that gravitate around those. Sometimes you don’t really want to make something new but rather do something that’s already done, but then again, you want to do it your way.

    Once you’ve got a pretty clear image of what you want to do, you need to be able to present your idea in a way that other people can see what the heck is this all about. Usually it takes a form of a concept art, a mock up picture, or a quick prototype. Even if you think the idea is great at the beginning, you should look objectively at those concepts and with an eye of a critic review your idea.

    If it doesn’t seem very appealing after the review, it surely won’t be later on, it’s better to simply try again with something else. If you still think it is the best game ever, you should show it to your friends, they surely won’t mind a few minutes lost, and their opinions are invaluable because they are given from other perspective than your own.

    The game we’re going to make in this tutorial is a 2D puzzle game that uses portals as its core mechanic. I’m sure you checked out the demo above so I don’t really have to explain much. I should probably show here some of my concepts for the game, but unfortunately many of them either weren’t saved or simply weren’t in digital form to begin with, I can present only a couple of them that I found lying here and there.

    The first level of the game.
    The sixth level of the game.
    The concept of the main character.

    You already know that we’re going to use Unity3D, but that’s not a very obvious choice especially if you want to make a 2D game. The main reason why I chose it is because it’s multiplatform. It can deploy a game to web browser via custom plugin, windows, mac, android, iOS, wii, and soon to xbox360 and ps3. There’s also a flash exporter in works. You may be sure that if you develop the game in unity then there are no worries about porting the game to other platforms.

    To make a 2D game we need to be able to deal with sprites, unfortunately unity doesn’t provide any built-in means to do that yet, but there are various plugins that are made specifically for this task by 3rd party developers. For this game I chose Sprite Manager 2 to serve this purpose. Aside from that, I’m also using Vectrosity to render lines and curves. I want to note that you don’t really need to use those plugins. If you have your own solution for rendering the sprites, that’s fine, but you must be prepared to fiddle with the code so you do replace what’s done with Sprite Manager 2 with the adequate code using your plugin. Of course the same applies to Vectrosity.


    Step 2: Create a New Project

    The first thing we need to do is to create a new project in Unity from the project wizard.

    Create new project wizard.

    Name it however you like and press Create, then the project will be created and opened. Now we should import all the the plugins so everything is on its place. The Sprite Manager 2 is in .unitypackage, so all you have to do is to double click this file and then press all so all the files will be imported and then import inside the unity editor.

    Import assets wizard.

    For Vectrosity we need to copy the folders into our Assets folder ourselves. Navigate to both, the Assets directory in your porject folder and VectrosityScripts.zip in your Vectrosity folder. Now extract the files from VectrosityScripts.zip. In the extracted folder there should be two others: Editor and Standard Assets. Simply copy those to the Assets directory. Here’s how your project’s directories should look like for now.

    Project window shows our project tree with all the assets and folders.

    Step 3 Setup the Scene

    First thing we should do is to set the resolution of our project. Let’s say we want our game to be 480 pixels wide and 320 pixels high. In that case we need to go to the Edit->Project Settings->Player.

    That's where you can find Player Settings.

    Now in the inspector window you can see player settings. We need to change the resolution in the web player, because that’s where we’ll be deploying our game.

    I bet you know what device this resolution fits.

    As you can see there are various settings here, what interests us is the Default Screen Width and the Default Screen Height. Change them accordingly to our needs. It’s reasonable to leave Run In Background unchecked, because that will pause the game when the browser is minimazed. The game still will be running if the user marely changes tabs though.

    Now go to File->Build Settings.

    Ctrl+Shift+B is the shortcut for Build Settings.
    Unity Build Settings.

    And switch the platform to Web Player. Also remember to check Streaming, this basically allows level streaming so if someone wants to play your game, they don’t have to wait for it to load completely. You can read a bit more on this topic at the Unity Manual page on streaming.

    You need to ise the new resolution.

    Now go ahead and change the resolution in Game window from default Free Aspect to Web (480×320). Also resize this window so you can see the dark grey border around blue area, because if the window is too small to fit our web resolution then it will be resized to do so, even if we have our Web (480×320) selected. It will still keep the aspect ratio though.

    Remember that unity allows you to drag and drop every window wherever you want, so you should setup your environment the way you are comfortable with it. I’m using a bit modified 2 by 3 view, I left everything as it was except draggin the Project window below the Hierarchy.

    My unity editor layout.

    Step 4 Setup the Camera

    If you are familiar with 3D editors of any kind, you should know that the concept of pixel kind of disappears and what is introduced are standardized physics units. When it comes to length, one unit doesn’t have to be equal to one pixel, and we don’t really care about it in a 3D world, but when we are working in 2D then it’s very useful to have one pixel to one unit binding. We’ll be able to do that by tweaking the camera in our scene. First select the Main Camera object from the Hierarchy window.

    All the objects in the scene can be found in hierarchy window.

    Once you selected it, the inspector should show our camera settings. The first setting we should change is Projection. Since our game is not 3D, we don’t really need a perspective, we rather want a flat orthrographic view.

    Setting properly the camera is important for 2D game.

    Once you selected Orthographic projection, there should appear a new property called Size right below it. It basically indicates how long in world units is half of screen height. Since we want to have one to one pixel to world unit correlation, we need to set it to half of our resolution height. The width is worked out behind the scenes using the aspect ratio. Go ahead and change the default value of 100 to 160, which is our resolution height (320) divided by 2.


    Step 5 Import the First Asset

    Before we create our first sprite, we need to import the assets into unity. It’s as simple as to drag and drop the files to the project’s folder. Here is the texture we want to import for our sprite.

    Our first asset. We'll use it for quite a while.

    Remember that if you are using photoshop files in unity then you have to deal with white borders around the sprite. To solve this problem you can use a method presented in this Blurst Technology blog post or this Unity Manual page.

    To make everything clean we should create a folder for our textures. To create a folder you can simply create one in the explorer or do so directly from editor by right-clicking in the project window and then select Create->Folder.

    It's better to keep everything in folders.

    Rename the folder to Textures and drag our ball texture to it.

    If you didn’t do this yet, we should save the scene. But before that, let’s create the folder the same way we just did. This time let’s call it Scenes. Then go to File->Save Scene, navigate to our Scenes folder and save it there. Call the saved scene demo.

    Save the scene often!

    Remember to save often, it should become a habit.


    Step 6 Create a Sprite

    Let’s create our first sprite. First thing you need to do is to create a game object inside our editor. To create an object simply go to GameObject and then click on Create Empty. This will create an empty object in the scene, it will also be visible in the hierarchy window. It’s named GameObject by default.

    The base of every object.

    Let’s change the name of our object to Ball, because the first sprite will be just that, a ball. You can change the name of an object by double-clicking on it in the hierarchy window or changing it in the inspector window, it’s the first edit box on the very top of it. Now change the ball’s position to the very center of the world – change all its position components to zero. You can edit X, Y and Z position values in the Transform component attached to our sprite. After you do that, the ball’s inspector should look like this.

    Transform is a component that every GameObject possess.

    Remember that no matter how far from the camera the sprite is, it will be the same size due to camera being in orthographic mode. Nonetheless, since our camera’s z position is -10, we need to remember that our sprites need to be less than that to allow the camera capturing them. Either that, or we could change camera’s own Z position.

    Now it’s time to make use of Sprite Manager 2. Before we do that though, I would like to recommend watching the introductory videos from the developer of Sprite Manager 2. You can find them at Sprite Manager 2 page. I will guide you through the process of creating the sprite anyway, but diving into the greater details won’t hurt you. :)

    In our project window expand Plugins->Sprite Scripts, so you can see a bunch of C# scripts there. To create a sprite, we need to use either PackedSprite or Sprite script. The basic difference between those two is that the PackedSprite creates and menages the texture atlas on which sit all the frames of the sprite, while Sprite requires a premade texture atlas and a couple of additional settings for it to work. To attach the script to our ball, you can either drag and drop it on the object in the hierarchy window you want it attached to, or if you have the object selected, then drag and drop it in the inspector window or go to Component->Script->PackedSprite. Now below our Transform component, there are a couple of others with PackedSprite on top.

    We're making the first use of Sprite Manager 2 here.

    As you can see, there is a lot of things to set here. We’ll take care of it later. For now, go to the Window->Sprite Timeline.

    Here you can also edit and add animations.

    A new window should pop up. If you don’t have our ball selected, you should do that now in order to be able to work on it. You can drag the window next to our Game window so it’ll work as a tab next to it. Here’s how the window should look like.

    For now we don't have anything to display.

    As you can see, there isn’t much going on here. There is a place for Static Texture, which is basically a texture that will be displayed if the sprite won’t be animating. Let’s drag and drop our ball texture here.

    Now there's a texture that we'll use for sprite frame.

    Now let’s go back to our inspector. In order to see the sprite, it has to have positive width and height. We want our sprite to display in its original size, to achieve that, we need to check Pixel Perfect checkbox. By doing that Auto Resize is checked automatically, it makes sure that the sprite proportions are the same as the original texture.

    Remember to tick it if you want to render your sprite most accurately.

    Now we need to assign the material for our sprite. There’s a default material for sprites situated at Plugins/AnBSoft Common/Standard Material, it’s called Sprite Material. Let’s drag it from the project window on our Ball object, that’s all we need to do to assign this material to it. Now in the inspector there will be a material assigned to the sprite’s Mesh Renderer.

    We need to assign a material before we can build an atlas.

    Now it’s time to build an atlas for our sprite. To do that, we need to go to Tools->AB Software->Build Atlases.

    Alt+A if you don't like wasting those precious seconds.

    A small wizard will pop up. All settings are set to suit our needs by default, so all we need to do is to click Create.

    Build Atlases Settings are optimal by default.

    All that’s left is to press play and see how our sprite looks.

    Sprite rendered not accurately.

    As you can see, it’s far from perfect. We’ll take care of it in the next step.


    Step 7: Align the Sprite

    The issue at hand is explained at this MSDN page. We need to offset our sprite by half of the pixel to make renderer display it accurately. Let’s see if that works. let’s change our sprite’s position to (0.5, 0.5, 0.0).

    Offsetting the sprite.
    Sprite rendered accurately this time.

    As you can see, it worked well, the image displayed is now very sharp. Generally this kind of quality drop doesn’t matter for objects that move a lot. It also doesn’t matter for high resolution sprites, because then it’s unnoticable. Since our ball will be in constant movement, it won’t matter whether we align it every frame or not because the changes won’t be noticable as well. For static objects, we can align them right away in the editor and they will stay in a good shape. The problem could arise if we were dealing with low resolution sprites that are not in a constant movement. In that case we would need to align it every frame, which isn’t a huge problem at all. In fact, we’ll create a script which does that right now.


    Step 8: Create a Script

    The first thing we need to do is to create a script file. We can do that in our project window, but before we do that, let’s create a new folder and name it Game Scripts. After it’s created, you can right-click on it and then go to Create->C Sharp Script. You can rename the script by pressing F2 or clicking on its name. Name it Align.

    Align script in our Game Scripts folder.

    Everyone has their favourite script editor of choice, I’m using the one that comes with unity – MonoDevelop. It integrates with unity really well, and it’s the only one that allows for script debugging. If you use it too, I recommend to go with these preferences, which you can find under Edit->Preferences….

    Scripting tools preferences.

    Now double-click on the Align script, so it will open in our script editor.

    
    
    using UnityEngine;
    using System.Collections;
    
    public class NewBehaviourScript : MonoBehaviour {
    
    	// Use this for initialization
    	void Start () {
    
    	}
    
    	// Update is called once per frame
    	void Update () {
    
    	}
    }
    

    There’s already some code in here. When using the C# with unity, you always need those first two lines.

    
    
    using UnityEngine;
    using System.Collections;
    

    The next thing is a class declaration. In our case, we want to name it Align, so let’s change NewBehaviourScript to that.

    
    
    public class Align : MonoBehaviour {
    

    Note that everything with exception of two first lines goes inside the class. By default we’ve got two function declared here, void Update(), which is called every frame and void Start(), which is called once and that’s before the first Update() call. We don’t need the latter, so let’s remove it from the script.

    
    
    using UnityEngine;
    using System.Collections;
    
    public class Align : MonoBehaviour
    {
    
    	// Update is called once per frame
    	void Update() {
    
    	}
    }
    

    Step 9: Script the Alignment

    Alright, let’s think of how should our aligning work. Since we are going to align the position of sprite, we will need another vector to hold its true position, the way it would be unaligned. Let’s call it realPos. We need a Vector3 for holding a position, so that’s the type the realPos is going to be. You can declare class variable like this.

    
    
    public class Align : MonoBehaviour {
    
    	Vector3 realPos;
    
    	// Update is called once per frame
    	void Update() {
    
    	}
    }
    

    The next thing which we need to do is to think how will we be able to return from the aligned position to the original one. That’s pretty simple. We need to know how much we aligned it in the first place, and then unalign it. So we know that we will need to know how much alignment did take place, we need to align in both, x and y axes. A 2D vector would suffice, but since we’re working with positions in 3D space here, it would be better to keep using 3D vectors. Let’s declare another Vector3 and name it offset.

    
    
    public class Align : MonoBehaviour {
    
    	Vector3 realPos;
    	Vector3 offset;
    
    	// Update is called once per frame
    	void Update() {
    
    	}
    }
    

    Alright, it seems like everything is in place. Let’s write down our alignment code. Firstly, let’s save our original position to realPos variable.

    
    
    public class Align : MonoBehaviour {
    
    	Vector3 realPos;
    	Vector3 offset;
    
    	// Update is called once per frame
    	void Update() {
    		realPos = transform.position;
    	}
    }
    

    To get to our current position, we need to access the Transform component. In unity, you can access built-in components by simply using a reference which is always called by the name of the component. The only difference is that it doesn’t start with a capital letter. So if we want to access Transform component attached to our sprite, we can simply use transform reference for it. If we’ve got that, then all that’s left to do is to access the position vector.

    We need to calculate the offset. The offset is a difference between our original position and the aligned one. Well, we know what our position is, so we only need to calculate the aligned one. To do that we simply round the original position to integers, and then add 0.5 to that so it’s aligned properly. Now to do that in code.

    
    
    new Vector3(Mathf.Floor(realPos.x) + 0.5f, Mathf.Floor(realPos.y) + 0.5f, realPos.z);
    

    So we created new Vector3, to package our aligned position into a 3D vector. Notice that we used a math library here, you can access it whenever you need to do any math. In this case we used Mathf.Floor(), which simply returns the nearest integer lower or equal to the float value we submitted. Now we only need to substract it from the realPos, and that’s our offset!

    
    
    public class Align : MonoBehaviour {
    
    	Vector3 realPos;
    	Vector3 offset;
    
    	// Update is called once per frame
    	void Update() {
    		realPos = transform.position;
    
    		offset = realPos - new Vector3(Mathf.Floor(realPos.x) + 0.5f, Mathf.Floor(realPos.y) + 0.5f, realPos.z);
    	}
    }
    

    Now it’s a simple matter to align our position. It’s our offset substracted from realPos.

    
    
    public class Align : MonoBehaviour {
    
    	Vector3 realPos;
    	Vector3 offset;
    
    	// Update is called once per frame
    	void Update() {
    		realPos = transform.position;
    
    		offset = realPos - new Vector3(Mathf.Floor(realPos.x) + 0.5f, Mathf.Floor(realPos.y) + 0.5f, realPos.z);
    
    		transform.position = realPos - offset;
    	}
    }
    

    Remember that since we don’t want to alter the original position in any way, we need to unalign it before we start our calculations. To do that, simply add the previously substracted offset to the realPos, which is our original position.

    
    
    public class Align : MonoBehaviour {
    
    	Vector3 realPos;
    	Vector3 offset;
    
    	// Update is called once per frame
    	void Update() {
    		realPos = transform.position + offset;
    
    		offset = realPos - new Vector3(Mathf.Floor(realPos.x) + 0.5f, Mathf.Floor(realPos.y) + 0.5f, realPos.z);
    
    		transform.position = realPos - offset;
    	}
    }
    

    Finnaly, we shoud remove the constant, 0.5f and replace it with a variable, so we can align our object’s however we want, be it integers or not. Let’s declare a float and call it alignment.

    
    
    	Vector3 realPos;
    	Vector3 offset;
    	public float alignment = 0.5f;
    

    Making the variable public will allow us to change it in object’s inspector. Notice that this time we created a default value for this variable, it’s 0.5f, so if we attach our script to an object, it will have alignment equal to 0.5f by default. Let’s swap our constants with this variable.

    
    
    offset = realPos - new Vector3(Mathf.Floor(realPos.x) + alignment, Mathf.Floor(realPos.y) + alignment, realPos.z);
    

    That’s it. To check out the script simply drag and drop it from the project window on our Ball in hierarchy window. After doing so, it should be visible in the inspector window, near the bottom.

    Script is also a component.

    To test the script out, you can start the game and drag the sprite around in the scene window. You’ll see in the inspector that the position is aligned properly, and in the game window the sprite never appears to be blurry. As I stated before, this treatment wasn’t really necessary to our ball, because it will be moving constantly, but I hope that writing such a simple script served as a good introduction into scripting in unity. To remove the component, simply right-click on it in the inspector window and then select Remove Component.


    Step 10: Add Components to the Sprite

    It’s time to add some physics into the game. It’s a very simple process. The first thing we want to do is to add a Collider component. With our Ball selected go to Components->Physics->Sphere Collider.

    Radius is set automatically.

    As you should see in the editor, a green colored circle appears which represents the collider. Its size automatically fits the sprite’s mesh, so we don’t have to worry about that.

    Gizmo around the sprite.

    There is also a checkbox for Is Trigger, checking that would make our sprite a trigger, and we don’t really want that. Triggers receive a collision callback, but they are permeable. We want the ball to be a proper physical object. Now let’s attach Rigidbody. This component brings our object to life in our game world. Go to Components->Physics->Rigidbody to attach it.

    Rigidbody settings.

    We need to change a few settings here. If a Rigidbody Is Kinematic, then it’s pretty much static, no physical force can move it, the only way to change its position is to do so directly through Transform. That’s not the kind of object we want our ball to be, so we better leave that option unchecked. We want to check collisions of our ball to the Continuous Dynamic mode, by doing this the physics solver will always be detecting collisions against both, static and dynamic objects. The next thing are constraints. We don’t really want our sprite to move along z axis, nor do we want it to rotate around any other than z axis, so we’ve got to check those appropiately.

    Rigidbody settings adjusted for our needs.

    You can now hit play and should see the ball falling very slowly.

    Click here to try the demo.


    Step 11: Tweak the Physics

    The ball falls too slowly and that’s because our world unit is very small. Because we want it to be one pixel, we need to tweak the gravity so the ball falls faster. Go to Edit->Project Settings->Physics.

    Physics settings.

    After playing with it a bit, I set the gravity to -250. Another value that we should change while we tweak the physics is Min Penetration For Penalty. It’s set to 0.01 in world units, which is incredibly small value in our case. Let’s change it to one pixel.

    Physics settings adjusted for our needs.

    Click here to try the demo.


    Step 12: Create Prefabs

    The most common explanation for prefab is that it’s a blueprint of an object. It’s basic function is that if you have multiple objects of the same kind in the scene, if you want to modify them all you can modify the prefab and apply the changes to all objects at once. Every sprite needs a prefab. When generating the atlas, Sprite Manager 2 looks up which textures it will need in the current scene, and there is no way to access other scenes to see which textures they need. Creating atlases per scene is pretty much unacceptable, so what Sprite Manager 2 does is looking for prefabs in the project folder and looking up which textures they need, because prefabs are not assigned to any particular scene. This way it can build atlases that cover all of the sprites in the project.

    To create a prefab, you can right-click in the project window area and go to Create->Prefab. The next thing you need to do is to drag and drop the object which you need a prefab of from the hierarchy window on the prefab in project window.

    Prefab of our ball sprite.

    To keep everything clean, let’s create a folder named Prefabs, and throw the Ball prefab there. Note that objects that are connected to a prefab have blue font color in hierarchy window.

    Ball is now blue in the hierarchy window.

    Step 13: More Sprites

    Now it’s time to create something our ball can roll on. Here are two textures, first is for the solid ground.

    Tile for our solid ground.

    The second is for the background.

    Tile for the background.

    Now import them, preferably to Textures folder, and before you turn them into sprites, let’s clean up the project a bit more. Instead of using the same material for ball and tiles, let’s duplicate the one we already have. It’s sometimes useful to have objects that differentiate so much from each other on separate materials, because that allows you to treat them in a different way. You can duplicate any asset or object by either going to Edit->Duplicate or using a shortcut, Ctrl+D, of course the object we want to duplicate must be selected.

    Our materials inside Plugins folder.

    We should move our materials to folder exclusive for them, let’s call it Materials.

    Material moved to Materials folder

    Now create two new sprites the same way we created the first one. Remember that you need to assign Tiles Material to each of them. The sprites may look broken or not render at all right after building atlases, just hit play and everything should set up automatically.

    Ball, ground and background.

    Step 14: Ground and Background

    To make our ground tiles inpenetrable, we need to attach a Collider for them. Since our tile is basically a square, we need to attach a Box Collider instead of Sphere Collider. Go to Components->Physics->Box Collider while having our ground tile selected to attach the collider.

    Gizmo around our ground tile.

    If you move our tile below the ball and hit play, you will see that the ball doesn’t go through the ground. Note that the z value of collider’s size is 0. That’s because the mesh is basically a quad. We should change the collider’s z value to 30, so more objects with varying depth can fit on it.

    Size along Z axis should be pretty big.

    Click here to try the demo.

    Alright, let’s not forget about making every sprite into a prefab. Let’s create two new prefabs, each for one of our new sprites.

    Two other prefabs join the Ball.

    Let’s duplicate our tiles and fill the scene with them. First let’s set up the ground tiles.

    Ground laid out.

    Two rows look well. After duplicating the object so many times, the hierarchy window isn’t in a very good state.

    Lots of ground tiles in our hierarchy window.

    The solution for this is very simple. Create an empty object and drag and drop all of the platforms on it. This way, the empty object becomes the parent object of all those platforms. It basically means that if you do any actions on parent’s transform, like moving, scaling or rotating, the same action will be applied to all of its children. We can also collapse the parent, so children are invisible in the inspector.

    Parent of our tiles.

    Remember to name the parent appropiately. In our case Ground Tiles will suit it will.

    Do the same action with the background, but this time make sure that the background is actually behind both, ball and ground tiles. It would be wise to create the parent at the beginning, change its z position to something like 20 so it’s pretty far from our main plane. Make sure that childrens’ z position is equal to 0 in that case, because the parent is pretty far away already, and the parent’s position stacks on top of childrens’. If you both, children and parent would have Z position equal to 20, then in fact the childrens’ Z position in world space would be equal to 40. After you created the first child, you can duplicate and the copy will have autoamtically the same parent assigned.

    Background tiles laid out.
    Background needs to be far away.

    Step 15: More Physics Tweaking

    Drag the ball in the editor really high up, let’s say to the top of our screen and then hit play.

    Click here to try the demo.

    As you can see, the ball doesn’t bounce at all. That’s because there’s no physic material assigned to our ball, and because of that the default one is used. The default material isn’t very bouncy, and so we have to create our own. The first step would be to create a folder called Physic Materials, to keep things clean. Once you have it, right-click it and go to Create->Physic Material.

    New Physic Material.

    As you can see, there’s quite a few options to tweak here. Before we get into them though, it would be nice to change the material’s name to Ball, it’s going to be a material for our ball after all. The most interesting option for us is Bounciness. The default value is equal to 0, and that simply means that the object with this material will not bounce. We can also tweak Dynamic Friction, which is the friction applied when the object is moving and Static friction, which is the friction applied when the object stays still. Besides that, there’s also Friction Combine and Bounce Combine, which define how the material will react upon colliding with another object. You can read more on the physic materials at this Unity Reference Manual page. I played a bit with those settings, and here’s what I came up with.

    Physic material settings.

    Of course creating the material isn’t enough. We have to assign it to our ball. Simple drag and drop will do the work, but you could assign it in the Sphere Collider component attached to the ball.

    Collider with physic material.

    Hit play and see the results.

    Click here to try the demo.

    As you can see, the ball bounces properly now.


    Step 16: Approaching Portal Creation

    The general idea of a portal is that whatever enters it, it immidiately appears at another portal, so the object gets warped. Additionally, we want portals to be two-sided, so a portal has two sides which correspond to the other two of another portal. Since we grasp the general idea what do we want to do, it’s time to think of how exactly are we going to do it. As always, there are multiple options to consider. We’ll choose the one that suits us best. We should initially assume that we won’t be cutting part of an object and then change its position, because that would be a very hard thing to do.

    The easiest way to approach this problem is to create a copy of an object that goes through first portal, and this copy will be synchornized with the first one so it appears like it’s the second part of the first object.

    Two objects that seem to be one.

    Now we need to figure out how to display only a certain part of a sprite. Since we want portals to be usable from two sides, the standard trick in which we could make a ball disappear behind a wall does not come into play.

    Part of an object hides behind the wall.

    As you can see, by this method we would be able to use only one side of portal, and additionally the portals could be positioned only on the wall or the floor, so, though it’s simple, it’s not flexible at all.

    Another idea that might pop into a head while thinking about this, is to make use of render targets. It would basically mean that we would have to overlay the area of where the ball is going with a texture that was there before the ball moved into that area.

    Part of an object hides behind the texture.

    This option is not very flexible too, because we would be required to keep the area we replaced with the texture static, so nothing could move into it. Not to mention that render textures are a feature of Unity3D Pro only.


    Step 17: Hide Part of a Sprite

    What’s left for us is instead of manipulating the world so it hides part of our sprite, is to make part of a sprite disappear. There is a very nice functionality in Sprite Manager 2 that allows us to hide any part of sprite by simply declaring a rectangle in which our sprite should be visible.

    Hiding everything besides the rectangular area.

    It makes use of sprite’s ClippingRect, but it doesn’t actually define the area in which sprite is visible, but rather adjusts the UVs of the sprite to display only the pixels contained in this ClippingRect. Unfortunately, because of the way it works, it doesn’t work for rotated sprites, or to be more accurate: the sprites can be clipped correctly when unrotated. Since our warping object is a ball, this method isn’t really acceptable.

    Another way to solve this problem is to write a custom shader which would cut off part of our sprite’s texture along any axis. This way we will be able to have rotated sprite rendered properly.

    Cutom shader work.

    It will be a lot of work, but creating a shader seems like the best option for us. It will be as flexible as we will make it, so we can precisely create what do we need.


    Step 18: Create a Shader

    Let’s create a shader. You can do so by right-clicking in the project window and then goto Create->Shader. Now let’s create a folder named Shaders and put the new shader in it, you should also rename it so it makes more sense than NewShader. Cutoff will be OK.

    
    
    Shader "Cutoff" {
    	Properties {
    		_MainTex ("Base (RGB)", 2D) = "white" {}
    	}
    	SubShader {
    		Tags { "RenderType"="Opaque" }
    		LOD 200
    
    		CGPROGRAM
    		#pragma surface surf Lambert
    
    		sampler2D _MainTex;
    
    		struct Input {
    			float2 uv_MainTex;
    		};
    
    		void surf (Input IN, inout SurfaceOutput o) {
    			half4 c = tex2D (_MainTex, IN.uv_MainTex);
    			o.Albedo = c.rgb;
    			o.Alpha = c.a;
    		}
    		ENDCG
    	}
    	FallBack "Diffuse"
    }
    

    As you can see, there’s quite a lot of code here already. You can delete it whole and replace it with the following template.

    
    
    Shader "Transparent/Cutoff" {
    Properties {
    	_MainTex ("Main Texture", 2D) = "white" {}
    }
    
    Category {
    	Tags {"Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
    	ZWrite Off
    	Blend SrcAlpha OneMinusSrcAlpha
    	SubShader {
            Pass  {
    
    ColorMaterial AmbientAndDiffuse
    Lighting Off
    Cull Off
    
    CGPROGRAM
    #include "UnityCG.cginc"
    #pragma vertex vert
    #pragma fragment frag
    
    sampler2D _MainTex;
    float4 _MainTex_ST;
    
    struct v2f {
        float4  pos : SV_POSITION;
        float2  uv : TEXCOORD0;
    };
    
    v2f vert (appdata_base v)
    {
    }
    
    half4 frag (v2f i) : COLOR
    {
    }
    
    ENDCG
    		}
    
    		}
    	}
    }
    

    There’s even more code here. Now, if you’re not familiar with writing shaders in unity, or even shaders in general this code must seem very unapproachable, in fact I’m not a graphics programmer and I’m not familiar with shaders at all, but with some patience if you grasp the concept then creating a simple shader like the one we are creating now is not that hard. A lot of what you see here are simple settings that you have little control of, you can see what are they about at this Unity Reference Manual page. For example Cull Off allows us to see sprites from both sides, front and back, ZWrite Off disables writing to Z Buffer, Lighting Off disables lighting and so on. There’s also a syntax specific for Shader Lab which unity uses, so if you want to know what goes where and with what, then you should really see that Unity Reference Manual page. The meat of the shader in our case is what goes between CGPROGRAM and ENDCG. Aside from that, what interests us is in the Properties{} brackets.

    Between CGPROGRAM and ENDCG we can write a custom shader in CG language. That’s all there is to it, though we need to remember here to #include "UnityCG.cginc", so we can use custom unity functionality in the shader. Another thing that we must do is to define the names of our vertex and fragment programs. To do that, we use #pragma vertex vert and #pragma fragment frag. This way the compiler will know that our vertex program is named vert and our fragment program is called frag. Next thing is sampler2D _MainTex. This is basically our texture input, the texture on which sit our sprite’s frames. Right next to it is float4 _MainTex_ST. We don’t do anything with it, we just need it defined and it can sit here, it is used to specify tiling and offset for our texture. We won’t use it directly, but as always, nothing is without purpose. The next thing is struct v2f which is basically a struct for our vertex program output and fragment program input. It contains two variables, float4 pos and float2 uv. They are containers for our vertex position ad UV respectively. Next is our vertex program. Its input is of appdata_base type, which means that it’s a vertex with position, normal and texture coordinate. It returns our output structure which we defined earlier. The last thing is our fragment program, its input is the output of the vertex shader, so it’s type is our struct v2f. It returns the COLOR, which is basically four 16-bits floats. ENDCG ends our shader.

    The properties , which go inside Properties{} brackets, allow us to submit input data directly from unity to the shader. For now we’ve got only one, _MainTex which is the texture our sprite’s frames sit on. Notice that they need to be declared here as well as in the CG shader.


    Step 19: Vertex Shader

    
    
    v2f vert (appdata_base v)
    {
        v2f o;
        o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
        o.uv = TRANSFORM_TEX (v.texcoord, _MainTex);
        return o;
    }
    

    First thing we do in our vertex shader is creating our output structure which we need to set here. To calculate the position, we simply need to multiply the position of the vertex (in object space) by UNITY_MATRIX_MVP, which is a predefined matrix. Next, we need to calculate our UV, we do that by using TRANSFORM_TEX macro. We only need to submit the texcoord from our vertex data and the the texture our sprite is using. TRANSFORM_TEX uses our _MainTex_ST, that’s why we had to define it. Finally we can return our output.


    Step 20: Fragment Shader

    In fragment shader we need it to make any pixels that go behind the axis invisible. In fact, this is the meat of our shader, here we’ll tell which texels should be displayed, and which shouldn’t. For that we need a linear equation. Linear equation can be easly used to split the sprite into two parts, and that’s all we need to do in this shader. If you forgot about how does linear equation work, you can visit this wikipedia page on linear equation. We’re going to use the standard form. So what kind of parameters does linear equation have? Those are A, B and C. The first two set the direction of the axis, and the third one only offsets the whole axis. That’s very useful, because by offsetting the whole axis we can tweak how much of the sprite should be invisible. So we need three new properties to declare, let’s call them _A, _B and _Cutoff.

    
    
    Properties {
    	_MainTex ("Main Texture", 2D) = "white" {}
    	_A ("_A", float) = 0.5
    	_B ("_B", float) = 0.5
    	_Cutoff ("_Cutoff", Range(-1.0, 1.0)) = 0.0
    }
    

    The _Cutoff is of Range type. This will give us a nice slider in editor to edit this value. Notice that its range is between -1.0 and 1.0, suggesting that the zero is minimum, and one is maximum cutoff. The first two parameters for our linear equation are normal floats, with initial value set to 0.5.

    Properties of our shader appearing in the inspector.

    Remember that we also need to define our properties in the CG program.

    
    
    sampler2D _MainTex;
    float4 _MainTex_ST;
    float _Cutoff;
    float _A;
    float _B;
    

    Alright, now let’s go back to our fragment shader.

    
    
    half4 frag (v2f i) : COLOR
    {
    
    }
    

    The first thing we should do, is to sample the appropiate color of the current pixel from the texture and assign it to our output color. Let’s name our output color c.

    
    
    half4 frag (v2f i) : COLOR
    {
    	half4 c = tex2D(_MainTex, i.uv);
    }
    

    Now, let’s check whether the pixel crosses the line from our line equation. If it’s below it, let’s change its alpha value to 0, so it will be invisible. We know our current position on the texture thanks to i.uv. It’s equal to (i.uv.x, i.uv.y).

    
    
    half4 frag (v2f i) : COLOR
    {
    	half4 c = tex2D(_MainTex, i.uv);
    
    	if (i.uv.x*_A + i.uv.y*_B < _Cutoff)
        	c.a = 0;
    }
    

    Now let’s return our color.

    
    
    half4 frag (v2f i) : COLOR
    {
    	half4 c = tex2D(_MainTex, i.uv);
    
    	if (i.uv.x*_A + i.uv.y*_B < _Cutoff)
        	c.a = 0;
    
    	return c;
    }
    

    Also, it would be nice if we allowed to tint the sprites with color of choice. Let’s create a new property called _Color.

    
    
    Properties {
    	_Color ("Main Color", Color) = (1,1,1,1)
    	_MainTex ("Main Texture", 2D) = "white" {}
    	_A ("_A", float) = 0.5
    	_B ("_B", float) = 0.5
    	_Cutoff ("_Cutoff", Range(-1.0, 1.0)) = 0.0
    }
    

    Now we need to do the same in CG..

    
    
    float4 _Color;
    sampler2D _MainTex;
    float4 _MainTex_ST;
    float _A;
    float _B;
    float _Cutoff;
    

    And multyply it with our output color in the fragment shader.

    And we're done. You can try it out and play with _A and _B parameters.

    
    
    half4 frag (v2f i) : COLOR
    {
    	half4 c = tex2D(_MainTex, i.uv);
    
    	if (i.uv.x*_A + i.uv.y*_B < _Cutoff)
        	c.a = 0;
    
    	return c*_Color;
    }
    

    That's it for the shader. You can assign it to the material by drag and drop action. Drop our shader on the Ball Material, if you want you can fiddle with factors and see how does it cut the texture. Also, if the sprite appears darker after the change of the material's shader, change Main Color to the white in the Ball Material.

    Part of the sprite is invisible.

    Now we have a lot of work to do to supply the shader with the right data. That'll come in Part 2, where we work on letting the Roly character move through a portal, hiding the part of him that's "inside" it.


  10. Michael James Williams says:
    August 19, 2011 at 4:51 am

    From today onwards, our focus is changing. Instead of covering everything to do with Flash, Unity and Silverlight, we’ll be covering the design and development of browser-based apps and games in general. This means no more tutorials on full-Flash websites or AIR, and lots of new content on game design, UI, and HTML5. Read on to find out what we’ve got in store!


    What’s Coming Up?

    We’ve been preparing this change for a while, so we have a lot of articles planned, including:

    A 2D Unity Game With a Portal Mechanic

    Activetuts+ New Focus: Unity Game Tutorials

    Daniel Branicki has built a great little puzzle game with a Portal mechanic in Unity. In this multi-part tutorial (part Premium, part free), he’ll show you how to do the same.

    Kinect With Flash, in the Mac Web Browser

    Jonathan Reid takes his excellent guide to using augmented reality in Flash further with this Premium tutorial, explaining how you can use the Kinect controller with AS3.

    An Introduction to FlashPunk

    Daniel Sidhion shows you how to get to grips with the increasingly popular FlashPunk framework, which is designed for making Flash games and based on the Game Maker scripting language.

    Pairs, Using Photographs From Flickr

    Activetuts+ New Focus: Flash Game Tutorials

    James Tyner recreates the classic card game of Pairs, but in his version, the images all come from Flickr, based on a keyword selected by the player. A great introduction to loading data and images from an external site.

    Build a Finite State Machine in AS3

    John Reyes explains how to build a finite-state machine, which can (among many other things) be used as the basis of a game engine.

    Design a Photo Viewer App

    Activetuts+ New Focus: Browser-Based App Design Tutorials

    Daniel Apt takes you through the process of designing and animating the interface for this “Polaroid” photo viewer.

    Guide to FDT

    Michael Plank gives you a tour of FDT, an excellent development environment for Flash, showing you its unique features and explaining how to get started with it.

    Linear Kinematics

    Activetuts+ New Focus: Game Mechanics Tutorials

    Kah Shiu Chong complements his inverse kinematics tutorial with this explanation of the reverse process: linear kinematics.

    The Programmer’s Guide to UI Design

    Ashish Bogawat teaches you the basics of user interface design, so coders can create apps that look good and feel intuitive.

    Ashish will also be offering public feedback on the design of web applications, so if you’ve built one that you’d like him to critique, get in touch!

    Plus…

    We’ll also be publishing articles about:

    • Game design, including tips from professional browser game developers,
    • The geekier aspects of coding, like data structures and big O notation, and
    • HTML5 development, starting with a simple avoider game tutorial.

    If there’s anything you particularly want to see within those topics, please let us know in the comments below!


    What About the Old Tutorials?

    Don’t worry! All the tutorials we’ve published so far will remain on the site. However, we won’t be publishing any new tutorials on full-Flash website design or AIR application development.

    If you want to learn about effective website design, check out Webdesigntuts+ (it’s run by Ian Yates, who was the editor of Activetuts+ until recently). And for mobile app development, of course there’s Mobiletuts+.


    Can I Write for You?

    Send us a pitch! We’re looking for in-depth tutorials about developing browser-based apps and games, as well as articles about game design, UI and UX, and case studies of such projects you’ve worked on.

    We pay for these articles and give you full credit; see our Tutorial Submission Guidelines for more details and to find out how to submit your ideas.


Leave a Reply

Click here to cancel reply.

search search search search search
Find an Article
Categories
  • Flash Video Training
  • Hints and Tips
  • Recommended
Please Support Our Sponsors
Recent Posts
  • Workshop Coding Challenge: Fix This Breakout Game
  • Enable the Latest AIR SDK in Flash Professional CS5.5+
  • Quick Tip: Versioning Your Files With Dropbox (via Webdesigntuts+)
  • Workshop: Nuclear Outrun – Critique
  • Understanding Variables, Arrays, Loops, and Null: The Post-it Note Analogy
Tag Cloud
2011 ActionScript Active Activetuts+ Adobe animation Basic Basix Best Build Button Character Create Creating Critique Custom design Effect Effects Files Flash from Game Guide HTML5 Introduction Macromedia Motion Muzzle part Player Premium Professional Quick Silverlight Simple Text Tool Tutorial Tuts+ Tween Using Video website Workshop
About Our Site:

Hey there and welcome to "Flash Video Training Source", a resource for anybody interested in learning more about Adobe's great tool. We feature educational videos, which will help you master Adobe Flash and help you get to know all of its features. We at "Flash Video Training Source" believe that video training and video... more

Why don't you follow us on Twitter and get the latest video tutorials twitted to your account. Just click on the floating twitter bar to your right!

Go Back In Time
May 2012
M T W T F S S
« Apr    
 123456
78910111213
14151617181920
21222324252627
28293031  
Pretty Blank Box
top

Blogroll

  • Development Blog
  • Documentation
  • Plugins
  • Suggest Ideas
  • Support Forum
  • Themes
  • WordPress Planet

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org

Archives

  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011
  • November 2011
  • October 2011
  • September 2011
  • August 2011
  • July 2011
  • June 2011
  • May 2011
  • April 2011
  • March 2011
  • February 2011
  • January 2011
  • December 2010
  • November 2010
  • October 2010
  • September 2010
  • August 2010
  • July 2010
  • June 2010
  • May 2010
  • April 2010
Powered by WordPress  |  Designed by Elegant Themes  |  Lightning Fast Hosting by Site 5 Hosting