Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

19. November 2012

 

Over on the PlayStation Mobile forums, a user asked:

For example, if I had a 100 x 100 image, I could use the source rectangle to  draw, say, the left part of the image 50 x 100.  This is useful when I have two images that represent the same object, e.g. a fancy progress meter, one light, the other dark.  SpriteUV has Quad which allows me to stretch and skew the image, but not crop.

Am I missing something? If not, what are my options?

 

My answer wasn’t a short one, so I decided to essentially turn it in to a tutorial post in and of itself.  So, if you want to learn how to do this, or how UV coordinates work in the first place, read on!

 

The answer is, yes, you can very much do this with PSM Studio, but the way might not be completely intuitive.  Each sprite has a TRS set ( Translation/Rotation/Scale ) that represents its UV coordinates within its textures.    Essentially when you work with a SpriteTile, it’s handling all this magic for you.  The good news is, you can manipulate the UV values of a SpriteUV to accomplish exactly the effects described in the question above.  If what you are looking to do is create a sprite sheet animation however, there is a much better way.

 

Alright, let’s jump right in with some code:

 

using System;
using Sce.PlayStation.Core;
using Sce.PlayStation.Core.Graphics;
using Sce.PlayStation.Core.Input;
using Sce.PlayStation.HighLevel.GameEngine2D;
using Sce.PlayStation.HighLevel.GameEngine2D.Base;

namespace Test
{
    public class AppMain
    {
        public static void Main (string[] args)
        {
            Director.Initialize();
            Scene scene = new Scene();
            scene.Camera.SetViewFromViewport();
            
            SpriteUV sprite = new SpriteUV(new TextureInfo("/Application/watch.png"));
            sprite.Scale = new Vector2(Director.Instance.GL.Context.Screen.Width,
                                       Director.Instance.GL.Context.Screen.Height);
            sprite.Schedule((dt) => {
                var g = GamePad.GetData(0);
                if((g.Buttons & GamePadButtons.Up) == GamePadButtons.Up){
                    // Top left
                    sprite.UV.S = new Vector2(0.5f,0.5f);
                    sprite.UV.T = new Vector2(0.0f,0.5f);
                }
                else if((g.Buttons & GamePadButtons.Left) == GamePadButtons.Left){
                    // Bottom left
                    sprite.UV.S = new Vector2(0.5f,0.5f);
                    sprite.UV.T = new Vector2(0.0f,0.0f);
                }
                else if ((g.Buttons & GamePadButtons.Down) == GamePadButtons.Down){
                    // Bottom right                
                    sprite.UV.S = new Vector2(0.5f,0.5f);
                    sprite.UV.T = new Vector2(0.5f,0.0f);
                }
                else if ((g.Buttons & GamePadButtons.Right) == GamePadButtons.Right){
                    // Top right
                    sprite.UV.S = new Vector2(0.5f,0.5f);
                    sprite.UV.T = new Vector2(0.5f,0.5f);
                }
                else if((g.Buttons & GamePadButtons.Cross) == GamePadButtons.Cross){
                    // Back to full screen
                    sprite.UV.S = new Vector2(1.0f,1.0f);
                    sprite.UV.T = new Vector2(0.0f,0.0f);
                }
            },0);
            
            scene.AddChild(sprite);
            Director.Instance.RunWithScene(scene);
        }
    }
}

 

Run this code and you will see:

full

 

Now press an arrow key ( here is the results for UP ) and you will see a fraction of the original texture:

topleft

Press X to go back to the full texture dimensions.

 

So… what’s happening here?

 

First off, we Initialize our Director singleton, create a Scene and set the camera up to match the device screen dimensions.  We then create a SpriteUV and TextureInfo in a single line, loading an image of the famous Watchmen logo.  We then scale the sprite to also match the dimensions of the screen.

 

It’s in the Schedule lambda the bulk of our UV manipulation logic takes place.  As you can see, we get the GamePad state, and handle the user pressing the d-pad or X button ( S key on simulator ).  In the event the user presses a direction button, we manipulate the sprite’s UV.S and UV.T values depending on which direction the user pressed, as indicated by the comment in each if statement.  If the user presses the X button, we set the UV.S and UV.T values back to full size and the origin respectively.  Finally we add the sprite to the scene, then run the scene.

 

