Introduction to Graphics

Revision as of 00:51, 13 August 2020 by MoKaLux (talk | contribs) (Timelined animations with Movieclip)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

The Ultimate Guide to Gideros Studio

Graphics and animation

Introduction to graphics

In Gideros Studio, all graphical content is constructed by creating graphical instances and adding them to the scene tree. For example, the Bitmap class is used to display bitmap graphics, and TextField is used to display text object. Sprite class is used to group and transform these instances.

Sprite is the base class of all display classes and has no visual representation. It’s the main construction element and used to create display hierarchies. Sprites can have other sprites as their children and these children inherit properties such as position, scaling, and transparency from their parent sprite. Hierarchy is an important feature in graphics - when you move your parent sprite, all the child (and grandchild) sprites also move simultaneously. Here are some examples:

- Create a new Sprite instance:
local childSprite = Sprite.new()
- Add the new Sprite as a child:
mySprite:addChild(childSprite)
- Set the position:
mySprite:setPosition(10, 20)
- Set the scaling:
mySprite:setScale(0.5, 1)
- Set the rotation angle:
mySprite:setRotation(90)
- Set the alpha transparency:
mySprite:setAlpha(0.7)
- Get the first child:
mySprite:getChildAt(1)
- Remove the child:
mySprite:removeChild(childSprite)

Sprites can have only one parent. Therefore if you add a child object that already has a different sprite as a parent, the sprite is removed from the child list of the other sprite and then added to this sprite.

Stage

The scene tree is the hierarchy of all graphical objects currently displayed and this hierarchy needs a root. The root of the scene tree is an instance of the Stage class which is automatically created and set as a global variable when Gideros starts. You can access this global variable with the name stage.

When Gideros starts, the display list hierarchy contains one item (the global Stage instance) only and we can add more:

- Create a Sprite object
local mySprite = Sprite.new()
- Add this sprite to the stage:
stage:addChild(mySprite)

Textures and Bitmaps

Texture class is used to load an image file and holds the data stored in the image file. The Bitmap class inherits from Sprite and wraps a Texture object for on-screen display. By separating image display (Bitmap) from data (Texture), it’s possible to create many Bitmap objects simultaneously display the same Texture object each with its own display characteristics.

- Load a texture:
local texture = Texture.new("image.png")
- Load a texture with filtering:
local texture = Texture.new("image.png", true)
- Create a Bitmap object to display the texture
local bitmap = Bitmap.new(texture)
- Add the Bitmap object to the stage
stage:addChild(bitmap)

Anchor Point

Each Bitmap object has an anchor point that affects the positioning of the texture displayed. By modifying the anchor point, you change the origin of the texture. For example, setting the anchor point to (0.5, 0.5) moves the center of the texture to the origin. If you set the anchor point to (1, 1) instead, the bottom-right corner of the texture will be the origin. The default value of anchor point is (0, 0) which means top-left of the texture is the origin by default.

Anchorpoint.png

setAnchorPoint(0,0), setAnchorPoint(0.5, 0.5), setAnchorPoint(1,1)

In this example, we set the anchor point to (0.5, 0.5):

local bitmap = Bitmap.new(Texture.new("image.png"))
bitmap:setAnchorPoint(0.5, 0.5)

Texture Atlas

A Texture Atlas is a single large image which contains many smaller sub-images. Each sub-image contained in the texture atlas is defined with a rectangular area.

There are two main reasons for using a texture atlas instead of many independent textures:

1. Texture atlases usually consume less memory.

To use an image as a texture, its width and height always have to be a power of two. Gideros automatically increase the texture size to conform to this rule. For example, an image with dimensions of 100x200 becomes a texture with dimensions of 128x256 in memory. That’s where the texture atlas becomes handy. Texture atlases usually have power-of-two dimensions and therefore don’t need to be enlarged.

2. Rendering from a texture atlas is usually faster.

Each texture is bound to OpenGL just before rendering it and binding is a costly operation. Using texture atlases instead of individual textures helps in reducing bind operations.

TextureRegion

The TextureRegion class specifies a texture and a rectangular region in it. It is used to define independent texture regions within a texture atlas. Displaying texture regions is the same as displaying textures: create a Bitmap object that wraps the TextureRegion object:

-- Load a texture
local texture = Texture.new("image.png")
-- Create a texture region as top left point is (30, 40) with dimensions (100, 50)
local textureRegion = TextureRegion.new(texture, 30, 40, 100, 50)
-- Create a Bitmap object to display the texture region
local bitmap = Bitmap.new(textureRegion)

TexturePack

The TexturePack class is used to create and load texture atlases. You can either create your texture atlas dynamically in your game or use a pre-packed texture atlas. After creating your texture pack, you can get a region of it as a TextureRegion object by using the getTextureRegion function. These features are described below in more details.

Dynamic Creation of Texture Packs

To create a texture pack dynamically (at run-time), create a TexturePack object with an array of file names of textures:

local texturePack = TexturePack.new({"1.png", "2.png", "3.png", "4.png"})

Gideros loads and packs these images fast and gives you a ready to use texture pack. After creating your texture pack, you can display it easily since it's also a texture in itself:

local bitmap = Bitmap.new(texturePack)
stage:addChild(bitmap)

