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
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Game Development

368 Articles
article-image-2d-game-development-monkey
Packt
20 Apr 2012
9 min read
Save for later

2D game development with Monkey

Packt
20 Apr 2012
9 min read
Call the Monk and start praying—the Monkey IDE We are just kidding here; there are no religious activities planned in this article. Even though sometimes you will find yourself praying that a new piece of code you have created works like it should.If you haven't installed Monkey already, then it is time to do that now.The software can be downloaded from the site http://www.monkeycoder.co.nz/. Some prebuilt scripts are available as the support code files for the book Monkey Game Development Beginner's Guide. Why learn about Monk? Monk is the code editor/IDE that ships with Monkey. It is the first place that you will fire up when you start using Monkey. So, it is important to know your first main tool, if you want to develop games with Monkey. Starting up Monk It's time now to start Monk. You will do this by double-clicking on the Monk.app icon on OSX or start Monk.exe in Windows. Monk's user interface Monk's user interface is divided into three sections: The toolbar The code editor area The info box The toolbar All functions of Monk can be called through keyboard shortcuts and through the main menu. Some functions are also reachable through the toolbar. The code editor area The code editor in Monk supports syntax highlighting and automatic casing of the basic commands in the Monkey programming language. Sadly, it doesn't highlight and auto-case the commands from the modules, which is something that could help tremendously. But, the usual suspects are all there—copy, cut, paste, search and replace, Block in and out denting, goto line, and Find in Files will get you a long way before you ask for more The info box The info box is your navigation system, when it comes to Monkey coding. You can open your code files, and also the files included with Monkey, from the Nav tree view: In the bananas section of the Nav tree view, you will find all the sample scripts that ship with Monkey. Shortly, we will go there and start a sample script from there. The next tab header is the Code tree view. It contains all function and method headers of the included classes in the currently visible code file The last Debug tab is a relic from Monk's origins, being the native editor for BlitzMax. There, it has a built-in debugger, something that Monkey lacks at the moment. So, please just ignore that tab. Ok, now let's do something. How about opening one of the sample scripts? Time for action – opening a sample script Opening an existing script can be done through several methods. One is through the toolbar. Follow the given steps: Click on the Open icon in the toolbar: Next, you will see a file dialog where you can select a .Monkey file to be opened. Navigate, within the dialog, into the bananas folder of Monkey's main directory. There, you have subfolders from some authors of sample scripts. Head to the mak folder, and from within that, to the firepaint folder. Inside, you will find the firepaint.Monkey file. Select it and click on the Open button in the File dialog. Voila! Monk just opened the selected script: Of course, there are other ways to open a script. For example, you can double-click on a filename inside the Nav tree view What just happened? You have opened your first Monkey script. Good job! Please note how the GUI has changed. In the top of Monk, you see the file path of your currently visible script. Also, for each script you open or create, Monk creates a new tab inside the code area. In our example, this tab is named firepaint.Monkey. If you have several scripts open at once, you can switch between them by clicking on the tab header or press Ctrl + the left/right key on Windows or cmd + the left/right key on OSX. Where is my navi? Games are not usually coded with just 10-20 lines. We talk here about at least a few hundred lines of code. And to help you navigate through your code more easily, Monk supports the Code tab in the info box on the right. To practice navigation in a script file a little, here is the next task. Time for action - navigating to the main() function Every Monkey game needs a Main() function. To find it, select the Code tab in the info box. There you find two parent nodes. Try to find Main() in one of them. Found it? Good. Click on it. You will see that the code area changed and the cursor jumped to the top line of the definition of the Main() function: What just happened? Navigating through a script is very easy. Search for the item you want to jump to inside the Code tab of the info box and click on it. The content of the code tab always reflects the changes inside the code area! Save... save... save! One of the first and most important rules of software development is save your code, save it a lot. Remember this and live by it. There is nothing worse than a hard drive failure or a power outage after an hour of coding. Time for action - saving a script To save a script, here are some things you have to do Open an empty script by pressing Ctrl + N in Windows or cmd + N on OSX. Monkey will open a fresh and empty code area for you. Next, type anything inside it, just anything. Now, save your script. For this, you should use your mouse and the menu. Click on File | Save as. A dialog opens where you can set the filename and location to save your script to. Do this and click on Save. What just happened? You have saved your first script. Most likely, it isn't even close to a run-worthy script, but you have learned how to save your creation. Did you notice how the caption of the tab for the code area changed? And also the title bar of Monk's window? They now reflect the name you gave your script when you saved it. Projects—bringing in some organization When you look at the Nav tab of the info box, it's nice that you can browse through the folders of Monkey and open scripts from there. Good news is near; you can do this with your own code too. That is why Monk supports projects. They become new entries under the initial tree view inside the Nav tab. Time for action - creating a project Let's assume that we want to turn the FirePaint example into a project. For this, you have to create a new project first. Follow the ensuing steps: Click on File | Project Manager, in the menu. A new dialog will open: There, you will first see the Monkey project. To create a new one, click on Add Project. In the following dialog, you need to give your project a name. For now, My firepaint project should be fine. Also select the folder where the previous sample script was loaded from. After you do this, the top of the dialog should look a little like this: The bottom of the dialog with fields including sub-version controls is not functional and is probably a relic from Monk's origins of being the BlitzMAX IDE. Now, click on OK to create your project. What just happened? In the first dialog, there is now a new line with the project title. If you select this line, you could either change the properties of your project or remove it completely. You can close this dialog for now. Another thing you will notice is that, in the info box on the Nav tab, there is now a new project entry with the name you have given before. Browse through this entry and open the scripts from there by double-clicking on the script name. Convenient, isn't it? Yes, it is. And the cool thing is that this now stays there, even if you close Monk. At the next start of Monk, your new project entry is still there. The Monkey programming language To create games with Monkey, you should know a little bit about its programming language and its features. We won't cover the whole manual here, but will go through some of the most important parts of it. But first, you should write your first script. Without any practice, you say? Right, just like that! Time for action - Monkey's Hello World Here is a version of the famous Hello World script, done in Monkey. You have to start somewhere. You will learn what the starting point of every Monkey app looks like, the Main() function, and how to print some text to the browser. Ok, let's go! Start with a single line comment that describes the app: 'Monkeys Hello World Next is the function header for the Main() function, the piece of code that will be called at the start of the app. Every function starts with the keyword Function, then its name, followed by opening and closing parentheses: Function Main() Now, it's time to print the famous text Hello World. For this, Monkey provides the Print command. And don't forget to indent the code through the menu or just by pressing the Tab key once: Print ("Hello World") Every function needs to be closed. In Monkey, we do this with the End command: End Now, save your script. The name and folder are not important. Build and run the script by clicking on the tilted rocket in the toolbar. What just happened? Drum roll please.... tadaaaa! You have coded your first Monkey script and just ran it inside the browser. If everything is correct, you will have seen a plain (white) background and then the text Hello World printed on it. Running your first script in a browser To start this script, press Ctrl + R for Windows or cmd + R for OSX, to build and run the script. For this, select HTML5 as the target platform. You should see something like this: Cool, isn't it? And you did this all yourself.
Read more
  • 0
  • 0
  • 4516

article-image-hours-1-12-your-quest-begins
Packt
03 Apr 2012
4 min read
Save for later

Hours 1-12: Your Quest Begins!

Packt
03 Apr 2012
4 min read
Dealing with the Game Jam "theme" Virtually every Jam requires that you try to make a game that fits a theme. This is either a surprise word that the moderators came up with or one that has been voted upon earlier. The theme for a Jam is typically announced immediately before it begins. The anticipation and surprise gives the start of the event extra excitement and serves as a means to inspire the participants in the same way that the "secret ingredient" is used in the TV show Iron Chef . Once the theme word or words have been announced, digest it for a while. Some suggestions for coming up with a great game concepts based on the theme are as follows: Take a walk Listen to music Mull over ideas away from the computer Come back home and sketch your idea Visualize the game being played before touching the keyboard Talk about the theme over dinner with a friend Sleep on it and start in the morning Use this theme word as the genesis for your creative spark. Let it inspire you to think outside your normal comfort zone. Don't get discouraged if you think the theme isn't something you like: any game concept can be easily manipulated to fit a theme. Add one subtle reference and whatever game you'd hoped to make is still a possibility. Haiku Time: Many ideas. They all seem to fit the theme! Must I choose just one? Games that tend to win Game Jam competitions often make use of the theme word to find endless material for humor. One very strange statistical anomaly is that in most Game Jams, these three themes always score well in the voting stages: evolution, kittens, and fishing. Time and time again they are "always a bridesmaid, never a bride" and tend to be in the top ten, rather than the chosen theme. In Ludum Dare, for example, the "evolution" theme has been in the top ten almost a dozen times over the last six or seven years. When will "the evolution of kitten fishing" finally be the theme of a Game Jam? What the experts say: Chevy Ray Johnston A great way to come up with an idea to fit the theme is to write down the first five things that come to mind, then toss 'em. Those are the ideas everybody else is already thinking of and/or making. If I could give one piece of advice to newcomers, it would be to make a really simple game, and spend all your time polishing it like crazy! Really polished games are addictive, impressive, and always popular. Visual polish of some sort always seems to give games a boost-up in votes in compos, and makes them more likely to be clicked on by judges (especially in short Jams, where 90% of the games have little to no graphics). But unless you just care about winning, don't sacrifice a fun or engaging and interesting game just to make it look pretty. The best thing about Game Jams is the ridiculous shortcuts and solutions developers come up with to solve design problems in such a short time span. I hope that in the future, Game Jams will see more people developing not just video games, but other types of games as well; and creative things in general. I'm talking about writing Jams, board Game Jams, card Game Jams, and tech Jams where people get together and try to solve technological problems with the same mindset and ambition. Jams are great. Chevy Ray Johnston is author of many games including Fat Wizard and Skullpogo, the creator of the FlashPunk game engine (which is frequently used in Game Jams), and two time winner of Ludum Dare with the games FleeBuster and Beacon. Twitter: http://twitter.com/chevyray Flashpunk : http://flashpunk.net/ Google+ : https://plus.google.com/103872388664329802170   An example of a winning entry Let's take an example theme and see what it might inspire you to create. Take "ESCAPE," the theme of Ludum Dare 21. The winner of Ludum Dare 21 (theme: ESCAPE) created a game where you had to run away from an alien death beam in various platform-style obstacle courses. Try it out: Flee Buster by Chevy Ray Johnston. Other notable entrants created puzzle games where you had to escape from a mansion, jail, dungeon, or reverse pinball where you were the ball trying to get past the bottom. The possibilities are endless. The key qualities that the top ten entries all had were: Humor Simple gameplay Simple graphics Easy to pick up and play (simple controls)
Read more
  • 0
  • 0
  • 2593