The heart of this example is the UV property, which is a TRS object.  If the term UV is unfamiliar to you, they are simply texture coordinates on a face.  They are called UV simply because there are two coordinates, U and V. The UV values  describe how a texture is mapped to a polygon face.  U and V values go from 0 to 1 and start in the bottom left corner of an image.  This means (0,0) is the bottom left corner of the texture, (1,1) is the top right coordinate of the texture while (0.5,0.5) is the very center of the texture.

 

So, using the SpriteUV.UV property, we can alter the Translation ( position ), Rotation and Scale of the selection within SpriteUV’s texture that is going to be drawn.  Think of these values as describing the location of a select box within the texture that are going to be copied and drawn as the texture.  Here is a bad diagram to attempt to explain what’s happening.

 

image

 

The background is our SpriteUV texture.  By default the UV.T is (0,0), meaning drawing will start from the bottom left.  By default the UV.S values will be (1,1), meaning no scaling will occur.  Using these defaults, when we draw our sprite, the entire image will be drawn.

 

Now consider the blue selection rectangle.  This has a UV.T value of (0.3,0.3) and a UV.S value of (0.5,0.5) …. okay… my drawing to scale kind sucked, just imagine that the blue rectange was a quarter of the entire image size.  These values mean that at position 0.3,0.3… or 30% right and 30% up from the origin in the bottom left, we start our selection.  Due to our S(cale) value of (0.5,0.5) it means our selection size is half the height and half the width of the texture.  In this example we are not making use of TR.R(otation).

 

Therefore, assuming the following diagram was to scale, with a Translation UV value of 0.3, 0.3 and Scale UV value of 0.5 and 0.5, when we draw our texture we will see:

image

 

And that is how you can use UV values to draw a portion of a sprite’s texture.  You may notice that SpriteUV has a pair of properties, FlipU and FlipV.  All these do is reverse the direction of the U or V coordinate, for example, flipping U would make (0,0) be at the bottom right of the image instead of the bottom left.

 

You can download the complete archive here.  Obviously the Watchman logo is protected under copyright and cannot be used commercially in any way whatsover, period, ever. For real.

Programming , , ,

18. November 2012

This recipe looks at how to rotate one sprite relative to another point.  In this example, we rotate a jet sprite to face the position of the mouse.

 



Mouse over the application to your right to see how the centred sprite follows the mouse cursor.  You may need to tap the screen to focus the mouse. As you move the mouse you can see the angle between the sprite and the mouse cursor.  The X and Y values represent the current location of the mouse on the HTML canvas.  You may notice that 0/360 degrees is to right hand side, this is a side effect of the Atan2 method.

 

 

Just The Math 

var angle = Math.atan2(stage.mouseY - jetSprite.y, stage.mouseX - jetSprite.x );

angle = angle * (180/Math.PI);

Description

First we get the distance between the sprite and the mouse.  This is obtained simply by subtracting the mouse location from the sprite location.  We then take the atan2 of the resulting coordinates.  One warning with atan2, the parameters are (y,x) not (x,y)!  Atan2 will return the angle, with a few gotchas.  First off, the angle is returned in radians.  Depending on your graphic library, you may need to convert to degrees to perform a rotation ( such as the case with EaselJs ).  If your language/library of choice doesn't have a RadiansToDegrees function, the formula is simply degrees = radiansToConvert * (180 divided by Pi).  Keep in mind, Pi (π 3.14159____ ) represents half a circle, so 2π is a complete circle( 360 degrees ), 1/2π is 90 degrees, etc.
 
Second, the angle is relative to the positive X axis, meaning that 0 degrees is pointing right.  If you look at the full source code to the example, you will notice that the source image itself actually points up, so we increase the angle by 90 degrees to adjust for orientation of the jet sprite image.  Also, depending on origin your graphic library uses, you may need to flip the sign in the y direction.
 
One other side effect of atan2 is it returns the results as a value range of -180 to 180.  If you want the value to be 0 to 360, perform the following:
 

if(angle < 0)

