Difference between revisions of "Introduction to Graphics"
(→Description: added more content) |
|||
(12 intermediate revisions by 2 users not shown) | |||
Line 6: | Line 6: | ||
== Introduction to graphics == | == 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. | |
− | |||
− | 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: | Here are some examples: | ||
− | + | <syntaxhighlight lang="lua"> | |
- Create a new Sprite instance: | - Create a new Sprite instance: | ||
local childSprite = Sprite.new() | local childSprite = Sprite.new() | ||
Line 28: | Line 27: | ||
- Remove the child: | - Remove the child: | ||
mySprite:removeChild(childSprite) | mySprite:removeChild(childSprite) | ||
+ | </syntaxhighlight> | ||
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. | 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 == | == 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. | 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: | When Gideros starts, the display list hierarchy contains one item (the global Stage instance) only and we can add more: | ||
− | + | <syntaxhighlight lang="lua"> | |
- Create a Sprite object | - Create a Sprite object | ||
local mySprite = Sprite.new() | local mySprite = Sprite.new() | ||
- Add this sprite to the stage: | - Add this sprite to the stage: | ||
stage:addChild(mySprite) | stage:addChild(mySprite) | ||
+ | </syntaxhighlight> | ||
== Textures and Bitmaps == | == 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. | 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. | ||
− | + | <syntaxhighlight lang="lua"> | |
- Load a texture: | - Load a texture: | ||
local texture = Texture.new("image.png") | local texture = Texture.new("image.png") | ||
Line 54: | Line 53: | ||
- Add the Bitmap object to the stage | - Add the Bitmap object to the stage | ||
stage:addChild(bitmap) | stage:addChild(bitmap) | ||
+ | </syntaxhighlight> | ||
=== Anchor Point === | === 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. | 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. | ||
[[File:Anchorpoint.png]] | [[File:Anchorpoint.png]] | ||
− | setAnchorPoint(0,0) | + | |
+ | setAnchorPoint(0,0), setAnchorPoint(0.5, 0.5), setAnchorPoint(1,1) | ||
In this example, we set the anchor point to (0.5, 0.5): | In this example, we set the anchor point to (0.5, 0.5): | ||
− | + | <syntaxhighlight lang="lua"> | |
local bitmap = Bitmap.new(Texture.new("image.png")) | local bitmap = Bitmap.new(Texture.new("image.png")) | ||
bitmap:setAnchorPoint(0.5, 0.5) | bitmap:setAnchorPoint(0.5, 0.5) | ||
+ | </syntaxhighlight> | ||
− | == | + | == 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. | |
− | Texture | ||
− | <gallery widths= | + | <gallery widths=250px heights=350px perrow=1> |
Ikonomikon screenshot 01.png| | Ikonomikon screenshot 01.png| | ||
</gallery> | </gallery> | ||
− | There are two main reasons | + | There are two main reasons for using a texture atlas instead of many independent textures: |
+ | |||
1. Texture atlases usually consume less memory. | 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 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. | + | |
+ | 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. | 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. | |
− | |||
− | - Load a texture | + | === 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: | ||
+ | <syntaxhighlight lang="lua"> | ||
+ | -- Load a texture | ||
local texture = Texture.new("image.png") | local texture = Texture.new("image.png") | ||
− | - Create a texture region as top left point is (30, 40) with dimensions (100, 50) | + | -- Create a texture region as top left point is (30, 40) with dimensions (100, 50) |
local textureRegion = TextureRegion.new(texture, 30, 40, 100, 50) | local textureRegion = TextureRegion.new(texture, 30, 40, 100, 50) | ||
− | - Create a Bitmap object to display the texture region | + | -- Create a Bitmap object to display the texture region |
local bitmap = Bitmap.new(textureRegion) | local bitmap = Bitmap.new(textureRegion) | ||
+ | </syntaxhighlight> | ||
− | TexturePack | + | === TexturePack === |
− | TexturePack class is used to create and load texture atlases. You can either create your texture atlas dynamically in your game | + | 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: | ||
+ | <syntaxhighlight lang="lua"> | ||
local texturePack = TexturePack.new({"1.png", "2.png", "3.png", "4.png"}) | local texturePack = TexturePack.new({"1.png", "2.png", "3.png", "4.png"}) | ||
+ | </syntaxhighlight> | ||
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: | 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: | ||
− | + | <syntaxhighlight lang="lua"> | |
local bitmap = Bitmap.new(texturePack) | local bitmap = Bitmap.new(texturePack) | ||
stage:addChild(bitmap) | stage:addChild(bitmap) | ||
+ | </syntaxhighlight> | ||
− | 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 | + | '''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 | + | ==== 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. | 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 | + | === Getting Texture Regions from Texture Packs === |
To get the texture region from the texture pack, you need to call the name of the image: | To get the texture region from the texture pack, you need to call the name of the image: | ||
− | + | <syntaxhighlight lang="lua"> | |
local texturePack = TexturePack.new({"1.png", "2.png", "3.png", "4.png"}) | local texturePack = TexturePack.new({"1.png", "2.png", "3.png", "4.png"}) | ||
local textureRegion = texturePack:getTextureRegion(“1.png”) | local textureRegion = texturePack:getTextureRegion(“1.png”) | ||
+ | </syntaxhighlight> | ||
== Automatic image resolution == | == 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. | 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. | + | 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: | Now right click on the project name and select “Properties…” to understand how we configure automatic image resolution parameters: | ||
Line 129: | Line 135: | ||
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. | 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: | ||
[[File:Image scales.png]] | [[File:Image scales.png]] | ||
− | So if you have a base image with resolution 200x200 | + | 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.png (200x200) | ||
• image@1.5x.png (300x300) | • image@1.5x.png (300x300) | ||
Line 139: | Line 146: | ||
and let Gideros pick the appropriate one. | and let Gideros pick the appropriate one. | ||
− | Providing the alternative images ( | + | 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: | |
− | |||
[[File:Image scales 2.png]] | [[File:Image scales 2.png]] | ||
Line 149: | Line 158: | ||
== Automatic screen scaling == | == 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. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | stage | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | The | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
== Using tilemaps == | == Using tilemaps == | ||
Line 526: | Line 180: | ||
== Timelined animations with Movieclip == | == 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: | |
− | Note: Currently there’s no way to set the animation speed, however you can prepare different animations for different speeds like: | + | <syntaxhighlight lang="lua"> |
− | |||
local eliAnim = MovieClip.new{ | local eliAnim = MovieClip.new{ | ||
{1, 7, self.anim[1]}, | {1, 7, self.anim[1]}, | ||
Line 539: | Line 192: | ||
eliAnim:gotoAndPlay(1) --> play slow animation | eliAnim:gotoAndPlay(1) --> play slow animation | ||
eliAnim:gotoAndPlay(16) --> play fast animation | eliAnim:gotoAndPlay(16) --> play fast animation | ||
+ | </syntaxhighlight> | ||
This way, you can position your MovieClip wherever you want (e.g. running player, walking player, flying helicopter, etc). | This way, you can position your MovieClip wherever you want (e.g. running player, walking player, flying helicopter, etc). | ||
+ | |||
+ | |||
+ | '''PREV.''': [[Scene Management]]<br/> | ||
+ | '''NEXT''': [[Introduction to Graphics Shapes]] | ||
+ | |||
+ | |||
+ | {{GIDEROS IMPORTANT LINKS}} |
Latest revision as of 22:17, 18 November 2023
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.
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:
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:
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:
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