article-image-getting-started-gamesalad
Packt
20 Mar 2012
10 min read
Save for later

Getting Started with GameSalad

Packt
20 Mar 2012
10 min read
Let's get to it shall we?   System requirements In order for you to run GameSalad and create amazingly awesome games, you must meet the minimum system requirements, which are as follows:   Intel Mac (Any Mac from 2006 and above) Mac OS X 10.6 or higher At least 1GB RAM A device running iOS (iPad, iPhone 3G and up, or iPod Touch) If your computer exceeds these requirements, perfect! If not, you will need to upgrade your computer. Keep in mind, these are the minimum requirements, having a computer with better specs is recommended.   Let's get into GameSalad Let's start by downloading GameSalad and registering for an account. Let's go to GameSalad's website, www.gamesalad.com. Click the "Download Free App – GameSalad Creator" button.   While you are waiting for GameSalad to download, you should sign up for a free account. At the top of the page click Sign Up, enter your email address and create a username and password. You have two options for GameSalad membership, you can keep the Basic Pricing, which is completely free or select Professional Pricing. The difference is when you publish your App, you will have a Created with GameSalad splash screen, not a big deal right? Especially, not when you can get this awesome program for free! The Professional Pricing, which is $499 (USD) per year gives you all the features of the free version of GameSalad, plus it allows you to use iAds, Game Center, Promotional Links, your own Custom Splash Screen, and Priority Technical Support.   This does not include your Apple developer cost, which is $99 a year Other tools that are recommended for game development:   Adobe Photoshop (http://www.adobe.com/products/photoshop.html) or a free equivalent, Inkscape, Gimp, and Pixelmator Drawing Tablet (Makes creating sprites much easier but not required) Getting familiar with GameSalad's interface Once you open GameSalad, you are presented with several options on the screen.   Following are the options:   Home: It shows you the latest GameSalad links (Success stories, their latest game release, and so on...). News: It is self-explanatory, this shows you the latest update notes, and what is new in the GS community. Start: The getting started screen, here you have video tutorials, Wiki Docs, Blog, and more. Profile: This shows you, your GameSalad's profile page, messages, followers, and likes. New: These are all your new projects, Blank templates, and various bare bone templates to get you started. Recent: This shows you all of your recently saved projects. Portfolio: This shows all your published Apps through GameSalad.   Back/Forward buttons: Used when navigating back and forth between windows Web Preview: Allows you to see what your game will look like within the browser (HTML5) Home: This takes you right back to the project's main window Publish: Brings up the Publish window, here you can chose to deploy your game to the web, iPhone, iPad, Mac, or Android Scenes: Gives you a drop-down menu of all your scenes Feedback: Have some thoughts about GameSalad? Click this to send them to the Creators! Preview: At the main menu, or while editing an actor this starts your game from the beginning. If you are in a level, it will preview the level Help: Brings up the GameSalad documentation, which lists many help topics. Target Platform and Orientation: This drop-down menu gives you, your device options, iPhone Landscape, iPhone Portrait, GameSalad.com, iPad Landscape, iPad Portrait, and 720p HD Enable Resolution Independence (only when iPhone and iPad device is set): Check this option if you are creating a game specifically for the iPhone 4, 4S, iPad, or Kindles and Nooks. This takes your high resolution images and converts them for iPhone 3GS, 3G, and iPhone (1st Gen) Scenes Tab: Switch to this to see all your wonderful levels! Actors Tab: Select this tab to see all your actors in the game project. From this tab, you can group different types of actors, such as platforms and enemies. This comes in handy when an actor has to collide with numerous other actors (enemies or platforms) + button: Adds a Level - button (when a level is selected): Deletes a level Inspector (with Game selected) Actors: Here, you will see all your in-game items (Players, platforms, collectables, and so on) Attributes: Here, you can edit all the attributes of the game such as the display size. Devices: Here, you can edit all the settings for the mouse, touch screen, accelerometer, screen, and audio. Inspector (with Scene selected) o Attributes: Here, you can edit all the attributes of the current level, such as the size of the level, screen wrap (X,Y), Gravity, background color, camera settings, and autorotate. o Layers: Here, you can create numerous layers with scrollable on or off. For example, a layer called UI with scrollable deselected will have all your user interface items, and they will stay on the screen. Library (with Behaviors selected) o Standard: These are all the standard GameSalad behaviors (Movements, change actor attributes, and more) o Custom: These are your own custom behaviors. Let's say, you needed the same behavior throughout numerous actors but you didn't want to keep re-adding and changing the behavior for each actor. Once, you create the Behavior, drag it into this box and you can use it as much as you want. o Pro: These are all the professional behaviors (only available when you have paid for the professional membership). These include Game Center Connect, iAd, and Open URL Library (with Images selected) Project: This shows all your imported images into this project. Purchased: This is a new feature that shows the images you have purchased through GameSalad's Marketplace. (When you click Purchase Images..., this will take you to the GameSalad Marketplace where you will have a plethora of Content packs and more to purchase and import into your game) When you click the "+" button, you can import images from your hard drive, alternately, you can drag them directly into the Library from the Finder Library (with Sounds selected): This shows you all of your sound effects and music that you have imported into your project. As with images, when you click the "+" button you can import sound effects or music from your hard drive, or drag them directly in from the Finder. Actor Mode: This involves normal mouse functions; it allows you to select actors within the level. Following is the screenshot of the icon: Camera Mode: It allows you to edit the camera, position, and scrolling hot spots for characters that control the camera. Following is the screenshot of the icon: Reset Scene: While previewing your level and if this button is pressed, everything will go back to its initial state. Following is the screenshot of the icon: Play: This will start a preview of the current level. This is different from the green Project Preview button, as this will only preview the current level, and not the whole project. When you complete the level, an alert will appear telling you the scene has ended, and you can either select to preview the next level, or reset the current scene. Following is the screebshot of the icon: Show Initial State: If you have run a preview, and want to see the initial state without ending the preview, then pause the preview, click on the following icon and the initial state is seen. Following is the screenshot of the icon: For now, let's click New | My Great Project This is a fresh project; everything is empty. You can see that you have one level so far, but you can add more at a later time. See the Scenes and Actors Tabs? Currently, Scenes is selected, this shows you all of your levels, but if you click the Actors tab, you will be able to see all your actors (or game objects, characters, collectables, and so on.) in the game. You can also rearrange all of the actors in Actor Tags, to give you an idea of what these are useful for. Take for example, if you have 30 different enemies, when you are setting up your collisions within behaviors, you won't have to set up 30 different collisions. Rather, when you set up all the enemies within a tag named Enemies you can do a single collision behavior for all actors of the tag! This reduces a lot of time when coding. We will get into more detail about actor tags, when we get into creating some games later in the book. If you double-click on the Initial Scene, you will be taken to the level editor. Before we do that, let's go through the buttons shown in the following screenshot: The descriptions of the buttons in the previous screenshot are as as follows: Seems pretty easy, right? It is! GameSalad's user interface is simple. Even if you don't know what a certain button does, just hover your mouse over the button and a tooltip appears and tells you what the button does. Even though it's a very simple user interface, it is very powerful. Take for example, something as simple as the Enable Resolution Independence option. Simply selecting this takes out a lot of time from having to create two sets of images, a high resolution retina-friendly image, and a lower quality set for non-retina display images. With this option, all you have to do is create a high resolution set. Choose this option and GameSalad automatically creates a lower quality set of images for non-retina devices. How great is that? Such a simple option and yet it saves so much time and effort, and isn't simplicity what everyone wants? Now let's get into the scene editor Double-click our initial scene and you will see the Scene Editor, yes it may be a little daunting, but once you get used to the user interface, it is really quite simple. Let's break down all the buttons and see what they do: What do all these buttons mean? Following is a description of all the buttons and boxes: There we go! The GameSalad interface really is that easy to navigate! In this article, you set up an account with GameSalad, you downloaded and installed it and now you know how to use the interface. GameSalad has such a simple interface, but it is really powerful. As we looked at earlier, an option as simple as Resolution Independence is so easy to select and yet one click takes off so much time from creating different sets of images that can be used for developing. This is what makes GameSalad so great; it's such a simple user interface and yet it is so powerful. What is so amazing about all of it, is that there's no programming involved whatsoever! For those who don't have the smartness to program a full game, this is what everyone else wants, simple, quick, and super powerful.
Read more
  • 0
  • 0
  • 6691
Visually different images

article-image-configuration-and-handy-tweaks-udk
Packt
01 Mar 2012
18 min read
Save for later

Configuration and Handy Tweaks for UDK