{

    angle = 360 - (-angle);

}

 

The Complete Code

<!DOCTYPE html>

<html>

<head>

    <script src="http://code.createjs.com/easeljs-0.5.0.min.js"></script>

    <script>

 

    var jetSprite;

    var stage;

    var textOut;

 

    function demo(){

        stage = new createjs.Stage("theCanvas");

 

        // onFrame will be called each "tick". Default is 50ms, or 20FPS

        createjs.Ticker.addListener(onFrame);

 

        // Create and configure our jet sprite. regX/Y set the pivot point, we center it

        jetSprite = new createjs.Bitmap("jetsprite.png");

        jetSprite.regX = jetSprite.image.width/2;

        jetSprite.regY = jetSprite.image.height/2;

        jetSprite.x = stage.canvas.width/2;

        jetSprite.y = stage.canvas.height/2;

 

        //Now we create a Text object, used for displaying some debug details

        textOut = new createjs.Text("Debug","24px Arial","red");

        textOut.x = 5;

        textOut.y = 5;

        textOut.maxWidth = 390;

 

        //All the worlds a stage after all... add our sprite and text to it

        stage.addChild(jetSprite);

        stage.addChild(textOut);

 

        //And go...

        stage.update();

    }

 

    function onFrame(elapsedTime) {

        var angle = Math.atan2(stage.mouseY - jetSprite.y, stage.mouseX - jetSprite.x );

        angle = angle * (180/Math.PI);

 

        // The following if statement is optional and converts our angle from being

        // -180 to +180 degrees to 0-360 degrees.  It is completely optional

        if(angle < 0)

        {

            angle = 360 - (-angle);

        }

 

        textOut.text = "X:" + stage.mouseX + " Y:" + stage.mouseY + " angle:" + Math.round(angle);

 

        // Atan2 results have 0 degrees point down the positive X axis, while our image is pointed up.

        // Therefore we simply add 90 degrees to the rotation to orient our image

        // If 0 degrees is to the right on your image, you do not need to add 90

        jetSprite.rotation =90 + angle;

 

        stage.update();

    }

    </script>

</head>

<body onload="demo()">

    <canvaswidth=400pxheight=400pxid="theCanvas"style="background-color:black"/>

</body>

</html>

 

See Also

http://gamedev.stackexchange.com/questions/14602/what-are-atan-and-atan2-used-for-in-games

 

 

Additions and Edits

The results of Atan2 can be a bit confusing, depending on the way your brain works.  In the full source code, you can see that I add 90 degrees to the rotation angle.  This is because the image ( and my mindset ) view 0 degrees as being up the positive Y axis.  Of course, this is completely arbitrary.

 

Consider for a moment the philosophical question "where does a circle begin?".  The answer completely depends on who you ask.  If you ask me, 0 degrees is up.  If you ask atan2, 0 degrees is to the right.  Consider the following diagram:

Jet on Cartesian plane

 

As you can see, the position atan2 considers to be zero is offset 90 degrees from the position I consider ( and have drawn my art according to ) to be 0 degrees.  Fortunately the answer is as simple as adding 90 degrees to the angle during rotations.  Of course, you could simply draw your art as if 0 degrees was along the positive X axis and you won't have any problems.

Programming

14. November 2012

 

Ok… is it engine release day? 

 

Anyway, again the title says it all, CryEngine 3.4.3 was released today.  If you are un-aware, CryEngine is a 3D game engine like UDK or Unity, which is available for free to get started ( 20% royalty on shipped titles ).  In addition to the FarCry series of games, Mechwarrior Online is powered by CryEngine.  If nothing else, this engine is capable of creating extremely pretty games!

 

Top Features:

  • Dedicated Server
  • Revamped Launcher menu
  • Sandbox Welcome screen, link to docs & smart open
  • Terrain precision/smoothing improved
  • Many tweaks/fixes/cleanups to the Sandbox UI
  • SSAO improvements
  • Improved SSR
  • Terrain shadow casting support
  • Box projected cubemaps
  • Improved DX9 support for Environment Probes

 

Other than the briefest look, I haven’t looked all that closely at the CryEngine SDK.  Therefore I have no idea if this is a big release or not…  dedicated server sounds like a handy addition…

 

 

