Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Events
Videos
Audiobooks
Packt Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials

7018 Articles
article-image-unity-3-0-enter-third-dimension
Packt
28 Dec 2011
10 min read
Save for later

Unity 3-0 Enter the Third Dimension

Packt
28 Dec 2011
10 min read
(For more resources on Unity 3D, see here.) Getting to grips with 3D Let's take a look at the crucial elements of 3D worlds, and how Unity lets you develop games in three dimensions. Coordinates If you have worked with any 3D application before, you'll likely be familiar with the concept of the Z-axis. The Z-axis, in addition to the existing X for horizontal and Y for vertical, represents depth. In 3D applications, you'll see information on objects laid out in X, Y, Z format—this is known as the Cartesian coordinate method. Dimensions, rotational values, and positions in the 3D world can all be described in this way. As in other documentation of 3D, you'll see such information written with parenthesis, shown as follows: (3, 5, 3) This is mostly for neatness, and also due to the fact that in programming, these values must be written in this way. Regardless of their presentation, you can assume that any sets of three values separated by commas will be in X, Y, Z order. In the following image, a cube is shown at location (3,5,3) in the 3D world, meaning it is 3 units from 0 in the X-axis, 5 up in the Y-axis, and 3 forward in the Z-axis: Local space versus world space A crucial concept to begin looking at is the difference between local space and world space. In any 3D package, the world you will work in is technically infinite, and it can be difficult to keep track of the location of objects within it. In every 3D world, there is a point of origin, often referred to as the 'origin'> or 'world zero', as it is represented by the position (0,0,0). All world positions of objects in 3D are relative to world zero. However, to make things simpler, we also use local space (also known as object space) to define object positions in relation to one another. These relationships are known as parent-child relationships. In Unity, parent-child relationships can be established easily by dragging one object onto another in the Hierarchy. This causes the dragged object to become a child, and its coordinates from then on are read in terms relative to the parent object. For example, if the child object is exactly at the same world position as the parent object, its position is said to be (0,0,0), even if the parent position is not at world zero. Local space assumes that every object has its own zero point, which is the point from which its axes emerge. This is usually the center of the object, and by creating relationships between objects, we can compare their positions in relation to one another. Such relationships, known as parent-child relationships, mean that we can calculate distances from other objects using local space, with the parent object's position becoming the new zero point for any of its child objects. This is especially important to bear in mind when working on art assets in 3D modelling tools, as you should always ensure that your models are created at 0,0,0 in the package that you are using. This is to ensure that when imported into Unity, their axes are read correctly. We can illustrate this in 2D, as the same conventions will apply to 3D. In the following example: The first diagram (i) shows two objects in world space. A large cube exists at coordinates(3,3), and a smaller one at coordinates (6,7). In the second diagram (ii), the smaller cube has been made a child object of the larger cube. As such the smaller cube's coordinates are said to be (3,4), because its zero point is the world position of the parent. Vectors You'll also see 3D vectors described in Cartesian coordinates. Like their 2D counterparts, 3D vectors are simply lines drawn in the 3D world that have a direction and a length. Vectors can be moved in world space, but remain unchanged themselves. Vectors are useful in a game engine context, as they allow us to calculate distances, relative angles between objects, and the direction of objects. Cameras Cameras are essential in the 3D world, as they act as the viewport for the screen. Cameras can be placed at any point in the world, animated, or attached to characters or objects as part of a game scenario. Many cameras can exist in a particular scene, but it is assumed that a single main camera will always render what the player sees. This is why Unity gives you a Main Camera object whenever you create a new scene. Projection mode—3D versus 2D The Projection mode of a camera states whether it renders in 3D (Perspective) or 2D (Orthographic). Ordinarily, cameras are set to Perspective Projection mode, and as such have a pyramid shaped Field of View (FOV). A Perspective mode camera renders in 3D and is the default Projection mode for a camera in Unity. Cameras can also be set to Orthographic Projection mode in order to render in 2D—these have a rectangular field of view. This can be used on a main camera to create complete 2D games or simply used as a secondary camera used to render Heads Up Display (HUD) elements such as a map or health bar. In game engines, you'll notice that effects such as lighting, motion blurs, and other effects are applied to the camera to help with game simulation of a person's eye view of the world—you can even add a few cinematic effects that the human eye will never experience, such as lens flares when looking at the sun! Most modern 3D games utilize multiple cameras to show parts of the game world that the character camera is not currently looking at—like a 'cutaway' in cinematic terms. Unity does this with ease by allowing many cameras in a single scene, which can be scripted to act as the main camera at any point during runtime. Multiple cameras can also be used in a game to control the rendering of particular 2D and 3D elements separately as part of the optimization process. For example, objects may be grouped in layers, and cameras may be assigned to render objects in particular layers. This gives us more control over individual renders of certain elements in the game. Polygons, edges, vertices, and meshes In constructing 3D shapes, all objects are ultimately made up of interconnected 2D shapes known as polygons. On importing models from a modeling application, Unity converts all polygons to polygon triangles. By combining many linked polygons, 3D modeling applications allow us to build complex shapes, known as meshes. Polygon triangles (also referred to as faces) are in turn made up of three connected edges. The locations at which these edges meet are known as points or vertices. By knowing these locations, game engines are able to make calculations regarding the points of impact, known as collisions, when using complex collision detection with Mesh Colliders, such as in shooting games to detect the exact location at which a bullet has hit another object. In addition to building 3D shapes that are rendered visibly, mesh data can have many other uses. For example, it can be used to specify a shape for collision that is less detailed than a visible object, but roughly the same shape. This can help save performance as the physics engine needn't check a mesh in detail for collisions. This is seen in the following image from the Unity car tutorial, where the vehicle itself is more detailed than its collision mesh: In the second image, you can see that the amount of detail in the mesh used for the collider is far less than the visible mesh itself: In game projects, it is crucial for the developer to understand the importance of the polygon count. The polygon count is the total number of polygons, often in reference to models, but also in reference to props, or an entire game level (or in Unity terms, 'Scene'). The higher the number of polygons, the more work your computer must do to render the objects onscreen. This is why we've seen an increase in the level of detail from early 3D games to those of today. Simply compare the visual detail in a game such as id's Quake(1996) with the details seen in Epic's Gears Of War (2006) in just a decade. As a result of faster technology, game developers are now able to model 3D characters and worlds, for games that contain a much higher polygon count and resultant level of realism, and this trend will inevitably continue in the years to come. This said, as more platforms emerge such as mobile and online, games previously seen on dedicated consoles can now be played in a web browser thanks to Unity. As such, the hardware constraints are as important now as ever, as lower powered devices such as mobile phones and tablets are able to run 3D games. For this reason, when modeling any object to add to your game, you should consider polygonal detail, and where it is most required. Materials, textures, and shaders Materials are a common concept to all 3D applications, as they provide the means to set the visual appearance of a 3D model. From basic colors to reflective image-based surfaces, materials handle everything. Let's start with a simple color and the option of using one or more images—known as textures. In a single material, the material works with the shader, which is a script in charge of the style of rendering. For example, in a reflective shader, the material will render reflections of surrounding objects, but maintain its color or the look of the image applied as its texture. In Unity, the use of materials is easy. Any materials created in your 3D modeling package will be imported and recreated automatically by the engine and created as assets that are reusable. You can also create your own materials from scratch, assigning images as textures and selecting a shader from a large library that comes built-in. You may also write your own shader scripts or copy-paste those written by fellow developers in the Unity community, giving you more freedom for expansion beyond the included set. When creating textures for a game in a graphics package such as Photoshop or GIMP, you must be aware of the resolution. Larger textures will give you the chance to add more detail to your textured models, but be more intensive to render. Game textures imported into Unity will be scaled to a power of 2 resolution. For example: 64px x 64px 128px x 128px 256px x 256px 512px x 512px 1024px x 1024px Creating textures of these sizes with content that matches at the edges will mean that they can be tiled successfully by Unity. You may also use textures scaled to values that are not powers of two, but mostly these are used for GUI elements.  
Read more
  • 0
  • 0
  • 3446

article-image-qooxdoo-working-layouts
Packt
27 Dec 2011
16 min read
Save for later

qooxdoo: Working with Layouts

Packt
27 Dec 2011
16 min read
(For more resources on this topic, see here.) qooxdoo uses the generic terminology of the graphical user interface. So, it is very easy to understand the concepts involved in it.. The basic building block in qooxdoo is termed a widget. Each widget (GUI component) is a subclass of the Widget class. A widget also acts as a container to hold more widgets. Wherever possible, grouping of the widgets to form a reusable component or custom widget is a good idea. This allows you to maintain consistency across your application and also helps you to build the application quicker than the normal time. It also increases maintainability, as you need to fix the defect at only one place. qooxdoo provides a set of containers too, to carry widgets, and provides public methods to manage. Let's start with the framework's class hierarchy: Base classes for widgets qooxdoo framework abstracts the common functionalities required by all the widgets into a few base classes, so that it can be reused by any class through object inheritance. Let's start with these base classes. qx.core.Object Object is the base class for all other qooxdoo classes either directly or indirectly. The qx.core.Object class has the implementation for most of the functionalities, such as, object management, logging, event handling, object-oriented features, and so on. A class can extend the qx.core.Object class to get all the functionalities defined in the this class. When you want to add any functionality to your class, just inherit the Object class and add the extra functionalities in the subclass. The major functionalities of the Object class are explained in the sections that follow. Object management   The Object class provides the following methods for object management, such as, creation, destruction, and so on: base(): This method calls base class method dispose(): This method disposes or destroys the object isDisposed(): This method returns a true value if the object is disposed toString(): This method returns the object in string format toHashCode(): This method returns hash code of the object Event handling The Object class provides the following methods for event creation, event firing, event listener, and so on: addListener(): This method adds the listener on the event target and returns the ID of the listener addListenerOnce(): This method adds the listener and listens only to the first occurrence of the event dispatchEvent(): This method dispatches the event fireDataEvent(): This method fires the data event fireEvent(): This method fires the event removeListener(): This method removes the listener removeListenerById(): This method removes the listener by its ID, given by addListener() Logging The Object class provides the following methods to log the message at different levels: warn(): Logs the message at warning level info(): Logs the message at information level error(): Logs the message at error level debug(): Logs the message at the debugging level trace(): Logs the message at the tracing level Also, the Object class provides the methods for setters and getters for properties, and so on. qx.core.LayoutItem LayoutItem is the super most class in the hierarchy. You can place only the layout items in the layout manager. LayoutItem is an abstract class. The LayoutItem class mainly provides properties, such as, height, width, margins, shrinking, growing, and many more, for the item to be drawn on the screen. It also provides a set of public methods to alter these properties. Check the API documentation for a full set of class information. qx.core.Widget Next in the class hierarchy is the Widget class, which is the base class for all the GUI components. Widget is the super class for all the individual GUI components, such as, button, text field, combobox, container, and so on, as shown in the class hierarchy diagram. There are different kinds of widgets, such as, containers, menus, toolbars, form items, and so on; each kind of widgets are defined in different namespaces. We will see all the different namespaces or packages, one-by-one, in this article. A widget consists of at least three HTML elements. The container element, which is added to the parent widget, has two child elements—the decoration and the content element. The decoration element decorates the widget. It has a lower z-index and contains markup to render the widget's background and border styles, using an implementation of the qx.ui.decoration.IDecorator interface. The content element is positioned inside the container element, with the padding, and contains the real widget element. Widget properties Common widget properties include:   Visibility: This property controls the visibility of the widget. The possible values for this property are: visible: Makes the widget visible on screen. hidden: Hides the widget, but widget space will be occupied in the parent widget's layout. This is similar to the CSS style visibility:hidden. exclude: Hides the widget and removes from the parent widget's layout, but the widget is still a child of its parent's widget. This is similar to the CSS style display:none. The methods to modify this property are show(), hide(), and exclude(). The methods to check the status are isVisible(), isHidden(), and isExcluded(). Tooltip: This property displays the tooltip when the cursor is pointing at the widget. This tooltip information consists of toolTipText and toolTipIcon. The different methods available to alter this property are: setToolTip()/getToolTip(): Sets or returns the qx.ui.tooltip.ToolTip instance. The default value is null. setToolTipIcon()/getToolTipIcon(): Sets or returns the URL for the icon. The default value is null. setToolTipText()/getToolTipText(): Sets or returns the string text. It also supports the HTML markup. Default value is null. Text color: The textColor property sets the frontend text color of the widget. The possible values for this property are any color or null. Padding: This property is a shorthand group property for paddingTop, paddingRight, paddingBottom and paddingLeft of the widget. The available methods are setPadding() and resetPadding(), which sets values for top, right, bottom, and left padding, consecutively. If any values are missing, the opposite side values will be taken for that side. Also, set/get methods for each padding side are also available. Tab index: This property controls the traversal of widgets on the Tab key press. Possible values for this property are any integer or null. The traversal order is from lower value to higher value. By default, tab index for the widgets is set in the order in which they are added to the container. If you want to provide a custom traversal order, set the tab index accordingly. The available methods are setTabIndex() and getTabIndex(). These methods, respectively set and return the integer value (0 to 32000) or null. Font: The Font property defines the font for the widget. The possible value is either a font name defined in the theme, or an instance of qx.bom.Font, or null. The available methods are: setFont(): Sets the font getFont(): Retrieves the font initFont(): Initializes the font resetFont(): Resets the font Enabled: This property enables or disables the widget for user input. Possible values are true or false (Boolean value). The default value is true. The widget invokes all the input events only if it is in the enabled state. In the disabled state, the widget will be grayed out and no user input is allowed. The only events invoked in the disabled state are mouseOver and mouseOut. In the disabled state, tab index and widget focus are ignored. The tab traversal focus will go to the next enabled widget. setEnabled()/getEnabled() are the methods to set or get a Boolean value, respectively. Selectable: This property says whether the widget contents are selectable. When a widget contains text data and the property is true, native browser selection can be used to select the contents. Possible values are true or false. The default value is false. setSelectable(), getSelectable(), initSelectable(), resetSelectable(), and toggleSelectable() are the methods available to modify the Selectable property. Appearance: This property controls style of the element and identifies the theme for the widget. Possible values are any string defined in the theme; the default value is widget. setAppearence(), getAppearence(), initAppearence(), and resetAppearence() are the methods to alter the appearance. Cursor: This property specifies which type of cursor to display on mouse over the widget. The possible values are any valid CSS2 cursor name defined by W3C (any string) and null. The default value is null. Some of the W3C-defined cursor names are default, wait, text, help, pointer, crosshair, move, n-resize, ne-resize, e-resize, se-resize, s-resize, sw-resize, w-resize, and nw-resize. setCursor(), getCursor(), resetCursor(), and initCursor() are the methods available to alter the cursor property. qx.application The starting point for a qooxdoo application is to write a custom application class by inheriting one of the qooxdoo application classes in the qx.application namespace or package. Similar to the main method in Java, the qooxdoo application also starts from the main method in the custom application class. qooxdoo supports three different kinds of applications: Standalone: Uses the application root to build full-blown, standalone qooxdoo applications. Inline: Uses the page root to build traditional web page-based applications, which are embedded into isles in the classic HTML page. Native: This class is for applications that do not involve qooxdoo's GUI toolkit. Typically, they only make use of the IO (AJAX) and BOM functionality (for example, to manipulate the existing DOM). Whenever a user creates an application with the Python script, a custom application class gets generated with a default main method. Let's see the custom application class generated for our Team Twitter application. After generation, the main function code is edited to add functionality to communicate to the RPC server and say "hello" to the qooxdoo world. The following code is the content of the Application.js class file with an RPC call to communicate with the server: /** * This is the main application class of your custom application "teamtwitter" */ qx.Class.define("teamtwitter.Application", { extend : qx.application.Standalone, members : { /** * This method contains the initial application code and gets called during startup of the application * @lint ignoreDeprecated(alert) */ main : function() { // Call super class this.base(arguments); // Enable logging in debug variant if (qx.core.Variant.isSet("qx.debug", "on")) { // support native logging capabilities, e.g. Firebug for Firefox qx.log.appender.Native; // support additional cross-browser console. Press F7 to toggle visibility qx.log.appender.Console; } /* Below is your actual application code... */ // Create a button var button1 = new qx.ui.form.Button("First Button", "teamtwitter/test.png"); // Document is the application root var doc = this.getRoot(); // Add button to document at fixed coordinates doc.add(button1, {left: 100, top: 50}); // Add an event listener button1.addListener("execute", function(e) { var rpc = new qx.io.remote.Rpc(); rpc.setCrossDomain( false ); rpc.setTimeout(1000); var host = window.location.host; var proto = window.location.protocol; var webURL = proto + "//" + host + "/teamtwitter/.qxrpc"; rpc.setUrl(webURL); rpc.setServiceName("qooxdoo.test"); rpc.callAsync(function(result, ex, id){ if (ex == null) { alert(result); } else { alert("Async(" + id + ") exception: " + ex); } }, "echo", "Hello to qooxdoo World!"); }); } } }); We've had an overview of the class hierarchy of the qooxdoo framework and got to know the base classes for the widgets. Now, we have an idea of the core functionalities available for the widgets, the core properties of the widgets, and the methods to manage those properties. We've received more information on the application in the qooxdoo framework. Now, it is time to learn about the containers. Containers A container is a kind of widget. It holds multiple widgets and exposes public methods to manage their child widgets. One can configure a layout manager for the container to position all the child widgets in the container. qooxdoo provides different containers for different purposes. Let's check different containers provided by the qooxdoo framework and understand the purpose of each container. Once you understand the purpose of each container, you can select the right container when you design your application. Scroll Whenever the content widget size (width and height) is larger than the container size (width and height), the Scroll container provides vertical, or horizontal, or both scroll bars automatically. You have to set the Scroll container's size carefully to make it work properly. The Scroll container is used most commonly if the application screen size is large. The Scroll container has a fixed layout and it can hold a single child. So, there is no need to configure the layout for this container. The following code snippet demonstrates how to use the Scroll container: // create scroll containervar scroll = new qx.ui.container.Scroll().set({width: 300,height: 200});// adding a widget with larger widget and height of the scrollscroll.add(new qx.ui.core.Widget().set({width: 600,minWidth: 600,height: 400,minHeight: 400})); // add to the root widget.this.getRoot().add(scroll); The GUI look for the preceding code is as follows: Stack The Stack container puts a widget on top of an old widget. This container displays only the topmost widget. The Stack container is used if there are set of tasks to be carried out in a flow. An application user can work on each user interface one-by-one in order. The following code snippet demonstrates how to use the Stack container: // create stack containervar stack = new qx.ui.container.Stack();// add some childrenstack.add(new qx.ui.core.Widget().set({backgroundColor: "red"}));stack.add(new qx.ui.core.Widget().set({backgroundColor: "green"}));stack.add(new qx.ui.core.Widget().set({backgroundColor: "blue"}));this.getRoot().add(stack); The GUI look for the preceding code is as follows: Resizer Resizer is a container that gives flexibility for resizing at runtime. This container should be used only if you want to allow the application user to dynamically resize the container. The following code snippet demonstrates how to use the Resizer container: var resizer = new qx.ui.container.Resizer().set({marginTop : 50,marginLeft : 50,width: 200,height: 100});resizer.setLayout(new qx.ui.layout.HBox());var label = new qx.ui.basic.Label("Resize me <br>I'm resizable");label.setRich(true);resizer.add(label);this.getRoot().add(resizer); The GUI look for the preceding code is as follows: Composite This is a generic container. If you do not want any of the specific features, such as, resize on runtime, stack, scroll, and so on, but just want a container, you can use this container. This is one of the mostly used containers. The following code snippet demonstrates the Composite container usage. A horizontal layout is configured to the Composite container. A label and a text field are added to the container. The horizontal layout manager places them horizontally: // create the compositevar composite = new qx.ui.container.Composite()// configure a layout.composite.setLayout(new qx.ui.layout.HBox());// add some child widgetscomposite.add(new qx.ui.basic.Label("Enter Text: "));composite.add(new qx.ui.form.TextField());// add to the root widget.this.getRoot().add(composite); The GUI look for the preceding code is as follows: Window Window is a container that has all features, such as, minimize, maximize, restore, and close. The icons for these operations will appear on the top-right corner. Different themes can be set to get the look and feel of a native window within a browser. This window is best used when an application requires Multiple Document Interface (MDI) or Single Document Interface (SDI). The following code snippet demonstrates a window creation and display: var win = new qx.ui.window.Window("First Window");win.setWidth(300);win.setHeight(200);// neglecting minimize buttonwin.setShowMinimize(false);this.getRoot().add(win, {left:20, top:20});win.open(); The GUI look for the preceding code is as follows: TabView The TabView container allows you to display multiple tabs, but only one tab is active at a time. The TabView container simplifies the GUI by avoiding the expansive content spreading to multiple pages, with a scroll. Instead, the TabView container provides the tab title buttons to navigate to other tabs. You can group the related fields into each tab and try to avoid the scroll by keeping the most-used tab as the first tab and making it active. Application users can move to other tabs, if required. TabView is the best example for the stack container usage. It stacks all pages one over the other and displays one page at a time. Each page will have a button at the top, in a button bar, to allow switching the page. Tabview allows positioning the button bar on top, bottom, left, or right. TabView also allows adding pages dynamically; a scroll appears when the page buttons exceed the size. The following code snippet demonstrates the usage of TabView: var tabView = new qx.ui.tabview.TabView();// create a pagevar page1 = new qx.ui.tabview.Page("Layout", "icon/16/apps/utilitiesterminal.png");// add page to tabviewtabView.add(page1);var page2 = new qx.ui.tabview.Page("Notes", "icon/16/apps/utilitiesnotes.png");page2.setLayout(new qx.ui.layout.VBox());page2.add(new qx.ui.basic.Label("Notes..."));tabView.add(page2);var page3 = new qx.ui.tabview.Page("Calculator", "icon/16/apps/utilities-calculator.png");tabView.add(page3);this.getRoot().add(tabView, {edge : 0}); The GUI look for the preceding code is as follows: GroupBox GroupBox groups a set of form widgets and shows an effective visualization with the use of a legend, which supports text and icons to describe the group. As with the container, you can configure any layout manager and allow adding a number of form widgets to the GroupBox. Additionally, it is possible to use checkboxes or radio buttons within the legend. This allows you to provide group functionalities such as selecting or unselecting all the options in the group. This feature is most important for complex forms with multiple choices. The following code snippet demonstrates the usage of GroupBox: // group boxvar grpBox = new qx.ui.groupbox.GroupBox("I am a box");this.getRoot().add(grpBox, {left: 20, top: 70});// radio group boxvar rGrpBox = new qx.ui.groupbox.RadioGroupBox("I am a box");rGrpBox.setLayout(new qx.ui.layout.VBox(4));rGrpBox.add(new qx.ui.form.RadioButton("Option1"));rGrpBox.add(new qx.ui.form.RadioButton("Option2"));this.getRoot().add(rGrpBox, {left: 160, top: 70});// check group boxvar cGrpBox = new qx.ui.groupbox.CheckGroupBox("I am a box");this.getRoot().add(cGrpBox, {left: 300, top: 70}); The GUI look for the preceding code is as follows: We got to know the different containers available in the qooxdoo framework. Each container provides a particular functionality. Based on the information displayed on the GUI, you should choose the right container to have better usability of the application. Containers are the outer-most widgets in the GUI. Once you decide on the containers for your user interface, the next thing to do is to configure the layout manager for the container. Layout manager places the child widgets in the container, on the basis of the configured layout manager's policies. Now, it's time to learn how to place and arrange widgets inside the container, that is, how to lay out the container.
Read more
  • 0
  • 0
  • 5334