Packt
01 Mar 2012
18 min read
(For more resources on UDK, see here.) Groundwork for adjusting configuration defaults In this article we'll build up from simply changing some trivial configuration settings to orchestrating unique gaming experiences. To start out, we need to make clear how UDK configures content under the hood by introducing the layout and formatting for this kind of file. The experience in this recipe can be likened to savoring morsels of cake samples in a shop before committing to a purchase; while you're not actually changing major settings yet, the aim is to make some tasty observations so later the changes you make will come from informed decisions. Getting ready In your UDK installation, you have a folder called C:UDK~UDKGameConfig and it is worthwhile to browse the files here and get to know them. Treat them like the faces of colleagues in a new company. It may take a while, but you'll eventually know all their names! You may want to make an alternative install of UDK before starting this article, to protect any content you've been working on. In these examples we're going to assume you are using ConTEXT, or a notepad alternative that highlights UnrealScript syntax, like those listed at http://wiki.beyondunreal.com/Legacy:Text_Editor. The advantage with ConTEXT is that you have a history of recently opened files, and several concurrently open files can be arranged in tabs; also, you can view specific lines in the file in response to line error warnings from the UDK log, should they arise. In ConTEXT, to display line numbers go to the Options | Environment Options menu then click on the Editor tab in the options dialog, tick on Line Numbers and press Apply. How to do it... Open the file C:UDK~UDKGameConfigDefaultCharInfo.INI using ConTEXT. Alongside it, open C:UDK~UDKGameConfigUDKCharInfo.INI, which is a rather similar file. Values we set from an existing class are presented after a reference to the class in square brackets which surround the folder and class name, such as [UTGame.UTCharInfo]. Commented out lines or notes are distinguished using ; and the entire line isn't parsed. This differs from the // used to comment out lines in UnrealScript. In some configuration files you will see BasedOn=... followed by the path to another configuration file. This helps you track where the info is coming from. Values for variables are set in the configuration file as in the example: LOD1DisplayFactor=0.4. In ConTEXT , click on File | Open... and scroll down the list of files. Notice that it previews the contents of the highlighted .INI files before you open them. Choose DefaultWeapon.INI and edit line 3 (strictly speaking line 1 is empty). Press Ctrl + G (or View | Go to Line) and enter the line number 3. This line specifies CrosshairColor for the weapon. If you change the value A=255 to A=0 you will effectively have hidden the weapon target. Supposing you wanted to do so, you'd just have to save this file then reload UDK. No compiling is needed for adjusting configuration files, unlike classes, unless the configuration is defining custom scripts to be used in some way. Let's assume for now that you don't want to hide the weapon cursor, so close the file without saving by pressing Ctrl + W and choose No for the file save option. Open the file UDKEditor.INI and go to line 12: Bindings=(Key="S",SeqObjClassName="Engine.SeqAct_PlaySound") then look at line 28: Bindings=(Key="S",bControl=true,SeqObjClassName="Engine.SeqEvent_LevelLoaded"). What's important here is the added bControl=true for the S key. S will create a Play Sound node in Kismet. Ctrl + S will create a Level Loaded event. We really don't need to change anything but you can, for instance, change Ctrl + S to Ctrl + L in line 28, for adding a new Level Loaded event node in Kismet: Bindings=(Key="L",bControl=true,SeqObjClassName="Engine.SeqEvent_LevelLoaded") . Make sure that UDK is closed before you save the change or the file will not be effected at all. Reloading UDK after saving the change will see it take effect. Unless you have very long hands you will probably want to test this using the right Ctrl button on the right-hand side of the keyboard so your fingers can hold L and Ctrl and left mouse click all at once. You should get the Level Loaded event in Kismet from this key combination now. On that note, when you are specifying hotkeys for your game, bear in mind the idea of user friendly interface as you decide what keys to use. Often used keys should be easy to remember, fast to reach, and possibly semantically clustered together. How it works... What we looked at in this recipe were some formatting features that occur in every configuration file. In particular it is important to know that edits should be made while UDK is closed or they get scrubbed back out immediately. Also you will have noticed that the values we change reference UnrealScript classes from the C:UDK~DevelopmentSrc folder, and reading through their layout can help you learn how the default content in UDK is made to work during gameplay. There's more... Consider a version control software for editing UDK content There is a free version control system called Bazaar ( http://bazaar.canonical.com) that integrates with Windows folders. What version control software does is keep track of changes you have made to files, protecting them through a history based backup that lets you review and revert changes to a previous state if needed. You can init a folder, then browse it, add content and commit changes to changed files with comments that help you track what's going on. Where needed you can review the change history and revert files to any previously committed state. Alternatives to Bazaar are the commercial tool Alienbrain Essentials for Artists, or the free repository TortoiseSVN. The utility of version control in the case of UDK development is to prevent unrecoverable problems when doing a script compile when changes haven't been tracked and therefore can't be restored without re-installing from scratch, and to allow assets to be overwritten with a history. Enabling the remote control for game inspection This is a method for turning on an extra feature of UDK called the Remote Control that can be used to manipulate render nodes, inspect Actors, and evaluate performance. How to do it... In Windows, go to the Start menu or your desktop and find the shortcut for the UDK Editor and right-click on it to expose its properties. In the Target field edit it to read: C:UDK~BinariesUDKLift.exe editor -wxwindows -remotecontrol -log. The main point of this entry is so that we can launch a tool called RemoteControl. The usefulness of running the -log window increases over time. It is used for tracking what is happening while you run the editor and PIE. When trouble shooting problems in Kismet or with missing assets for example, it is a good first port of call for seeing where and when errors occur. In the following screenshot, the log shows the creation of a Trigger Touch event in the main Kismet sequence based on the actor Trigger_0 in the scene: Having edited the UDK launch properties to allow RemoteControl to launch, now load the Midday Lighting map template and PIE (F8). If you press Tab and type remotecontrol you should get a pop-up window like this: If you hit the Actors tab you get access to properties of certain actors, and you can change properties live while playing. For example, expand Actors | DominantDirectionalLight and double-click on DominantDirectionalLight_0 . Then in the light's property Movement | Rotation | Yaw or Pitch, try out different angle values. However, the changed values will revert to the editor state after PIE is closed. See also: http://udn.epicgames.com/Three/RemoteControl.html. An additional note: if you happen to minimize the RemoteControl window in some cases it may stay like that until you press Alt + Space . And to swap between the game and the Remote Control window press Alt + Tab . Pressing Show Flags lets you display various elements of the scene such as Collision, Bones, and Bounds. Go to the Stats tab and tick on Memory in the listing, then expand it and tick on the item within it called Lightmap Memory . This shows the cost of displaying lighting backed into lightmaps. Further down in the Stats tab list, tick on the item D3D9RHI and look at the DrawPrimitive calls. In the game, look straight up at the empty sky and note the value. Now look at the box on the ground. Notice the value increases. This is because the view has to draw the added objects (ground and box). In a large scene, especially on iOS, there is a functional limit to the number of drawcalls. How it works... The RemoteControl tool is external to the game window and is created using wxWindows. It is meant for use during PIE, for evaluation of performance. The Actors tab shows us a tree list of what is in the level, along with filters. You can access Actor Properties for an actor under the crosshairs using the icon [] or access them from a list. What you see in this screenshot is the result of turning the memory statistics on within a scene and the frame rate indicator (FPS = frames per second) through the Rendering tab in the Stats section, as well as the display of bones used in the scene. In Remote Control , you can set the Game Resolution (or game window size) under Rendering | View Settings. In the next recipe, we'll look at how to do this in UDK's configuration. Changing the Play in Editor view resolution This is a very short method for setting the view size for PIE sessions. How to do it... In C:UDK~UDKGameConfigDefaultEngineUDK.INI press Ctrl + F and search for [SystemSettings]. This should expose the lines: [SystemSettings] ; NOTE THAT ANY ITEMS IN THIS SECTION AFFECT ALL PLATFORMS! bEnableForegroundShadowsOnWorld=False bEnableForegroundSelfShadowing=False ResX=1024 ResY=768 Change the ResX and ResY values to suit yourself, using screen resolutions that make sense, such as 1920x1080. This will update UDKEngine.INI in the same folder so you will see the change reflected in these lines: PlayInEditorWidth=1920 PlayInEditorHeight=1080 Load a level and PIE to see the difference. Note that if you update UDKEngine.INI directly it will just revert to whatever is set in DefaultEngineUDK.INI. There is a lot of redundancy built into UDK's configuration that takes some time and practice to get used to. Removing the loading hints and similar articles Quickly getting rid of all the peripheral text and imagery that wraps around a given level, especially in console mode, is not easy. A few options exist for removing the more distracting elements such as splash screens and menus. You may want to do this if you wish to show your work without any artwork made by someone else getting in the way of your own. One method is called destructive editing, where your delete or blank out assets at the source, and this isn't as safe as it is quick. Instead you can provide your own menus, splash, and UI by extending on the classes that call up the default ones. How to do it... Removing the console mode videos during map loading Open C:UDK~UDKGameConfigDefaultEngine.INI. Press Ctrl + F and search for [FullScreenMovie] , which should expose the startup and loadmap references. Comment out the entries as follows: [FullScreenMovie] //+StartupMovies=UDKFrontEnd.UDK_loading //+LoadMapMovies=UDKFrontEnd.UDK_loading Load a level and play in console mode []. You won't get the movies that precede gameplay. If you take out all the pre-loading content there may occur the problem of getting a look at the level too early and "pre-caching" showing up. To learn how to instead swap out the .BIK files that constitute the loading movies between levels you can follow the video by Michael J Collins: http://www.youtube.com/watch?v=SX1VQK1w4NU. Removing the level loading hints To totally prevent .BIK movies during development, you can open C:UDK~EngineConfigBaseEngine.INI and search for NoMovies, then adjust the FALSE in the exposed lines: // Game Type name //class'Engine'.static.AddOverlay( LoadingScreenGameTypeNameFont, Desc, 0.1822, 0.435, 1.0, 1.0, false); // becomes class'Engine'.static.AddOverlay( LoadingScreenGameTypeNameFont, Desc, 0.1822, 0.435, 1.0, 0, false); // and Map name // class'Engine'.static.AddOverlay( LoadingScreenMapNameFont, MapName, 0.1822, 0.46, 2.0, 2.0, false); // becomes class'Engine'.static.AddOverlay( LoadingScreenMapNameFont, MapName, 0.1822, 0.46, 2.0, 0, false); What's happening here is that the last digit of four in an entry 1,1,1,1 is the Alpha value, controlling transparency, so 1,1,1,0 will be invisible. The first three numbers are RGB values, but they can be anything if the Alpha is 0. Removing the default exit menu Open C:UDK~UDKGameConfigDefaultInput.INI and press Ctrl + F to search for Escape. The first time will expose a removed key binding, so search from the cursor again to find in line 205: .Bindings=(Name="Escape",Command="GBA_ShowMenu" and comment it out with ; then add this line underneath instead: .Bindings=(Name="Escape",Command="quit" if UDK should close directly. If you want to provide a custom menu type: .Bindings=(Name="Escape",Command="open Menu" , where players pressing Esc will be sent to Menu.UDK (a scene of your own design) instead of the default menu. This won't do anything if you don't provision a Menu.UDK map first and cook it with your game levels. The map Menu.UDK would typically include some kind of clickable exit, resume, and reload buttons. If you want Esc to automatically restart the level you're playing, put in "open YOURMAPNAME" but bear in mind the only way to exit then will be Alt + F4. Possibly a strong way to approach the Escape option is to have a Pause command that permits a choice about leaving the game through a floating button: Resume or Exit. In addition you might have a similar floating button when the player dies: Replay or Exit, rather than the default Fire to Respawn. Editing DefaultEngineUDK to allow 4096x4096 texture compression This is a method for enabling UDK to use textures larger than its default limit. Conventional wisdom says that game textures should be highly optimized, but large resolution artwork is always enticing for many designers, and computers are getting better all the time. Performance issues aside, it's a good goal to push the graphic envelope and larger textures allow detail to hold up better on close inspection. Getting ready We've provided one really large texture that is 4096x4096 that you may find convenient, intended for use as a Skydome. If you are going to use a large texture it would most likely be on a very important model like a key character always close to the camera or else of a very large model which is always visible, such as a Skydome, or Skybox. A simple tutorial for making a Skybox is at http://www.worldofleveldesign.com/categories/UDK/UDK-how-add-skybox.php but this recipe assumes the use of a provided one. How to do it... With UDK closed, open C:UDK~UDKGameConfigDefaultEngineUDK.INI. Press Ctrl + F in ConTEXT and search for Skybox . You should be directed to line 127: TEXTUREGROUP_Skybox=(MinLODSize=512,MaxLODSize=2048,LODBias=0,MinMagFilter=aniso,MipFilter=point). Change the value for MaxLODSize=2048 to 4096. To really force it, you can also set the MinLODSize=4096 too. Doing this for a Skybox is okay, since there's normally only one used in a map, but you'd risk slowing the game down to do this with regular textures. Note, the TEXTUREGROUP_Skybox will allow a texture for a Skybox to be large, but not other things like character textures. For that, you can edit the relevant values in the other TEXTUREGROUP lines. Further down, in the SystemSettingsMobile section, the texture sizes are much smaller, which is due to the relatively limited processing power of mobile devices. Now save, and next we'll verify this in fact worked by adding a large sky to a scene in UDK. Look in the Content Browser and search the Packt folder for Packt_SkyDome , which is a typical mesh for a sky. You can see there is a completed version, and a copy called Packt_SkyDomeStart which has no material. Go to the Packt texture group. You will see there is already a provisioned 4096x4096 texture for Packt_SkyDome , but let's import a fresh one. Right-click in the Content Browser panel and choose Import , and browse to find Packt_SkydomeStart.PNG which is just a copy of the already existing texture. The reason to import it, is to verify you understand the compression setting. In the options you will see a panel that lets you specify the name info, which you should enter as Packt.Texture.SkyDomeTest or something unique. Further down you will see the compression settings. Choose LODGroup and from the expanding list choose TEXTUREGROUP_Skybox, as shown in the next screenshot, since this is what we have set to have 4096x4096 compression enabled in the configuration: The file may take some time to process, given its size. Once it is complete you can create a new Material Packt.Material.SkyDomeTest_mat. Open it and in the Material Editor hold T and click to add the highlighted SkyDomeTest texture to the Emissive channel. Skies are self lighting, so in the PreviewMaterial node's properties, set the Lighting Model to MLM_Unlit . The mesh Packt_SkyDomeStart is already UV mapped to match the texture, and if you double-click on it you can assign the new Material Packt.Material.SkyDomeTest_mat in the LODGroupInfo by expanding until you access the empty Material channel. Select the Material in the Content Browser then use the assign icon [] to assign it. Then you can save the package and place the mesh in the level. Be sure to access its properties (F4) and under the Lighting turn off Cast Shadow and set the Lighting Channels tick on Skybox and uncheck Static , as shown in the next screenshot: You could scale the mesh in the scene to suit, and perhaps drop it down below Z=0 a little. You could also use an Exponential Height Fog to hide the horizon. Since there is a specific sun shown in the sky image, you will need to place a Dominant Directional light in the scene and rotate it so its arrow (representing its direction) approximates the direction the sunlight would be coming from. It would be appropriate to tint the light warmly for a sunset. Setting the preview player size reference object In UDK versions greater than April 2011, pressing the key in the editor Perspective view will show a mesh that represents the player height. By default this is just a cube. The mesh to display can be set in the configuration file UDKEditorUserSettings.INI and we'll look at how to adjust this. This is to help designers maintain proper level metrics. You'll be able to gauge how tall and wide to make doors so there's sufficient space for the player to move through without getting stuck. Getting ready Back up C:UDK~UDKGameConfigUDKEditorUserSettings.INI then open it in ConTEXT with UDK closed. How to do it... Press Ctrl + F and search for [EditorPreviewMesh] . Under it, we will change the entry PreviewMeshNames=" EditorMeshes.TexPropCube ". Note the we need to replace this with a StaticMesh, and a good place to put this to ensure loading would be the EngineContent package EditorMeshes . First, open UDK and in the Content Browser search using the type field for TexPropCube . When this appears, right-click on the asset and choose Find Package . The packages list will show us EngineContentEditorMeshes and in here right-click and choose Import . You'll be prompted to browse in Windows, so from the provided content folder, find SkinTail.ASE which is a character model and import this into EditorMeshes. There's no need to set a group name for this. Importing this file as a StaticMesh enables it to be used as a preview model. By contrast, the SkeletalMesh Packt.Mesh.Packt_SkinTail won't work for what we are trying to do. If you set up a SkeletalMesh for the preview model the log will return cannot find staticmesh Yourmodelname whenever you press in the editor. It is optional, but you can double click the imported StaticMesh and assign a Material to it after expanding the LOD_Info property to show the Material channel. For the SkinTail content, choose Packt.Material.Packt_CharMat . Then save the EditorMeshes package including SkinTail and quit UDK. Use ConTEXT to edit the file UDKEditorUserSettings.INI so that the line we were looking at in Step 1 is changed to: PreviewMeshNames=" EditorMeshes.SkinTail " Eventually you'll opt to use your own StaticMesh. Save, close, and restart UDK. Open a map, and press in the editor to see if SkinTail will display. If it doesn't, run UDK using the -log option and check for error warnings when is pressed. Note that PreviewMeshNames=" EditorMeshes.TexPropCube " can also be adjusted in these configuration files: C:UDK~EngineConfigBaseEditorUserSettings.INI or C:UDK~UDKGameConfigDefaultEditorUserSettings.INI.
Read more
  • 0
  • 0
  • 4479

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
  • 2701

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
  • 1687
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 $15.99/month. Cancel anytime
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
  • 3037

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
  • 2470