Anyway, you can read full details here.

 

You can download it here.

News ,

14. November 2012

Title pretty much says it all, Unity 4 is now available.  Not a huge shock given the beta release announced two weeks ago.

 

The key new features are:

  • Direct X 11 rendering
  • New target platform: Flash
  • New target platform: Linux
  • Updated image effects including
    • New water shaders and prefabs
    • Render to texture effects
    • Full screen effects such as Depth of Field, Color correction, lens effects, etc. (Pro only)
  • Shuriken particle system
  • Lightmap Baking
  • Mobile profiler (Pro only)
  • Cross platform font rendering
  • Hardware cursor api
  • New project browser with fast integrated search

 

Unity Pro is priced at 1500$.

Unity “Base” is still free.

iOs, Android and Flash are each 400$.  Linux appears to be included in the base package.

No details given on upgrade pricing.

 

 

For more details click here

 

My personal 2cents, it doesn’t really look like a full version upgrade to me.  The new targets were announced in 3.x, at first glance I’m not really seeing any reason to upgrade.  What do you think?

News ,

13. November 2012

In this world of cheap mass market cross platform game engines like UDK and Unity, the barrier of entry to creating a polished game have never been lower.  Except of course when it comes to art that is.  Take a quick look at GameFromScratch's 3D application list for an idea of what kind of prices we are talking about here.  There have been a few options on the lower/cheap end with Blender and the GIMP being the two most popular free options.  There are a few other options, like the MacOS only Cheetah, the now-defunct Silo or Shade Basic available for a hundred dollars or so.  The next jump up is to applications like Modo and Cinema4D, both with a price tag nearing or over the 1000$ mark.  From this point we jump drastically to the various Autodesk applications, all with a price tag in the many thousands dollar range. 

 

Simply put, if you are creating your first game, perhaps a mobile title on a truly indie budget, if you don't like Blender or aren't breaking the law, you are pretty much screwed.  Sorta.

 

Autodesk Maya actually has an incredibly interesting option available.  You can now license Autodesk 3D Studio Max or Maya 2013 for 90 days for a price of 199$.  Yes, that is a full commercial license, so you can ship a game and make money on a 90 day license.

 

1. What are Autodesk 3ds Max and Autodesk Maya 90-day fixed term licenses?
90-day fixed term licenses*, sometimes referred to as “project licenses,” are fully
operational, commercial licenses of Autodesk 3ds Max 2013 or Autodesk Maya 2013
software that enable a license holder to use the software for a period of 90 days only.

2. Can an Autodesk 3ds Max or Autodesk Maya 90-day fixed term license be used
for commercial purposes?
Yes, unlike the free, 30-day trial which can be used for evaluation purposes only, you can
use a 90-day fixed term license of either Autodesk 3ds Max 2013 or Autodesk Maya 2013
software in production for commercial purposes.

 

You can read the complete FAQ here (PDF LINK).  You cannot renew the license, so be sure that you can complete your project in 3 months or you will need a full license.  You can however also get a 30 day trial of either Max or Maya ( which you can't ship using ) to get started, giving you a total of 4 months to create your game.  

 

That covers you on the 3D side, what about Photoshop?  Well, you have options there too…  The Photoshop CS suite normally has a price tag around a 1000$.  A while back, Adobe started offering their software on a subscription basis for about 50$ a month.  Interestingly enough, since then they have started offering Photoshop for as low as 20$ a month ( with a year commitment ), or for 30$ a month on a pay as you go basis.

 

Also like Autodesk, they offer a 30 day trial.  Therefore, if you are able to create your game in less than 4 months, you can legally use Photoshop and Maya (or Max) for a total price of 289$ ( 199$ + 30$ x 3 months, + 1 month trial ).  

 

Four months might not seem like enough time, but it is actually a reasonable development window for a typical mobile game, especially if you are working full time.  Hopefully your game will then be successful enough to justify and pay for full licenses for both products.  Another interesting side effect of both license structures is they give a credible ( and affordable ) pathway for pirates to go legit if they are using pirated software.  

Art

Month List

Popular Comments