article-image-developing-flood-control-using-xna-game-development
Packt
22 Dec 2011
15 min read
Save for later

Developing Flood Control using XNA Game Development

Packt
22 Dec 2011
15 min read
(For more resources on XNA, see here.) Animated pieces We will define three different types of animated pieces: rotating, falling, and fading. The animation for each of these types will be accomplished by altering the parameters of the SpriteBatch.Draw() call. Classes for animated pieces In order to represent the three types of animated pieces, we will create three new classes. Each of these classes will inherit from the GamePiece class, meaning they will contain all of the methods and members of the GamePiece class, but will add additional information to support the animation. Child classes Child classes inherit all of their parent's members and methods. The RotatingPiece class can refer to the _pieceType and _pieceSuffix of the piece, without recreating them within RotatingPiece itself. Additionally, child classes can extend the functionality of their base class, adding new methods and properties, or overriding old ones. In fact, Game1 itself is a child of the Micrsoft.Xna.Game class, which is why all of the methods we use (Update(),Draw(),LoadContent(), and so on) are declared with the Overrides modifier. Let's begin by creating the class we will use for rotating pieces. Time for action – rotating pieces Open your existing Flood Control project in Visual Studio, if it is not already active. Add a new class to the project called RotatingPiece. Under the class declaration (Public Class RotatingPiece), add the following line: Inherits GamePiece Add the following declarations to the RotatingPiece class: Public Clockwise As BooleanPublic Shared RotationRate As Single = (MathHelper.PiOver2/10)Private _rotationAmount As SinglePublic rotationTicksRemaining As Single = 10 Add a property to retrieve the current RotationAmount: Public ReadOnly Property RotationAmount As Single Get If Clockwise Then Return _rotationAmount Else Return (MathHelper.Pi * 2) - _rotationAmount End If End GetEnd Property Add a constructor for the RotatingPiece class as follows: Public Sub New(type As String, clockwise As Boolean) MyBase.New(type) Me.Clockwise = clockwiseEnd Sub Add a method to update the piece as follows: Public Sub UpdatePiece() _rotationAmount += RotationRate rotationTicksRemaining = CInt(MathHelper.Max(0, rotationTicksRemaining - 1))End Sub What just happened? In step 3, we modified the RotatingPiece class, by adding Inherits GamePiece on the line, after the class declaration. This indicates to Visual Basic that the RotatingPiece class is a child of the GamePiece class. The Clockwise variable stores a true value, if the piece will be rotating clockwise, and false if the rotation is counter clockwise. When a game piece is rotated, it will turn a total of 90 degrees (or pi/2 radians) over 10 animation frames. The MathHelper class provides a number of constants to represent commonly used numbers, with MathHelper.PiOver2 being equal to the number of radians in a 90 degree angle. We divide this constant by 10 and store the result as the rotationRate for use later. This number will be added to the _rotationAmount single, which will be referenced when the animated piece is drawn. Working with radians All angular math is handled in radians in XNA. A complete (360 degree) circle contains 2*pi radians. In other words, one radian is equal to about 57.29 degrees. We tend to relate to circles more often in terms of degrees (a right angle being 90 degrees, for example), so if you prefer to work with degrees, you can use the MathHelper.ToRadians() method to convert your values, when supplying them to XNA classes and methods. The final declaration, rotationTicksRemaining, is reduced by one, each time the piece is updated. When this counter reaches zero, the piece has finished animating. When the piece is drawn, the RotationAmount property is referenced by a spriteBatch.Draw() call, and returns either the _rotationAmount variable (in the case of a clockwise rotation) or 2*pi (a full circle) minus the _rotationAmount, if the rotation is counter clockwise. The constructor in step 6 illustrates how the parameters passed to a constructor can be forwarded to the class' parent constructor via the MyBase call. Since, the GamePiece class has a constructor that accepts a piece type, we can pass that information along to its constructor, while using the second parameter (clockwise) to update the clockwise member that does not exist in the GamePiece class. In this case, since both the Clockwise member variable and the clockwise parameter have identical names, we specify Me.Clockwise to refer to the clockwise member of the RotatingPiece class. Simply, clockwise in this scope refers only to the parameter passed to the constructor. Me notation You can see that it is perfectly valid for Visual Basic code to have method parameter names that match the names of class variables, thus potentially hiding the class variables from being used in the method (since, referring to the name inside the method will be assumed to refer to the parameter). To ensure that you can always access your class variables even when a parameter name conflicts, you can preface the variable name with Me. when referring to the class variable. Me. indicates to Visual Basic that the variable you want to use is part of the class, and not a local method parameter. In C#, a similar type of notation is used, prefacing class-level members with this. to access a hidden variable. Lastly, the UpdatePiece() method simply increases the _rotationAmount member, while decreasing the rotationTicksRemaining counter (using MathHelper.Max() to ensure that the value does not fall below zero). Time for action – falling pieces Add a new class to the Flood Control project called FallingPiece. Add the Inherits line after the class declaration as follows: Inherits GamePiece Add the following declarations to the FallingPiece class: Public VerticalOffset As IntegerPublic Shared FallRate As Integer = 5 Add a constructor for the FallingPiece class: Public Sub New(type As String, verticalOffset As Integer) MyBase.New(type) Me.VerticalOffset = verticalOffsetEnd Sub Add a method to update the piece: Public Sub UpdatePiece() VerticalOffset = CInt(MathHelper.Max(0, VerticalOffset - FallRate))End Sub What just happened? Simpler than a RotatingPiece, a FallingPiece is also a child of the GamePiece class. A FallingPiece has an offset (how high above its final destination it is currently located) and a falling speed (the number of pixels it will move per update). As with a RotatingPiece, the constructor passes the type parameter to its base class constructor, and uses the verticalOffset parameter to set the VerticalOffset member. Again, we use the Me. notation to differentiate the two identifiers of the same name. Lastly, the UpdatePiece() method subtracts FallRate from VerticalOffset, again using the MathHelper.Max() method to ensure that the offset does not fall below zero. Time for action – fading pieces Add a new class to the Flood Control project called FadingPiece. Add the following line to indicate that FadingPiece also inherits from GamePiece: Inherits GamePiece Add the following declarations to the FadingPiece class: Public AlphaLevel As Single = 1.0Public Shared AlphaChangeRate As Single = 0.02 Add a constructor for the FadingPiece class as follows: Public Sub New(type As String, suffix As String) MyBase.New(type, suffix)End Sub Add a method to update the piece: Public Sub UpdatePiece() AlphaLevel = MathHelper.Max(0, AlphaLevel - AlphaChangeRate)End Sub What just happened? The simplest of our animated pieces, the FadingPiece only requires an alpha value (which always starts at 1.0f, or fully opaque) and a rate of change. The FadingPiece constructor simply passes the parameters along to the base constructor. When a FadingPiece is updated, alphaLevel is reduced by alphaChangeRate, making the piece more transparent. Managing animated pieces Now that we can create animated pieces, it will be the responsibility of the GameBoard class to keep track of them. In order to do that, we will define a Dictionary object for each type of piece. A Dictionary is a collection object similar to a List, except that instead of being organized by an index number, a Dictionary consists of a set of key and value pairs. In an array or a List, you might access an entity by referencing its index as in dataValues(2) = 12. With a Dictionary, the index is replaced with your desired key type. Most commonly, this will be a string value. This way, you can do something like fruitColors("Apple")="red". Time for action – updating GameBoard to support animated pieces In the declarations section of the GameBoard class, add three Dictionaries, shown as follows: Public FallingPieces As Dictionary(Of String, FallingPiece) = New Dictionary(Of String, FallingPiece)Public RotatingPieces As Dictionary(Of String, RotatingPiece) = New Dictionary(Of String, RotatingPiece)Public FadingPieces As Dictionary(Of String, FadingPiece) = New Dictionary(Of String, FadingPiece) Add methods to the GameBoard class to create new falling piece entries in the Dictionaries: Public Sub AddFallingPiece(x As Integer, y As Integer, type As String, verticalOffset As Integer) FallingPieces.Add( x.ToString() + "_" + y.ToString(), New FallingPiece(type, verticalOffset))End SubPublic Sub AddRotatingPiece(x As Integer, y As Integer, type As String, clockwise As Boolean) RotatingPieces.Add( x.ToString() + "_" + y.ToString(), New RotatingPiece(type, clockwise))End SubPublic Sub AddFadingPiece(x As Integer, y As Integer, type As String) FadingPieces.Add( x.ToString() + "_" + y.ToString(), New FadingPiece(type, "W"))End Sub Add the ArePiecesAnimating() method to the GameBoard class: Public Function ArePiecesAnimating() As Boolean If (FallingPieces.Count + FadingPieces.Count + RotatingPieces.Count) = 0 Then Return False Else Return True End IfEnd Function Add the UpdateFadingPieces() method to the GameBoard class: Public Sub UpdateFadingPieces() Dim RemoveKeys As Queue(Of String) = New Queue(Of String) For Each thisKey As String In FadingPieces.Keys FadingPieces(thisKey).UpdatePiece() If FadingPieces(thisKey).AlphaLevel = 0 Then RemoveKeys.Enqueue(thisKey) End If Next While RemoveKeys.Count > 0 FadingPieces.Remove(RemoveKeys.Dequeue()) End WhileEnd Sub Add the UpdateFallingPieces() method to the GameBoard class: Public Sub UpdateFallingPieces() Dim RemoveKeys As Queue(Of String) = New Queue(Of String) For Each thisKey As String In FallingPieces.Keys FallingPieces(thisKey).UpdatePiece() If FallingPieces(thisKey).VerticalOffset = 0 Then RemoveKeys.Enqueue(thisKey) End If Next While RemoveKeys.Count > 0 FallingPieces.Remove(RemoveKeys.Dequeue()) End WhileEnd Sub Add the UpdateRotatingPieces() method to the GameBoard class as follows: Public Sub UpdateRotatingPieces() Dim RemoveKeys As Queue(Of String) = New Queue(Of String) For Each thisKey As String In RotatingPieces.Keys RotatingPieces(thisKey).UpdatePiece() If RotatingPieces(thisKey).rotationTicksRemaining = 0 Then RemoveKeys.Enqueue(thisKey) End If Next While RemoveKeys.Count > 0 RotatingPieces.Remove(RemoveKeys.Dequeue()) End WhileEnd Sub Add the UpdateAnimatedPieces() method to the GameBoard class as follows: Public Sub UpdateAnimatedPieces() If (FadingPieces.Count = 0) Then UpdateFallingPieces() UpdateRotatingPieces() Else UpdateFadingPieces() End IfEnd Sub What just happened? After declaring the three Dictionary objects, we have three methods used by the GameBoard class to create them when necessary. In each case, the key is built in the form X_Y, so an animated piece in column 5 on row 4 will have a key of 5_4. Each of the three Add... methods simply pass the parameters along to the constructor for the appropriate piece types, after determining the key to use. When we begin drawing the animated pieces, we want to be sure that animations finish playing, before responding to other input or taking other game actions (like creating new pieces). The ArePiecesAnimating() method returns true, if any of the Dictionary objects contain entries. If they do, we will not process any more input or fill empty holes on the game board, until they have completed. The UpdateAnimatedPieces() method will be called from the game's Update() method, and is responsible for calling the three different update methods previously (UpdateFadingPiece(), UpdateFallingPiece(), and UpdateRotatingPiece()) for any animated pieces, currently on the board. The first line in each of these methods declares a Queue object called RemoveKeys. We will need this, because Visual Basic does not allow you to modify a Dictionary (or List, or any of the similar generic collection objects), while a for each loop is processing them. A Queue is yet another generic collection object that works like a line at the bank. People stand in a line and await their turn to be served. When a bank teller is available, the first person in the line transacts his/her business and leaves. The next person then steps forward. This type of processing is known as FIFO (First In, First Out). Using the Enqueue() and Dequeue() methods of the Queue class, objects can be added to the Queue(Enqueue()), where they await processing. When we want to deal with an object, we Dequeue() the oldest object in the Queue, and handle it. Dequeue() returns the first object waiting to be processed, which is the oldest object added to the Queue. Collection classes The .NET Framework provides a number of different collection classes, such as the Dictionary, Queue, List, and Stack objects. Each of these classes provide different ways to organize and reference the data in them. For information on the various collection classes and when to use each type, see the following MSDN entry: Each of the update methods loops through all of the keys in its own Dictionary, and in turn calls the UpdatePiece() method for each key. Each piece is then checked to see if its animation has completed. If it has, its key is added to the RemoveKeys queue. After, all of the pieces in the Dictionary have been processed, any keys that were added to RemoveKeys are then removed from the Dictionary, eliminating those animated pieces. If there are any FadingPieces currently active, those are the only animated pieces that UpdateAnimatedPieces() will update. When a row is completed, the scoring tiles fade out, the tiles above them fall into place, and new tiles fall in from above. We want all of the fading to finish before the other tiles start falling (or it would look strange as the new tiles pass through the fading old tiles). Fading pieces In the discussion of UpdateAnimatedPieces(), we stated that fading pieces are added to the board, whenever the player completes a scoring chain. Each piece in the chain is replaced with a fading piece. Time for action – generating fading pieces In the Game1 class, modify the CheckScoringChain() method by adding the following call inside the for each loop, before the square is set to Empty: _gameBoard.AddFadingPiece( CInt(thisPipe.X), CInt(thisPipe.Y), _gameBoard.GetSquare( CInt(thisPipe.X), CInt(thisPipe.Y))) What just happened? Adding fading pieces is simply a matter of getting the type of piece currently occupying the square that we wish to remove (before it is replaced with an empty square), and adding it to the FadingPieces dictionary. We need to use the CInt typecasts, because the thisPipe variable is a Vector2 value, which stores its X and Y components as Singles. Falling pieces Falling pieces are added to the game board in two possible locations: From the FillFromAbove() method when a piece is being moved from one location on the board to another, and in the GenerateNewPieces() method, when a new piece falls in from the top of the game board. Time for action – generating falling pieces Modify the FillFromAbove() method of the GameBoard class by adding a call to generate falling pieces right before the rowLookup = -1 line (inside the If block): AddFallingPiece(x, y, GetSquare(x, y), GamePiece.PieceHeight * (y - rowLookup)) Update the GenerateNewPieces() method by adding the following call, right after the RandomPiece(x,y) line as follows: AddFallingPiece(x, y, GetSquare(x, y), GamePiece.PieceHeight * (GameBoardHeight + 1)) What just happened? When FillFromAbove() moves a piece downward, we now create an entry in the FallingPieces dictionary that is equivalent to the newly moved piece. The vertical offset is set to the height of a piece (40 pixels) times the number of board squares the piece was moved. For example, if the empty space was at location 5, 5 on the board, and the piece above it (5, 4) is being moved down one block, the animated piece is created at 5, 5 with an offset of 40 pixels (5-4 = 1, times 40). When new pieces are generated for the board, they are added with an offset equal to the height (in pixels) of the game board (recall that we specified the height as one less than the real height, to account for the allocation of the extra element in the boardSquares array), determined by multiplying the GamePiece.PieceHeight value by GameBoardHeight +1. This means, they will always start above the playing area and fall into it. Rotating pieces The last type of animated piece that we need to deal with adding, during the play is the rotation piece. This piece type is added, whenever the user clicks on a game piece. Time for action – modify Game1 to generate rotating pieces Update the HandleMouseInput() method in the Game1 class to add rotating pieces to the board by adding the following inside the "if mouseInfo.LeftButton = ButtonState.Pressed" block, before _gameBoard.RotatePiece() is called: _gameBoard.AddRotatingPiece(x, y, _gameBoard.GetSquare(x, y), False) Still in HandleMouseInput(), add the following in the same location inside the if block for the right-mouse button: _gameBoard.AddRotatingPiece(x, y, _gameBoard.GetSquare(x, y), True) What just happened? Recall that the only difference between a clockwise rotation and a counter-clockwise rotation (from the standpoint of the AddRotatingPiece() method) is a true or false in the final parameter. Depending on which button is clicked, we simply add the current square (before it gets rotated, otherwise the starting point for the animation would be the final position) and true for right-mouse clicks or false for left-mouse clicks.
Read more
  • 0
  • 0
  • 3824