article-image-cocos2d-uses-box2d-physics-engine
Packt
13 Dec 2011
7 min read
Save for later

Cocos2d: Uses of Box2D Physics Engine

Packt
13 Dec 2011
7 min read
  (For more resources on Cocos2d, see here.)   Box2D setup and debug drawing In our first physics recipe, we will explore the basics of creating a Box2D project and setting up a Box2D world. The example creates a scene that allows the user to create realistic 2D blocks. Getting ready Please refer to the project RecipeCollection02 for full working code of this recipe. How to do it... The first thing we need to do is create a Box2D project using the built-in Box2D project template: Go to File | New Project. Under User Templates click on Cocos2d. Now, right click on Cocos2d Box2d Application. Click Choose, name your project, and hit Save. Now, execute the following code: #import "Box2D.h"#import "GLES-Render.h"//32 pixels = 1 meter#define PTM_RATIO 32@implementation Ch4_BasicSetup-(CCLayer*) runRecipe { [super runRecipe]; /* Box2D Initialization *///Set gravity b2Vec2 gravity; gravity.Set(0.0f, -10.0f); //Initialize world bool doSleep = YES; world = new b2World(gravity, doSleep); world->SetContinuousPhysics(YES); //Initialize debug drawing m_debugDraw = new GLESDebugDraw( PTM_RATIO ); world->SetDebugDraw(m_debugDraw); uint32 flags = 0; flags += b2DebugDraw::e_shapeBit; m_debugDraw->SetFlags(flags); //Create level boundaries [self addLevelBoundaries]; //Add batch node for block creation CCSpriteBatchNode *batch = [CCSpriteBatchNodebatchNodeWithFile:@"blocks.png" capacity:150]; [self addChild:batch z:0 tag:0]; //Add a new block CGSize screenSize = [CCDirector sharedDirector].winSize; [self addNewSpriteWithCoords:ccp(screenSize.width/2, screenSize.height/2)]; //Schedule step method [self schedule:@selector(step:)]; return self;}/* Adds a polygonal box around the screen */-(void) addLevelBoundaries { CGSize screenSize = [CCDirector sharedDirector].winSize; //Create the body b2BodyDef groundBodyDef; groundBodyDef.position.Set(0, 0); b2Body *body = world->CreateBody(&groundBodyDef); //Create a polygon shape b2PolygonShape groundBox; //Add four fixtures each with a single edge groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO,0)); body->CreateFixture(&groundBox,0); groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO),b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO)); body->CreateFixture(&groundBox,0); groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO),b2Vec2(0,0)); body->CreateFixture(&groundBox,0); groundBox.SetAsEdge(b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,0)); body->CreateFixture(&groundBox,0);}/* Adds a textured block */-(void) addNewSpriteWithCoords:(CGPoint)p { CCSpriteBatchNode *batch = (CCSpriteBatchNode*) [selfgetChildByTag:0]; //Add randomly textured block int idx = (CCRANDOM_0_1() > .5 ? 0:1); int idy = (CCRANDOM_0_1() > .5 ? 0:1); CCSprite *sprite = [CCSprite spriteWithBatchNode:batchrect:CGRectMake(32 * idx,32 * idy,32,32)]; [batch addChild:sprite]; sprite.position = ccp( p.x, p.y); //Define body definition and create body b2BodyDef bodyDef; bodyDef.type = b2_dynamicBody; bodyDef.position.Set(p.x/PTM_RATIO, p.y/PTM_RATIO); bodyDef.userData = sprite; b2Body *body = world->CreateBody(&bodyDef); //Define another box shape for our dynamic body. b2PolygonShape dynamicBox; dynamicBox.SetAsBox(.5f, .5f);//These are mid points for our 1m box //Define the dynamic body fixture. b2FixtureDef fixtureDef; fixtureDef.shape = &dynamicBox; fixtureDef.density = 1.0f; fixtureDef.friction = 0.3f; body->CreateFixture(&fixtureDef);}/* Draw debug data */-(void) draw { //Disable textures glDisable(GL_TEXTURE_2D); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); //Draw debug data world->DrawDebugData(); //Re-enable textures glEnable(GL_TEXTURE_2D); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY);}/* Update graphical positions using physical positions */-(void) step: (ccTime) dt { //Set velocity and position iterations int32 velocityIterations = 8; int32 positionIterations = 3; //Steo the Box2D world world->Step(dt, velocityIterations, positionIterations); //Update sprite position and rotation to fit physical bodies for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) { if (b->GetUserData() != NULL) { CCSprite *obj = (CCSprite*)b->GetUserData(); obj.position = CGPointMake( b->GetPosition().x * PTM_RATIO,b->GetPosition().y * PTM_RATIO); obj.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()); } }}/* Tap to add a block */- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { for( UITouch *touch in touches ) { CGPoint location = [touch locationInView: [touch view]]; location = [[CCDirector sharedDirector] convertToGL: location]; [self addNewSpriteWithCoords: location]; }}@end How it works... The Box2D sample project is a simple way to understand what a physics system looks like. Initialization: Upon initialization of the b2World object, we set a few things including gravity, object sleeping, and continuous physics. Sleeping allows bodies that are at rest to take up less system resources. Gravity is typically set to a negative number in the Y direction but can be reset at any time using the following method on b2World: void SetGravity(const b2Vec2& gravity); In addition to storing a pointer to the main b2World instance, we also usually store a pointer to an instance of GLESDebugDraw. Debug drawing: Debug drawing is handled by the GLESDebugDraw class as defined in GLESRender.h. Debug drawing encompasses drawing five different elements onscreen. These include shapes, joint connections, AABBs (axis-aligned bounding boxes), broad-phase pairs, and a center of mass bit. Visual to physical drawing ratio: We define the constant PTM_RATIO at 32, to allow consistent conversion between the physical world and the visual world. PTM stands for pixel to meter. Box2D measures bodies in meters and is built and optimized to work with bodies between the sizes of 0.1 to 10.0 meters. Setting this ratio to 32 is a common convention for optimal shapes to appear between 3.2 to 320 pixels on screen. Optimization aside, there is no upper or lower limit to Box2D body size. Level boundaries: In this and many future examples, we add a level boundary roughly encompassing the entire screen. This is handled with the creation of a b2Body object with four fixtures. Each fixture has a b2Polygon shape that defines a single edge. Creating an edge typically involves the following: b2BodyDef bodyDef;bodyDef.position.Set(0, 0);b2Body *body = world->CreateBody(&bodyDef);b2PolygonShape poly;poly.SetAsEdge(b2Vec2(0,0), b2Vec2(480/PTM_RATIO,0));body->CreateFixture(&poly,0); Because these edges have no corresponding visual components (they are invisible), we do not need to set the bodyDef.userData pointer. Creating the blocks: Blocks are created much in the same way that the level boundaries are created. Instead of calling SetAsEdge, we call SetAsBox to create a box-shaped polygon. We then set the density and friction attributes of the fixture. We also set bodyDef.userData to point to the CCSprite we created. This links the visual and the physical, and allows our step: method to reposition sprites as necessary. Scheduling the world step: Finally, we schedule our step method. In this method, we run one discrete b2World step using the following code: int32 velocityIterations = 8;int32 positionIterations = 3;world->Step(dt, velocityIterations, positionIterations); The Box2D world Step method moves the physics engine forward one step. The Box2D constraint solver runs in two phases: the velocity phase and position phase. These determine how fast the bodies move and where they are in the game world. Setting these variables higher results in a more accurate simulation at the cost of speed. Setting velocityIterations to 8 and positionIterations to 3 is the suggested baseline in the Box2D manual. Using the dt variable syncs the logical timing of the application with the physical timing. If a game step takes an inordinate amount of time, the physics system will move forward quickly to compensate. This is referred to as a variable time step. An alternative to this would be a fixed time step set to 1/60th of a second. In addition to the physical step, we also reposition and re-orientate all CCSprites according to their respective b2Body positions and rotations: for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) { if (b->GetUserData() != NULL) { CCSprite *obj = (CCSprite*)b->GetUserData(); obj.position = CGPointMake( b->GetPosition().x * PTM_RATIO,b->GetPosition().y * PTM_RATIO); obj.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle()); }} Taken together, these pieces of code sync the physical world with the visual.  