Note: Gideros uses an algorithm called MaxRects to pack the textures. This algorithm is considered as one of the best packing algorithms in terms of speed and efficiency. If you are interested, you can find the details of MaxRects algorithm at http://clb.demon.fi/projects/even-more-rectangle-bin-packing

Pre-packed Texture Packs

Another option to create texture packs is to use an external texture packer tool. Gideros Texture Packer, which comes with the installation package can be used to create texture packs.

Getting Texture Regions from Texture Packs

To get the texture region from the texture pack, you need to call the name of the image:

local texturePack = TexturePack.new({"1.png", "2.png", "3.png", "4.png"})
local textureRegion = texturePack:getTextureRegion(1.png)

Automatic image resolution

There are multiple resolutions that game developers should consider. To efficiently use texture memory and processing power of GPUs, applications should use low-resolution images on devices with low-resolution screens and high-resolution images on devices with high-resolution screens. With the help of automatic image resolution, you can bundle both low and high-resolution images together with your application and Gideros automatically selects the best resolution according to your scaling.

Automatic image resolution is directly related to automatic screen scaling. For example, if your screen is automatically scaled by 2, then using the double-sized image is the best choice in terms of quality and efficiency.

Open the project “Hardware/Automatic Image Resolution” to see automatic image resolution in action. Run this example multiple times by selecting different resolutions on Gideros Player such as 320x480, 640x960, and 480x800. As you can see, for the different resolutions, the original 200x200 image or high-resolution variants (300x300 and 400x400) are selected and displayed automatically.

Now right click on the project name and select “Properties…” to understand how we configure automatic image resolution parameters:

Project properties.png

In this example, our logical dimensions are 320x480 and scale mode is Letterbox. So the scaling factor for a device with screen resolution 320x480 (older iPhones) is 1, scaling factor for 480x960 (iPhone 4) is 2 and scaling factor for 480x800 (Samsung Galaxy S) is around 1.5.

We have configured image scales as:

Image scales.png

So if you have a base image with a resolution of 200x200 and a name “image.png”, you provide these 3 images:

   • image.png (200x200)
   • image@1.5x.png (300x300)
   • image@2x.png (400x400)

and let Gideros pick the appropriate one.

Providing the alternative images (image@1.5x.png and image@2x.png) is optional but you should always provide the base image (image.png). When Gideros cannot find the alternative image to load, it loads the base image. Also, size calculations are done according to the size of the base image.

Design for High-Resolution Devices

In our example, we set the logical dimensions as 320x480 and provided higher-resolution alternative images.

On the other hand, it is possible to set the logical dimensions as 480x960 or 768x1024 and provide lower-resolution images. In this case, we can configure the image scales like:

Image scales 2.png

and provide alternative images with suffix “@half” as half-resolution of the original ones.

Automatic screen scaling

To handle a wide variety of resolutions, Gideros provides a functionality called Automatic Screen Scaling.

Before starting your project, you determine your logical resolution and position all your sprites according to this.

For example, if you determine your logical resolution as 320x480, your upper left corner will be (0, 0), your lower right corner will be (319, 479) and the center coordinate of your screen will be (160, 240). Then according to your scale mode, Gideros automaticaly scales your screen according to the real resolution of your hardware.

There are 8 types of scaling modes:

  • No scale: No scaling simply tells your application not to scale at all. In this mode, there’s no scaling at all, and your stage sits on the upper left corner of the device screen.
  • No scale, center: This mode is similar to “no scale”, except one minor difference: Stage is centered on the device screen.
  • Pixel perfect: This mode is similar to “No scale, center”, with a minor difference: Scale value is rounded to values like 1/3, ½, 1, 2 or 3. This mode can be used in games which benefit from pixel art games - it guarantees a crisp look and feel for screen sprites.
  • Letterbox: Preserving the aspect ratio, it scales the stage so it fits the content on the device screen. There’s a possibility that blank areas may occur on the device. Mostly, developer keeps the background a bit “bigger” in order to eliminate these blank areas and fill it with background.
  • Crop: This mode again does preserve the aspect ratio, and ensures that no blank areas are left on the screen. Hence, some part of the background may be outside the visible area.
  • Stretch: The whole stage sits on the screen. Since x/y is not preserved, there’s a possibility that aspect ratio might change.
  • Fit width: This mode fits the width of the stage, preserving the aspect ratio. It’s possible that there might be blank areas at the top and bottom of the screen, or these areas may be outside the visible area. If you have more than one screen in your application, and screen transition is from left to right (or vice versa), then this mode is a perfect fit for you.
  • Fit height: Similar to fit width, this time guaranteeing to fit the height. Very suitable for shoot'em-up type games.

Using tilemaps

Optimization and memory management

Timelined animations with Movieclip

Note: Currently there’s no way to set the animation speed, however you can prepare different animations for different speeds like:

local eliAnim = MovieClip.new{
{1, 7, self.anim[1]},
{8, 15, self.anim[2]},
{16, 18, self.anim[1]},
{19, 21, self.anim[2]},
}
eliAnim:setGotoAction(15, 1) --> frames 1-15: slow animation
eliAnim:setGotoAction(21, 16) --> frames 16-21: fast animation
eliAnim:gotoAndPlay(1) --> play slow animation
eliAnim:gotoAndPlay(16) --> play fast animation

This way, you can position your MovieClip wherever you want (e.g. running player, walking player, flying helicopter, etc).


PREV.: Scene Management
NEXT: Introduction to Graphics Shapes