article-image-appcelerator-titanium-creating-animations-transformations-and-understanding-drag-and-d
Packt
22 Dec 2011
10 min read
Save for later

Appcelerator Titanium: Creating Animations, Transformations, and Understanding Drag-and-drop

Packt
22 Dec 2011
10 min read
(For more resources related to this subject, see here.) Animating a View using the "animate" method Any Window, View, or Component in Titanium can be animated using the animate method. This allows you to quickly and confidently create animated objects that can give your applications the "wow" factor. Additionally, you can use animations as a way of holding information or elements off screen until they are actually required. A good example of this would be if you had three different TableViews but only wanted one of those views visible at any one time. Using animations, you could slide those tables in and out of the screen space whenever it suited you, without the complication of creating additional Windows. In the following recipe, we will create the basic structure of our application by laying out a number of different components and then get down to animating four different ImageViews. These will each contain a different image to use as our "Funny Face" character. Complete source code for this recipe can be found in the /Chapter 7/Recipe 1 folder. Getting ready To prepare for this recipe, open up Titanium Studio and log in if you have not already done so. If you need to register a new account, you can do so for free directly from within the application. Once you are logged in, click on New Project, and the details window for creating a new project will appear. Enter in FunnyFaces as the name of the app, and fill in the rest of the details with your own information. Pay attention to the app identifier, which is written normally in reverse domain notation (that is, com.packtpub.funnyfaces). This identifier cannot be easily changed after the project is created and you will need to match it exactly when creating provisioning profiles for distributing your apps later on. The first thing to do is copy all of the required images into an images folder under your project's Resources folder. Then, open the app.js file in your IDE and replace its contents with the following code. This code will form the basis of our FunnyFaces application layout. // this sets the background color of the master UIView Titanium.UI.setBackgroundColor('#fff');////create root window//var win1 = Titanium.UI.createWindow({ title:'Funny Faces', backgroundColor:'#fff'});//this will determine whether we load the 4 funny face//images or whether one is selected alreadyvar imageSelected = false;//the 4 image face objects, yet to be instantiatedvar image1;var image2;var image3;var image4;var imageViewMe = Titanium.UI.createImageView({ image: 'images/me.png', width: 320, height: 480, zIndex: 0 left: 0, top: 0, zIndex: 0, visible: false});win1.add(imageViewMe);var imageViewFace = Titanium.UI.createImageView({ image: 'images/choose.png', width: 320, height: 480, zIndex: 1});imageViewFace.addEventListener('click', function(e){ if(imageSelected == false){ //transform our 4 image views onto screen so //the user can choose one! }});win1.add(imageViewFace);//this footer will hold our save button and zoom slider objectsvar footer = Titanium.UI.createView({ height: 40, backgroundColor: '#000', bottom: 0, left: 0, zIndex: 2});var btnSave = Titanium.UI.createButton({ title: 'Save Photo', width: 100, left: 10, height: 34, top: 3});footer.add(btnSave);var zoomSlider = Titanium.UI.createSlider({ left: 125, top: 8, height: 30, width: 180});footer.add(zoomSlider);win1.add(footer);//open root windowwin1.open(); Build and run your application in the emulator for the first time, and you should end up with a screen that looks just similar to the following example: How to do it… Now, back in the app.js file, we are going to animate the four ImageViews which will each provide an option for our funny face image. Inside the declaration of the imageViewFace object's event handler, type in the following code: imageViewFace.addEventListener('click', function(e){ if(imageSelected == false){ //transform our 4 image views onto screen so //the user can choose one! image1 = Titanium.UI.createImageView({ backgroundImage: 'images/clown.png', left: -160, top: -140, width: 160, height: 220, zIndex: 2 }); image1.addEventListener('click', setChosenImage); win1.add(image1); image2 = Titanium.UI.createImageView({ backgroundImage: 'images/policewoman.png', left: 321, top: -140, width: 160, height: 220, zIndex: 2 }); image2.addEventListener('click', setChosenImage); win1.add(image2); image3 = Titanium.UI.createImageView({ backgroundImage: 'images/vampire.png', left: -160, bottom: -220, width: 160, height: 220, zIndex: 2 }); image3.addEventListener('click', setChosenImage); win1.add(image3); image4 = Titanium.UI.createImageView({ backgroundImage: 'images/monk.png', left: 321, bottom: -220, width: 160, height: 220, zIndex: 2 }); image4.addEventListener('click', setChosenImage); win1.add(image4); image1.animate({ left: 0, top: 0, duration: 500, curve: Titanium.UI.ANIMATION_CURVE_EASE_IN }); image2.animate({ left: 160, top: 0, duration: 500, curve: Titanium.UI.ANIMATION_CURVE_EASE_OUT }); image3.animate({ left: 0, bottom: 20, duration: 500, curve: Titanium.UI.ANIMATION_CURVE_EASE_IN_OUT }); image4.animate({ left: 160, bottom: 20, duration: 500, curve: Titanium.UI.ANIMATION_CURVE_LINEAR }); }}); Now launch the emulator from Titanium Studio and you should see the initial layout with our "Tap To Choose An Image" view visible. Tapping the choose ImageView should now animate our four funny face options onto the screen, as seen in the following screenshot: How it works… The first block of code creates the basic layout for our application, which consists of a couple of ImageViews, a footer view holding our "save" button, and the Slider control, which we'll use later on to increase the zoom scale of our own photograph. Our second block of code is where it gets interesting. Here, we're doing a simple check that the user hasn't already selected an image using the imageSelected Boolean, before getting into our animated ImageViews, named image1, image2, image3, and image4. The concept behind the animation of these four ImageViews is pretty simple. All we're essentially doing is changing the properties of our control over a period of time, defined by us in milliseconds. Here, we are changing the top and left properties of all of our images over a period of half a second so that we get an effect of them sliding into place on our screen. You can further enhance these animations by adding more properties to animate, for example, if we wanted to change the opacity of image1 from 50 percent to 100 percent as it slides into place, we could change the code to look something similar to the following: image1 = Titanium.UI.createImageView({ backgroundImage: 'images/clown.png', left: -160, top: -140, width: 160, height: 220, zIndex: 2, opacity: 0.5});image1.addEventListener('click', setChosenImage);win1.add(image1);image1.animate({ left: 0, top: 0, duration: 500, curve: Titanium.UI.ANIMATION_CURVE_EASE_IN, opacity: 1.0}); Finally, the curve property of animate() allows you to adjust the easing of your animated component. Here, we used all four animation-curve constants on each of our ImageViews. They are: Titanium.UI.ANIMATION_CURVE_EASE_IN: Accelerate the animation slowly Titanium.UI.ANIMATION_CURVE_EASE_OUT: Decelerate the animation slowly Titanium.UI.ANIMATION_CURVE_EASE_IN_OUT: Accelerate and decelerate the animation slowly Titanium.UI.ANIMATION_CURVE_LINEAR: Make the animation speed constant throughout the animation cycles Animating a View using 2D matrix and 3D matrix transforms You may have noticed that each of our ImageViews in the previous recipe had a click event listener attached to them, calling an event handler named setChosenImage. This event handler is going to handle setting our chosen "funny face" image to the imageViewFace control. It will then animate all four "funny face" ImageView objects on our screen area using a number of different 2D and 3D matrix transforms. Complete source code for this recipe can be found in the /Chapter 7/Recipe 2 folder. How to do it… Replace the existing setChosenImage function, which currently stands empty, with the following source code: //this function sets the chosen image and removes the 4//funny faces from the screenfunction setChosenImage(e){ imageViewFace.image = e.source.backgroundImage; imageViewMe.visible = true; //create the first transform var transform1 = Titanium.UI.create2DMatrix(); transform1 = transform1.rotate(-180); var animation1 = Titanium.UI.createAnimation({ transform: transform1, duration: 500, curve: Titanium.UI.ANIMATION_CURVE_EASE_IN_OUT }); image1.animate(animation1); animation1.addEventListener('complete',function(e){ //remove our image selection from win1 win1.remove(image1); }); //create the second transform var transform2 = Titanium.UI.create2DMatrix(); transform2 = transform2.scale(0); var animation2 = Titanium.UI.createAnimation({ transform: transform2, duration: 500, curve: Titanium.UI.ANIMATION_CURVE_EASE_IN_OUT }); image2.animate(animation2); animation2.addEventListener('complete',function(e){ //remove our image selection from win1 win1.remove(image2); }); //create the third transform var transform3 = Titanium.UI.create2DMatrix(); transform3 = transform3.rotate(180); transform3 = transform3.scale(0); var animation3 = Titanium.UI.createAnimation({ transform: transform3, duration: 1000, curve: Titanium.UI.ANIMATION_CURVE_EASE_IN_OUT }); image3.animate(animation3); animation3.addEventListener('complete',function(e){ //remove our image selection from win1 win1.remove(image3); }); //create the fourth and final transform var transform4 = Titanium.UI.create3DMatrix(); transform4 = transform4.rotate(200,0,1,1); transform4 = transform4.scale(2); transform4 = transform4.translate(20,50,170); //the m34 property controls the perspective of the 3D view transform4.m34 = 1.0/-3000; //m34 is the position at [3,4] //in the matrix var animation4 = Titanium.UI.createAnimation({ transform: transform4, duration: 1500, curve: Titanium.UI.ANIMATION_CURVE_EASE_IN_OUT }); image4.animate(animation4); animation4.addEventListener('complete',function(e){ //remove our image selection from win1 win1.remove(image4); }); //change the status of the imageSelected variable imageSelected = true;} How it works… Again, we are creating animations for each of the four ImageViews, but this time in a slightly different way. Instead of using the built-in animate method, we are creating a separate animation object for each ImageView, before calling the ImageView's animate method and passing this animation object to it. This method of creating animations allows you to have finer control over them, including the use of transforms. Transforms have a couple of shortcuts to help you perform some of the most common animation types quickly and easily. The image1 and image2 transforms, as shown in the previous code, use the rotate and scale methods respectively. Scale and rotate in this case are 2D matrix transforms, meaning they only transform the object in two-dimensional space along its X-axis and Y-axis. Each of these transformation types takes a single integer parameter; for scale, it is 0-100 percent and for rotate, the number of it is 0-360 degrees. Another advantage of using transforms for your animations is that you can easily chain them together to perform a more complex animation style. In the previous code, you can see that both a scale and a rotate transform are transforming the image3 component. When you run the application in the emulator or on your device, you should notice that both of these transform animations are applied to the image3 control! Finally, the image4 control also has a transform animation applied to it, but this time we are using a 3D matrix transform instead of the 2D matrix transforms used for the other three ImageViews. These work the same way as regular 2D matrix transforms, except that you can also animate your control in 3D space, along the Z-axis. It's important to note that animations have two event listeners: start and complete. These event handlers allow you to perform actions based on the beginning or ending of your animation's life cycle. As an example, you could chain animations together by using the complete event to add a new animation or transform to an object after the previous animation has finished. In our previous example, we are using this complete event to remove our ImageView from the Window once its animation has finished.
Read more
  • 0
  • 0
  • 7077