Read more
  • 0
  • 0
  • 1996

article-image-unity-ios-essentials-flyby-background
Packt
08 Dec 2011
12 min read
Save for later

Unity iOS Essentials: Flyby Background

Packt
08 Dec 2011
12 min read
(For more resources on UnityiOS, see here.) Set up a background scene Typically, the background scene for the menu system will also be a scene from the game. But because the player will not be interacting with the menu's background scene, they will not be able to see it from all angles, jump on objects, and so on. It is possible to strip out many of the components from the scene to optimize it for use as a menu background. Another option is to create a brand new background scene that incorporates game assets from multiple game levels into a single menu background to give the player a full picture of the scope of our game. Again, we can achieve this by being selective about the game assets that we use and stripping out all but the most essential visual components of those assets. The background scene can be a teaser, it can include Easter Egg hints, it can contain character cameos from other games, and it can contain parts of other games. Finally, the background scene can be a selling opportunity. It can contain advertising or it can contain objects that the player may be interested in purchasing, using game purchase. The contents of the menu background scene are limited only by what we can imagine. In the following image, we show the original first level of a game that we have selected to be used as the background scene for our game: The scene is adequate and we could use it as the background for our game menu, but we want to give the game player a better idea, right on the main menu, of just how large the game is. So instead, we add some buildings from a second level (we could do more; we could make our menu level huge, but this should do for now), and come up with the new, much larger scene, as shown in the following screenshot to use as the background for our main menu: Set up the camera path Once we have decided on the final scene that we want to use as the background for our main menu, we need to decide on the path that the camera will follow as it moves through the scene. While it is not a requirement that the camera moves along a path, it adds interest to the menu, and so we will continue with that menu theme for our game. This is an opportunity for us to tease the player, since it may be some time before they arrive at a specific part of the menu scene during actual gameplay. We can flyby Easter Eggs or we can flyby specific objectives. Again, this is the part of the game where we get to be creative and draw the player into the game. If we want to, we can even defy the physics of the game and fly through things, so that we don't give away the secret of how to achieve a game objective or how to obtain an Easter Egg, but we do let the player know that they are there. We need to be careful to do this in such a way as to fade through scenes rather than clip through the geometry, so that we don't disturb the immersive feel of the game in order to hide things from the player's view. To set up a path, the first thing we need to do is create a gizmo. A gizmo is an image that appears in the Unity3D editor at the position of a game object's transform, but otherwise will not be visible in the game. As a game designer, we use gizmos to arrange these game objects graphically in the editor, rather than having to find each object in the game hierarchy, and enter x, y, and z values to position the transformation. Gizmos, while not necessary, are very useful because they allow us to create a visual representation of an otherwise empty game object in the Unity3D editor. To create a gizmo, you need two things: A gizmo image A gizmo script The following is an example of a gizmo image. It can be anything you want. In this case, we have simply chosen an image of the letter W – for waypoint. The image file is named Waypoint.tif, and it has been imported into Unity3D as a standard GUITexture as follows: The following is an example of a gizmo script that draws a waypoint gizmo image at the location of the game object transform to which it is attached: // Draw the waypoint gizmo at the Game Object's// transform position. // You can use any image that you want // This gizmo will be pickable which means you// can click on it in the editor to select// the attached game object function OnDrawGizmos (){//The image must be in Assets/Gizmos – the size of the image//is how large it will be drawn in the scene view Gizmos.DrawIcon (transform.position, "Waypoint.tif");} To use a waypoint in the editor, we need to do the following: Create an empty game object Attach the waypoint.js script to the game object The following image shows our example level with a number of waypoints added to define the path that we want the camera to follow for our menu flyby. Everywhere you see the letter W in this image, denotes a waypoint along the path: Adding waypoints and drawing a gizmo at a waypoint's location in the editor is helpful, but one more thing that we can do to make the order of the waypoints clear is to draw a line between the waypoints. So, for example, we would draw a line from wp1 to wp2, from wp2 to wp3, and so on. The following script fragment, which is part of the SeekSteer script, shows how to draw the lines between the waypoints: // draws a line from waypoint to waypoint public void OnDrawGizmos() { Vector3 l_prevWaypointPosition; Vector3 l_currentWaypointPosition; // Choose a color, it can be any color you like Gizmos.color = Color.red; // Draws a line between the last waypoint // and the first waypoint l_prevWaypointPosition = waypoints[waypoints.Length-1].position; l_currentWaypointPosition = waypoints[0].position; Gizmos.DrawLine(l_prevWaypointPosition, l_currentWaypointPosition); // Choose another color, it can be any color you like // except the first color Gizmos.color = Color.green; // For each remaining waypoint, in the waypoints array // draw a line between the two points for (int i=1;i < waypoints.Length;i++) { l_currentWaypointPosition = waypoints[i].position; l_prevWaypointPosition = waypoints[i-1].position; Gizmos.DrawLine(l_prevWaypointPosition, l_currentWaypointPosition); } } The following screenshot shows the new scene with lines being drawn between the waypoints. It's easy to identify the first and last waypoint, because they are the points with the red lines between them: Once the waypoints have been set up, we need something to follow them. There are literally dozens of ways that we can use to follow a path, and many kinds of paths that we can follow. In fact, there are complete Unity3D projects devoted to path finding. In this case, we have chosen to use the SteerSeaker method of following a path. The SteerSeaker creates an array (or list) of all the waypoints, and moves from one waypoint to the next in the same amount of time. In order to keep the time between waypoints constant, the SteerSeaker speeds up or slows down based on the distance between the waypoints, which makes it easy for us to predict the total time it will take to follow our path and create sections of both slow and fast movement. The rest of the SteerSeaker script (remember we looked at the previous image that draws lines between the waypoints) is shown as follows: This script is written in C# rather than JavaScript. While many people new to Unity3D prefer to work in either JavaScript or C#, it's important that we become familiar with both scripting languages, so that we can take advantage of all the open source resources available in the Unity3D community. While we don't need to be able to program in both languages, we do need to be able to read both languages. // SeekSteer.cs// Based on the original SeekSteer by Matthew Hughes// -- 19 April 2009// -- Uploaded to Unify Community Wiki on 19 April 2009// -- URL:http://www.unifycommunity.com/wiki/index.php?title=SeekSteer//// Changes by BurningThumb Software// -- March 2010//using UnityEngine;using System.Collections;public class SeekSteer : MonoBehaviour{ // This is the array of waypoints public Transform[] waypoints; // This is the radius, in meteres of a waypoint public float waypointRadius = 1.5f; // Damping is used to limit the rate at which // the object turns towards the next waypoint. // Smaller numbers slow down turns, larger // numbers speed up turns public float damping = 0.1f; // Set loop to true if the object loops // continuously around the waypoints and // to false if the object only goes around // one time public bool loop = false; // The time between waypoints is constant // so the object will speed up or slow down to // achieve this time regardless of the distance // between the points public float transittime = 2.0f; // Set faceHeading to true to make the object // turn to face the forward direction and to // false to not turn to face the forward // direction public bool faceHeading = true; // The current heading of the object private Vector3 currentHeading; // The desired heading of the object private Vector3 targetHeading; // The array index of the waypoint that the // object is heading toward private int targetwaypoint; // A reference to the transform of the object // used to speed up the script by caching the // reference which is used many times private Transform thisTransform; // If the object has a rigid body then this // is a reference to the rigid body of the object // used to speed up the script by caching the // reference which is used several times private Rigidbody thisRigidbody; // Use this for initialization protected void Start () { // If the waypoints array is empty this script // logs a message and disables itself. You need // to add waypoints to the array in the Unity3D // editor if (waypoints.Length <= 0) { Debug.Log("No waypoints on "+name); enabled = false; } // Cache a reference to the transform to speed // up the execution of the script thisTransform = transform; // Set the current heading to be forward currentHeading = thisTransform.forward; // The first target waypoint, is the first // one in the array targetwaypoint = 0; // Cache a reference to the attached Rigidbody to // speed up execution of the script. If // no Rigidbody is attached this will be null thisRigidbody = rigidbody; } // calculates a new heading. This is done in // fixed update just in case there is a // Rigidbody attached and physics are // involved protected void FixedUpdate () { // A simple Lerp with damping to adjust // the heading towards the current target // waypoint targetHeading = waypoints[targetwaypoint].position - thisTransform.position; currentHeading = Vector3.Lerp(currentHeading, targetHeading, damping * Time.deltaTime); } // moves us along current heading protected void Update() { // If a Rigidbody is attached then // physics is in use so add velocity if (thisRigidbody) { thisRigidbody.velocity = currentHeading * transittime; } // Otherwise set the position directly else { thisTransform.position = thisTransform.position + (currentHeading * Time.deltaTime * transittime); } // If the object needs to face the heading, // make it look that way if (faceHeading) { thisTransform.LookAt(thisTransform.position + currentHeading); } // Check to see if the object is inside the // waypoint radius if (Vector3.Distance(thisTransform.position, waypoints[targetwaypoint].position) <= waypointRadius) { // Add one to the target waypoint to select // the next waypoint targetwaypoint++; // if the next waypoint is past // the end of the array if(targetwaypoint>=waypoints.Length) { // set it back to the beginning targetwaypoint = 0; // If the object is only supposed // to transit the waypoints one // time then disables the script if (!loop) { enabled = false; } } } } With this final script, we create the SteerSeeker game object and attach not only the SteerSeaker script, but also a gizmo script to display the letter S. This is done so that we can see the position of the game object in the Unity3D editor. The following image shows the SteerSeaker object settings in the Unity3D editor: The variables declared as public in the script are the ones that will appear in the Unity3D editor. The following image shows its position on the waypoint path, as we run the game in the editor: Finally, we need to have the main camera follow the SteerSeaker object as it moves along the waypoint path. The advantage of using a script, instead of a simple timeline, is that we can create more dynamic camera movement, for example, a rollercoaster effect where the camera changes angles as it moves, or a script that "gobbles" up jewels along the path as it moves. It's important to understand the concept of using a script and its benefits, rather than simply looking at what this specific example does. Often, as in this case, example code is kept simple to convey the concept or idea, and is not meant to be the final solution that we would deploy in a game. This is done by attaching the FollowTransform script from the iPhone Standard Assets to the main camera, while assigning the SeekSteerObject to the Target Transform and checking the box Face Forward on that script. This is shown as follows: The output is shown in the following image:
Read more
  • 0
  • 0
  • 1674