article-image-adobe-flash-11-stage3d-setting-our-tools
Packt
21 Dec 2011
10 min read
Save for later

Adobe Flash 11 Stage3D: Setting Up Our Tools

Packt
21 Dec 2011
10 min read
(For more resources on Adobe Flash, see here.) Before we begin programming, there are two simple steps required to get everything ready for some amazing 3D graphics demos. Step 1 is to obtain the Flash 11 plugin and the Stage3D API. Step 2 is to create a template as3 project and test that it compiles to create a working Flash SWF file. Once you have followed these two steps, you will have properly "equipped" yourself. You will truly be ready for the battle. You will have ensured that your tool-chain is set up properly. You will be ready to start programming a 3D game. Step 1: Downloading Flash 11 (Molehill) from Adobe Depending on the work environment you are using, setting things up will be slightly different. The basic steps are the same regardless of which tool you are using but in some cases, you will need to copy files to a particular folder and set a few program options to get everything running smoothly. If you are using tools that came out before Flash 11 went live, you will need to download some files from Adobe which instruct your tools how to handle the new Stage3D functions. The directions to do so are outlined below in Step 1. In the near future, of course, Flash will be upgraded to include Stage3D. If you are using CS5.5 or another new tool that is compatible with the Flash 11 plugin, you may not need to perform the steps below. If this is the case, then simply skip to Step 2. Assuming that your development tool-chain does not yet come with Stage3D built in, you will need to gather a few things before we can start programming. Let's assemble all the equipment we need in order to embark on this grand adventure, shall we? Time for action – getting the plugin It is very useful to be running the debug version of Flash 11, so that your trace statements and error messages are displayed during development. Download Flash 11 (content debugger) for your web browser of choice. At the time of writing, Flash 11 is in beta and you can get it from the following URL: http://labs.adobe.com/downloads/flashplayer11.html Naturally, you will eventually be able to obtain it from the regular Flash download page: http://www.adobe.com/support/flashplayer/downloads.html On this page, you will be able to install either the Active-X (IE) version or the Plugin (Firefox, and so on) version of the Flash player. This page also has links to an uninstaller if you wish to go back to the old version of Flash, so feel free to have some fun and don't worry about the consequences for now. Finally, if you want to use Chrome for debugging, you need to install the plugin version and then turn off the built-in version of Flash by typing about:plugins in your Chrome address bar and clicking on Disable on the old Flash plugin, so that the new one you just downloaded will run. We will make sure that you installed the proper version of Flash before we continue. To test that your browser of choice has the Stage3D-capable incubator build of the Flash plugin installed, simply right-click on any Flash content and ensure that the bottom of the pop-up menu lists Version 11,0,1,60 or greater, as shown in the following screenshot. If you don't see a version number in the menu, you are running the old Flash 10 plugin. Additionally, in some browsers, the 3D acceleration is not turned on by default. In most cases, this option will already be checked. However, just to make sure that you get the best frame rate, right-click on the Flash file and go to options, and then enable hardware acceleration, as shown in the following screenshot: You can read more about how to set up Flash 11 at the following URL: http://labs.adobe.com/technologies/flashplatformruntimes/flashplayer11/ Time for action - getting the Flash 11 profile for CS5 Now that you have the Stage3D-capable Flash plugin installed, you need to get Stage3D working in your development tools. If you are using a tool that came out after this book was written that includes built-in support for Flash 11, you don't need to do anything—skip to Step 2. If you are going to use Flash IDE to compile your source code and you are using Flash CS5, then you need to download a special .XML file that instructs it how to handle the newer Stage3D functionality. The file can be downloaded from the following URL: http://download.macromedia.com/pub/labs/flashplatformruntimes/incubator/flashplayer_inc_flashprofile_022711.zip If the preceding link no longer works, do not worry. The files you need are included in the source code that accompanies this book. Once you have obtained and unzipped this file, you need to copy some files into your CS5 installation. FlashPlayer11.xml goes in: Adobe Flash CS5CommonConfigurationPlayers playerglobal.swc goes in: Adobe Flash CS5CommonConfigurationActionScript 3.0FP11 Restart Flash Professional after that and then select 'Flash Player 11' in the publish settings. It will publish to a SWF13 file. As you are not using Flex to compile, you can skip all of the following sections regarding Flex. Simple as it can be! Time for action – upgrading Flex If you are going to use pure AS3 (by using FlashDevelop or Flash Builder), or even basic Flex without any IDE, then you need to compile your source code with a newer version of Flex that can handle Stage3D. At the time of writing, the best version to use is build 19786. You can download it from the following URL: http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+Hero Remember to change your IDE's compilation settings to use the new version of Flex you just downloaded. For example, if you are using Flash Builder as part of the Abode Flex SDK, create a new ActionScript project: File | New | ActionScript project. Open the project Properties panel (right-click and select Properties). Select ActionScript Compiler from the list on the left. Use the Configure Flex SDK's option in the upper-right hand corner to point the project to Flex build 19786 and then click on OK. Alternately, if you are using FlashDevelop, you need to instruct it to use this new version of Flex by going into Tools | Program Settings | AS3 Context | Flex SDK Location and browsing to your new Flex installation folder. Time for action – upgrading the Flex playerglobal.swc If you use FlashDevelop, Flash Builder, or another tool such as FDT, all ActionScript compiling is done by Flex. In order to instruct Flex about the Stage3D-specific code, you need a small file that contains definitions of all the new AS3 that is available to you. It will eventually come with the latest version of these tools and you won't need to manually install it as described in the following section. During the Flash 11 beta period, you can download the Stage3D-enabled playerglobal.swc file from the following URL: http://download.macromedia.com/pub/labs/flashplatformruntimes/flashplayer11/flashplayer11_b1_playerglobal_071311.swc Rename this file to playerglobal.swc and place it into an appropriate folder. Instruct your compiler to include it in your project. For example, you may wish to copy it to your Flex installation folder, in the flex/frameworks/libs/player/11 folder. In some code editors, there is no option to target Flash 11 (yet). By the time you read this book, upgrades may have enabled it. However, at the time of writing, the only way to get FlashDevelop to use the SWC is to copy it over the top of the one in the flex/frameworks/libs/player/10.1 folder and target this new "fake" Flash 10.1 version. Once you have unzipped Flex to your preferred location and copied playerglobal.swc to the preceding folder, fire up your code editor. Target Flash 11 in your IDE—or whatever version number that is associated with the folder, which you used as the location for playerglobal.swc. Be sure that your IDE will compile this particular SWC along with your source code. In order to do so in Flash Builder, for example, simply select "Flash Player 11" in the Publish Settings. If you use FlashDevelop, then open a new project and go into the Project--->Properties--->Output Platform Target drop-down list. Time for action – using SWF Version 13 when compiling in Flex Finally, Stage3D is considered part of the future "Version 13" of Flash and therefore, you need to set your compiler options to compile for this version. You will need to target SWF Version 13 by passing in an extra compiler argument to the Flex compiler: -swf-version=13. If you are using Adobe Flash CS5, then you already copied an XML file which has all the changes, as outlined below and this is done automatically for you. If you are using Flex on the command line, then simply add the preceding setting to your compilation build script command-line parameters. If you are using Flash Builder to compile Flex, open the project Properties panel (right-click and choose Properties). Select ActionScript Compiler from the list on the left. Add to the Additional compiler arguments input: -swf-version=13. This ensures the outputted SWF targets SWF Version 13. If you compile on the command line and not in Flash Builder, then you need to add the same compiler argument. If you are using FlashDevelop, then click on Project | Properties | Compiler Options | Additional Compiler Options, and add -swf-version=13 in this field. Time for action – updating your template HTML file You probably already have a basic HTML template for including Flash SWF files in your web pages. You need to make one tiny change to enable hardware 3D. Flash will not use hardware 3D acceleration if you don't update your HTML file to instruct it to do so. All you need to do is to always remember to set wmode=direct in your HTML parameters. For example, if you use JavaScript to inject Flash into your HTML (such as SWFObject.js), then just remember to add this parameter in your source. Alternately, if you include SWFs using basic HTML object and embed tags, your HTML will look similar to the following: <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="640" height="480"><param name="src" value="Molehill.swf" /> <param name="wmode" value="direct" /><embed type="application/ x-shockwave-flash" width="640" height="480" src="Molehill.swf" wmode="direct"></embed></object> The only really important parameter is wmode=direct (and the name of your swf file)— everything else about how you put Flash into your HTML pages remains the same. In the future, if you are running 3D demos and the frame rate seems really choppy, you might not be using hardware 3D acceleration. Be sure to view-source of the HTML file that contains your SWF and check that all mentions of the wmode parameter are set to direct.   Stage3D is now set up! That is it! You have officially gone to the weapons store and equipped yourself with everything you require to explore the depths of Flash 11 3D graphics. That was the hard part. Now we can dive in and get to some coding, which turns out to be the easy part.
Read more
  • 0
  • 0
  • 3880

article-image-ajax-basic-utilities
Packt
20 Dec 2011
8 min read
Save for later

Ajax: Basic Utilities