article-image-unreal-development-toolkit-level-design-hq
Packt
23 Nov 2011
5 min read
Save for later

Unreal Development Toolkit: Level Design HQ

Packt
23 Nov 2011
5 min read
(For more resources related to this subject, see here.) So let's get on with it. We will first look at downloading the UDK, and install it on your PC. Time for action – UDK download and installation Download the latest version of UDK. Log on to www.udk.com and download the latest version of unreal development kit beta. Once you download the UDK Installer, go ahead and install the UDK. The default directory for installing UDK is C:UDKUDK-VersionRelease. Version Release will be the month and year that the UDK you downloaded was built. UDK folder structure The UDK folder structure looks like the following screenshot: The UDK folder structure consists of the following four folders: Binaries: game/binary executable. Development: source code for UDK. Engine: engine files. UTGame: game files. For level-design and environment creation, the important folder here is the content folder. The packaged environment's assets such as models, textures, materials, sounds, and such are stored here. For environment creation and level design, the most important folder is UTGame | Content | Environments. It contains all the files you need to create your map, as shown in the following screenshot: UDK extension is the UDK package's name. This is how the models and textures are stored in UDK. Think of UDK extension as folders. Inside those folders are stored all the models, animations, textures, materials, and similar assets. You can browse the UDK files through the UDK editor.   UDK is the map file extension.   Time for action – launching the editor To launch the unreal editor, go to the Start Menu | Unreal Development Kit | UDK Version | Editor. Another way to launch the editor is to create a shortcut. To do this, go to the installation folder: UDKUDK-VersionReleaseBinaries, locate UDKLift.exe, right-click and select Send To | Desktop (create shortcut), as shown in the following screenshot: Once on you have created the shortcut on your desktop, right-click the shortcut and select Properties. Then, in the Target box under the Shortcut tab, add editor at the end of the text. It should look something like the following screenshot: Now double-click on the desktop icon and launch the UDK Editor. Autosave When you first launch the editor, you will have Autosave automatically enabled. This will save your map at a chosen timed interval. You can set how often it will automatically save by clicking the Left Mouse Button (LMB) on the arrow on the bottom-right of the Autosave Interval and choosing the time you want, as shown in the following screenshot: You will find the Autosave feature at the bottom right of the editor. If you enable Autosave, there are a few options such as Interval and Type. Save manually by going up to File | Save As. Content browser Content browser is where you will find off the game's assets. Placing static meshes (models), textures, sounds, and game entities such as player starts, weapons, and so on, can all be done through the content browser. You will be using the content browser very often. To open the content browser click on the top menu bar, as shown in the following screenshot: Packages are where you will find specific items contained within the UDK. Things such as static meshes are contained within a package. You can search for a package, or just find the package you want to use and select it as shown in the following screenshot: The top of the content browser contains a search box as well as a filter box. This is very useful. You can sort out the content in the browser by animation sets, material instances, static meshes, sounds, and so on. This helps a lot when looking for items. The next screenshot lists full names of the items within a selected package. You can sort by clicking on the Name, Type, Tags, or Path fields, and it will re-arrange the content's preview: The content browser is one of the most commonly used tools in UDK. Get comfortable using the content browser. Spend some time navigating around it. UDK basics covers the most essential tools and functions you need to know to get started with UDK. You'll be able to quickly jump into UDK and begin feeling comfortable using the most commonly used functions. What just happened? So we know how to launch the editor, how to use the Autosave function, and where to find the content browser. We are now going to look at how to move and rotate around the editor. Time for action – movement and rotation Time to have a look at movement, rotation, and navigating around the editor. Navigation Buttons used to navigate around UDK. UDK These are your primary keys for navigating and rotating using the editor: Left Mouse Button (LMB): pan right/left/forward/backward movements Right Mouse Button (RMB): rotate, look around LMB+RMB: up/down WASD key navigation The following are other forms of primary keys for navigating and rotating around the editor: Click and hold RMB. As you hold it, use the WASD keyboard keys to move around as you would in a first person shooter game. WASD movement is great if you are familiar with hammer source mapping. MAYA users If you are familiar with Maya, the following will be your primary keys for navigating and rotating around the editor. Hold down the U key U+ LMB: rotate, look around U+ RMB: forward/backward movements U+ MMB: right/left/up/down movements What just happened? Now that you have installed UDK and know what the content browser is, you are ready to begin. So let's get started.
Read more
  • 0
  • 0
  • 1941

article-image-irrlicht-creating-basic-template-application
Packt
21 Nov 2011
3 min read
Save for later

Irrlicht: Creating a Basic Template Application

Packt
21 Nov 2011
3 min read
(For more resources related to this topic, see here.) Creating a new empty project Let's get started by creating a new project from scratch. Follow the steps that are given for the IDE and operating system of your choice. Visual Studio Open Visual Studio and select File | New | Project from the menu. Expand the Visual C++ item and select Win32 Console Application. Click on OK to continue: In the project wizard click on Next to edit the Application Settings. Make sure Empty project is checked. Whether Windows application or Console application is selected will not matter. Click on Finish and your new project will be created: Let's add a main source file to the project. Right-click on Source Files and select Add New Item...|. Choose C++ File(.cpp) and call the file main.cpp: CodeBlocks Use the CodeBlocks project wizard to create a new project as described in the last chapter. Now double-click on main.cpp to open this file and delete its contents. Your main source file should now be blank. Linux and the command line Copy the make file of one of the examples from the Irrlicht examples folder to where you wish to create your new project. Open the make file with a text editor of your choice and change, in line 6, the target name to what you wish your project to be called. Additionally, change, in line 10, the variable IrrlichtHome to where you extracted your Irrlicht folder. Now create a new empty file called main.cpp. Xcode Open Xcode and select File | New Project. Select Command Line Tool from Application. Make sure the type of the application is set to C++ stdc++: When your new project is created, change Active Architecture to i386 if you are using an Intel Mac, or ppc if you are using a PowerPC Mac. Create a new target by right-clicking on Targets, select Application and click on Next. Target Name represents the name of the compiled executable and application bundle: The target info window will show up. Fill in the location of the include folder of your extracted Irrlicht package in the field Header Search Path and make sure the field GCC_ PREFIX_HEADER is empty: Right-click on the project file and add the following frameworks by selecting Add Existing Frameworks...|: Cocoa.framework Carbon.framework IOKit.framework OpenGL.framework Now, we have to add the static library named libIrrlicht.a that we compiled in Chapter 1, Installing Irrlicht. Right-click on the project file and click on Add | Existing Frameworks.... Now click on the button Add Other... and select the static library. Delete the original compile target and delete the contents of main.cpp. Time for action – creating the main entry point Now that our main file is completely empty, we need a main entry point. We don't need any command-line parameters, so just go ahead and add an empty main() method as follows: int main(){ return 0;} If you are using Visual Studio, you need to link against the Irrlicht library. You can link from code by adding the following line of code: #pragma comment(lib, "Irrlicht.lib") This line should be placed between your include statements and your main() function. If you are planning to use the same codebase for compiling on different platforms, you should use a compiler-specific define statement, so that this line will only be active when compiling the application with Visual Studio. #if defined(_MSC_VER) #pragma comment(lib, "Irrlicht.lib")#endif
Read more
  • 0
  • 0
  • 4428

Packt
07 Sep 2011
8 min read
Save for later

Unity 3: Building a Rocket Launcher

Packt
07 Sep 2011
8 min read
  (For more resources on this subject, see here.) Mission briefing We will create a character that carries a rocket launcher and is able to shoot it as well as creating the camera view looking back from the character shoulder (third-person camera view). Then, we will add the character controller script to control our character, and the player will have to hold the Aim button to be able to shoot the rocket, similar to the Resident Evil 4 or 5 styles. What does it do? We will start with applying the built-in CharacterMotor, FPSInputController, and MouseLook scripts from the built-in FPS character controller. Then, we will add the character model and start creating a new script by adapting part of the code in the FPSInputController script. Then, we will be able to control the animation for our character to shoot, walk, run, and remain idle. Next, we will create a rocket prefab and the rocket launcher script to fire our rocket. We will use and adapt the built-in explosion and fire trial particle in Unity, and attach them to our rocket prefab. We will also create a new smoke particle, which will appear from the barrel of the rocket launcher when the player clicks Shoot. Then, we will create the scope target for aiming. We will also create the launcher and smoke GameObject, which are the start position of the rocket and the smoke particle. Finally, we will add the rocket GUITexture object and script to track the number of bullets we have let, at player each shot. We will also add the Reload but on to refill our bullet when the character is out of the bullet. Why Is It Awesome? When we complete this article, we will be able to create the third-person shooter style camera view and controller, which is very popular in many games today. We will also be able to create a rocket launcher weapon and particle by using the prefab technique. Finally, we will be able to create an outline text with the GUITexture object for tracking the number of bullets left. Your Hotshot Objectives In this article, we will use a third-person controller script to control our character and combine it with the built-in first-person controller prefab style to create our third-person shooter script to fire a rocket from the rocket launcher. Here is what we will do: Setting up the character with the first-person controller prefab Creating the New3PSController and MouseLook_JS scripts Create a rocket launcher and a scope target Create the rockets and particles Create the rocket bullet UI Mission Checklist First, we need the chapter 5 project package, which will include the character model with a gun from the Unity FPS tutorial website, and all the necessary assets for this article. So, let's browse to http://www.packtpub.com/support?nid=8267 and download Chapter5.zip package. Unzip it and we will see Chapter5.unitypackage, and we are ready. Setting up the character with the first-person controller prefab In the first section of this article, we will make all the necessary settings before we create our character on the scene. We will set up the imported assets and make sure that all the assets are imported in the proper way and are ready to use by using the Import Package in the Project view inside Unity. Then, we will set the light, level, camera, and put our character in the scene with the first-person controller prefab. We will import the Chapter5.unitypackage package to Unity, which contains the Chapter5 folder. Inside this folder, we will see five subfolders, which are Fonts, Level, Robot Artwork, Rocket, and UI. The Fonts folder will contain the Font file, which will be used by the GUI. The Level folder will contain the simple level prefab, its textures, and materials. Robot Artwork is the folder that includes the character FBX model, materials, and textures, which can be taken from the Unity FPS tutorial. The Rocket folder contains the rocket and rocket launcher FBX models, materials, and textures, which can be taken from the Unity FPS tutorial. Finally, the UI folder includes all the images, which we will use to create the GUI. Prepare for Lift Off In this section, we will begin by importing the chapter 5 Unity package, checking all the assets, setting up the level, and adding the character to the scene with the FPS controller script. First, let's create a new project and name it RocketLauncher, and this time we will include the built-in Character Controller package and Particles package by checking the Character Controller.unityPackage and Particles.unityPackage checkboxes in the Project Wizard. Then, we will click on the Create Project but on, as shown in the following screenshot: Next, import the assets package by going to Assets | Import Package | Custom Package.... Choose Chapter5.unityPackage, which we just downloaded, and then click on the Import but on in the pop-up window link, as shown in the following screenshot: Wait until it's done, and you will see the Chapter5 folder in the Window view. Make sure that we have all have folders, which are Fonts, Level, Robot Artwork, Rocket, and UI, inside this folder. Now, let's create something. Engage Thrusters In this section, we will set up the scene, camera view, and place our character in the scene: First, let's begin with creating the directional light by going to GameObject | Create Other | Directional Light, and go to its Inspector view to set the rotation X to 30 and the position (X: 0, Y: 0, Z: 0). Then, add the level to our scene by clicking on the Chapter5 folder in the Project view. In the Level folder, you will see the Level Prefab; drag it to the Hierarchy view and you will see the level in our scene. Next, remove the Main Camera from the Hierarchy view because we will use the camera from the built-in First Person Controller prefab. So, right-click on the Main Camera on the Hierarchy view and choose Delete to remove it. Then, add the built-in First Person Controller prefab to the Hierarchy view by going to the Standard Assets folder. Under the Character Controllers folder, you will see the First Person Controller prefab; drag it to the Hierarchy view. In the Hierarchy view, click on the arrow in the front of the First Person Controller object to see its hierarchy, similar to the one shown in the following screenshot: Then, we go back to the Project view. In the Chapter5 folder inside Robot Artwork, drag the robot.fbx object (as shown in the following screenshot) on top of the Main Camera inside the First Person Controller object in the Hierarchy. This will cause the editor to show the window that tells us this action will break the prefab, so we just click on the Continue but on to break it. It means that this game object will not be linked to the original prefab. Next, remove the Graphics object above the Main Camera. Right-click on it and choose Delete. Now we will see something similar to the following screenshot: We have put the robot object as a child of the camera because we want our character to rotate with the camera. This will make our character always appear in front of the camera view, which is similar to the third-person view. This setup is different from the original FPS prefab because in the first person view, we will not see the character in the camera view, so there is no point in calculating the rotation of the character Now, click on the First Person Controller object in the Hierarchy view to bring up the Inspector view, and set up the Transform Position of X: 0, Y: 1.16, Z: 0|. Then, go to the Character Controller, and set all values as follows: Character Controller (Script) Height: 2.25 Center X: -0.8, Y: 0.75, Z: 1.4 Move down one step by clicking on Main Camera in the Hierarchy view and go to its Inspector view to set the value of Transform and Mouse Look as follows: Transform Position X: 0, Y: 1.6, Z: 0 Mouse Look (Script) Sensitivity Y: 5 Minimum Y: -15 We will leave all the other parameters as default and use the default values. Then, we will go down one more step to set the Transform of the robot by clicking on it to bring up its Inspector view, and set the following: Now, we are done with this step. In the next step, we will adjust and add some code to control the animation and movement of our character the FPSInputController script. If the user presses it, we want the character to stop moving and play the shooting animation to prepare the character to be able to fire. We also set the maximum and minimum of the camera rotation on the Y-axis, which limits the camera to rotate up and down only. Then, we set the motor.inputMoveDirection to Vector3. zero because we don't want our character to move while he/she is executing the shooting action. On the other hand, if the user doesn't press E, we check for the user input. If the user presses the right arrow or let arrow, we change the speed to run speed; if not we set it to walk speed. Then, we applied the movement speed to motor. movement.maxForwardSpeed, motor.movement.maxSidewaysSpeed, and motor.movement.maxBackwardsSpeed.
Read more
  • 0
  • 0
  • 4319
article-image-html5-games-development-using-local-storage-store-game-data
Packt
05 Sep 2011
8 min read
Save for later

HTML5 Games Development: Using Local Storage to Store Game Data

Packt
05 Sep 2011
8 min read
  (For more resources on this subject, see here.)   The following screenshot shows the final result we will create through this article. So, let's get on with it: Storing data by using HTML5 local storage Imagine now we have published our CSS3 memory matching game (Code Download-Ch:3) and players are trying their best to perform well in the game. We want to show the players whether they played better or worse than the last time. We will save the latest score and inform players whether they are better or not this time by comparing the scores. They may feel proud when performing better. This may make them addicted and they may keep trying to get higher scores. Creating a game over dialog Before actually saving anything in the local storage, we need a game over screen. Imagine now we are playing the CSS3 memory matching game that we built and we successfully match and remove all cards. Once we finish, a game over screen pops up and shows the time we utilized to complete the game. Time for action – Creating a game over dialog with the elapsed played time Open the CSS3 matching game folder as our working directory. Download a background image from the following URL (we will use it as the background of the pop up): http://gamedesign.cc/html5games/popup_bg.jpg Place the image in the images folder. Open index.html into any text editor. We will need a font for the game over pop up. Add the following font embedding CSS into the head section: <link href="http://fonts.googleapis.com/css?family=Orbitron:400,700" rel="stylesheet" type="text/css" > Before the game section, we add a div named timer to show the elapsed playing time. In addition, we add a new popup section containing the HTML markup of the pop-up dialog: <div id="timer"> Elapsed time: <span id="elapsed-time">00:00</span></div><section id="game"> <div id="cards"> <div class="card"> <div class="face front"></div> <div class="face back"></div> </div> <!-- .card --> </div> <!-- #cards --></section> <!-- #game --><section id="popup" class="hide"> <div id="popup-bg"> </div> <div id="popup-box"> <div id="popup-box-content"> <h1>You Won!</h1> <p>Your Score:</p> <p><span class='score'>13</span></p> </div> </div></section> We will now move on to the style sheet. As it is just for styling and not related to our logic yet, we can simply copy the matchgame.css file from matching_game_with_game_over in the code example bundle (Ch:3). It is time to edit the game logic part. Open the html5games.matchgame.js file in an editor. In the jQuery ready function, we need a variable to store the elapsed time of the game. Then, we create a timer to count the game every second as follows: $(function(){ ...// reset the elapsed time to 0.matchingGame.elapsedTime = 0; // start the timer matchingGame.timer = setInterval(countTimer, 1000);} Next, add a countTimer function which will be executed every second. It displays the elapsed seconds in the minute and second format: function countTimer(){ matchingGame.elapsedTime++; // calculate the minutes and seconds from elapsed time var minute = Math.floor(matchingGame.elapsedTime / 60); var second = matchingGame.elapsedTime % 60; // add padding 0 if minute and second is less then 10 if (minute < 10) minute = "0" + minute; if (second < 10) second = "0" + second; // display the elapsed time $("#elapsed-time").html(minute+":"+second);} In the removeTookCards function which we wrote earlier, add the following highlighted code that executes the game over logic after removing all cards: function removeTookCards(){$(".card-removed").remove(); // check if all cards are removed and show game over if ($(".card").length == 0) { gameover(); } } At last, we create the following gameover function. It stops the counting timer, displays the elapsed time in the game over pop up, and finally shows the pop up: function gameover(){ // stop the timer clearInterval(matchingGame.timer); // set the score in the game over popup $(".score").html($("#elapsed-time").html()); // show the game over popup $("#popup").removeClass("hide");} Now, save all files and open the game in a browser. Try finishing the memory matching game and the game over screen will pop up, as shown in the following screenshot: What just happened? We have used the CSS3 transition animation to show the game over pop up. We benchmark the score by using the time a player utilized to finish the game. Saving scores in the browser Imagine now we are going to display how well the player played the last time. The game over screen includes the elapsed time as the last score alongside the current game score. Players can then see how well they do this time compared to last time. Time for action – Saving the game score First, we need to add a few markups in the popup section to display the last score. Add the following HTML in the popup section in index.html: <p> <small>Last Score: <span class='last-score'>20</span> </small></p> Then, we open the html5games.matchgame.js to modify some game logic in the gameover function. Add the following highlighted code in the gameover function. It loads the saved score from local storage and displays it as the score last time. Then, save the current score in the local storage: function gameover(){ // stop the timer clearInterval(matchingGame.timer); // display the elapsed time in the game over popup $(".score").html($("#elapsed-time")); // load the saved last score from local storage var lastElapsedTime = localStorage.getItem ("last-elapsed-time"); // convert the elapsed seconds into minute:second format // calculate the minutes and seconds from elapsed time var minute = Math.floor(lastElapsedTime / 60); var second = lastElapsedTime % 60; // add padding 0 if minute and second is less then 10 if (minute < 10) minute = "0" + minute; if (second < 10) second = "0" + second; // display the last elapsed time in game over popup $(".last-score").html(minute+":"+second); // save the score into local storage localStorage.setItem ("last-elapsed-time", matchingGame.elapsedTime); // show the game over popup $("#popup").removeClass("hide");} It is now time to save all files and test the game in the browser. When you finish the game for the first time, the last score should be 00:00. Then, try to finish the game for the second time. The game over pop up will show the elapsed time you played the last time. The following screenshot shows the game over screen with the current and last score: What just happened? We just built a basic scoring system that compares a player's score with his/her last score. Storing and loading data with local storage We can store data by using the setItem function from the localStorage object. The following table shows the usage of the function: localStorage.setItem(key, value); In our example, we save the game elapsed time as the score with the following code by using the key last-elapsed-item: localStorage.setItem("last-elapsed-time", matchingGame.elapsedTime); Complementary to setItem, we get the stored data by using the getItem function in the following way: localStorage.getItem(key); The function returns the stored value of the given key. It returns null when trying to get a non-existent key. This can be used to check whether we have stored any data for a specific key. The local storage saves the string value The local storage stores data in a key-value pair. The key and value are both strings. If we save numbers, Boolean, or any type other than string, then it will convert the value into a string while saving. Usually, problems occur when we load a saved value from the local storage. The loaded value is a string regardless of the type we are saving. We need to explicitly parse the value into the correct type before using it. For example, if we save a floating number into the local storage, we need to use the parseFloat function when loading it. The following code snippet shows how we can use parseFloat to retrieve a stored floating number: var score = 13.234;localStorage.setItem("game-score",score);// result: stored "13.234".var gameScore = localStorage.getItem("game-score");// result: get "13.234" into gameScore;gameScore = parseFloat(gameScore);// result: 13.234 floating value In the preceding code snippet, the manipulation may be incorrect if we forget to convert the gameScore from string to float. For instance, if we add the gameScore by 1 without the parseFloat function, the result will be 13.2341 instead of 14.234. So, be sure to convert the value from local storage to its correct type. Size limitation of local storageThere is a size limitation on the data stored through localStorage for each domain. This size limitation may be slightly different in different browsers. Normally, the size limitation is 5 MB. If the limit is exceeded, then the browser throws a QUOTA_EXCEEDED_ERR exception when setting a key-value into localStorage. Treating the local storage object as an associated array Besides using the setItem and getItem functions, we can treat the localStorage object as an associated array and access the stored entries by using square brackets. For instance, we can replace the following code with the latter version: Using the setItem and getItem: localStorage.setItem("last-elapsed-time", elapsedTime);var lastElapsedTime = localStorage.getItem("last-elapsed-time"); Access localStorage as an array as follows: localStorage["last-elapsed-time"] = elapsedTime;var lastElapsedTime = localStorage["last-elapsed-time"];