Packt
20 Dec 2011
8 min read
(For more resources on PHP Ajax, see here.) Validating a form using Ajax The main idea of Ajax is to get data from the server in real time without reloading the whole page. In this task we will build a simple form with validation using Ajax. Getting ready As a JavaScript library is used in this task, we will choose jQuery. We will download (if we haven't done it already) and include it in our page. We need to prepare some dummy PHP code to retrieve the validation results. In this example, let's name it inputValidation.php. We are just checking for the existence of a param variable. If this variable is introduced in the GET request, we confirm the validation and send an OK status back to the page: <?php $result = array(); if(isset($_GET["param"])){ $result["status"] = "OK"; $result["message"] = "Input is valid!"; } else { $result["status"] = "ERROR"; $result["message"] = "Input IS NOT valid!"; } echo json_encode($result); ?> How to do it... Let`s start with basic HTML structure. We will define a form with three input boxes and one text area. Of course, it is placed in : <body> <h1>Validating form using Ajax</h1> <form class="simpleValidation"> <div class="fieldRow"> <label>Title *</label> <input type="text" id="title" name="title" class="required" /> </div> <div class="fieldRow"> <label>Url</label> <input type="text" id="url" name="url" value="http://" /> </div> <div class="fieldRow"> <label>Labels</label> <input type="text" id="labels" name="labels" /> </div> <div class="fieldRow"> <label>Text *</label> <textarea id="textarea" class="required"></textarea> </div> <div class="fieldRow"> <input type="submit" id="formSubmitter" value="Submit" disabled= "disabled" /> </div> </form> </body> <style> For visual confirmation of the valid input, we will define CSS styles: label{ width:70px; float:left; } form{ width:320px; } input, textarea{ width:200px; border:1px solid black; float:right; padding:5px; } input[type=submit] { cursor:pointer; background-color:green; color:#FFF; } input[disabled=disabled], input[disabled] { background-color:#d1d1d1; } fieldRow { margin:10px 10px; overflow:hidden; } failed { border: 1px solid red; } </style> Now, it is time to include jQuery and its functionality: <script src="js/jquery-1.4.4.js"></script> <script> var ajaxValidation = function(object){ var $this = $(object); var param= $this.attr('name'); var value = $this.val(); $.get("ajax/inputValidation.php", {'param':param, 'value':value }, function(data) { if(data.status=="OK") validateRequiredInputs(); else $this.addClass('failed'); },"json"); } var validateRequiredInputs = function (){ var numberOfMissingInputs = 0; $('.required').each(function(index){ var $item = $(this); var itemValue = $item.val(); if(itemValue.length) { $item.removeClass('failed'); } else { $item.addClass('failed'); numberOfMissingInputs++; } }); var $submitButton = $('#formSubmitter'); if(numberOfMissingInputs > 0){ $submitButton.attr("disabled", true); } else { $submitButton.removeAttr('disabled'); } } </script> We will also initialize the document ready function: <script> $(document).ready(function(){ var timerId = 0; $('.required').keyup(function() { clearTimeout (timerId); timerId = setTimeout(function(){ ajaxValidation($(this)); }, 200); }); }); </script> When everything is ready, our result is as follows: How it works... We created a simple form with three input boxes and one text area. Objects with class required are automatically validated after the keyup event and calling the ajaxValidation function. Our keyup functionality also includes theTimeoutfunction to prevent unnecessary calls if the user is still writing. The validation is based on two steps: Validation of the actual input box: We are passing the inserted text to the ajax/inputValidation.php via Ajax. If the response from the server is not OK we will mark this input box as failed. If the response is OK, we proceed to the second step. Checking the other required fields in our form. When there is no failed input box left in the form, we will enable the submit button. There's more... Validation in this example is really basic. We were just checking if the response status from the server is OK. We will probably never meet a validation of the required field like we have here. In this case,it's better to use the length property directly on the client side instead of bothering the server with a lot of requests,simply to check if the required field is empty or filled. This task was just a demonstration of the basic Validationmethod. It would be nice to extend it with regular expressions on the server-side to directly check whether the URL form or the title already exist in our database, and let the user know what the problem is and how he/she can fix it. Creating an autosuggest control This recipe will show us how to create an autosuggest control. This functionality is very useful when we need to search within huge amounts of data. The basic functionality is to display the list of suggested data based on text in the input box. Getting ready We can start with the dummy PHP page which will serve as a data source. When we call this script with GET method and variable string, this script will return the list of records (names) which include the selected string: <?php $string = $_GET["string"]; $arr = array( "Adam", "Eva", "Milan", "Rajesh", "Roshan", // ... "Michael", "Romeo" ); function filter($var){ global $string; if(!empty($string)) return strstr($var,$string); } $filteredArray = array_filter($arr, "filter"); $result = ""; foreach ($filteredArray as $key => $value){ $row = "<li>".str_replace($string, "<strong>".$string."</strong>", $value)."</li>"; $result .= $row; } echo $result; ?> How to do it... As always, we will start with HTML. We will define the form with one input box and an unsorted list datalistPlaceHolder: <h1>Dynamic Dropdown</h1> <form class="simpleValidation"> <div class="fieldRow"> <label>Skype name:</label> <div class="ajaxDropdownPlaceHolder"> <input type="text" id="name" name="name" class="ajaxDropdown" autocomplete="OFF" /> <ul class="datalistPlaceHolder"></ul> </div> </div> </form> When the HTML is ready, we will play with CSS: <style> label { width:80px; float:left; padding:4px; } form{ width:320px; } input, textarea{ width:200px; border:1px solid black; border-radius: 5px; float:right; padding:5px; } input[type=submit] { cursor:pointer; background-color:green; color:#FFF; } input[disabled=disabled] { background-color:#d1d1d1; } fieldRow { margin:10px 10px; overflow:hidden; } validationFailed { border: 1px solid red; } validationPassed { border: 1px solid green; } .datalistPlaceHolder { width:200px; border:1px solid black; border-radius: 5px; float:right; padding:5px; display:none; } ul.datalistPlaceHolder li { list-style: none; cursor:pointer; padding:4px; } ul.datalistPlaceHolder li:hover { color:#FFF; background-color:#000; } </style>   Now the real fun begins. We will include jQuery library and define our keyup events: <script src="js/jquery-1.4.4.js"></script> <script> var timerId; var ajaxDropdownInit = function(){ $('.ajaxDropdown').keyup(function() { var string = $(this).val(); clearTimeout (timerId); timerId = setTimeout(function(){ $.get("ajax/dropDownList.php", {'string':string}, function(data) { if(data) $('.datalistPlaceHolder').show().html(data); else $('.datalistPlaceHolder').hide(); }); }, 500 ); }); } </script> When everything is set, we will call the ajaxDropdownInit function within the document ready function: <script>$(document).ready(function(){ajaxDropdownInit();});</script>  Our autosuggest control is ready. The following screenshot shows the output: How it works... The autosuggest control in this recipe is based on the input box and the list of items in datalistPlaceHolder. After each keyup event of the input box,datalistPlaceHolder will load the list of items from ajax/dropDownList.php via the Ajax function defined in ajaxDropdownInit. A good feature of this recipe is thetimerID variable that,when used with thesetTimeout method, will allow us to send the request on the server only when we stop typing (in our case it is 500 milliseconds). It may not look so important, but it will save a lot of resources. We do not want to wait for the response of "M" typed in the input box, when we have already typed in "Milan". Instead of 5 requests (150 milliseconds each), we have just one. Multiply it, for example, with 10,000 users per day and the effect is huge. There's more... We always need to remember that the response from the server is in the JSON format. [{ 'id':'1', 'contactName':'Milan' },...,{ 'id':'99', 'contactName':'Milan (office)' }] Using JSON objects in JavaScript is not always useful from the performance point of view. Let's imagine we have 5000 contacts in one JSON file. It may take a while to build HTML from 5000 objects but, if we build a JSON object, the code will be as follows: [{ "status": "100", "responseMessage": "Everything is ok! :)", "data": "<li><h2><ahref="#1">Milan</h2></li> <li><h2><ahref="#2">Milan2</h2></li> <li><h2><ahref="#3">Milan3</h2></li>" }] It may take a while to build HTML from 5000 objects but, if we build a JSON object, the code will be as follows: <?php echo "STEP 1"; // Same for 2 and 3 ?> In this case, we will have the complete data in HTML and there is no need to create any logic to create a simple list of items.
Read more
  • 0
  • 0
  • 1950
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at ₹800/month. Cancel anytime
Packt
20 Dec 2011
8 min read
Save for later

Ajax:Basic Utilities

Packt
20 Dec 2011
8 min read
Validating a form using Ajax The main idea of Ajax is to get data from the server in real time without reloading the whole page. In this task we will build a simple form with validation using Ajax. Getting ready As a JavaScript library is used in this task, we will choose jQuery. We will download (if we haven't done it already) and include it in our page. We need to prepare some dummy PHP code to retrieve the validation results. In this example, let's name it inputValidation.php. We are just checking for the existence of a param variable. If this variable is introduced in the GET request, we confirm the validation and send an OK status back to the page: ?php $result = array(); if(isset($_GET["param"])){ $result["status"] = "OK"; $result["message"] = "Input is valid!"; } else { $result["status"] = "ERROR"; $result["message"] = "Input IS NOT valid!"; } echo json_encode($result); ?> How to do it... Let`s start with basic HTML structure. We will define a form with three input boxes and one text area. Of course, it is placed in : <body> <h1>Validating form using Ajax</h1> <form class="simpleValidation"> <div class="fieldRow"> <label>Title *</label> <input type="text" id="title" name="title" class="required" /> </div> <div class="fieldRow"> <label>Url</label> <input type="text" id="url" name="url" value="http://" /> </div> <div class="fieldRow"> <label>Labels</label> <input type="text" id="labels" name="labels" /> </div> <div class="fieldRow"> <label>Text *</label> <textarea id="textarea" class="required"></textarea> </div> <div class="fieldRow"> <input type="submit" id="formSubmitter" value="Submit" disabled="disabled" /> </div> </form> </body> <style> For visual confirmation of the valid input, we will define CSS styles: label{ width:70px; float:left; } form{ width:320px; } input, textarea{ width:200px; border:1px solid black; float:right; padding:5px; } input[type=submit] { cursor:pointer; background-color:green; color:#FFF; } input[disabled=disabled], input[disabled] { background-color:#d1d1d1; } fieldRow { margin:10px 10px; overflow:hidden; } failed { border: 1px solid red; } </style> Now, it is time to include jQuery and its functionality: <script src="js/jquery-1.4.4.js"></script> <script> var ajaxValidation = function(object){ var $this = $(object); var param= $this.attr('name'); var value = $this.val(); $.get("ajax/inputValidation.php", {'param':param, 'value':value }, function(data) { if(data.status=="OK") validateRequiredInputs(); else $this.addClass('failed'); },"json"); } var validateRequiredInputs = function (){ var numberOfMissingInputs = 0; $('.required').each(function(index){ var $item = $(this); var itemValue = $item.val(); if(itemValue.length) { $item.removeClass('failed'); } else { $item.addClass('failed'); numberOfMissingInputs++; } }); var $submitButton = $('#formSubmitter'); if(numberOfMissingInputs > 0){ $submitButton.attr("disabled", true); } else { $submitButton.removeAttr('disabled'); } } </script> We will also initialize the document ready function: <script> $(document).ready(function(){ var timerId = 0; $('.required').keyup(function() { clearTimeout (timerId); timerId = setTimeout(function(){ ajaxValidation($(this)); }, 200); }); }); </script> When everything is ready, our result is as follows: How it works... We created a simple form with three input boxes and one text area. Objects with class required are automatically validated after the keyup event and calling the ajaxValidation function. Our keyup functionality also includes theTimeoutfunction to prevent unnecessary calls if the user is still writing. The validation is based on two steps: Validation of the actual input box: We are passing the inserted text to the ajax/inputValidation.php via Ajax. If the response from the server is not OK we will mark this input box as failed. If the response is OK, we proceed to the second step. Checking the other required fields in our form. When there is no failed input box left in the form, we will enable the submit button. There's more... Validation in this example is really basic. We were just checking if the response status from the server is OK. We will probably never meet a validation of the required field like we have here. In this case,it's better to use the length property directly on the client side instead of bothering the server with a lot of requests,simply to check if the required field is empty or filled. This task was just a demonstration of the basic Validationmethod. It would be nice to extend it with regular expressions on the server-side to directly check whether the URL form or the title already exist in our database, and let the user know what the problem is and how he/she can fix it. Creating an autosuggest control This recipe will show us how to create an autosuggest control. This functionality is very useful when we need to search within huge amounts of data. The basic functionality is to display the list of suggested data based on text in the input box. Getting ready We can start with the dummy PHP page which will serve as a data source. When we call this script with GET method and variable string, this script will return the list of records (names) which include the selected string: <?php $string = $_GET["string"]; $arr = array( "Adam", "Eva", "Milan", "Rajesh", "Roshan", // ... "Michael", "Romeo" ); function filter($var){ global $string; if(!empty($string)) return strstr($var,$string); } $filteredArray = array_filter($arr, "filter"); $result = ""; foreach ($filteredArray as $key => $value){ $row = "<li>".str_replace($string, "<strong>".$string."</strong>", $value)."</li>"; $result .= $row; } echo $result; ?> How to do it... As always, we will start with HTML. We will define the form with one input box and an unsorted list datalistPlaceHolder: <h1>Dynamic Dropdown</h1> <form class="simpleValidation"> <div class="fieldRow"> <label>Skype name:</label> <div class="ajaxDropdownPlaceHolder"> <input type="text" id="name" name="name" class="ajaxDropdown" autocomplete="OFF" /> <ul class="datalistPlaceHolder"></ul> </div> </div> </form> When the HTML is ready, we will play with CSS: <style> label { width:80px; float:left; padding:4px; } form{ width:320px; } input, textarea{ width:200px; border:1px solid black; border-radius: 5px; float:right; padding:5px; } input[type=submit] { cursor:pointer; background-color:green; color:#FFF; } input[disabled=disabled] { background-color:#d1d1d1; } fieldRow { margin:10px 10px; overflow:hidden; } validationFailed { border: 1px solid red; } validationPassed { border: 1px solid green; } .datalistPlaceHolder { width:200px; border:1px solid black; border-radius: 5px; float:right; padding:5px; display:none; } ul.datalistPlaceHolder li { list-style: none; cursor:pointer; padding:4px; } ul.datalistPlaceHolder li:hover { color:#FFF; background-color:#000; } </style> Now the real fun begins. We will include jQuery library and define our keyup events: <script src="js/jquery-1.4.4.js"></script> <script> var timerId; var ajaxDropdownInit = function(){ $('.ajaxDropdown').keyup(function() { var string = $(this).val(); clearTimeout (timerId); timerId = setTimeout(function(){ $.get("ajax/dropDownList.php", {'string':string}, function(data) { if(data) $('.datalistPlaceHolder').show().html(data); else $('.datalistPlaceHolder').hide(); }); }, 500 ); }); } </script> When everything is set, we will call the ajaxDropdownInit function within the document ready function: <script> $(document).ready(function(){ ajaxDropdownInit(); }); </script> Our autosuggest control is ready. The following screenshot shows the output: How it works... The autosuggest control in this recipe is based on the input box and the list of items in datalistPlaceHolder. After each keyup event of the input box,datalistPlaceHolder will load the list of items from ajax/dropDownList.php via the Ajax function defined in ajaxDropdownInit. A good feature of this recipe is thetimerID variable that,when used with thesetTimeout method, will allow us to send the request on the server only when we stop typing (in our case it is 500 milliseconds). It may not look so important, but it will save a lot of resources. We do not want to wait for the response of "M" typed in the input box, when we have already typed in "Milan". Instead of 5 requests (150 milliseconds each), we have just one. Multiply it, for example, with 10,000 users per day and the effect is huge. There's more... We always need to remember that the response from the server is in the JSON format. [{ 'id':'1', 'contactName':'Milan' },...,{ 'id':'99', 'contactName':'Milan (office)' }] Using JSON objects in JavaScript is not always useful from the performance point of view. Let's imagine we have 5000 contacts in one JSON file. It may take a while to build HTML from 5000 objects but, if we build a JSON object, the code will be as follows: [{ "status": "100", "responseMessage": "Everything is ok! :)", "data": "<li><h2><ahref=\"#1\">Milan</h2></li> <li><h2><ahref=\"#2\">Milan2</h2></li> <li><h2><ahref=\"#3\">Milan3</h2></li>" }] It may take a while to build HTML from 5000 objects but, if we build a JSON object, the code will be as follows: <?php echo "STEP 1"; // Same for 2 and 3 ?>   In this case, we will have the complete data in HTML and there is no need to create any logic to create a simple list of items.
Read more
  • 0
  • 0
  • 1570

article-image-setting-online-shopping-cart-drupal-and-ubercart
Packt
19 Dec 2011
7 min read
Save for later

Setting up an online shopping cart with Drupal and Ubercart

Packt
19 Dec 2011
7 min read
(For more resources on Drupal, see here.) Setting up the e-commerce system Ubercart has existed since Drupal 6 so those users who have used Ubercart with Drupal 6 will have some experience setting up and configuring this module for Drupal 7. In this section we'll install and set up the basic Ubercart configuration. Goal Set up the system that will allow visitors to purchase take-out from the website. Additional modules needed Ubercart, Token, Views, CTools, Entity, Token, Rules (http://drupal.org/project/ubercart). Configuring Ubercart In order to utilize an e-commerce solution within a website, you must either build a solution from scratch or use a ready-made solution. Because building a professional e-commerce solution from scratch would take an entire book and weeks or months to build, we are fortunate to have Ubercart, which is a professional quality e-commerce solution tailor-made for Drupal. To begin using Ubercart: Download and install the module from its project page. The current stable release for Drupal 7 is 7.x-3.0-rc3. To use Ubercart, you will also need to install some dependency modules in order to get the best functionality and performance from Ubercart. These dependencies are listed on the Ubercart Website: Token, Views, Rules, CTools, Entity API, Entity Token and Token. Go ahead and install and enable the dependency modules and Ubercart. Once installed, we will begin by enabling the following Ubercart modules: All of the modules in the Ubercart—Core section including Cart, Order, Product, and Store. Then enable the following Core (Optional) modules: Catalog, File downloads, Payment, Product Attributes, Reports, Roles, and Taxes. Then in the Extra section enable the following: Product Kit and Stock. For our Payment method and module enable the Credit card, PayPal, and Test Gateway modules. We will not be shipping any items so we do not need to enable shipping modules at this point. There are a variety of other modules that can be optionally enabled. We will explore some of these in future topics. If you are planning to use the PayPal Express Checkout payment method with Ubercart you should make sure you have enabled the CURL PHP extension for use in your PHP configuration. To do this you can ask your hosting company to enable the CURL extension in your php.ini file. Otherwise if you have access to the php.ini file you can open the file and uncomment the CURL extension to enable it. Then save your php.ini file and restart the Web server. When you check your PHP info via the Drupal status report you should see the following section showing you that the PHP CURL extension is enabled.     Now, you should see the following Ubercart modules that you have enabled on your main modules configuration page:   Ubercart installs a new menu item called Store next to the menu item called Dashboard in the Administer menu bar, which includes the options shown in the following screenshot:   The first thing you'll notice is a warning message telling you that one or more problems exist with your Drupal install. Click on the Status report link. On the Status report page you'll see a warning telling you to enable credit card encryption. In order to use Ubercart for payment processing for your online store transactions you first need to set up an encryption location for your credit card data.   To do this click on the credit card security settings link. That will load the Credit card settings screen. Under Basic Settings, for now let's enable the Test Gateway. Later we'll discuss integrating PayPal but for testing purposes we can use the Test Gateway configuration.   Click on the Security Settings tab. Here we need to set up our card number encryption settings. We can first create a folder outside of our document root (outside of our Drupal directory) but on our web server to hold our encrypted data. We'll create a folder at the root level of our MAMP install called "keys". Go ahead and do this then type in /Applications/MAMP/keys in your Card number encryption key file path field. Also make sure the folder allows for write permissions.   Now click on the PayPal Website Payments Pro tab and disable the gateway for use. Click on the Test Gateway tab and leave this enabled for use. Click on Credit card settings and leave the defaults selected. Under Customer messages you can specify any custom messages you want to show the user if their credit card fails during the transaction process. Click Save configuration. When you save your configuration you should get the following success message: Credit card encryption key file generated. Card data will now be encrypted. The configuration options have been saved. Now, we have successfully set up our payment processing with the Test gateway enabled. We're ready to start using Ubercart. To begin using Ubercart, we will need to: Edit the Configuration settings, which are shown in the following screenshot: Clicking on the Store link allows you to configure several options that control how information on the site is displayed, as well as specify some basic contact information for the site To edit the settings for a section, click on the tab for that section. On the Store settings page, we simply need to update the Store name, Store owner, e-mail address, phone and fax numbers for the store. You can also enter store address information. If your store is not located in the United States, you will also need to modify the Currency Format settings. If you are shipping items you may need to tweak the Weight and Length formats. You can also specify a store help page where you'll provide help information. You can simply create a new page in Drupal and alias it, and then type the alias in here. Once you finish entering your Store settings click the Save configuration button Configuring Ubercart user permissions You should also create a role for store administration, by clicking on User management and then Roles. We will call our role Store Administrator. Click Add role to finish building the role. After the role has been added, click the edit permissions link for the role to define the permissions for the new role. Ubercart includes several sections of permissions including: Catalog Credit Card File Downloads Store Payment Product Product attributes Product kit Order Taxes Since this is an administrative role you may just want to give this staff person all permissions for an admin level role on the site. Go ahead and check off the permissions you need to grant and then save your role's permissions.If your site has employees, you may also want to create a separate role (or several roles) that do not give full control over the store for your employees. For example, you may not want an employee to be able to create or delete products, but you would like them to be able to take new orders. Ubercart provided blocks The Ubercart module ships with a core block that you can enable to make it easier for visitors to your site to see what they have ordered and to check out. Go to your blocks administrative page and you can enable the Shopping cart block to show in one of your block regions. I'll put it in the Sidebar second region. These are the basic configuration options which need to be done after you enable the block. Click on the configure link and then you can title your block, select whether to display the shopping cart icon, make the cart block collapsible, add cart help text ,and more. I'll leave the defaults selected for now. You should see a block admin screen similar to the following:  
Read more
  • 0
  • 0
  • 4606

article-image-article-making-foliage-for-game-assets
Packt
19 Dec 2011
5 min read
Save for later

Making Foliages for Game Assets

Packt
19 Dec 2011
5 min read
In this article by Robin de Jongh, author of Google SketchUp for Game Design, you'll learn about making foliages for game assets. Making Foliage for Game Assets Here's a technique that's one of the mainstays of asset creation. It's completely independent of what Game Engine you use. Let's call it The Invisible Pixel. You can see this technique in action when you take a look in the sample chapter for Google SketchUp for Game Design. This technique adds unparalleled realism to your games. For this short tutorial, you will need a photo of a branch which you can find on http://www.cgtexture.com named Leaves0110. Also, you need to have Photoshop or install GIMP at http://www.gimp.org. Time for action – creating foliage Open the image in GIMP. Go to Filters ¦ Blur ¦ Blur. This blurring of the image helps the Fuzzy Select tool do its magic. Select the Fuzzy Select tool and change the Threshold setting to 20. Click on an area of the cardboard background. Now, select more areas holding down Shift to add them to the selection, as shown next: This way you gradually build up a selection of only the cardboard. Or, in other words, you build up a selection around the branch and leaves. Use the Ctrl key and click if you wish to remove any part of the selection and if it has accidentally selected part of the leaves. When you're part way to finish, but you can't see the wood for the trees, go to Layer ¦ Mask ¦ Add Layer Mask. Select Selection and Invert Mask. Don't worry about the brick background for now. We'll remove this later. You can see better what you're doing now. Go to Select ¦ None. Continue selecting areas of cardboard that remain. You may need to reduce threshold to 15. You can see my progress as shown in the next screenshot: Whenever you want to add your selection to the mask, click on the mask in the Layer Pallet, select the Fill Bucket, and then click inside your selection. You must have the following settings selected: Now, reset your selection, click on the normal layer in the layer pallet, and continue using the Fuzzy Select tool. Continue until you're either happy with the outcome or bored to death. You might have something like the following: Now, there are things you can do to speed up the removal of the fiddly bits you missed. First, use a large brush with the Paint Brush tool on the mask layer to remove all the brick. Then use a smaller brush to remove the stray areas that got away. Right–click on the Layer Mask and select Mask to Selection. Now go to Select ¦ Shrink and type in 2 and click on OK. Go to Select ¦ Invert. Select the layer mask and then use the Fill tool on the same settings as before. Create a black layer and move it below this one, so you can see if there are any haloes around the leaves. This looks pretty good so far, but at the edge of some leaves you can see there's a little light too: You can adjust the mask manually here if you need to unmask any areas such as thin branches. You can also go around the edge if you wish using the Paint Brush tool (with the mask selected) to remove haloes. Now, delete the black background layer. Go to Layer ¦ Transform ¦ Arbitrary Rotation. Use the mouse to rotate the image layer so that the branch is horizontal. Click on Rotate. Now, crop the image. Go to Image ¦ Fit Canvas to Layers. Add a background layer in green. Right–click on the mask. Select Mask to Selection. Now, go to Selection ¦ Feather. Select 2 or 3 pixels and click on OK. Now, create a mask for the green layer. Select the Selection option and deselect Invert Mask. This fills all the gaps you may have accidentally left, with green, so you don't notice. Save the .xcf file. Reduce the images size to 512 pixel wide (you'll learn why, and how to do this in Chapter 3 of Google SketchUp for Game Design). Now, save a copy in the PNG file format named Tree_Branch_512.png. Here's your finished branch. What just happened? You've isolated the branch in the photo from the background. This is usually laborious and the only way to really speed it up is to start with a photo on a plainer background. So, from now on, you can use your own photos taken on a piece of blue card or cloth. It's just the same technique as blue screens used in films. Your image has an alpha channel so that it will appear without the background in SketchUp or a game engine such as Unity 3D. You didn't even need to create the alpha channel because it was created by masking your layers. The reason you shrunk your selection earlier was to get rid of the halo effect—a light color that surrounds alpha masked images that have been poorly cut out. Now, you can import your branch into SketchUp to create a tree, plant, or shrub to use in your games or architectural visualizations. Here are a couple of my attempts, importing the foliage into Google SketchUp and rendering with Kerkythea. I used the Make Fur plugin to arrange the branches:
Read more
  • 0
  • 0
  • 1209

article-image-integrating-ibm-cognos-tm1-ibm-cognos-8-bi
Packt
16 Dec 2011
4 min read
Save for later

Integrating IBM Cognos TM1 with IBM Cognos 8 BI

Packt
16 Dec 2011
4 min read
(For more resources on IBM, see here.) Before proceeding with the actual steps of the recipe, we will take a note of the following integration considerations: The measured Dimension in the TM1 Cube needs to be explicitly identified. The Data Source needs to be created in IBM Cognos Connection which points to the TM1 Cube. New Data Source can also be created from IBM Cognos Framework Manager, but for the sake of simplicity we will be creating that from IBM Cognos Connection itself. The created Data Source is used in IBM Cognos Framework Manager Model to create a Metadata Package and publish to IBM Cognos Connection. Metadata Package can be used to create reports, generate queries, slice and dice, or event management using one of the designer studios available in IBM Cognos BI. We will focus on each of the above steps in this recipe, where we will be using one of the Cubes created as part of demodata TM1 Server application and we will be using the Cube as a Data Source in the IBM Cognos BI layer. Getting ready Ensure that the TM1 Admin Server service is started and demodata TM1 Server is running. We should have IBM Cognos 8 BI Server running and IBM Cognos 8 Framework Manager installed. How to do it... Open the TM1 Architect and right-click on the Sales_Plan Cube. Click on Properties. In the Measures Dimension box, click on Sales_Plan_Measures and then for Time Dimension click on Months. Note that the preceding step is compulsory if we want to use the Cube as a Data Source for the BI layer. We need to explicitly define a measures dimension and a time dimension. Click on OK and minimize the TM1 Architect, keep the server running. Now from the Start menu, open IBM Cognos Framework Manager, which is desktop-based tool used to create metadata models. Create a new project from IBM Cognos 8 Framework Manager. Enter the Project name as Demodata and provide the Location where the model file will be located. Note that each project generates a .cpf file which can be opened in the IBM Cognos Framework Manager. Provide valid user credentials so that IBM Cognos Framework Manager can link to a running IBM Cognos BI Server setup. Users and roles are defined by IBM Cognos BI admin user. Choose English as the authoring language when the Select Language list comes up. This will open the Metadata Wizard - Select Metadata Source. We use the Metadata Wizard to create a new Data Source or point to an existing Data Source. In the Metadata Wizard make sure that Data Sources is selected and click on the Next button. In the next screen, click on the New button to create a new Data Source by the name of TM1_Demodata_Sales_Plan. This will open a New data source wizard, where we need to specify the name of the Data Source. On next screen, it will ask for the Data Source Type for which we will specify TM1 from the drop-down, as we want to create a new Data Source based on the TM1 Cube Sales_Data. On the next screen specify the connection parameters. For Administration Host we can specify a name or localhost, depending on the name of the server. In our case, we have specified name of the server as ankitgar, hence we are using an actual name instead of a localhost. In the case of TM1 sitting on another server within the network, we will provide the IP address or name of the host in UNC format. Test the connection to test whether the connection to the TM1 Cube is successful. Click on Close and proceed. Click on the Finish button to complete the creation of the Data Source. The new Data Source is created on the Cognos 8 Server and now can be used by anyone with valid privileges given by the admin user. It's just a connection to the Sales_Plan TM1 Cube which now can be used to create metadata models and, hence, reports and queries perform the various functions suggested in the preceding sections. Now it will return to Metadata Wizard as shown, with the new Data Source appearing with the list of already created Data Sources. Click on the newly created Data Source and on the Next button. It will display all available Cubes on the DemoData TM1 Server, the machine name being the server name (localhost/ankitgar). Click on the Sales_Plan cube and then on Next.
Read more
  • 0
  • 0
  • 3894
article-image-wordpress-customizing-content-display
Packt
14 Dec 2011
8 min read
Save for later

WordPress: Customizing Content Display

Packt
14 Dec 2011
8 min read
(For more resources on WordPress, see here.) At its most basic, a simple implementation of the loop could work like this: <?php if (have_posts()) : while (have_posts()) : the_post(); ?><?php the_title(); ?><?php the_content(); ?><?php endwhile; else: ?><p>Sorry, no posts matched your criteria.'</p><?php endif; ?> In the real world, however, the WordPress loop is rarely that simple. This is one of those concepts best explained by referring to a real world example, so open up the index.php file of your system's TwentyEleven theme. Look for the following lines of code: <?php if ( have_posts() ) : ?><?php twentyeleven_content_nav( 'nav-above' ); ?><?php /* Start the Loop */ ?><?php while ( have_posts() ) : the_post(); ?><?php get_template_part( 'content', get_post_format()); ?><?php endwhile; ?><?php twentyeleven_content_nav( 'nav-below' ); ?><?php else : ?><article id="post-0" class="post no-results not-found"><header class="entry-header"><h1 class="entry-title"><?php _e( 'Nothing Found','twentyeleven' ); ?></h1></header><!-- .entry-header --><div class="entry-content">3<p><?php _e( 'Apologies, but no results were foundfor the requested archive. Perhaps searching will helpfind a related post.', 'twentyeleven' ); ?></p><?php get_search_form(); ?></div><!-- .entry-content --></article><!-- #post-0 --><?php endif; ?> Most of the extra stuff seen in the loop from TwentyEleven is there to add in additional page elements, including content navigation; there's also some code to control what happens if there are no posts to display. The nature of the WordPress loops means that theme authors can add in what they want to display and thereby customize and control the output of their site. As you would expect, the WordPress Codex includes an extensive discussion of the WordPress loop. Visit http://codex.wordpress.org/The_Loop. Accessing posts within the WordPress loop In this recipe, we look at how to create a custom template that includes your own implementation of the WordPress loop. Getting ready All you need to execute this recipe is your favorite code editor and access to the WordPress files on your server. You will also need a theme template file, which we will use to hold our modified WordPress loop. How to do it Let's assume you have created a custom template. Inside of that template you will want to include the WordPress loop. Follow these steps to add the loop, along with a little customization: Access the active theme files on your WordPress installation. Find a template file and open it for editing. If you're not sure which one to use, try the index.php file. Add to the file the following line of code, which will start the loop: <?php if ( have_posts() ) : while ( have_posts() ) : the_post();?> Next, let's display the post title, wrapped in an h2 tag: <h2><?php the_title() ?></h2> Let's also add a link to all posts by this author. Add this code immediately below the previous line: <?php the_author_posts_link() ?> For the post content, let's wrap it in a div for easy styling: <div class="thecontent"><?php the_content(); ?></div> Next, let's terminate the loop and add some code to display a message if there were no posts to display: <?php endwhile; else: ?><p>Oops! There are no posts to display.</p> Finally, let's put a complete stop to the loop by ending the if statement that began the code in step number 3, above: <?php endif; ?> Save the file. That's all there is to it. Your code should look like this: ?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?><h2><?php the_title() ?></h2><?php the_author_posts_link() ?><div class="thecontent"><?php the_content(); ?></div><?php endwhile; else: ?><p>Oops! There are no posts to display.</p><?php endif; ?> How it works... This basic piece of code first checks if there are posts in your site. If the answer is yes, the loop will repeat until every post title and their contents are displayed on the page. The post title is displayed using the_title(). The author's name and link are added with the_ author_posts_link() function. The content is displayed with the_content() function and styled by the div named thecontent. Finally, if there are no posts to display, the code will display the message Oops! There are no posts to display. There's more... In the preceding code you saw the use of two template tags: the_author_posts_link and the_content. These are just two examples of the many template tags available in WordPress. The tags make your life easier by reducing an entire function to just a short phrase. You can find a full list of the template tags at: http://codex.wordpress.org/ Template_Tags. The template tags can be broken down into a number of categories: General tags: The tags in this category cover general page elements common to most templates Author tags: Tags related to author information Bookmark tags: The tag to list bookmarks Category tags: Category, tag, and item description-related Comment tags: Tags covering the comment elements Link tags: Tags for links and permalinks Post tags: Tags for posts, excerpts, titles, and attachments Post Thumbnail tags: Tags that relate to the post thumbnails Navigation Menu tags: Tags for the nav menu and menu tree Retrieving posts from a specific category There are times when you might wish to display only those posts that belong to a specific category, for example, perhaps you want to show only the featured posts. With a small modification to the WordPress loop, it's easy to grab only those posts you want to display. In this recipe we introduce query_posts(),which can be used to control which posts are displayed by the loop. Getting ready To execute this recipe, you will need a code editor and access to the WordPress files on your server. You will also need a theme template file, which we will use to hold our modified WordPress loop. To keep this recipe short and to the point, we use the loop we created in the preceding recipe. How to do it... Let's create a situation where the loop shows only those posts assigned to the Featured category. To do this, you will need to work through two different processes. First, you need to find the category ID number of the Featured category. To do this, follow these steps: Log in to the Dashboard of your WordPress site. Click on the Posts menu. Click on the Categories option. Click on the category named Featured. Look at the address bar of your browser and you will notice that part of the string looks something like this:&tag_ID=9. On the site where we are working, the Featured category has the ID of 9. Category IDs vary from site to site. The ID used in this recipe may not be the same as the ID for your site! Next, we need to add a query to our loop that will extract only those posts that belong to the Featured category, that is, to those posts that belong to the category with the ID of 9. Follow these steps: Open the file that contains the loop. We'll use the same file we created in the preceding recipe. Find the loop: <?php if ( have_posts() ) : while ( have_posts() ) :the_post(); ?><h2><?php the_title() ?></h2><?php the_author_posts_link() ?><div class="thecontent"><?php the_content(); ?></div><?php endwhile; else: ?><p>Oops! There are no posts to display.</p><?php endif; ?> Add the following line of code immediately above the loop: <?php query_posts($query_string.'&cat=9'); ?> Save the file. That's all there is to it. If you visit your site, you will now see that the page displays only the posts that belong to the category with the ID of 9. How it works... The query_posts() function modifies the default loop. When used with the cat parameter, it allows you to specify one or more categories that you want to use as filters for the posts. For example: query_posts(&query_string.'&cat=5');: Get posts from the category with ID 5 only query_posts(&query_string.'&cat=5,6,9');: Get posts from the category with IDs 5, 6, and 9 query_posts(&query_string.'&cat=-3');: Get posts from all categories, except those from the category with ID 3 For more information, visit the WordPRess Codex page on query posts: http://codex.wordpress.org/Function_Reference/query_posts
Read more
  • 0
  • 0
  • 5152

article-image-article-integrating-ios-features-using-monotouch
Packt
13 Dec 2011
10 min read
Save for later

Integrating iOS Features Using MonoTouch

Packt
13 Dec 2011
10 min read
(For more resources on this topic, see here.) Mobile devices offer a handful of features to the user. Creating an application that interacts with those features to provide a complete experience to users can surely be considered as an advantage. In this article, we will discuss some of the most common features of iOS and how to integrate some or all of their functionality to our applications. We will see how to offer the user the ability to make telephone calls and send SMS and e-mails, either by using the native platform applications, or by integrating the native user interface in our projects. Also, we will discuss the following components: MFMessageComposeViewController: This controller is suitable for sending text (SMS) messagesIntegrating iOS Features MFMailComposeViewController: This is the controller for sending e-mails with or without attachments ABAddressBook: This is the class that provides us access to the address book database ABPersonViewController: This is the controller that displays and/or edits contact information from the address book EKEventStore: This is the class that is responsible for managing calendar events Furthermore, we will learn how to read and save contact information, how to display contact details, and interact with the device calendar. Note that some of the examples in this article will require a device. For example, the simulator does not contain the messaging application. To deploy to a device, you will need to enroll as an iOS Developer through Apple's Developer Portal and obtain a commercial license of MonoTouch. Starting phone calls In this recipe, we will learn how to invoke the native phone application to allow the user to place a call. Getting ready Create a new project in MonoDevelop, and name it PhoneCallApp. The native phone application is not available on the simulator. It is only available on an iPhone device. How to do it... Add a button on the view of MainController, and override the ViewDidLoad method. Implement it with the following code. Replace the number with a real phone number, if you actually want the call to be placed: this.buttonCall.TouchUpInside += delegate {  NSUrl url = new NSUrl("tel:+123456789012");  if (UIApplication.SharedApplication.CanOpenUrl(url)){    UIApplication.SharedApplication.OpenUrl(url);  }  else{    Console.WriteLine("Cannot open url: {0}", url.AbsoluteString);  }} ; Compile and run the application on the device. Tap the Call! button to start the call. The following screenshot shows the phone application placing a call: How it works... Through the UIApplication.SharedApplication static property, we have access to the application's UIApplication object. We can use its OpenUrl method, which accepts an NSUrl variable to initiate a call: UIApplication.SharedApplication.OpenUrl(url); Since not all iOS devices support the native phone application, it would be useful to check for availability frst: if (UIApplication.SharedApplication.CanOpenUrl(url))   When the OpenUrl method is called, the native phone application will be executed, and it will start calling the number immediately. Note that the tel: prefx is needed to initiate the call. There's more... MonoTouch also supports the CoreTelephony framework, through the MonoTouch. CoreTelephony namespace. This is a simple framework that provides information on call state, connection, carrier info, and so on. Note that when a call starts, the native phone application enters into the foreground, causing the application to be suspended. The following is a simple usage of the CoreTelephony framework: CTCallCenter callCenter = new CTCallCenter();callCenter.CallEventHandler = delegate(CTCall call) {  Console.WriteLine(call.CallState);} ;   Note that the handler is assigned with an equals sign (=) instead of the common plus-equals (+=) combination. This is because CallEventHandler is a property and not an event. When the application enters into the background, events are not distributed to it. Only the last occured event will be distributed when the application returns to the foreground. More info on OpenUrl The OpenUrl method can be used to open various native and non-native applications. For example, to open a web page in Safari, just create an NSUrl object with the following link: NSUrl url = new NSUrl("http://www.packtpub.com");   See also In this article: Sending text messages and e-mails Sending text messages and e-mails In this recipe, we will learn how to invoke the native mail and messaging applications within our own application. Getting ready Create a new project in MonoDevelop, and name it SendTextApp. How to do it... Add two buttons on the main view of MainController. Override the ViewDidLoad method of the MainController class, and implement it with the following code: this.buttonSendText.TouchUpInside += delegate {  NSUrl textUrl = new NSUrl("sms:");  if (UIApplication.SharedApplication.CanOpenUrl(textUrl)){    UIApplication.SharedApplication.OpenUrl(textUrl);  } else{    Console.WriteLine("Cannot send text message!");  }} ;this.buttonSendEmail.TouchUpInside += delegate {  NSUrl emailUrl = new NSUrl("mailto:");  if (UIApplication.SharedApplication.CanOpenUrl(emailUrl)){    UIApplication.SharedApplication.OpenUrl(emailUrl);  } else{    Console.WriteLine("Cannot send e-mail message!");  }} ; Compile and run the application on the device. Tap on one of the buttons to open the corresponding application. How it works... Once again, using the OpenUrl method, we can send text or e-mail messages. In this example code, just using the sms: prefx will open the native text messaging application. Adding a cell phone number after the sms: prefx will open the native messaging application: UIApplication.SharedApplication.OpenUrl(new NSUrl("sms:+123456789012"));     Apart from the recipient number, there is no other data that can be set before the native text message application is displayed. For opening the native e-mail application, the process is similar. Passing the mailto: prefx opens the edit mail controller. UIApplication.SharedApplication.OpenUrl(new NSUrl("mailto:"));     The mailto: url scheme supports various parameters for customizing an e-mail message. These parameters allows us to enter sender address, subject, and message: UIApplication.SharedApplication.OpenUrl("mailto:recipient@example.com?subject=Email%20with%20MonoTouch!&body=This%20is%20the%20message%20body!"); There's more... Although iOS provides access to opening the native messaging applications, pre-defning message content in the case of e-mails, this is where the control from inside the application stops. There is no way of actually sending the message through code. It is the user that will decide whether to send the message or not. More info on opening external applications The OpenUrl method provides an interface for opening the native messaging applications. Opening external applications has one drawback: the application that calls the OpenUrl method transitions to the background. Up to iOS version 3.*, this was the only way of providing messaging through an application. Since iOS version 4.0, Apple has provided the messaging controllers to the SDK. The following recipes discuss their usage. See also In this article: Starting phone calls Using text messaging in our application Using text messaging in our application In this recipe, we will learn how to provide text messaging functionality within our application using the native messaging user interface. Getting ready Create a new project in MonoDevelop, and name it TextMessageApp. How to do it... Add a button on the view of MainController. Enter the following using directive in the MainController.cs fle: using MonoTouch.MessageUI; Implement the ViewDidLoad method with the following code, changing the recipient number and/or the message body at your discretion: private MFMessageComposeViewController messageController;public override void ViewDidLoad (){  base.ViewDidLoad ();  this.buttonSendMessage.TouchUpInside += delegate {    if (MFMessageComposeViewController.CanSendText){      this.messageController = new          MFMessageComposeViewController();      this.messageController.Recipients = new          string[] { "+123456789012" };      this.messageController.Body = "Text from MonoTouch";      this.messageController.MessageComposeDelegate =          new MessageComposerDelegate();      this.PresentModalViewController(         this.messageController, true);    } else{      Console.WriteLine("Cannot send text message!");    }  } ;} Add the following nested class: private class MessageComposerDelegate :    MFMessageComposeViewControllerDelegate{  public override void Finished (MFMessageComposeViewController     controller, MessageComposeResult result){    switch (result){      case MessageComposeResult.Sent:        Console.WriteLine("Message sent!");      break;      case MessageComposeResult.Cancelled:        Console.WriteLine("Message cancelled!");      break;      default:        Console.WriteLine("Message sending failed!");      break;    }    controller.DismissModalViewControllerAnimated(true);  }} Compile and run the application on the device. Tap the Send message button to open the message controller. Tap the Send button to send the message, or the Cancel button to return to the application. How it works... The MonoTouch.MessageUI namespace contains the necessary UI elements that allow us to implement messaging in an iOS application. For text messaging (SMS), we need the MFMessageComposeViewController class. Only the iPhone is capable of sending text messages out of the box. With iOS 5, both the iPod and the iPad can send text messages, but the user might not have enabled this feature on the device. For this reason, checking for availability is the best practice. The MFMessageComposeViewController class contains a static method, named CanSendText, which returns a boolean value indicating whether we can use this functionality. The important thing in this case is that we should check if sending text messages is available prior to initializing the controller. This is because when you try to initialize the controller on a device that does not support text messaging, or the simulator, you will get the following message on the screen:   To determine when the user has taken action in the message UI, we implement a Delegate object and override the Finished method: private class MessageComposerDelegate :    MFMessageComposeViewControllerDelegate   Another option, provided by MonoTouch, is to subscribe to the Finished event of the MFMessageComposeViewController class. Inside the Finished method, we can provide functionality according to the MessageComposeResult parameter. Its value can be one of the following three: Sent: This value indicates that the message was sent successfully Cancelled: This value indicates that the user has tapped the Cancel button, and the message will not be sent Failed: This value indicates that message sending failed The last thing to do is to dismiss the message controller, which is done as follows: controller.DismissModalViewControllerAnimated(true);   After initializing the controller, we can set the recipients and body message to the appropriate properties: this.messageController.Recipients = new string[] { "+123456789012" };this.messageController.Body = "Text from MonoTouch";   The Recipients property accepts a string array that allows for multiple recipient numbers. You may have noticed that the Delegate object for the message controller is set to its MessageComposeDelegate property, instead of the common Delegate. This is because the MFMessageComposeViewController class directly inherits from the UINavigationController class, so the Delegate property accepts values of the type UINavigationControllerDelegate. There's more... The fact that the SDK provides the user interface to send text messages does not mean that it is customizable. Just like invoking the native messaging application, it is the user who will decide whether to send the message or discard it. In fact, after the controller is presented on the screen, any attempts to change the actual object or any of its properties will simply fail. Furthermore, the user can change or delete both the recipient and the message body. The real beneft though is that the messaging user interface is displayed within our application, instead of running separately. SMS only The MFMessageComposeViewController can only be used for sending Short Message Service (SMS) messages and not Multimedia Messaging Service (MMS).
Read more
  • 0
  • 0
  • 3561

article-image-creating-basic-vaadin-project
Packt
13 Dec 2011
10 min read
Save for later

Creating a Basic Vaadin Project

Packt
13 Dec 2011
10 min read
  (For more resources on this topic, see here.)   Understanding Vaadin In order to understand Vaadin, we should first understand what is its goal regarding the development of web applications. Vaadin's philosophy Classical HTML over HTTP application frameworks are coupled to the inherent request/response nature of the HTTP protocol. This simple process translates as follows: The client makes a request to access an URL. The code located on the server parses request parameters (optional). The server writes the response stream accordingly. The response is sent to the client. All major frameworks (and most minor ones, by the way) do not question this model: Struts, Spring MVC, Ruby on Rails, and others, completely adhere to this approach and are built upon this request/response way of looking at things. It is no mystery that HTML/HTTP application developers tend to comprehend applications through a page-flow filter. On the contrary, traditional client-server application developers think in components and data binding because it is the most natural way for them to design applications (for example, a select-box of countries or a name text field). A few recent web frameworks, such as JSF, tried to cross the bridge between components and page-flow, with limited success. The developer handles components, but they are displayed on a page, not a window, and he/she still has to manage the flow from one page to another. The Play Framework (http://www.playframework.org/) takes a radical stance on the page-flow subject, stating that the Servlet API is a useless abstraction on the request/response model and sticks even more to it. Vaadin's philosophy is two-fold: It lets developers design applications through components and data bindings It isolates developers as much as possible from the request/response model in order to think in screens and not in windows This philosophy lets developers design their applications the way it was before the web revolution. In fact, fat client developers can learn Vaadin in a few hours and start creating applications in no time. The downside is that developers, who learned their craft with the thin client and have no prior experience of fat client development, will have a hard time understanding Vaadin as they are inclined to think in page-flow. However, they will be more productive in the long run. Vaadin's architecture In order to achieve its goal, Vaadin uses an original architecture. The first fact of interest is that it is comprised of both a server and a client side. The client side manages thin rendering and user interactions in the browser The server side handles events coming from the client and sends changes made to the user interface to the client Communication between both tiers is done over the HTTP protocol. We will have a look at each of these tiers.   Client server communication Messages in Vaadin use three layers: HTTP, JSON, and UIDL. The former two are completely un-related to the Vaadin framework and are supported by independent third parties; UIDL is internal. HTTP protocol Using the HTTP protocol with Vaadin has the following two main advantages: There is no need to install anything on the client, as browsers handle HTTP (and HTTPS for that matter) natively. Firewalls that let pass the HTTP traffic (a likely occurrence) will let Vaadin applications function normally. JSON message format Vaadin messages between the client and the server use JavaScript Objects Notation (JSON). JSON is an alternative to XML that has the following several differences: First of all, the JSON syntax is lighter than the XML syntax. XML has both a start and an end tag, whereas JSON has a tag coupled with starting brace and ending brace. For example, the following two code snippets convey the same information, but the first requires 78 characters and the second only 63. For a more in depth comparison of JSON and XML, refer to the following URL: http://json.org/xml.html <person> <firstName>John</firstName> <lastName>Doe</lastName> </person> {"person" { {"firstName": "John"}, {"lastName": "Doe"} } The difference varies from message to message, but on an average, it is about 40%. It is a real asset only for big messages, and if you add server GZIP compression, size difference starts to disappear. The reduced size is no disadvantage though. Finally, XML designers go to great length to differentiate between child tags and attributes, the former being more readable to humans and the latter to machines. JSON messages design is much simpler as JSON has no attributes. UIDL "schema" The last stack that is added to JSON and HTTP is the User Interface Definition Language (UIDL). UIDL describes complex user interfaces with JSON syntax. The good news about these technologies is that Vaadin developers won't be exposed to them. The client part The client tier is a very important tier in web applications as it is the one with which the end user directly interacts. In this endeavor, Vaadin uses the excellent Google Web Toolkit (GWT) framework. In the GWT development, there are the following mandatory steps: The code is developed in Java. Then, the GWT compiler transforms the Java code in JavaScript. Finally, the generated JavaScript is bundled with the default HTML and CSS files, which can be modified as a web application. Although novel and unique, this approach provides interesting key features that catch the interest of end users, developers, and system administrators alike: Disconnected capability, in conjunction with HTML 5 client-side data stores Displaying applications on small form factors, such as those of handheld devices Development only with the Java language Excellent scalability, as most of the code is executed on the client side, thus freeing the server side from additional computation On the other hand, there is no such thing as a free lunch! There are definitely disadvantages in using GWT, such as the following: The whole coding/compilation/deployment process adds a degree of complexity to the standard Java web application development. Although a Google GWT plugin is available for Eclipse and NetBeans, IDEs do not provide standard GWT development support. Using GWT development mode directly or through one such plugin is really necessary, because without it, developing is much slower and debugging almost impossible. For more information about GWT dev mode, please refer to the following URL: http://code.google.com/intl/en/webtoolkit/doc/latest/DevGuideCompilingAndDebugging.html There is a consensus in the community that GWT has a higher learning curve than most classic web application frameworks; although the same can be said for others, such as JSF. If the custom JavaScript is necessary, then you have to bind it in Java with the help of a stack named JavaScript Native Interface (JSNI), which is both counter-intuitive and complex. With pure GWT, developers have to write the server-side code themselves (if there is any). Finally, if ever everything is done on the client side, it poses a great security risk. Even with obfuscated code, the business logic is still completely open for inspection from hackers. Vaadin uses GWT features extensively and tries to downplay its disadvantages as much as possible. This is all possible because of the Vaadin server part. The server part Vaadin's server-side code plays a crucial role in the framework. The biggest difference in Vaadin compared to GWT is that developers do not code the client side, but instead code the server side that generates the former. In particular, in GWT applications, the browser loads static resources (the HTML and associated JavaScript), whereas in Vaadin, the browser accesses the servlet that serves those same resources from a JAR (or the WEB-INF folder). The good thing is that it completely shields the developer from the client-code, so he/she cannot make unwanted changes. It may be also seen as a disadvantage, as it makes the developer unable to change the generated JavaScript before deployment. It is possible to add custom JavaScript, although it is rarely necessary. In Vaadin, you code only the server part! There are two important tradeoffs that Vaadin makes in order achieve this: As opposed to GWT, the user interface related code runs on the server, meaning Vaadin applications are not as scalable as pure GWT ones. This should not be a problem in most applications, but if you need to, you should probably leave Vaadin for some less intensive part of the application; stick to GWT or change an entirely new technology. While Vaadin applications are not as scalable as applications architecture around a pure JavaScript frontend and a SOA backend, a study found that a single Amazon EC2 instance could handle more than 10,000 concurrent users per minute, which is much more than your average application. The complete results can be found at the following URL: http://vaadin.com/blog/-/blogs/vaadin-scalabilitystudy-quicktickets Second, each user interaction creates an event from the browser to the server. This can lead to changes in the user interface's model in memory and in turn, propagate modifications to the JavaScript UI on the client. The consequence is that Vaadin applications simply cannot run while being disconnected from the server! If your requirements include the offline mode, then forget Vaadin. Terminal and adapter As in any low-coupled architecture, not all Vaadin framework server classes converse with the client side. In fact, this is the responsibility of one simple interface: com.vaadin.terminal.Terminal. In turn, this interface is used by a part of the framework aptly named as the Terminal Adapter, for it is designed around the Gang of Four Adapter (http://www.vincehuston.org/dp/adapter.html) pattern. This design allows for the client and server code to be completely independent of each other, so that one can be changed without changing the other. Another benefit of the Terminal Adapter is that you could have, for example, other implementations for things such as Swing applications. Yet, the only terminal implementation provided by the current Vaadin implementation is the web browser, namely com.vaadin.terminal.gwt.server.WebBrowser. However, this does not mean that it will always be the case in the future. If you are interested, then browse the Vaadin add-ons directory regularly to check for other implementations, or as an alternative, create your own! Client server synchronization The biggest challenge when representing the same model on two heterogeneous tiers is synchronization between each tier. An update on one tier should be reflected on the other or at least fail gracefully if this synchronization is not possible (an unlikely occurrence considering the modern day infrastructure). Vaadin's answer to this problem is a synchronization key generated by the server and passed on to the client on each request. The next request should send it back to the server or else the latter will restart the current session's application. This may be the cause of the infamous and sometimes frustrating "Out of Sync" error, so keep that in mind.  
Read more
  • 0
  • 0
  • 3062
article-image-google-apps-surfing-web
Packt
13 Dec 2011
8 min read
Save for later

Google Apps: Surfing the Web

Packt
13 Dec 2011
8 min read
Browsing and using websites Back in the day, when I first started writing, there were two ways to research—own a lot of books (I did and still do), and/or spend a lot of time at the library (I did, don't have to now). This all changed in the early 90s when Sir Tim Berners-Lee invented the World Wide Web (WWW) . The web used the Internet, which was already there, although Al Gore did not invent the Internet. Although earlier experiments took place, Vinton Cerf's development of the basic transmission protocols making all we enjoy today possible gives him the title "Father of the Internet". All of us reading this book use the Internet and the web almost every day. App Inventor itself relies extensively on the web; you have to use the web in designing apps and downloading the Blocks Editor to power them up. Adding web browsing to our apps gives us: Access to literally trillions of web pages (no one knows how many; Google said it was over a trillion in 2008, and growth has been tremendous since then). Lets us leverage the limited resources and storage capacity of the user's phone by many times as we use the millions of dollars invested in server farms (vast collections of interconnected computers) and thousands of web pages on commercial sites (which they want us to use, even beg us to use because it promotes their products or services). Makes it possible to write powerful and useful apps with really little effort on our part. Take, for example, what I referred to earlier in this book as a link app. This is an app that, when called by the user, simply uses ActivityStarter to open a browser and load a web page. Let's whip one up. Time for action – building an eBay link app Yes, eBay loves us—especially if we buy or sell items on this extensive online auction site. And they want you to do it not just at home but when you're out with only your smartphone. To encourage use from your phone, eBay has spent a gazillion dollars (that's a lot) in providing a mobile site (http://m.ebay.com) that makes the entire eBay site (hundreds of thousands, probably millions of pages) available and useful to you. Back to that word, leverage—the ancient Greek mathematician, Archimedes, said about levers, "Give me a place to stand on and I will move the Earth." Our app's leverage won't move the Earth, but we can sure bid on just about everything on it. Okay, the design of our eBay app is very simple since the screen will be there for only a second or so. I'll explain that in a moment. So, we need just a label and two non-visual components: ActivityStarter and Clock. In the Properties column for the ActivityStarter, put android.intent.action.VIEW in the Action field (again, this is how your app calls the phone's web browser, and the way it's entered is case-sensitive). This gives us something as shown in the following screenshot (with a little formatting added): Now, the reason for the LOADING...nInternet connection required (in the label, n being a line break) is a basic notifier and error trap. First, if the Internet connection is slow, it lets the user know something is happening. Second, if there is not 3G or Wi-Fi connection, it tells the user why nothing will happen until they get a connection. Simple additions like the previous (basically thinking of the user's experience in using our apps) define the difference between amateur and professional apps. Always try to anticipate, because if we leave any way possible at all to screw it up, some user will find it. And who gets blamed? Right. You, me, or whatever idiot wrote that defective app. And they will zing you on Android Market. Okay, now to our buddy: the Blocks Editor. We need only one small block group. Everything is in the Clock1.Timer block to connect to the eBay mobile site and then, job done, gracefully exit. Inside the clock timer frame, we put four blocks, which accomplish the following logic: In our ActivityStarter1.DataUri goes the web address of the eBay mobile website home: http://m.ebay.com. The ActivityStarter1.StartActivity block calls the phone's web browser and passes the address to it. Clock1.TimerAlwaysFires set to false tells AI, "Stop, don't do anything else." Finally, the close application block (which we should always be nice and include somewhere in our apps) removes the app from the phone or other Android device's memory, releasing those always scarce resources. Make a nice icon, and it's ready to go onto Android Market (I put mine on as eBay for Droids). What just happened? That's it—a complete application giving access to a few million great bargains on eBay. This is how it will look when the eBay mobile site home page opens on the user's phone: Pretty neat, huh? And there are lots of other major sites out there that offer mobile sites, easily converted into link apps such as this eBay example. But, what if you want to make the app more complex with a lot of choices? One that after the user finishes browsing a site, they come back to your app and choose yet another site to visit? No problem. Here's an example of that. I recently published an app called AVLnews (AVL is the airport code for Asheville, North Carolina where I live). This app actually lets the user drill down into local news for all 19 counties in the Western North Carolina mountains. Here's what the front page of the app looks like: Even with several pages of choices, this type of app is truly easy to create. You need only a few buttons, labels, and (as ever) horizontal and vertical arrangements for formatting. And, of course, add a single ActivityStarter for calling the phone's web browser. Now, here's the cool part! No matter how long and how many pages your user reads on the site a button sends him to, when he or she hits the hardware Back button on their phone, they return to your app. The preceding is the only way the Back button works for an App Inventor app! If user is within an AI app and hits the Back button, it immediately kills your app (except when a listpicker is displayed, in which case it returns you to the screen that invoked it). This is doubleplusungood, so to speak. So, always supply navigation buttons for changing pages and maybe a note somewhere not to use the hardware button. Okay, back to my AVLnews app as an example. The first button I built was for the Citizen-Times, our major newspaper in the area. They have a mobile site such as the one we saw earlier for eBay. It looks nice and is easy to read on a Droid or other smartphone, like the following: And, it's equally easy to program—this is all you need: I then moved on to other news sources for the areas. The small weekly newspapers in the more isolated, outlying mountain counties have no expensive mobile sites. The websites they do have are pretty conventional. But, when I linked to them, the page would come up with tiny, unreadable type. I had to move it around, do the double tap on the content to fit to the page trick to expand the page, turn the phone on its side, and many such more, and still had trouble reading stuff. Folks, you do not do things like that to your users. Not if you want them to think you are one cool app inventor, as I know you to be by now. So, here's the trick to making almost all web pages readable on a phone—Google Mobilizer! It's a free service of Google at http://www.google.com/gwt/n. Use it to construct links that return a nicely formatted and readable page as shown in the next screenshot. People will thank you for it and think you expended many hours of genius-level programming effort to achieve it. And, remember, it's not polite to disagree with people, eh? Often, the search terms and mobilizing of your link is long and goes on for some time (the following screenshot is only a part of it). However, that's where your real genius comes into play: building a search term that gets the articles fitting whatever is the topic on the button. Summing up: using the power of the web lets us build powerful apps that use few resources on the phone yet return thousands upon thousands of pages. Enjoy. Now, we will look at yet another Google service: Fusion Tables. And see how our App Inventor apps can take advantage of these online data sources.  
Read more
  • 0
  • 0
  • 2591

article-image-cocos2d-working-sprites
Packt
13 Dec 2011
6 min read
Save for later

Cocos2d: Working with Sprites

Packt
13 Dec 2011
6 min read
  (For more resources on Cocos2d, see here.)   Drawing sprites The most fundamental task in 2D game development is drawing a sprite. Cocos2d provides the user with a lot of flexibility in this area. In this recipe we will cover drawing sprites using CCSprite, spritesheets, CCSpriteFrameCache, and CCSpriteBatchNode. We will also go over mipmapping. In this recipe we see a scene with Alice from Through The Looking Glass. Getting ready Please refer to the project RecipeCollection01 for the full working code of this recipe. How to do it... Execute the following code: @implementation Ch1_DrawingSprites-(CCLayer*) runRecipe { /*** Draw a sprite using CCSprite ***/ CCSprite *tree1 = [CCSprite spriteWithFile:@"tree.png"]; //Position the sprite using the tree base as a guide (y anchor point = 0)[tree1 setPosition:ccp(20,20)]; tree1.anchorPoint = ccp(0.5f,0); [tree1 setScale:1.5f]; [self addChild:tree1 z:2 tag:TAG_TREE_SPRITE_1]; /*** Load a set of spriteframes from a PLIST file and draw one byname ***/ //Get the sprite frame cache singleton CCSpriteFrameCache *cache = [CCSpriteFrameCachesharedSpriteFrameCache]; //Load our scene sprites from a spritesheet [cache addSpriteFramesWithFile:@"alice_scene_sheet.plist"]; //Specify the sprite frame and load it into a CCSprite CCSprite *alice = [CCSprite spriteWithSpriteFrameName:@"alice.png"]; //Generate Mip Maps for the sprite [alice.texture generateMipmap]; ccTexParams texParams = { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE }; [alice.texture setTexParameters:&texParams]; //Set other information. [alice setPosition:ccp(120,20)]; [alice setScale:0.4f]; alice.anchorPoint = ccp(0.5f,0); //Add Alice with a zOrder of 2 so she appears in front of othersprites [self addChild:alice z:2 tag:TAG_ALICE_SPRITE]; //Make Alice grow and shrink. [alice runAction: [CCRepeatForever actionWithAction: [CCSequence actions:[CCScaleTo actionWithDuration:4.0f scale:0.7f], [CCScaleTo actionWithDuration:4.0f scale:0.1f], nil] ] ]; /*** Draw a sprite CGImageRef ***/ UIImage *uiImage = [UIImage imageNamed: @"cheshire_cat.png"]; CGImageRef imageRef = [uiImage CGImage]; CCSprite *cat = [CCSprite spriteWithCGImage:imageRef key:@"cheshire_cat.png"]; [cat setPosition:ccp(250,180)]; [cat setScale:0.4f]; [self addChild:cat z:3 tag:TAG_CAT_SPRITE]; /*** Draw a sprite using CCTexture2D ***/ CCTexture2D *texture = [[CCTextureCache sharedTextureCache]addImage:@"tree.png"]; CCSprite *tree2 = [CCSprite spriteWithTexture:texture]; [tree2 setPosition:ccp(300,20)]; tree2.anchorPoint = ccp(0.5f,0); [tree2 setScale:2.0f]; [self addChild:tree2 z:2 tag:TAG_TREE_SPRITE_2]; /*** Draw a sprite using CCSpriteFrameCache and CCTexture2D ***/ CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:texturerect:tree2.textureRect]; [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFrame:frame name:@"tree.png"]; CCSprite *tree3 = [CCSprite spriteWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:@"tree.png"]]; [tree3 setPosition:ccp(400,20)]; tree3.anchorPoint = ccp(0.5f,0); [tree3 setScale:1.25f]; [self addChild:tree3 z:2 tag:TAG_TREE_SPRITE_3]; /*** Draw sprites using CCBatchSpriteNode ***/ //Clouds CCSpriteBatchNode *cloudBatch = [CCSpriteBatchNodebatchNodeWithFile:@"cloud_01.png" capacity:10]; [self addChild:cloudBatch z:1 tag:TAG_CLOUD_BATCH]; for(int x=0; x<10; x++){ CCSprite *s = [CCSprite spriteWithBatchNode:cloudBatchrect:CGRectMake(0,0,64,64)]; [s setOpacity:100]; [cloudBatch addChild:s]; [s setPosition:ccp(arc4random()%500-50, arc4random()%150+200)]; } //Middleground Grass int capacity = 10; CCSpriteBatchNode *grassBatch1 = [CCSpriteBatchNodebatchNodeWithFile:@"grass_01.png" capacity:capacity]; [self addChild:grassBatch1 z:1 tag:TAG_GRASS_BATCH_1]; for(int x=0; x<capacity; x++){ CCSprite *s = [CCSprite spriteWithBatchNode:grassBatch1rect:CGRectMake(0,0,64,64)]; [s setOpacity:255]; [grassBatch1 addChild:s]; [s setPosition:ccp(arc4random()%500-50, arc4random()%20+70)]; } //Foreground Grass CCSpriteBatchNode *grassBatch2 = [CCSpriteBatchNodebatchNodeWithFile:@"grass_01.png" capacity:10]; [self addChild:grassBatch2 z:3 tag:TAG_GRASS_BATCH_2]; for(int x=0; x<30; x++){ CCSprite *s = [CCSprite spriteWithBatchNode:grassBatch2rect:CGRectMake(0,0,64,64)]; [s setOpacity:255]; [grassBatch2 addChild:s]; [s setPosition:ccp(arc4random()%500-50, arc4random()%40-10)]; } /*** Draw colored rectangles using a 1px x 1px white texture ***/ //Draw the sky using blank.png [self drawColoredSpriteAt:ccp(240,190) withRect:CGRectMake(0,0,480,260) withColor:ccc3(150,200,200) withZ:0]; //Draw the ground using blank.png [self drawColoredSpriteAt:ccp(240,30)withRect:CGRectMake(0,0,480,60) withColor:ccc3(80,50,25) withZ:0]; return self;}-(void) drawColoredSpriteAt:(CGPoint)position withRect:(CGRect)rectwithColor:(ccColor3B)color withZ:(float)z { CCSprite *sprite = [CCSprite spriteWithFile:@"blank.png"]; [sprite setPosition:position]; [sprite setTextureRect:rect]; [sprite setColor:color]; [self addChild:sprite]; //Set Z Order [self reorderChild:sprite z:z];}@end How it works... This recipe takes us through most of the common ways of drawing sprites: Creating a CCSprite from a file: First, we have the simplest way to draw a sprite. This involves using the CCSprite class method as follows: +(id)spriteWithFile:(NSString*)filename; This is the most straightforward way to initialize a sprite and is adequate for many situations. Other ways to load a sprite from a file: After this, we will see examples of CCSprite creation using UIImage/CGImageRef, CCTexture2D, and a CCSpriteFrame instantiated using a CCTexture2D object. CGImageRef support allows you to tie Cocos2d into other frameworks and toolsets. CCTexture2D is the underlying mechanism for texture creation. Loading spritesheets using CCSpriteFrameCache: Next, we will see the most powerful way to use sprites, the CCSpriteFrameCache class. Introduced in Cocos2d-iPhone v0.99, the CCSpriteFrameCache singleton is a cache of all sprite frames. Using a spritesheet and its associated PLIST file we can load multiple sprites into the cache. From here we can create CCSprite objects with sprites from the cache: +(id)spriteWithSpriteFrameName:(NSString*)filename; Mipmapping: Mipmapping allows you to scale a texture or to zoom in or out of a scene without aliasing your sprites. When we scale Alice down to a small size, aliasing will inevitably occur. With mipmapping turned on, Cocos2d dynamically generates lower resolution textures to smooth out any pixelation at smaller scales. Go ahead and comment out the following lines: [alice.texture generateMipmap]; ccTexParams texParams = { GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR,GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE }; [alice.texture setTexParameters:&texParams]; Now you should see this pixelation as Alice gets smaller. Drawing many derivative sprites with CCSpriteBatchNode: The CCSpriteBatchNode class, added in v0.99.5, introduces an efficient way to draw and re-draw the same sprite over and over again. A batch node is created with the following method: CCSpriteBatchNode *cloudBatch = [CCSpriteBatchNodebatchNodeWithFile:@"cloud_01.png" capacity:10]; Then, you create as many sprites as you want using the follow code: CCSprite *s = [CCSprite spriteWithBatchNode:cloudBatchrect:CGRectMake(0,0,64,64)]; [cloudBatch addChild:s]; Setting the capacity to the number of sprites you plan to draw tells Cocos2d to allocate that much space. This is yet another tweak for extra efficiency, though it is not absolutely necessary that you do this. In these three examples we draw 10 randomly placed clouds and 60 randomly placed bits of grass. Drawing colored rectangles: Finally, we have a fairly simple technique that has a variety of uses. By drawing a sprite with a blank 1px by 1px white texture and then coloring it and setting its textureRect property we can create very useful colored bars: CCSprite *sprite = [CCSprite spriteWithFile:@"blank.png"];[sprite setTextureRect:CGRectMake(0,0,480,320)];[sprite setColor:ccc3(255,128,0)]; In this example we have used this technique to create very simple ground and sky backgrounds.  
Read more
  • 0
  • 0
  • 3592
Modal Close icon
Modal Close icon