Read more
  • 0
  • 0
  • 5565

article-image-glsl-40-using-subroutines-select-shader-functionality
Packt
10 Aug 2011
7 min read
Save for later

GLSL 4.0: Using Subroutines to Select Shader Functionality

Packt
10 Aug 2011
7 min read
OpenGL 4.0 Shading Language Cookbook Over 60 highly focused, practical recipes to maximize your OpenGL Shading language use         In many ways it is similar to function pointers in C. A uniform variable serves as the pointer and is used to invoke the function. The value of this variable can be set from the OpenGL side, thereby binding it to one of a few possible definitions. The subroutine's function definitions need not have the same name, but must have the same number and type of parameters and the same return type. A single shader could be written to provide several shading algorithms intended for use on different objects within the scene. When rendering the scene, rather than swapping shader programs (or using a conditional statement), we can simply change the subroutine's uniform variable to choose the appropriate shading algorithm as each object is rendered. Since performance is crucial in shader programs, avoiding a conditional statement or a shader swap can be very valuable. With subroutines, we can implement the functionality of a conditional statement or shader swap without the computational overhead. In the following image, we see an example of a rendering that was created using subroutines. The teapot on the left is rendered with the full ADS shading model, and the teapot on the right is rendered with diffuse shading only. A subroutine is used to switch between shader functionality. Getting ready As with previous recipes, provide the vertex position at attribute location 0 and the vertex normal at attribute location 1. Uniform variables for all of the ADS coefficients should be set from the OpenGL side, as well as the light position and the standard matrices. We'll assume that, in the OpenGL application, the variable programHandle contains the handle to the shader program object. How to do it... To create a shader program that uses a subroutine to switch between pure-diffuse and ADS shading, use the following code: Use the following code for the vertex shader: #version 400 subroutine vec3 shadeModelType( vec4 position, vec3 normal); subroutine uniform shadeModelType shadeModel; layout (location = 0) in vec3 VertexPosition; layout (location = 1) in vec3 VertexNormal; out vec3 LightIntensity; struct LightInfo { vec4 Position; // Light position in eye coords. vec3 La; // Ambient light intensity vec3 Ld; // Diffuse light intensity vec3 Ls; // Specular light intensity }; uniform LightInfo Light; struct MaterialInfo { vec3 Ka; // Ambient reflectivity vec3 Kd; // Diffuse reflectivity vec3 Ks; // Specular reflectivity float Shininess; // Specular shininess factor }; uniform MaterialInfo Material; uniform mat4 ModelViewMatrix; uniform mat3 NormalMatrix; uniform mat4 ProjectionMatrix; uniform mat4 MVP; void getEyeSpace( out vec3 norm, out vec4 position ) { norm = normalize( NormalMatrix * VertexNormal); position = ModelViewMatrix * vec4(VertexPosition,1.0); } subroutine( shadeModelType ) vec3 phongModel( vec4 position, vec3 norm ) { // The ADS shading calculations go here (see: "Using // functions in shaders," and "Implementing // per-vertex ambient, diffuse and specular (ADS) shading") ... } subroutine( shadeModelType ) vec3 diffuseOnly( vec4 position, vec3 norm ) { vec3 s = normalize( vec3(Light.Position - position) ); return Light.Ld * Material.Kd * max( dot(s, norm), 0.0 ); } void main() { vec3 eyeNorm; vec4 eyePosition; // Get the position and normal in eye space getEyeSpace(eyeNorm, eyePosition); // Evaluate the shading equation. This will call one of // the functions: diffuseOnly or phongModel. LightIntensity = shadeModel( eyePosition, eyeNorm ); gl_Position = MVP * vec4(VertexPosition,1.0); } Use the following code for the fragment shader: #version 400 in vec3 LightIntensity; layout( location = 0 ) out vec4 FragColor; void main() { FragColor = vec4(LightIntensity, 1.0); } In the OpenGL application, compile and link the above shaders into a shader program, and install the program into the OpenGL pipeline. Within the render function of the OpenGL application, use the following code: GLuint adsIndex = glGetSubroutineIndex( programHandle, GL_VERTEX_SHADER,"phongModel" ); GLuint diffuseIndex = glGetSubroutineIndex(programHandle, GL_VERTEX_SHADER, "diffuseOnly"); glUniformSubroutinesuiv( GL_VERTEX_SHADER, 1, &adsIndex); ... // Render the left teapot glUniformSubroutinesuiv( GL_VERTEX_SHADER, 1, &diffuseIndex); ... // Render the right teapot How it works... In this example, the subroutine is defined within the vertex shader. The first step involves declaring the subroutine type. subroutine vec3 shadeModelType( vec4 position, vec3 normal); This defines a new subroutine type with the name shadeModelType. The syntax is very similar to a function prototype, in that it defines a name, a parameter list, and a return type. As with function prototypes, the parameter names are optional. After creating the new subroutine type, we declare a uniform variable of that type named shadeModel. subroutine uniform shadeModelType shadeModel; This variable serves as our function pointer and will be assigned to one of the two possible functions in the OpenGL application. We declare two functions to be part of the subroutine by prefixing their definition with the subroutine qualifier: subroutine ( shadeModelType ) This indicates that the function matches the subroutine type, and therefore its header must match the one in the subroutine type definition. We use this prefix for the definition of the functions phongModel and diffuseOnly. The diffuseOnly function computes the diffuse shading equation, and the phongModel function computes the complete ADS shading equation. We call one of the two subroutine functions by utilizing the subroutine uniform shadeModel within the main function. LightIntensity = shadeModel( eyePosition, eyeNorm ); Again, this call will be bound to one of the two functions depending on the value of the subroutine uniform shadeModel, which we will set within the OpenGL application. Within the render function of the OpenGL application, we assign a value to the subroutine uniform with the following steps. First, we query for the index of each subroutine function using glGetSubroutineIndex. The first argument is the program handle. The second is the shader stage. In this case, the subroutine is defined within the vertex shader, so we use GL_VERTEX_SHADER here. The third argument is the name of the subroutine. We query for each function individually and store the indexes in the variables adsIndex and diffuseIndex. To select the appropriate subroutine function, we need to set the value of the subroutine uniform shadeModel. To do so, we call glUniformSubroutinesuiv. This function is designed for setting multiple subroutine uniforms at once. In our case, of course, we are setting only a single uniform. The first argument is the shader stage (GL_VERTEX_SHADER), the second is the number of uniforms being set, and the third is a pointer to an array of subroutine function indexes. Since we are setting a single uniform, we simply provide the address of the GLuint variable containing the index, rather than a true array of values. Of course, we would use an array if multiple uniforms were being set. In general, the array of values provided as the third argument is assigned to subroutine uniform variables in the following way. The ith element of the array is assigned to the subroutine uniform variable with index i. Since we have provided only a single value, we are setting the subroutine uniform at index zero. You may be wondering, "How do we know that our subroutine uniform is located at index zero? We didn't query for the index before calling glUniformSubroutinesuiv!" The reason that this code works is that we are relying on the fact that OpenGL will always number the indexes of the subroutines consecutively starting at zero. If we had multiple subroutine uniforms, we could (and should) query for their indexes using glGetSubroutineUniformLocation, and then order our array appropriately. Finally, we select the phongModel function by setting the uniform to adsIndex and then render the left teapot. We then select the diffuseOnly function by setting the uniform to diffuseIndex and render the right teapot. There's more... A subroutine function defined in a shader can match multiple subroutine types. In that case, the subroutine qualifier can contain a comma-separated list of subroutine types. For example, if a subroutine matched the types type1 and type2, we could use the following qualifier: subroutine( type1, type2 ) This would allow us to use subroutine uniforms of differing types to refer to the same subroutine function. Summary With subroutines we can implement the functionality of a conditional statement or shader swap without the computational overhead. Further resources on this subject: Tips and Tricks for Getting Started with OpenGL and GLSL 4.0 [Article] OpenGL 4.0: Using Uniform Blocks and Uniform Buffer Objects [Article] OpenGL 4.0: Building a C++ Shader Program Class [Article] The Basics of GLSL 4.0 Shaders [Article] GLSL 4.0: Discarding Fragments to Create a Perforated Look [Article]
Read more
  • 0
  • 0
  • 5718