Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon

How-To Tutorials - 2D Game Development

64 Articles
article-image-creating-our-first-game
Packt
31 May 2013
11 min read
Save for later

Creating Our First Game

Packt
31 May 2013
11 min read
(For more resources related to this topic, see here.) Let's get serious – the game The game we will implement now is inspired by Frogger. In this old school arcade game, you played the role of a frog trying to cross the screen by jumping on logs and avoiding cars. In our version, the player is a developer who has to cross the network cable by jumping packets and then cross the browser "road" by avoiding bugs. To sum up, the game specifications are as follows: If the player presses the up arrow key once, the "frog" will go forward one step. By pressing the right and left arrow key, the player can move horizontally. In the first part (the network cable) the player has to jump on packets coming from the left of the screen and moving to the right. The packets are organized in lines where packets of each line travel at different speeds. Once the player is on a packet, he/she will move along with it. If a packet drives the player outside of the screen, or if the player jumps on the cable without reaching a packet, he/she will die and start at the beginning of the same level once again. In the second part (the browser part) the player has to cross the browser screen by avoiding the bugs coming from the left. If the player gets hit by a bug he/she will start at the beginning of the same level once again. These are very simple rules, but as you will see they will already give us plenty of things to think about. Learning the basics Throughout this article, we will use DOM elements to render game elements. Another popular solution would be to use the Canvas element. There are plus and minus points for both technologies and there are a few effects that are simply not possible to produce with only DOM elements. However, for the beginner, the DOM offers the advantage of being easier to debug, to work on almost all existing browsers (yes, even on Internet Explorer 6), and in most cases to offer reasonable speed for games. The DOM also abstracts the dirty business of having to target individual pixels and tracking which part of the screen has to be redrawn. Even though Internet Explorer supports most of the features we will see in this book, I would not recommend creating a game that supports it. Indeed, its market share is negligible nowadays (http://www.ie6countdown.com/) and you will encounter some performance issues. Now from some game terminology, sprites are the moving part of a game. They may be animated or nonanimated (in the sense of changing their aspect versus simply moving around). Other parts of the game may include the background, the UI, and tiles. Framework During this article, we will write some code; part of the code belongs to an example game and is used to describe scenes or logic that are specific to it. Some code, however, is very likely to be reused in each of your games. For this reason, we will regroup some of those functions into a framework that we will cleverly call gameFramework or gf in short. A very simple way to define a namespace in JavaScript is to create an object and add all your function directly to it. The following code gives you an example of what this might look like for two functions, shake and stir, in the namespace cocktail. // define the namespacevar cocktail = {};// add the function shake to the namespacecocktail.shake = function(){...}// add the function stir to the namespacecocktail.stir = function(){...} This has the advantage of avoiding collision with other libraries that use similar names for their objects or functions. Therefore, from now on when you see any function added to the namespace, it will mean that we think those functions will be used by the other games we will create later in this article or that you might want to create yourself. The following code is another notation for namespace. Which one you use is a personal preference and you should really use the one that feels right to you! var cocktail = {// add the function shake to the namespaceshake: function(){...},// add the function stir to the namespacestir: function(){...}}; Typically, you would keep the code of the framework in a JS file (let's say gameFramework.js) and the code of the game in another JS file. Once your game is ready to be published, you may want to regroup all your JavaScript code into one file (including jQuery if you wish so) and minimize it. However, for the whole development phase it will be way more convenient to keep them separate. Sprites Sprites are the basic building blocks of your game. They are basically images that can be animated and moved around the screen. To create them you can use any image editor. If you work on OS X, there is a free one that I find has been particularly well done, Pixen (http://pixenapp.com/). You can use animated gifs. With this method you have no way to access the index of the current frame through JavaScript, and no control over when the animation starts to play or when it ends. Furthermore, having many animated GIFs tends to slow things down a lot. You can change the source of the image. This is already a better solution, but provides worse performance if proposed and requires a large number of individual images. Another disadvantage is that you cannot choose to display only one part of the image; you have to show the entire image each time. Finally, if you want to have a sprite made of a repeating image, you will have to use many img elements. For the sake of completeness, we should mention here one advantage of img; it's really easy to scale an img element—just adjust the width and height. The proposed solution uses simple divs of defined dimensions and sets an image in the background. To generate animated sprites, you could change the background image, but instead we use the background position CSS property. The image used in this situation is called a sprite sheet and typically looks something like the following screenshot: The mechanism by which the animation is generated is shown in the following screenshot: Another advantage is that you can use a single sprite sheet to hold multiple animations. This way you will avoid having to load many different images. Depending on the situation, you may still want to use more than one sprite sheet, but it's a good thing to try to minimize their number. Implementing animations It's very simple to implement this solution. We will use .css() to change the background properties and a simple setInterval to change the current frame of the animation. Therefore, let's say that we have a sprite sheet containing 4 frames of a walk cycle where each frame measures 64 by 64 pixels. First, we simply have to create a div with the sprite sheet as its background. This div should measure 64 by 64 pixels, otherwise the next frame would leak onto the current one. In the following example, we add the sprite to a div with the ID mygame. $("#mygame").append("<div id='sprite1'>"); $("#sprite1").css("backgroundImage","url('spritesheet1.png')"); As the background image is by default aligned with the upper-left corner of the div, we will only see the first frame of the walk-cycle sprite sheet. What we want is to be able to change what frame is visible. The following function changes the background position to the correct position based on the argument passed to it. Take a look at the following code for the exact meaning of the arguments: /** * This function sets the current frame. * -divId: the Id of the div from which you want to change the * frame * -frameNumber: the frame number * -frameDimension: the width of a frame **/ gameFramework.setFrame = function(divId,frameNumber, frameDimension) { $("#"+divId) .css("bakgroundPosition", "" + frameNumber * frameDimension + "px 0px"); } Now we have to call this at regular intervals to produce the animation. We will use setInterval with an interval of 60 milliseconds, that is, around 17 frames per second. This should be enough to give the impression of walking; however, this really has to be fine-tuned to match your sprite sheet. To do this we use an anonymous function that we pass to setInterval, which will in turn call our function with the correct parameter. var totalNumberOfFrame = 4;var frameNumber = 0;setInterval(function(){gameFramework.setFrame("sprite1",frameNumber, 64);frameNumber = (frameNumber + 1) % totalNumberOfFrame;}, 60); You probably noticed that we're doing something special to compute the current frame. The goal is to cover values from 0 to 3 (as they're 4 frames) and to loop back to 0 when we reach 4. The operation we use for this is called modulo (%) and it's the rest of the integer division (also known as Euclidean division). For example, at the third frame we have 3 / 4 which is equal to 0 plus a remainder of 3, so 3 % 4 = 3. When the frame number reaches 4 we have 4 / 4 = 1 plus a remainder of 0, so 4 % 4 = 0. This mechanism is used in a lot of situations. Adding animations to our framework As you can see there are more and more variables needed to generate an animation: the URL of the image, the number of frames, their dimension, the rate of the animation, and the current frame. Furthermore, all those variables are associated with one animation, so if we need a second one we have to define twice as many variables. The obvious solution is to use objects. We will create an animation object that will hold all the variables we need (for now, it won't need any method). This object, like all the things belonging to our framework, will be in the gameFramework namespace. Instead of giving all the values of each of the properties of the animation as an argument, we will use a single object literal, and all the properties that aren't defined will default to some well-thought-out values. To do this, jQuery offers a very convenient method: $.extend. This is a very powerful method and you should really take a look at the API documentation (http://api.jquery.com/) to see everything that it can do. Here we will pass to it three arguments: the first one will be extended with the values of the second one and the resulting object will be extended with the values of the third. /*** Animation Object.**/gf.animation = function(options) {var defaultValues = {url : false,width : 64,numberOfFrames : 1,currentFrame : 0,rate : 30};$.extend(this, defaultValues, options);} To use this function we will simply create a new instance of it with the desired values. Here you can see the values used in the preceding examples: var firstAnim = new gameFramework.animation({url: "spritesheet1.png",numberOfFrames: 4,rate: 60}); As you can see, we didn't need to specify width: 64 because it's the default value! This pattern is very convenient and you should keep it in mind each time you need default values and also the flexibility to override them. We can rewrite the function to use the animation object: gf.setFrame = function(divId, animation) {$("#" + divId).css("bakgroundPosition", "" + animation.currentFrame *animation.width + "px 0px");} Now we will create a function for our framework based on the technique we've already seen, but this time it will use the new animation object. This function will start animating a sprite, either once or in a loop. There is one thing we have to be careful about—if we define an animation for a sprite that is already animated we need to deactivate the current animation and replace it with the new one. To do this we will need an array to hold the list of all intervals' handles. Then we'll only need to check if one exists for this sprite and clear it, then define it again. gf.animationHandles = {}; /** * Sets the animation for the given sprite. **/ gf.setAnimation = function(divId, animation, loop){ if(gf.animationHandles[divId]){ clearInterval(gf.animationHandles[divId]); } if(animation.url){ $("#"+divId).css("backgroundImage","url('"+animation. url+"')"); } if(animation.numberOfFrame > 1){ gf.animationHandles[divId] = setInterval(function(){ animation.currentFrame++; if(!loop && currentFrame > animation.numberOfFrame){ clearInterval(gf.animationHandles[divId]); gf.animationHandles[divId] = false; } else { animation.currentFrame %= animation. numberOfFrame; gf.setFrame(divId, animation); } }, animation.rate); } } This will provide a convenient, flexible, and quite high-level way to set an animation for a sprite.
Read more
  • 0
  • 0
  • 1347

article-image-article-making-money-your-game
Packt
17 May 2013
23 min read
Save for later

Making Money with Your Game

Packt
17 May 2013
23 min read
(For more resources related to this topic, see here.) Your game development strategy If you want to build a game to make some money, it is imperative you take a few things into consideration before starting off building one. The first question you will need to ask yourself is probably this: who am I going to build a game for? Are you aiming at everyone capable of playing games or do you want to target a very specific segment of people and meet their gaming needs? This is the difference between broad and niche targeting. An example of very broadly targeted games are most tower defense games, in which you need to build towers with diverse properties to repel an army. Games such as Tetris, Bejeweled, Minesweeper, and most light puzzle games in general. Angry Birds is another example of a game that is popular with a broad audience because of its simplicity, likeable graphics, and incredible amount of clever marketing. Casual games in general seem to appeal to the masses because of the following few factors: Simplicity prevails: most gamers get used to the game in mere minutes. There are little or no knowledge prerequisites: you are not expected to already know some of the background story or have experience in these types of games. Casual gamers tend to do well even though they put in less time to practice. Even if you do well from the start, you can still become better at it. A game at which you cannot become better by replaying doesn't hold up for long. Notable exceptions are games of chance like roulette and the slots, which do prove to be addictive; but that is for other reasons, such as the chance to win money. The main advantage to building casual games is that practically everyone is a potential user of your game. As such, the achievable success can be enormous. World of Warcraft is a game which has moved from rather hardcore and niche to more casual over the years. They did this because they had already reached most regular gamers out there, and decided to convince the masses that you can play World of Warcraft even if you don't play a lot in general. The downside of trying to please everyone is the amount of competition. Sticking out as a unique game among numerous games out there is tremendously difficult. This is especially true if you don't have an impressive marketing machine to back it up. A good example of a niche game is any game built after a movie. Games on Star Trek, Star Wars, Lord of the Rings, and so on, are mostly aimed at people who have seen and liked those movies. Niche games can also be niche because they are targeted solely at a specific group of gamers. For example, people who prefer playing FPS (First Person Shooters) games, and do so every single day. In essence, niche games have the following properties (note that they oppose casual or broadly targeted games): Steep learning curve: mastery requires many hours of dedicated gaming. Some knowledge or experience with games is required. An online shooter game such as PlanetSide 2 requires you to have at least some experience with shooter games in the past, since you are pitted against people who know what they are doing. The more you play the game, the more are the useful rewards you get. Playing a lot is often rewarded with items that make you even stronger in the game, thus reinforcing the fact that you already became better by playing more. StarCraft is a game released by Blizzard in 1998 and is still being played in tournaments today, even though there is a follow up: StarCraft 2. Games such as the original StarCraft are perfectly feasible to be built in HTML5 and run on a browser or smartphone. When StarCraft was released, the average desktop computer had less power than many smartphones have today. Technically, the road is open; replicating the same level of success is another matter though. The advantage of aiming at a niche of gamers is the unique position you can take in their lives. Maybe there are not many people in your target group, but it will be easier to get and keep their attention with your game since it is specifically built for them. In addition, it doesn't mean that because you have a well-defined aim, gamers can't drop in from unexpected corners. People you would have never thought would play your game can still like what you did. It is for this reason that knowing your gamers is so important, and why tools such as Playtomic exist. The disadvantage of the niche marketing is obvious: your game is very unlikely to grow beyond a certain point; it will probably never rank among the most played games in the world. The type of games you are going to develop is one choice, the amount of detail you put in each one of them is another. You can put as much effort into building a single game as you want. In essence, a game is never finished. A game can always have an extra level, Easter egg, or another nice little detail. When scoping your game, you must have decided whether you will use a shotgun or a sniper development strategy. In a shotgun strategy, you develop and release games quickly. Each game still has a unique element that should distinguish it from other games: the UGP (Unique Gaming Proposition). But games released under a shotgun strategy don't deliver a lot of details; they are not polished. The advantages of adopting a shotgun strategy are plenty: Low development cost; thus every game represents a low risk The short time to market allows for using world events as game settings You have several games on the market at once, but often you only need a single one to succeed in order to cover the expenses incurred for the others Short games can be given to the public for free but monetized by selling add-ons, such as levels However, it's not just rainbows and sunshine when you adopt this strategy. There are several reasons why you wouldn't choose shotgun strategy: A game that doesn't feel finished has less chance of being successful than a perfected one. Throwing your game on the market not only tests whether a certain concept works, but also exposes it to the competitors, who can now start building a copy. Of course, you have the first mover advantage, but it's not as big as it could have been. You must always be careful not to throw garbage on the market either, or you might ruin your name as a developer. However, don't get confused. The shotgun strategy is not an excuse for building mediocre games. Every game you release should have an original touch to it— something that no other game has. If a game doesn't have that new flavor, why would anyone prefer it over all the others? Then, of course, there is the sniper strategy, which involves building a decent and well-thought-out game and releasing it to the market with the utmost care and support. This is what distributors such as Apple urge developers to do, and for good reason—you wouldn't want your app store full of crappy games, would you? Some other game distributers, such as Steam, are even pickier in the games they allow to be distributed, making the shotgun strategy nearly impossible. But it is also the strategy most successful game developers use. Take a look at developers such as Rockstar (developer of the GTA series), Besthesda (developer of the Elder Scroll series), Bioware (developer of the Mass Effect series), Blizzard (developer of the Warcraft series), and many others. These are no small fries, yet they don't have that many games on the market. This tactic of developing high quality games and hoping they will pay off is obviously not without risk. In order to develop a truly amazing game, you also need the time and money to do so. If your game fails to sell, this can be a real problem for you or your company. Even for HTML5 games, this can be the case, especially since devices and browsers keep getting more and more powerful. When the machines running the games get more powerful, the games themselves often become more complex and take longer to develop. We have taken a look at two important choices one needs to make when going into the game-developing business. Let's now look at the distribution channels that allow you to make money with your game, but before that let's summarize the topic we have just covered: Deciding who you want to target is extremely important even before you start developing your game. Broad targeting is barely targeting at all. It is about making a game accessible and likeable by as many people as possible. Niche targeting is taking a deeper look and interest in a certain group of people and building a game to suit their specific gaming needs. In developing and releasing games, there are two big strategies: shotgun and sniper. In the shotgun strategy you release games rapidly. Each game still has unique elements that no other games possess, but they are not as elaborate or polished as they could be. With the sniper strategy you build only a few games, but each one is already perfected at the time of release and only needs slight polishing when patches are released for it. Making money with game apps If you built your game into an app, you have several distribution channels you can turn to, such as Firefox marketplace, the IntelAppUp center, Windows Phone Store, Amazon Appstore, SlideMe, Mobango, Getjar, and Apple Appsfire. But the most popular players on the market currently are Google Play and the iOS App Store. The iOS App Store is not to be confused with the Mac app store. iPad and Mac have two different operating systems, iOS and Mac OS, so they have separate stores. Games can be released both in the iOS and the Mac store. There could also be some confusion between Google Play and Chrome Web Store. Google Play contains all the apps available for smartphones that have Google's Android operating system. The Chrome Web Store lets you add apps to your Google Chrome browser. So there are quite a few distribution channels to pick from and here we will have a quick look at Google Play, the iOS App store, and the Chrome Web Store. Google Play Google Play is the Android's default app shop and the biggest competitor of the iOS App Store. If you wish to become an Android app developer, there is a $25 fee and a developer distribution agreement that you must read. In return for the entrance fee and signing this agreement, they allow you to make use of their virtual shelves and have all its benefits. You can set your price as you please, but for every game you sell, Google will cash in about 30 percent. It is possible to do some geological price discrimination. So you could set your price at, let's say €1 in Belgium, while charging €2 in Germany. You can change your price at any time; however, if you release a game for free, there is no turning back. The only way to monetize this app afterwards is by allowing in game advertising, selling add-ons, or creating an in-game currency that can be bought with real money. Introducing an in-game currency that is bought with real money can be a very appealing format. A really successful example of this monetizing scheme can be found in The Smurfs games. In this game you build your own Smurf village, complete with Big Smurf, Smurfette, and a whole lot of mushrooms. Your city gets bigger as you plant more crops and build new houses, but it is a slow process. To speed it up a bit you can buy special berries in exchange for real money, which in turn allows you to build exclusive mushrooms and other things. This monetization scheme becomes very popular as has been shown in games such as League Of Legends, PlanetSide 2, World of Tanks, and many others. For Google Play apps, this in-app payment system is supported by Android's Google Checkout. In addition, Google allows you access to some basic statistics for your game, such as the number of players and the devices on which they play, as shown in the following diagram: Image Information such as this allows you to redesign your game to boost your success. For example, you could notice if a certain device doesn't have that many unique users, even though it is a very popular device and is bought by many people. If this is the case, maybe your game doesn't looks nice on this particular smartphone or tablet and you should optimize for it. The biggest competitor and initiator of all apps is the iOS App Store, so let's have a look at this. iOS App Store The iOS App Store was the first of its kind and at the time of writing this book, it still has the biggest revenue. In order to publish apps in the iOS App Store, you need to subscribe to the iOS Developer Program, which costs $99 annually—almost four times the subscription fee of Google Play. In effect, they offer about the same thing as Google Play does; as you can see in this short list: You pick your own prices and get 70 percent of sales revenue You receive monthly payments without credit card, hosting, or marketing fees There is support and adequate documentation to get you started More importantly, here are the following differences between Google Play and the iOS App Store: As mentioned earlier, signing up for Google Play is cheaper. The screening process of Apple seems to be more strict than that of Google Play, which results in a longer time to reach the market and a higher chance of never even reaching the market. Google Play incorporates a refund option that allows the buyer of your app to be refunded if he or she uninstalls the app or game within 24 hours. If you want your game to make use of some Android core functionalities, this is possible since the platform is open source. Apple, on the other hand, is very protective of its iOS platform and doesn't allow the same level of flexibility for apps. This element might not seem that important for games just yet, but it might be for very innovative games that do want to make use of this freedom. iOS reaches more people than Android does, though the current trend indicates that this might change in the near future. There seem to be significant differences in the kind of people buying Apple devices and the users of smartphones or tablets with Android OS. Apple fans tend to have a lower barrier towards spending money on their apps than Android users do. In general, iPads and iPhones are more expensive than other tablets and smartphones, attracting people who have no problem with spending even more money on the device. This difference in target group seems to make it more difficult for Android game developers to make money from their games. The last option for selling apps that we will discuss here is the Chrome Web Store. The Chrome Web Store The Chrome Web Store differs from Google Play and the iOS App Store in that it provides apps specifically for the Chrome browser and not for mobile devices. The Chrome Store offers web apps. Web apps are like applications you would install on your PC, except web apps are installed in your browser and are mostly written using HTML, CSS, and JavaScript, like our ImpactJS games. The first thing worth noticing about the Chrome Store is the one-time $5 entrance fee for posting apps. If this in itself is not good enough, the transaction fee for selling an app is only 5 percent. This is a remarkable difference to both Google Play and the iOS App Store. If you are already developing a game for your own website and packaged it as an app for Android and/or Apple, you can just as well launch it on the Chrome Web Store. Turning your ImpactJS game into a web app for the Chrome Store can be done using AppMobi, yet Google itself provides detailed documentation on how to do this manually. One of the biggest benefits of the web app is the facilitation of the permission process. Let's say your web app needs the location of the user in order to work. While iPad apps ask for permission every time they need location data, the web app asks permission only once: at installation time. Furthermore, you have the same functionalities and payment modalities as in Google Play, give or take. For instance, there is also the option to incorporate a free trial version, also known as a freemium. A freemium model is when you allow downloading a demo version for free with the option of upgrading it to a full version for a price. The Smurfs game also uses the freemium model, albeit with a difference. The entire game is free, but players can opt to pay real money to buy things that would otherwise cost them a lot of time to acquire. In this freemium model, you pay for convenience and unique items. For instance, in PlanetSide 2, acquiring a certain sniper rifle might take you several days or $10, depending on how you choose to play the freemium game. If you plan on releasing an ImpactJS game for Android, there is no real reason why you wouldn't do so for the Chrome Web Store. That being said, let's have a quick recap: The time when the iOS app store was the only app store out there is long gone; there is an impressive repertoire of app stores to choose from, which includes Firefox Marketplace, Intel AppUp Center, Windows Phone Store, Amazon Appstore, SlideMe, Mobango, Getjar, Appsfire, Google Play, among others. The biggest app stores are currently Google Play and the iOS App Store. They differ greatly on several fronts, of which the most important ones are: Subscription fee Screening process Type of audience they attract The Chrome Web Store sells web apps that act like normal apps but are available in the Chrome browser. The Chrome Web Store is cheap and easy to subscribe to. You must definitely have a go at releasing your game on this platform. In-game advertising In-game advertising is another way to make money with your game. In-game advertising is a growing market and is currently already being used by major companies; it was also used by Barack Obama in both his 2008 and 2012 campaigns, as shown in the following in-game screenshot: Image There is a trend towards more dynamic in-game advertising. The game manufacturers make sure there is space for advertising in the game, but the actual ads themselves are decided upon later. Depending on what is known about you, these can then change to become relevant to you as a player and a real-life consumer. When just starting out to build games, in-game adverting doesn't get that spectacular though. Most of the best known in-game advertisers for online games don't even want their ads in startup games. The requirements for Google AdSense are the following: Game plays: Minimum 500,000 per day Game types: Web-based Flash only Integration: Must be technically capable of SDK integration Traffic source: Eighty percent of traffic must be from the US and the UK Content: Family-safe and targeted at users aged 13 and over Distribution: Must be able to report embedded destinations and have control over where the games are distributed The requirements for another big competitor, Ad4Game, aren't mild either: At least 10,000 daily unique visitors Sub-domains and blogs are not accepted The Alexa rank should be less than 400,000 Adult/violent/racist content is not allowed If you are just starting out, these prerequisites are not good news. Not only because you need such a large number of players before even starting the advertising, but also because currently all support goes to Flash games. HTML5 games are not fully supported yet, though that will probably change. Luckily, there are companies out there that do allow you to start using advertising even though you don't have 10,000 visitors a day. Tictacti is one of those companies. Once again, almost all support goes to the Flash games, but they do have one option available for an HTML5 game:pre-roll. Pre-roll simply means that a screen with an ad appears before you can start the game. Integration of the pre-roll advertising is rather straightforward and does not require a change to your game, but to your index.html file, as in the following example from Tictacti: code While adding this to your game's index.html file, you fill out your own publisher ID and you are basically ready to go. Tictacti is similar to Google Analytics, and it also provides you with some relevant information about the ads on your game's website, as shown in the following diagram: Image Be careful, however, pre-roll advertising is one of the most intruding and annoying kinds of advertising. Technically, it is not even in-game advertising at all, since it runs before you play the game. If your game is not yet well established enough to convince the player to endure the advertising before being able to play, don't choose this option. Give your game some time to build a reputation before putting your gamers through this. As the last option, we will have a look at selling your actual distribution rights with MarketJS. But let's first briefly recap on in-game advertising: In-game advertising is a growing market. Even Barack Obama made use of in-game billboards to support his campaign. There is a trend towards more dynamic in-game advertising—using your location and demographic information to adapt the ads in a game. Currently, even the most accessible companies that offer online in-game advertising are focused on Flash games and require many unique visitors before even allowing you to show their ads. Tictacti is a notable exception, as it has low prerequisites and an easy implementation; though advertising is currently limited to pre-roll ads. Always take care to first build a positive reputation for your game and allow advertisements later. Selling distribution rights with MarketJS The last option we will investigate in this chapter is selling your game's distribution rights. You can still make money by just posting your game to all the app stores and on your own website, but it becomes increasingly difficult to be noticed. Quality can only prevail if people know it is out there, thus making a good game is sometimes not enough—you need marketing. If you are a beginner game builder with great game ideas and the skills to back it up, that's great, but marketing may not be your cup of tea. This is where MarketJS comes into play. MarketJS acts as an intermediate between you as the game developer and the game publishers. The procedure is simple once you have a game: You sign up on their website, http://www.marketjs.com. Upload the game on your own website or directly to the MarketJS server. Post your game for publishers to see. You set several options such as the price and contract type that would suit you the best. You have five contract options: Complete distribtution contract: Sell all your distribution rights to the game. Exclusive distribution partner contract: Here you restrict yourself to work with one distributor but still retain the rights to the game. Non-exclusive contract: Here, any distributor can buy the rights to use your game, but you can go on selling rights as long as you want. Revenue share: Here you negotiate on how to split the revenues derived from the game. Customized contract: This can basically have any terms. You can choose this option if you are not sure yet what you want out of your game. A part of the webpage on which you fill out your contracting preferences is shown in the following screenshot: Image After you have posted a demo, it is a matter of waiting for a publisher to spot it, get stunned by its magnificence, and offer to work with you. The big contribution of MarketJS to the gaming field is this ability to let the game developer focus on developing games. Someone else takes care of the marketing aspect, which is a totally different ballgame. MarketJS also offers a few interesting statistics such as the average price of a game on their website, as shown in the following diagram. It grants you some insight on whether you should take up game developing as a living or keep doing it as a hobby. Image According to MarketJS, prices for non-exclusive rights average between $500 and $1000, while selling exclusive rights to a game range somewhere between $1500 and $2000. If you can build a decent game within this price range, you are more than ready to go: MarketJS is a company that brings game distributers and developers closer together. Their focus is on HTML5 games, so they are great if you are a startup ImpactJS game developer. They require no subscription fee and have a straightforward process to turn your game into a showcase with a price tag. Summary In this article we have taken a look at some important elements while considering your game development strategy. Do you wish to adapt a shotgun approach and develop a lot of games in a short time span? Or will you use the sniper strategy and only build a few, but very polished games? You also need to decide upon the audience you wish to reach out to with your game. You have the option of building a game that is liked by everyone, but the competition is steep. Making money on the application stores is possible, but for Android and Apple there are registration fees. If you decide to develop apps, it is worth giving the Chrome Web Store a try (it runs web apps). In-game advertising is another way to fund your efforts, though most companies offering this service for online games have high prerequisites and support Flash games more than they do the newer HTML5 games. One of the most promising of monetization schemes is the freemium model. Players are allowed to freely play your game but they pay real money for extras. This is an easily tolerated model since the game is essentially free to play for anyone not willing to spend money, and no annoying advertising is present either. A combination of in-game advertising and freemium is possible as well: people annoyed by the advertising pay a fee and in return they are not bothered by it anymore. A final option is leaving the marketing aspect to someone else by selling your distribution rights with the help of MarketJS. They aim for HTML5 games and this option is especially useful for the beginner game developer who has difficulty in marketing his or her game. Resources for Article : Further resources on this subject: HTML5: Developing Rich Media Applications using Canvas [Article] Flash 10 Multiplayer Game: The Lobby and New Game Screen Implementation [Article] Building HTML5 Pages from Scratch [Article]
Read more
  • 0
  • 0
  • 4148

article-image-running-simple-game-using-pygame
Packt
29 Mar 2013
5 min read
Save for later

Running a simple game using Pygame

Packt
29 Mar 2013
5 min read
How to do it... Imports: First we will import the required Pygame modules. If Pygame is installed properly, we should get no errors: import pygame, sys from pygame.locals import * Initialization: We will initialize Pygame by creating a display of 400 by 300 pixels and setting the window title to Hello world: pygame.init() screen = pygame.display.set_mode((400, 300)) pygame.display.set_caption('Hello World!') The main game loop: Games usually have a game loop, which runs forever until, for instance, a quit event occurs. In this example, we will only set a label with the text Hello world at coordinates (100, 100). The text has a font size of 19, red color, and falls back to the default font: while True: sys_font = pygame.font.SysFont("None", 19) rendered = sys_font.render('Hello World', 0, (255, 100, 100)) screen.blit(rendered, (100, 100)) for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() pygame.display.update() We get the following screenshot as the end result: The following is the complete code for the Hello World example: import pygame, sys from pygame.locals import * pygame.init() screen = pygame.display.set_mode((400, 300)) pygame.display.set_caption('Hello World!') while True: sysFont = pygame.font.SysFont("None", 19) rendered = sysFont.render('Hello World', 0, (255, 100, 100)) screen.blit(rendered, (100, 100)) for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() pygame.display.update() How it works... It might not seem like much, but we learned a lot in this recipe. The functions that passed the review are summarized in the following table: Function Description pygame.init() This function performs the initialization and needs to be called before any other Pygame functions are called. pygame.display.set_mode((400, 300)) This function creates a so-called   Surface object to draw on. We give this function a tuple representing the width and height of the surface. pygame.display.set_caption('Hello World!') This function sets the window title to a specified string value. pygame.font.SysFont("None", 19) This function creates a system font from a comma-separated list of fonts (in this case none) and a font size parameter. sysFont.render('Hello World', 0, (255, 100, 100)) This function draws text on a surface. The second parameter indicates whether anti-aliasing is used. The last parameter is a tuple representing the RGB values of a color. screen.blit(rendered, (100, 100)) This function draws on a surface. pygame.event.get() This function gets a list of Event objects. Events represent some special occurrence in the system, such as a user quitting the game. pygame.quit() This function cleans up resources used by Pygame. Call this function before exiting the game. pygame.display.update() This function refreshes the surface.   Drawing with Pygame Before we start creating cool games, we need an introduction to the drawing functionality of Pygame. As we noticed in the previous section, in Pygame we draw on the Surface objects. There is a myriad of drawing options—different colors, rectangles, polygons, lines, circles, ellipses, animation, and different fonts. How to do it... The following steps will help you diverge into the different drawing options you can use with Pygame: Imports: We will need the NumPy library to randomly generate RGB values for the colors, so we will add an extra import for that: import numpy Initializing colors: Generate four tuples containing three RGB values each with NumPy: colors = numpy.random.randint(0, 255, size=(4, 3)) Then define the white color as a variable: WHITE = (255, 255, 255) Set the background color: We can make the whole screen white with the following code: screen.fill(WHITE) Drawing a circle: Draw a circle in the center with the window using the first color we generated: pygame.draw.circle(screen, colors[0], (200, 200), 25, 0) Drawing a line: To draw a line we need a start point and an end point. We will use the second random color and give the line a thickness of 3: pygame.draw.line(screen, colors[1], (0, 0), (200, 200), 3) Drawing a rectangle: When drawing a rectangle, we are required to specify a color, the coordinates of the upper-left corner of the rectangle, and its dimensions: pygame.draw.rect(screen, colors[2], (200, 0, 100, 100)) Drawing an ellipse: You might be surprised to discover that drawing an ellipse requires similar parameters as for rectangles. The parameters actually describe an imaginary rectangle that can be drawn around the ellipse: pygame.draw.ellipse(screen, colors[3], (100, 300, 100, 50), 2) The resulting window with a circle, line, rectangle, and ellipse using random colors: The code for the drawing demo is as follows: import pygame, sys from pygame.locals import * import numpy pygame.init() screen = pygame.display.set_mode((400, 400)) pygame.display.set_caption('Drawing with Pygame') colors = numpy.random.randint(0, 255, size=(4, 3)) WHITE = (255, 255, 255) #Make screen white screen.fill(WHITE) #Circle in the center of the window pygame.draw.circle(screen, colors[0], (200, 200), 25, 0) # Half diagonal from the upper-left corner to the center pygame.draw.line(screen, colors[1], (0, 0), (200, 200), 3) pygame.draw.rect(screen, colors[2], (200, 0, 100, 100)) pygame.draw.ellipse(screen, colors[3], (100, 300, 100, 50), 2) while True: for event in pygame.event.get(): if event.type == QUIT: pygame.quit() sys.exit() pygame.display.update() Summary Here we saw how to create a basic game to get us started. The game demonstrated fonts and screen management in the time-honored tradition of Hello world examples. The next section of drawing with Pygame taught us how to draw basic shapes such as rectangles, ovals, circles, lines, and others. We also learned important information about colors and color management. Resources for Article : Further resources on this subject: Using Execnet for Parallel and Distributed Processing with NLTK [Article] TortoiseSVN: Getting Started [Article] Python 3 Object Oriented Programming: Managing objects [Article]
Read more
  • 0
  • 0
  • 7802

article-image-adding-bodies-world
Packt
11 Dec 2012
4 min read
Save for later

Adding Bodies to the World

Packt
11 Dec 2012
4 min read
(For more resources related on Spring, see here.) Creating a fixture A fixture is used to bind the shape on a body, and to define its material setting density, friction, and restitution. The first step is to create the fixture: var fixtureDef:b2FixtureDef = new b2FixtureDef(); fixtureDef.shape=circleShape; Once we have created the fixture with the constructor, we assign the previously created shape using the shape property. Finally we are ready to add the ball to the world: var theBall_b2Body=world.CreateBody(bodyDef); theBall.CreateFixture(fixtureDef); b2Body is the body itself: the physical, concrete body that has been created using the bodyDef attribute. To recap, use the following steps when you want to place a body in the world: i. Create a body definition, which will hold body information such as its position. ii. Create a shape, which is how the body will look. iii. Create a fixture to attach the shape to the body definition. iv. Create the body itself in the world using the fixture. Once you know the importance of each step, adding bodies to your Box2D World will be easy and fun. Back to our project. The following is how the class should look now: package {import flash.display.Sprite;import flash.events.Event;import Box2D.Dynamics.*;import Box2D.Collision.*;import Box2D.Collision.Shapes.*;import Bo x2D.Common.Math.*;public class Main extends Sprite {private var world:b2World;private var worldScale_Number=30;public function Main() {world=new b2World(new b2Vec2(0,9.81),true);var bodyDef_b2BodyDef=new b2BodyDef();bodyDef.position.Set(320/worldScale,30/worldScale);var circleShape:b2CircleShape;circleShape=new b2CircleShape(25/worldScale);var fixtureDef:b2FixtureDef = new b2FixtureDef();fixtureDef.shape=circleShape;var theBall_b2Body=world.CreateBody(bodyDef);theBall.CreateFixture(fixtureDef);addEventListener(Event.ENTER_FRAME,updateWorld);}private function updateWorld(e:Event):void {world.Step(1/30,10,10);world.ClearForces;}}} Time to save the project and test it. Ready to see your first Box2D body in action? Run the movie! Ok, it did not display anything. Before you throw this article, let me tell you that Box2D only simulates the physic world, but it does not display anything. This means your body is alive and kicking in your Box2D World; it's just that you can't see it. Creating a box shape Let's perform the following steps: First, body and fixture definitions can be reassigned to define our new body. This way, we don't need to declare another bodyDef variable, but we just need to reuse the one we used for the creation of the sphere by changing its position: bodyDef.position.Set(320/worldScale,470/worldScale); Now the body definition is located in the horizontal center, and close to the bottom of the screen. To create a polygon shape, we will use the b2PolygonShape class : var polygonShape_b2PolygonShape=new b2PolygonShape(); This way we create a polygon shape in the same way we created the circle shape earlier. Polygon shapes must follow some restrictions, but at the moment because we only need an axis-aligned box, the SetAsBox method is all we need. polygonShape.SetAsBox(320/worldScale,10/worldScale); The method requires two arguments: the half-width and the half-height of the box. In the end, our new polygon shape will have its center at pixels (320, 470), and it will have a width of 640 pixels and a height of 20 pixels—just what we need to create a fl oor. Now we change the shape attribute of the fixture definition, attaching the new polygon shape: fixtureDef.shape=polygonShape; Finally, we can create the world body and embed the fixture in it, just like we did with the sphere. var theFloor_b2Body=world.CreateBody(bodyDef); theFloor.CreateFixture(fixtureDef); The following is how your Main function should look now: public function Main() {world=new b2World(new b2Vec2(0,9.81),true);var bodyDef_b2BodyDef=new b2BodyDef();bodyDef.position.Set(320/worldScale,30/worldScale);var circleShape:b2CircleShape;circleShape=new b2CircleShape(25/worldScale);var fixtureDef_b2FixtureDef=new b2FixtureDef();fixtureDef.shape=circleShape;var theBall_b2Body=world.CreateBody(bodyDef);theBall.CreateFixture(fixtureDef);bodyDef.position.Set(320/worldScale,470/worldScale);var polygonShape_b2PolygonShape=new b2PolygonShape();polygonShape.SetAsBox(320/worldScale,10/worldScale);fixtureDef.shape=polygonShape;var theFloor_b2Body=world.CreateBody(bodyDef);theFloor.CreateFixture(fixtureDef);var debugDraw_b2DebugDraw=new b2DebugDraw();var debugSprite_Sprite=new Sprite();addChild(debugSprite);debugDraw.SetSprite(debugSprite);debugDraw.SetDrawScale(worldScale);debugDraw.SetFlags(b2DebugDraw.e_shapeBit);debugDraw.SetFillAlpha(0.5);world.SetDebugDraw(debugDraw);addEventListener(Event.ENTER_FRAME,updateWorld);} Test the movie and you'll see the floor:
Read more
  • 0
  • 0
  • 1749

article-image-microsoft-xna-40-game-development-receiving-player-input
Packt
02 Jul 2012
11 min read
Save for later

Microsoft XNA 4.0 Game Development: Receiving Player Input

Packt
02 Jul 2012
11 min read
(For more resources on Microsoft XNA 4.0, see here.) Adding text fields I'm generally a big fan of having as few text fields in an application as possible, and this holds doubly true for a game but there are some occasions when receiving some sort of textual information from the player is required so in these regrettable occasions, a textbox or field may be an appropriate choice. Unfortunately, a premade textbox isn't always available to us on any given gaming project, so sometimes we must create our own. Getting ready This recipe only relies upon the presence of a single SpriteFont file referring to any font at any desired size. How to do it... To start adding textboxes to your own games: Add a SpriteFont to the solution named Text: <?xml version="1.0" encoding="utf-8"?><XnaContent >    <FontName>Segoe UI Mono</FontName>    <Size>28</Size>    <Spacing>0</Spacing>    <UseKerning>true</UseKerning>    <Style>Regular</Style>    <CharacterRegions>      <CharacterRegion>        <Start>&#32;</Start>        <End>&#126;</End>      </CharacterRegion>    </CharacterRegions>  </Asset></XnaContent> Begin a new class to contain the text field logic, and embed a static mapping of the keyboard keys to their respective text characters: class Textbox{           private static Dictionary<Keys, char> characterByKey; Create a static constructor to load the mapping of keys to characters: static Textbox(){    characterByKey = new Dictionary<Keys, char>()    {        {Keys.A, 'a'},        {Keys.B, 'b'},        {Keys.C, 'c'},        {Keys.D, 'd'},     {Keys.E, 'e'},        {Keys.F, 'f'},        {Keys.G, 'g'},        {Keys.H, 'h'},        {Keys.I, 'i'},        {Keys.J, 'j'},        {Keys.K, 'k'},        {Keys.L, 'l'},        {Keys.M, 'm'},        {Keys.N, 'n'},        {Keys.O, 'o'},        {Keys.P, 'p'},        {Keys.Q, 'q'},        {Keys.R, 'r'},        {Keys.S, 's'},        {Keys.T, 't'},        {Keys.U, 'u'},        {Keys.V, 'v'},        {Keys.W, 'w'},        {Keys.X, 'x'},        {Keys.Y, 'y'},        {Keys.Z, 'z'},        {Keys.D0, '0'},        {Keys.D1, '1'},        {Keys.D2, '2'},        {Keys.D3, '3'},        {Keys.D4, '4'},        {Keys.D5, '5'},        {Keys.D6, '6'},        {Keys.D7, '7'},        {Keys.D8, '8'},        {Keys.D9, '9'},        {Keys.NumPad0, '0'},        {Keys.NumPad1, '1'},        {Keys.NumPad2, '2'},        {Keys.NumPad3, '3'},        {Keys.NumPad4, '4'},        {Keys.NumPad5, '5'},        {Keys.NumPad6, '6'},        {Keys.NumPad7, '7'},        {Keys.NumPad8, '8'},        {Keys.NumPad9, '9'},        {Keys.OemPeriod, '.'},        {Keys.OemMinus, '-'},    {Keys.Space, ' '}    };} Add the public instance fields that will determine the look and content of the display: public StringBuilder Text;public Vector2 Position;public Color ForegroundColor;public Color BackgroundColor;public bool HasFocus; Include instance-level references to the objects used in the rendering: GraphicsDevice graphicsDevice;SpriteFont font;SpriteBatch spriteBatch;        RenderTarget2D renderTarget;KeyboardState lastKeyboard;bool renderIsDirty = true; Begin the instance constructor by measuring the overall height of some key characters to determine the required height of the display, and create a render target to match: public Textbox(GraphicsDevice graphicsDevice, int width, SpriteFont font){    this.font = font;    var fontMeasurements = font.MeasureString("dfgjlJL");    var height = (int)fontMeasurements.Y;    var pp = graphicsDevice.PresentationParameters;    renderTarget = new RenderTarget2D(graphicsDevice,        width,        height,        false, pp.BackBufferFormat, pp.DepthStencilFormat); Complete the constructor by instantiating the text container and SpriteBatch:     Text = new StringBuilder();    this.graphicsDevice = graphicsDevice;    spriteBatch = new SpriteBatch(graphicsDevice);} Begin the Update() method by determining if we need to take any notice of the keyboard: public void Update(GameTime gameTime){    if (!HasFocus)    {        return;    } Retrieve all of the keys that are currently being depressed by the player and iterate through them, ignoring any that have been held down since the last update: var keyboard = Keyboard.GetState();foreach (var key in keyboard.GetPressedKeys()){    if (!lastKeyboard.IsKeyUp(key))    {        continue;    } Add the logic to remove a character from the end of the text, if either the Backspace or Delete key has been pressed: if (key == Keys.Delete ||    key == Keys.Back){    if (Text.Length == 0)    {        continue;    }    Text.Length--;    renderIsDirty = true;    continue;} Complete the loop and the method by adding the corresponding character for any keys we recognize, taking note of the case as we do so: char character;        if (!characterByKey.TryGetValue(key, out character))        {            continue;        }        if (keyboard.IsKeyDown(Keys.LeftShift) ||        keyboard.IsKeyDown(Keys.RightShift))        {            character = Char.ToUpper(character);        }        Text.Append(character);        renderIsDirty = true;    }                lastKeyboard = keyboard;} Add a new method to render the contents of the text field to RenderTarget if it has changed: public void PreDraw(){    if (!renderIsDirty)    {        return;    }    renderIsDirty = false;    var existingRenderTargets = graphicsDevice.GetRenderTargets();    graphicsDevice.SetRenderTarget(renderTarget);    spriteBatch.Begin();    graphicsDevice.Clear(BackgroundColor);    spriteBatch.DrawString(        font, Text,         Vector2.Zero, ForegroundColor);    spriteBatch.End();    graphicsDevice.SetRenderTargets(existingRenderTargets);} Complete the class by adding a method to render the image of RenderTarget to the screen: public void Draw(){    spriteBatch.Begin();    spriteBatch.Draw(renderTarget, Position, Color.White);    spriteBatch.End();} In your game's LoadContent() method, create a new instance of the text field: Textbox textbox;protected override void LoadContent(){    textbox = new Textbox(        GraphicsDevice,         400,         Content.Load<SpriteFont>("Text"))    {        ForegroundColor = Color.YellowGreen,        BackgroundColor = Color.DarkGreen,        Position = new Vector2(100,100),        HasFocus = true    };} Ensure that the text field is updated regularly via your game's Update() method: protected override void Update(GameTime gameTime){    textbox.Update(gameTime);    base.Update(gameTime);} In your game's Draw() method, let the text field perform its RenderTarget updates prior to rendering the scene including the text fi eld: protected override void Draw(GameTime gameTime){    textbox.PreDraw();    GraphicsDevice.Clear(Color.Black);    textbox.Draw();    base.Draw(gameTime);} Running the code should deliver a brand new textbox just waiting for some interesting text like the following: How it works... In the Update() method, we retrieve a list of all of the keys that are being depressed by the player at that particular moment in time. Comparing this list to the list we captured in the previous update cycle allows us to determine which keys have only just been depressed. Next, via a dictionary, we translate the newly depressed keys into characters and append them onto a StringBuilder instance. We could have just as easily used a regular string, but due to the nature of string handling in .NET, the StringBuilder class is a lot more efficient in terms of memory use and garbage creation. We could have also rendered our text directly to the screen, but it turns out that drawing text is a mildly expensive process, with each letter being placed on the screen as an individual image. So in order to minimize the cost and give the rest of our game as much processing power as possible, we render the text to RenderTarget only when the text changes, and just keep on displaying RenderTarget on screen during all those cycles when no changes occur. There's more... If you're constructing a screen that has more than one text field on it, you'll find the HasFocus state of the text field implementation to be a handy addition. This will allow you to restrict the keyboard input only to one text field at a time. In the case of multiple text fields, I'd recommend taking a leaf from the operating system UI handbooks and adding some highlighting around the edges of a text field to clearly indicate which text field has focus. Also, the addition of a visible text cursor at the end of any text within a text field with focus may help draw the player's eyes to the correct spot. On the phone If you do have access to a built-in text field control such as the one provided in the "Windows Phone XNA and Silverlight" project type, but still wish to render the control yourself, I recommend experimenting with enabling the prebuilt control, making it invisible, and feeding the text from it into your own text field display.
Read more
  • 0
  • 0
  • 1969

article-image-construct-game-development-platformer-revisited-2d-shooter
Packt
05 Jun 2012
11 min read
Save for later

Construct Game Development: Platformer Revisited, a 2D Shooter

Packt
05 Jun 2012
11 min read
(For more resources on Game Development, see here.) Before we start As there is a large amount of ground to cover in this chapter, we'll be moving quickly through steps similar to those we've done before. If it's been a while since you've used Construct, then you may find it useful to read through a chapter or two again before continuing, because certain steps assume that you are able to complete acO ons we have performed in the past. Multiplayer: getting your friends involved We're ready to start our next game, a multiplayer side-scrolling shooter, but before we add any shooO ng, we'll need to have the multiplayer side-scroller part finished first. So let's get to it! Time for action – creating the game assets and title screen The first thing we will need to do is to create our game content and create the first layout of the game, the title screen. First, draw up our player graphics and guns. We'll want the torso to be a separate object from the legs for easier animation. Use red dots where the legs will be attached to as markers for image point placement later on. Also include drawings for three weapons: a pistol, an uzi, and a shotgun: Next, we can draw up our enemies for the game. In this case, we'll use an enemy robot with a turret arm that shoots balls of plasma: We'll also need some scenery and ground objects for the levels: Finally, we'll need a graphic to tell the player to go onto the next screen when no enemies are present: Now we can move on to starting our game. Create a new project and set its Name to SideShooter, and enter your Creator name. Then set the window size to 800 by 600. Create the global variables CanGoNext, CurrentScreen, NumPlayers, P1Lives, P2Lives, GameWonLost, and RespawnY with values 0, 0, 1, 3, 3, 0, and 100 respectively. Following that, rename the first layout to Title and its event sheet to Title events . On this layout, create the layers Text, Buttons, and Background in top-to-bottom order. Selecting the Background layer, create a Panel object and name it Background before setting its top corner filters to Green and bottom corner filters to DarkGreen. Stretch this object to cover the whole of the layout and lock the layer. Now, on the Buttons layer, create a sprite and draw a box with the word Play in it. PosiO on this object in the center of the layout. This will be the start button for our game and should have the name btnPlay. Next, add the Mouse & Keyboard and XAudio2 objects into the layout and give them the global property. In order to finish the layout design, create a Text object on the Text layer and set its name to Title and its text to SideShooter, and position it above the btnPlay object: Switch over to the event sheet editor to add in a Start of layout event and use it to play a music file, Title.mp3, and loop it. This can be any title music you'd like, and it will also be played at the game's end screen. Next, create an event for the MouseKeyboard object with the condition Mouse is over object to check if the mouse overlaps btnPlay. Give this event the action Set colour filter for the btnPlay object to set the filter to Grey – 40. Now create an Else event to set the filter color back to White. In order to finish the event sheet, create an event with the condition On object clicked and select the object btnPlay. Add actions to this event to set the value of NumPlayers to 1 and the value of CurrentScreen to 0 before adding the final System action Next Layout: Time for action – designing the level Now that we have our graphics created, we can put them into our second layout and make the first playable level. Now we're ready to create a level layout. Create a layout and name it Level1 and its event sheet Level1 events . Then create our main game event sheet Game. For the layout, set its width to a multiple of the screen width (800), and check the box for Unbounded scrolling. In the event sheet of this layout, include our main event sheet Game. Next, give this layout the layers HUD, Foreground, FrontScenery, Objects, LevelLights, ShadowCasters, BackScenery, and Walls in top-to-bottom order. After that, set the ScrollX and ScrollY rates of the HUD and Walls layers to 0% On the objects layer, create a Tiled Background object named Ground and give it the smaller light gray tile image. Ensure it has the Solid attribute and stretch and place some of them to form a level design. Now create a Sprite object with the light green tile image and name it CrateBox . Give it the Solid attribute as well and place some around the level too. Have its collisions mode set to Bounding box. Next, create a Sprite named ExitLevel and fill it with a solid color. Give it a width of 32 and stretch it so that it's taller than the display height (600). Then finish the object by checking the box for Invisible on start and placing it at the end of the level: With the base layout complete, we can now add in three more invisible objects to handle scrolling. These are going to be Box objects with the names BackStopper, FrontStopper, and GoNextScreen. Have the BackStopper and FrontStopper objects colored red and marked Solid with a width of 120. Set the Hotspot property of the BackStopper object to Bottom-right, and the FrontStopper to Bottom-Left, before positioning them at 0,600 and 800,600 respectively. Next, have the GoNextScreen box colored green and a width of 32 as well as a Hotspot of Bottom-right. Position this object at 800,600: Time for action – creating player characters and conveyor belt objects Now we can create our player character objects and also add moving and staO c conveyor belts into our level. We are now ready to create our player objects. Start by inserting a Sprite and paste the standing image of the player character legs into it. Have an image point named 1 at the red spot that we drew earlier, and then place the hotspot at the bottom-middle point of the image ( num-pad 2) as shown in the following image: Name this sprite P1Legs, and for its Default animation, set the animation Tag to Stopped before checking the Auto Mirror checkbox in the main Appearance settings of the object. Next, give it the platform behavior with the settings shown as follows: Next, scroll down to the Angle properties box and check the Auto mirror checkbox. Now we are ready to add the object to a family. Scroll up to the Groups sub-group Families and click on Add to bring up the Construct: New Family screen. Note that Construct Classic comes with some default families, but will also display any family that have been used previously: Click on Edit Families to bring up the Construct: Families editor screen. On this screen, enter the name Legs and click on the + button: We can now draw the family image using the image editor that appears, shown as follows: After finishing the image, save it by exiting out of the image editor and check that the family is now in the list. Once finished, click on Done to return to the family selection page. Now select the Legs family and click on Ok: Now we can add the animation Walk in for our object. In this animation, set the Tag to Walking, and add the other leg sprites so they match the following image: Now change the settings of the animation to have an Animation speed of 5 and check the Loop checkbox. Next, copy the object and right-click on the layout to use the Paste Clone option, and name this clone as P2Legs. In the Platform behavior for this object, change the Control setting to Player 2 . Now go into the project properties and scroll to the bottom section, Controls. Click on the Add / Edit option for the Manage Controls setting at the bottom to bring up the controls box: Use the red X button to remove all of the controls below Jump. Then click on the Green plus button to add a new control. Select this control and click on the Pencil and paper button to change its name to Move Left. Click on the Key name for this control to bring up a drop-down box and set it to A. Now, in the Player drop-down box, select Player 2 for this control. It should match the following screenshot: Now continue to add controls until it matches the settings in the following screenshot before clicking on Done: Next, we'll create the bodies of our player objects. Create a Sprite called P1Torso and paste the normal body image of our character into it. Then position the Hotspot in the bottom-middle of the body. Give this sprite an image point 1 in the centre of its hand: Rename the Default animation to Normal and set its speed to 0, and check the Auto Mirror checkbox for this object as well. Create two more animations, Up and Down respectively. Set their frames to match the following screenshot: Now give the object a new family and name it Body. Then create Private Variables of names Weapon, Ammo, and GunAngle . Set the starting values to 0, 99, and 0 respectively. Clone this object as well to create P2Torso, and replace the sprites with the second player graphics. Now select P1Legs and scroll down to the Groups | Container properties to click on Add object and select P1Torso. The properties box and sprites should match the following screenshot: Next, put the P2Torso object into the container P2Legs using the same method. Now, on the Walls layer, create a Tiled Background object named FactoryWall and paste the dark wall graphic into it. Then resize it to 800 in Width by 600 in Height and set its position to 0,0 . The layout should look similar to the following screenshot: Switch to the FrontScenery layer and create a Tiled Background object called ConveyorMiddle, and give it the center piece of the conveyor belt images: Give this object the Private Variables of Direction and Speed with starting values of 0. Place these around the map to act as scenery, as well as using them as an object to move players with at certain points. Set the Direction variable to 1 to have the conveyor belt move right, and 2 to move left. Speed is the attribute used to determine how fast a player character is moved by the conveyor belt; a speed of 25 works well in this instance. The following screenshot shows a moving conveyor belt in the layout: On the same layer, create a Sprite with the name ConveyorStart and Collisions set to None. Use the starting conveyor belt image for this object and set the Hotspot to the middle-right (num-pad 6). Give this sprite the Attribute of Destroy on Startup. Create a second Sprite with the same setttigs called ConveyorEnd and a Hotspot in the middle-left (num-pad 4). Both sprites are shown in the following screenshot: Time for action – creating the HUD objects Now, we will move on to creating the Heads Up Display (HUD) objects for our game. We are now ready to create the HUD objects for our game. Switch to the HUD layer and create a Sprite called P1Face, and give it an image of the P1Torso head and set its Collisions mode to Bounding Box: Next, create a Text object called P1Info and set it up to match the following screenshot: Create similar objects replacing P1 with P2 for the second player. In this case, have the objects match the following layout screenshot: Now create a Text object for when the second player is not playing, and call it P2Join. Set its text to Press left control to join and have it matched to the following screenshot: Give it a Sine behavior to make it fade in and out by matching its settings to those in the following screenshot: Now create the final HUD item, a Sprite called NextSign, and place the next arrow image into it. Set the Collisions of this object to None:
Read more
  • 0
  • 0
  • 3603
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 $19.99/month. Cancel anytime
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
  • 1615

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

article-image-flash-game-development-making-astro-panic
Packt
11 Apr 2011
10 min read
Save for later

Flash Game Development: Making of Astro-PANIC!

Packt
11 Apr 2011
10 min read
  Flash Game Development by Example Build 10 classic Flash games and learn game development along the way         Read more about this book       (For more resources on flash, see here.) Astro-PANIC! was released as an all machine language Commodore 64 game to be typed in the February 1984 issue of COMPUTE!'s Gazette magazine. At that time there wasn't any blog with source codes to download or copy/paste into your projects, so the only way to learn from other programmers was buying computer magazines and typing the example codes on your computer. Since I suppose you never played this game, I would recommend you play it a bit on http://www.freewebarcade.com/game/astro-panic/. Defining game design Here are the rules to design our Astro-PANIC! prototype: The player controls a spaceship with the mouse, being able to move it horizontally on the bottom of the screen. At each level, a given number of enemy spaceships appear and roam around the stage at a constant speed in a constant direction. Enemies cannot leave the stage, and they will bounce inside it as they touch stage edges. Enemies don't shoot, and the only way they will kill the player is by touching the spaceship. The player can only have one bullet on stage at any time, and hitting an enemy with the bullet will destroy it. Destroying all enemies means passing the level, and at each level the number of enemies and their speed increases. These are the basic rules. We'll add some minor improvements during the design of the game itself, but before we start drawing the graphics, keep in mind we'll design something with the look and feel of old coin operator monitors, with bright glowing graphics. Creating the game and drawing the graphics Create a new file (File | New). Then, from New Document window select Actionscript 3.0. Set its properties as width to 640 px, height to 480 px, background color to #000000 (black) and frame rate to 60. Also define the Document Class as Main and save the file as astro-panic.fla. Though 30 frames per second is the ideal choice for smooth animations, we will use 60 frames per second to create a very fast paced game. There are three actors in this game: the player-controlled spaceship, the bullet and the enemy. In astro-panic.fla, create three new Movie Clip symbols and call them spaceship_mc for the spaceship, bullet_mc for the bullet, and enemy_mc for the enemy. Set them all as exportable for ActionScript. Leave all other settings at their default values, just like you did in previous article on Tetris. From left to right: The spaceship (spaceship_mc), the bullet (bullet_mc), and the enemy (enemy_mc). I made all assets with the shape of a circle. The spaceship is half a circle with a radius of 30 pixels, the bullet is a circle with a 4 pixels radius, and the enemy is a circle with a radius of 25 pixels. All of them have the registration point in their centers, and enemy_mc has a dynamic text field in it called level. If you've already met dynamic text fields during the making of Minesweeper it won't be a problem to add it. At the moment I am writing a couple of zeros to test how the dynamic text field fits in the enemy shape. Now we are ready to code. Adding and controlling the spaceship As usual we know we are going to use classes to manage both enter frame and mouse click events, so we'll import all the required classes immediately. The spaceship is controlled with the mouse, but can only move along x-axis. Without closing astro_panic.fla, create a new file and from New Document window select ActionScript 3.0 Class. Save this file as Main.as in the same path you saved astro_panic.fla. Then write: package { import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class Main extends Sprite { private var spaceship:spaceship_mc; public function Main() { placeSpaceship(); addEventListener(Event.ENTER_FRAME,onEnterFrm); } private function placeSpaceship():void { spaceship=new spaceship_mc(); addChild(spaceship); spaceship.y=479; } private function onEnterFrm(e:Event):void { spaceship.x=mouseX; if (spaceship.x<30) { spaceship.x=30; } if (spaceship.x>610) { spaceship.x=610; } } }} At this time you should know everything about the concept behind this script. placeSpaceship is the function which constructs, adds to Display List and places the spaceship_mc DisplayObject called spaceship. In enter_frame function we just move the spaceship in the same position of the x-axis of the mouse. We don't want the spaceship to hide in a corner, so it won't be able to follow the axis of the mouse if it gets too close to stage edges. Test the movie, and move the mouse. Your spaceship will follow it, while being bound to the ground. Now we should give the spaceship an old arcade look. Adding a glow filter AS3 allows us to dynamically apply a wide range of filters to DisplayObjects on the fly. We'll add a glow filter to simulate old 'arcades' pixel luminosity. flash.filters.GlowFilter class lets us apply a glow effect to DisplayObjects. First, we need to import it. import flash.display.Sprite;import flash.events.Event;import flash.events.MouseEvent;import flash.filters.GlowFilter; At this time, we can simply create a new variable to construct a GlowFilter object. Change placeSpaceship this way: private function placeSpaceship():void { ... var glow_GlowFilter=new GlowFilter(0x00FFFF,1,6,6,2,2); spaceship.filters=new Array(glow);} We specify the color as 0x00FFFF (cyan to draw the spaceship), the alpha (1 = full opacity), and the amount of horizontal and vertical blur (both 6). I want you to notice that I used 6 for horizontal and vertical blur because I like the effect I achieve with such value. If you are planning to use a lot of filters, remember values that are a power of 2 (such as 4 and 8, but not 6) render more quickly than other values. The remaining two arguments are the strength, that determines the spread of the filter (if you use Photoshop, it's something like spread and size of the glow filter you can apply on layers) and the quality. Quality can range from 1 to 15 but values higher than 3 may affect performances and the same final effect can be set playing with blur. Finally the filter is added. spaceship.filters=new Array(glow); filters DisplayObject's property wants an array with all the filters you want to associate to the DisplayObject. In our case, we are adding only one filter but we have to include it in the array anyway. Test the movie and you will see your spaceship glow. In the previous picture, you can see the difference between the spaceship without and with the glow effect applied. Now your spaceship is ready to fire. Making spaceship fire Nobody would face an alien invasion with a harmless spaceship, so we are going to make it fire. We need to create a variable to manage bullet_mc DisplayObject and I have said the spaceship can fire only one bullet at a time, so we need another variable to tell us if the spaceship is already firing. If it's firing, it cannot fire. If it's not firing, it can fire. Add two new class level variables: private var spaceship:spaceship_mc;private var isFiring_Boolean=false;private var bullet:bullet_mc; isFiring is the Boolean variable that we'll use to determine if the spaceship is firing. false means it's not firing. bullet will represent the bullet itself. The player will be able to fire with mouse click, so a listener is needed in Main function: public function Main() { placeSpaceship(); addEventListener(Event.ENTER_FRAME,onEnterFrm); stage.addEventListener(MouseEvent.CLICK,onMouseCk);} Now every time the player clicks the mouse, onMouseCk function is called. This is the function: private function onMouseCk(e:MouseEvent):void { if (! isFiring) { placeBullet(); isFiring=true; }} It's very easy: if isFiring is false (the spaceship isn't already firing), placeBullet function is called to physically place a bullet then isFiring is set to true because now the spaceship is firing. The same placeBullet function isn't complex: private function placeBullet():void { bullet=new bullet_mc(); addChild(bullet); bullet.x=spaceship.x; bullet.y=430; var glow_GlowFilter=new GlowFilter(0xFF0000,1,6,6,2,2); bullet.filters=new Array(glow);} It's very similar to placeSpaceship function, the bullet is created, added to Display List, placed on screen, and a red glow effect is added. The only thing I would explain is the concept behind x and y properties: bullet.x=spaceship.x; Setting bullet's x property equal to spaceship's x property will place the bullet exactly where the spaceship is at the moment of firing. bullet.y=430; 430 is a good y value to make the bullet seem as it were just fired from the turret. Test the movie, and you will be able to fire a bullet with a mouse click. The bullet at the moment remains static in the point where we fired it. Making the bullet fly To make the bullet fly, we have to define its speed and move it upwards. Then we'll remove it once it leaves the stage and reset isFiring to false to let the player fire again. Add a constant to class level variables: private const BULLET_SPEED_uint=5;private var spaceship:spaceship_mc;private var isFiring_Boolean=false;private var bullet:bullet_mc; BULLET_SPEED is the amount of pixels the bullet will fly at each frame. We won't manage upgrades or power-ups, so we can say its value will never change. That's why it's defined as a constant. To manage bullet movement, we need to add some lines at the end of onEnterFrm function. You may wonder why we are managing both the spaceship and the bullet inside the same class rather than creating a separate class for each one. You'll discover it when you manage enemies' movement, later in this article. Meanwhile, add this code to onEnterFrm function. private function onEnterFrm(e:Event):void { ... if (isFiring) { bullet.y-=BULLET_SPEED; if (bullet.y<0) { removeChild(bullet); bullet=null; isFiring=false; } }} The new code is executed only if isFiring is true. We are sure we have a bullet on stage when isFiring is true. bullet.y-=BULLET_SPEED; Moves the bullet upward by BULLET_SPEED pixels. if (bullet.y<0) { ... } This if statement checks if y property is less than 0. This means the bullet flew off the screen. In this case we physically remove the bullet from the game with removeChild(bullet);bullet=null; and we give the player the capability of firing again with isFiring=false; Test the movie and fire, now your bullets will fly until they reach the top of the stage. Then you will be able to fire again. Since nobody wants to fire for the sake of firing, we'll add some enemies to shoot down.
Read more
  • 0
  • 0
  • 1794

article-image-flash-game-development-creation-complete-tetris-game
Packt
25 Mar 2011
10 min read
Save for later

Flash Game Development: Creation of a Complete Tetris Game

Packt
25 Mar 2011
10 min read
Tetris features shapes called tetrominoes, geometric shapes composed of four squared blocks connected orthogonally, that fall from the top of the playing field. Once a tetromino touches the ground, it lands and cannot be moved anymore, being part of the ground itself, and a new tetromino falls from the top of the game field, usually a 10x20 tiles vertical rectangle. The player can move the falling tetromino horizontally and rotate by 90 degrees to create a horizontal line of blocks. When a line is created, it disappears and any block above the deleted line falls down. If the stacked tetrominoes reach the top of the game field, it's game over. Defining game design This time I won't talk about the game design itself, since Tetris is a well known game and as you read this article you should be used to dealing with game design. By the way, there is something really important about this game you need to know before you start reading this article. You won't draw anything in the Flash IDE. That is, you won't manually draw tetrominoes, the game field, or any other graphic assets. Everything will be generated on the fly using AS3 drawing methods. Tetris is the best game for learning how to draw with AS3 as it only features blocks, blocks, and only blocks. Moreover, although the game won't include new programming features, its principles make Tetris the hardest game of the entire book. Survive Tetris and you will have the skills to create the next games focusing more on new features and techniques rather than on programming logic. Importing classes and declaring first variables The first thing we need to do, as usual, is set up the project and define the main class and function, as well as preparing the game field. Create a new file (File | New) then from New Document window select Actionscript 3.0. Set its properties as width to 400 px, height to 480 px, background color to #333333 (a dark gray), and frame rate to 30 (quite useless anyway since there aren't animations, but you can add an animated background on your own). Also, define the Document Class as Main and save the file as tetris.fla. Without closing tetris.fla, create a new file and from New Document window select ActionScript 3.0 Class. Save this file as Main.as in the same path you saved tetris.fla. Then write: package { import flash.display.Sprite; import flash.utils.Timer; import flash.events.TimerEvent; import flash.events.KeyboardEvent; public class Main extends Sprite { private const TS_uint=24; private var fieldArray:Array; private var fieldSprite:Sprite; public function Main() { // tetris!! } } } We already know we have to interact with the keyboard to move, drop, and rotate tetrominoes and we have to deal with timers to manage falling delay, so I already imported all needed libraries. Then, there are some declarations to do: private const TS_uint=24; TS is the size, in pixels, of the tiles representing the game field. It's a constant as it won't change its value during the game, and its value is 24. With 20 rows of tiles, the height of the whole game field will be 24x20 = 480 pixels, as tall as the height of our movie. private var fieldArray:Array; fieldArray is the array that will numerically represent the game field. private var fieldSprite:Sprite; fieldSprite is the DisplayObject that will graphically render the game field. Let's use it to add some graphics. Drawing game field background Nobody wants to see an empty black field, so we are going to add some graphics. As said, during the making of this game we won't use any drawn Movie Clip, so every graphic asset will be generated by pure ActionScript. The idea: Draw a set of squares to represent the game field. The development: Add this line to Main function: public function Main() { generateField(); } then write generateField function this way: private function generateField():void { fieldArray = new Array(); fieldSprite=new Sprite(); addChild(fieldSprite); fieldSprite.graphics.lineStyle(0,0x000000); for (var i_uint=0; i<20; i++) { fieldArray[i]=new Array(); for (var j_uint=0; j<10; j++) { fieldArray[i][j]=0; fieldSprite.graphics.beginFill(0x444444); fieldSprite.graphics.drawRect(TS*j,TS*i,TS,TS); fieldSprite.graphics.endFill(); } } } Test the movie and you will see: The 20x10 game field has been rendered on the stage in a lighter gray. I could have used constants to define values like 20 and 10, but I am leaving it to you at the end of the article. Let's see what happened: fieldArray = new Array(); fieldSprite=new Sprite(); addChild(fieldSprite); These lines just construct fieldArray array and fieldSprite DisplayObject, then add it to stage as you have already seen a million times. fieldSprite.graphics.lineStyle(0,0x000000); This line introduces a new world called Graphics class. This class contains a set of methods that will allow you to draw vector shapes on Sprites. lineStyle method sets a line style that you will use for your drawings. It accepts a big list of arguments, but at the moment we'll focus on the first two of them. The first argument is the thickness of the line, in points. I set it to 0 because I wanted it as thin as a hairline, but valid values are 0 to 255. The second argument is the hexadecimal color value of the line, in this case black. Hexadecimal uses sixteen distinct symbols to represent numbers from 0 to 15. Numbers from zero to nine are represented with 0-9 just like the decimal numeral system, while values from ten to fifteen are represented by letters A-F. That's the way it is used in most common paint software and in the web to represent colors. You can create hexadecimal numbers by preceding them with 0x. Also notice that lineStyle method, like all Graphics class methods, isn't applied directly on the DisplayObject itself but as a method of the graphics property. for (var i_uint=0; i<20; i++) { ... } The remaining lines are made by the classical couple of for loops initializing fieldArray array in the same way you already initialized all other array-based games, and drawing the 200 (20x10) rectangles that will form the game field. fieldSprite.graphics.beginFill(0x444444); beginFill method is similar to lineStyle as it sets the fill color that you will use for your drawings. It accepts two arguments, the color of the fill (a dark gray in this case) and the opacity (alpha). Since I did not specify the alpha, it takes the default value of 1 (full opacity). fieldSprite.graphics.drawRect(TS*j,TS*i,TS,TS); With a line and a fill style, we are ready to draw some squares with drawRect method, that draws a rectangle. The four arguments represent respectively the x and y position relative to the registration point of the parent DisplayObject (fieldSprite, that happens to be currently on 0,0 in this case), the width and the height of the rectangle. All the values are to be intended in pixels. fieldSprite.graphics.endFill(); endFill method applies a fill to everything you drew after you called beginFill method. This way we are drawing a square with a TS pixels side for each for iteration. At the end of both loops, we'll have 200 squares on the stage, forming the game field. Drawing a better game field background Tetris background game fields are often represented as a checkerboard, so let's try to obtain the same result. The idea: Once we defined two different colors, we will paint even squares with one color, and odd squares with the other color. The development: We have to modify the way generateField function renders the background: private function generateField():void { var colors_Array=new Array("0x444444","0x555555");"); fieldArray = new Array(); var fieldSprite_Sprite=new Sprite(); addChild(fieldSprite); fieldSprite.graphics.lineStyle(0,0x000000); for (var i_uint=0; i<20; i++) { fieldArray[i]=new Array(); for (var j_uint=0; j<10; j++) { fieldArray[i][j]=0; fieldSprite.graphics.beginFill(colors[(j%2+i%2)%2]); fieldSprite.graphics.drawRect(TS*j,TS*i,TS,TS); fieldSprite.graphics.endFill(); } } } We can define an array of colors and play with modulo operator to fill the squares with alternate colors and make the game field look like a chessboard grid. The core of the script lies in this line: fieldSprite.graphics.beginFill(colors[(j%2+i%2)%2]); that plays with modulo to draw a checkerboard. Test the movie and you will see: Now the game field looks better. Creating the tetrominoes The concept behind the creation of representable tetrominoes is the hardest part of the making of this game. Unlike the previous games you made, such as Snake, that will feature actors of the same width and height (in Snake the head is the same size as the tail), in Tetris every tetromino has its own width and height. Moreover, every tetromino but the square one is not symmetrical, so its size is going to change when the player rotates it. How can we manage a tile-based game with tiles of different width and height? The idea: Since tetrominoes are made by four squares connected orthogonally (that is, forming a right angle), we can split tetrominoes into a set of tiles and include them into an array. The easiest way is to include each tetromino into a 4x4 array, although most of them would fit in smaller arrays, it's good to have a standard array. Something like this: Every tetromino has its own name based on the alphabet letter it reminds, and its own color, according to The Tetris Company (TTC), the company that currently owns the trademark of the game Tetris. Just for your information, TTC sues every Tetris clone whose name somehow is similar to "Tetris", so if you are going to create and market a Tetris clone, you should call it something like "Crazy Bricks" rather than "Tetriz". Anyway, following the previous picture, from left-to-right and from top-to-bottom, the "official" names and colors for tetrominoes are: I—color: cyan (0x00FFFF) T—color: purple (0xAA00FF) L—color: orange (0xFFA500) J—color: blue (0x0000FF) Z—color: red (0xFF0000) S—color: green (0x00FF00) O—color: yellow (0xFFFF00) The development: First, add two new class level variables: private const TS_uint=24; private var fieldArray:Array; private var fieldSprite:Sprite; private var tetrominoes:Array = new Array(); private var colors_Array=new Array(); tetrominoes array is the four-dimensional array containing all tetrominoes information, while colors array will store their colors. Now add a new function call to Main function: public function Main() { generateField(); initTetrominoes(); } initTetrominoes function will initialize tetrominoes-related arrays. private function initTetrominoes():void { // I tetrominoes[0]=[[[0,0,0,0],[1,1,1,1],[0,0,0,0],[0,0,0,0]], [[0,1,0,0],[0,1,0,0],[0,1,0,0],[0,1,0,0]]]; colors[0]=0x00FFFF; // T tetrominoes[1]=[[[0,0,0,0],[1,1,1,0],[0,1,0,0],[0,0,0,0]], [[0,1,0,0],[1,1,0,0],[0,1,0,0],[0,0,0,0]], [[0,1,0,0],[1,1,1,0],[0,0,0,0],[0,0,0,0]], [[0,1,0,0],[0,1,1,0],[0,1,0,0],[0,0,0,0]]]; colors[1]=0x767676; // L tetrominoes[2]=[[[0,0,0,0],[1,1,1,0],[1,0,0,0],[0,0,0,0]], [[1,1,0,0],[0,1,0,0],[0,1,0,0],[0,0,0,0]], [[0,0,1,0],[1,1,1,0],[0,0,0,0],[0,0,0,0]], [[0,1,0,0],[0,1,0,0],[0,1,1,0],[0,0,0,0]]]; colors[2]=0xFFA500; // J tetrominoes[3]=[[[1,0,0,0],[1,1,1,0],[0,0,0,0],[0,0,0,0]], [[0,1,1,0],[0,1,0,0],[0,1,0,0],[0,0,0,0]], [[0,0,0,0],[1,1,1,0],[0,0,1,0],[0,0,0,0]], [[0,1,0,0],[0,1,0,0],[1,1,0,0],[0,0,0,0]]]; colors[3]=0x0000FF; // Z tetrominoes[4]=[[[0,0,0,0],[1,1,0,0],[0,1,1,0],[0,0,0,0]], [[0,0,1,0],[0,1,1,0],[0,1,0,0],[0,0,0,0]]]; colors[4]=0xFF0000; // S tetrominoes[5]=[[[0,0,0,0],[0,1,1,0],[1,1,0,0],[0,0,0,0]], [[0,1,0,0],[0,1,1,0],[0,0,1,0],[0,0,0,0]]]; colors[5]=0x00FF00; // O tetrominoes[6]=[[[0,1,1,0],[0,1,1,0],[0,0,0,0],[0,0,0,0]]]; colors[6]=0xFFFF00; } colors array is easy to understand: it's just an array with the hexadecimal value of each tetromino color. tetrominoes is a four-dimensional array. It's the first time you see such a complex array, but don't worry. It's no more difficult than the two-dimensional arrays you've been dealing with since the creation of Minesweeper. Tetrominoes are coded into the array this way: tetrominoes[n] contains the arrays with all the information about the n-th tetromino. These arrays represent the various rotations, the four rows and the four columns. tetrominoes[n][m] contains the arrays with all the information about the n-th tetromino in the m-th rotation. These arrays represent the four rows and the four columns. tetrominoes[n][m][o] contains the array with the four elements of the n-th tetromino in the m-th rotation in the o-th row. tetrominoes[n][m][o][p] is the p-th element of the array representing the o-th row in the m-th rotation of the n-th tetromino. Such element can be 0 if it's an empty space or 1 if it's part of the tetromino. There isn't much more to explain as it's just a series of data entry. Let's add our first tetromino to the field.
Read more
  • 0
  • 0
  • 2885
article-image-designing-avatar-flash-multiplayer-virtual-worlds
Packt
27 Aug 2010
9 min read
Save for later

Designing an Avatar in Flash Multiplayer Virtual Worlds

Packt
27 Aug 2010
9 min read
(For more resources on Flash, see here.) Designing an avatar Avatar is very important in a virtual world because most of the features are designed around avatars. Users interact with each other via their avatars, they explore the virtual world via avatars, and they complete challenges to level up their avatars. An avatar is composited by graphics and animation. The avatar graphics are its looks. It is not a static image but a collection of images to display the directions and appearance. There are different approaches of drawing the avatar graphics depending on the render methods and how many directions and animations the avatar needs. Animations represent different actions of the avatar. The most basic animation is walking. Other animations such as hand waving and throwing objects are also common. There will be different animation sets for different virtual world designs. A fighting topic virtual world will probably contain a collection of fighting animation sets. A hunting topic virtual world will contain animations of collection items and using hunting tools. Determining the direction numbers of avatars' views Isometric tile is composed by diamond shapes with four-edge connection to the other tiles. It is not hard to imagine that every avatar in the isometric view may face towards four directions. They are the north east, south east, south west, and north west. However, sometimes using only these four directions may not be enough; some game designs may require the avatar to face the user or walk to the other isometric tile a cross the diamond corner. In this case, eight directions are required. The direction number of the avatars affects the artwork drawing directly. Just imagine that we are building a virtual world where players can fight with each other. How many animations are there for an avatar to fight? Say, five sets of animations. How many directions can the avatar faces? 4? 8? Or even 12? For example, we are now talking about five sets of animations with 8 directions of each avatar. That's already 40 animations for only one avatar. We may design the virtual world to have 12 kinds of avatars and each avatar to have different clothes for customization. The graphics workload keeps increasing when only one of these aspects increases. That's why I often consider different approaches that reduce the graphic workload of the avatars. Take four directions as an example. In most cases, we have very similar animations when the avatar is facing south-east and south-west. And the animation of north-east and north-west are similar too. Therefore, it is a common technique that mirrors the animation of west side into east side. It can be easily done in Flash by just changing the x-axis of the scaling property to between -1 and 1. This property results in the avatar flipping from one side to another side. For a 4-directions animation set, only 2 directions need to be drawn. In an 8-directions animation set, only 5 directions need to be drawn. Next, we will discuss the rendering methods that will conclude how the amount of directions, animations, and customization affect the graphic workload. Rendering avatars in Flash virtual world There are different approaches to render avatars in Flash virtual world. Each rendered method comes with both advantages and disadvantages. Some methods take more time to draw with fancy outlook while others may take more time to program. It is important to decide which rendering methods of the avatar are required in predevelopment stage. It will be much more difficult to change the rendering method after the project is in development. We will discuss different rendering methods and the pros and cons of them. Drawing an avatar using vector animation It is convenient to use the Flash native vector drawing for avatar because every drawing can be done within the Flash. The output can be cute and cartoon style. One advantage of using vector is that color customization is easy to implement by using the native ActionScript color transform. We can easily assign different colors to different parts of the avatar without extra graphic drawing. Another advantage of using vector animation is that we can scale up and down the avatars whenever needed. It is useful when we need to zoom in or out of the map and the avatars in the virtual world. The following graph shows the comparison of scaling up a vector and bitmap graphic: The disadvantage is that we need to draw the animation of every part of the avatar in every direction frame by frame. Flash tweening can help but the workload is heavier than other methods. We can prerender the animations or control them by ActionScript in methods discussed later. In vector animation, every animation is hand-drawn and thus any late modification on the avatar design can cost quite a lot of workload. There may not be too many directions of the avatars meaning the rotation of the avatars will not be very smooth. Rendering avatars using bitmap sprite sheet Sprite sheet is a graphics technique that is used in almost all game platforms. Sprite sheet is a large bitmap file that contains every frame of animation. Bitmap data from each frame is masked and rendered to the screen. A Flash developer may think that there is a timeline with frame one on the top left and counting the frame from left to right in each row from top to bottom. This technique is useful when the avatar graphic designer has experience in other game platforms. Another advantage of using bitmap data is faster rendering than vector in Flash player. The other advantage is the sprite sheet can be rendered from 3D software. For example, we can make an avatar model in Maya (http://autodesk.com/maya) or 3Ds Max (http://autodesk.com/3dsmax) with animations set up. Then we set up eight cameras with orthographic perspective. The orthographic perspective ensures the rendered image fits the isometric world. After setting up the scene, just render the whole animation with eight different cameras and we will get all the bitmap files of the avatar. The benefit is that the rendering process is automatic so that we can reduce the workload a lot. Later if we want to modify the character, we only need to modify it in the 3D software and render it again. One big disadvantage of using sprite sheet is the file size. The sprite sheets are in bitmap format and one set of animation can cost up to several hundred kilobytes. The file size can be very large when there are many animations and many more bitmaps for switching styles of the avatar. The other disadvantage is that changing color is quite difficult. Unlike vector rendering where color replacement can be done by ActionScript, we need to replace another bitmap data to change the color. That means every available color doubles the file size. Rendering avatars using real-time 3D engine We described how to use 3D software to prerender graphics of the avatars in the previous section. Instead of prerendering the graphics into 2D bitmap, we can integrate a Flash 3D engine to render the 3D model into isometric view in real time. Real-time 3D rendering is the next trend of Flash. There are several 3D engines available in the market that support rendering complex 3D models with animations. Papervision3D (http://blog.papervision3d.org/) and Away3D (http://away3d.com/) are two examples among them. The advantage of using 3D rendering in isometric is that the rotation of avatars can be very smooth. Also different textures can share the same model and different models can share the same animation skeleton. Thanks to this great graphic reusability, 3D rendering virtual world can create different combinations of avatar appearance and animations without adding extra graphic workload in development. However, one disadvantage of using 3D rendering is the Flash player performance. The latest version of Flash player is 10.1 at the time of writing. The following screenshots show that the CPU resources usage is very high when rendering the isometric 3D environment with three avatars on screen: Rendering avatars using 2D bone skeleton Bone skeleton used to be an uncommon method to render avatar. What it does is creates an animated skeleton and then glues different parts of body together onto the skeleton. It is somehow similar to the skeleton and mesh relationship in 3-D software but in two dimensions instead. A lot of mathematics is needed to calculate the position and rotation of each part of the body and make the implementation difficult. Thanks to the introduction of bone tool and inverse kinematics in Flash CS4, this technique is becoming more mature and easier to be used in the Flash world. Adobe has posted a tutorial about using bone tool to create a 2D character (http://www.adobe.com/devnet/flash/articles/character_animation_ik.html). The following screenshot shows another bone skeleton example from gotoAndPlay demonstrating how to glue the parts into a walking animation. The post can be found in this link: http://www.gotoandplay.it/_articles/2007/04/skeletal_animation.php The advantage of using 2D bone skeleton is that animations are controlled by ActionScript. The reusing of animations means this technique fits those game designs that require many animations. A dancing virtual world that requires a lot of different unique animations is one example that may need this technique. One disadvantage is that the large amount of mathematic calculation for the animations makes it difficult to implement. Every rendering methods has its own advantages and disadvantages and not one of the methods fits all type of games. It is the game designer's job to decide a suitable rendering method for a game or virtual world project. Therefore, it is important to know their limitations and consider thoughtfully before getting started with development. We can take a look at how other Flash virtual worlds render avatars by checking the showcase of the SmartFoxServer (http://www.smartfoxserver.com/showcase/).
Read more
  • 0
  • 0
  • 2996

article-image-customizing-avatar-flash-multiplayer-virtual-worlds
Packt
27 Aug 2010
5 min read
Save for later

Customizing an Avatar in Flash Multiplayer Virtual Worlds

Packt
27 Aug 2010
5 min read
(For more resources on Flash, see here.) Customizing your avatar A Flash virtual world is a social community in which players interact with each other and have their own identity. Virtual world usually lets a user decide the avatar's appearance by choosing the combination of different styles and colors. Customizing different styles Each part of the avatar will have different styles and shapes to form different combinations of the appearance of the avatar. Thanks to the timeline and movie clip features in Flash, we can put different styles of each part within the movie clip. For example, the following screenshot shows the head movie clip with different head styles placed frame by frame and we can use gotoAndStop to display the style we want. Customizing the color ActionScript supports changing the color transform for a given movie clip. It supports not only color tint but also applying color filter and detailed RGB transformation. We will use the simple color tint to change the color of the avatar. As the color transform is applying to the whole movie clip, we cannot simply tint the avatar movie clip because that will make the whole avatar tint to one solid color. In order to tint a partial part of the movie clip, we specifically create a movie clip in each part and name it color_area. We later program the ActionScript to change all movie clip names with color_area to the customized color. Adding customization to avatar class We are going to change the style and color by ActionScript in avatar class. We need to import the ColorTransform class in flash.geom package to change the color with ActionScript. import flash.geom.ColorTransform; We need several instance variables to hold the styles and color state. public const totalStyles:Number = 3;public var currentColor:Number = 0x704F4C;public var currentStyle:Number = 1; We wrap the whole block of color transform code into one function. The color transform adds RGB color transformation to the target movie clip. We only use colorTransform to tint the color here but it also supports percentage transform that adds partial color to the target movie clip. We will apply the color transform to the color area inside the head of the avatar in 4 directions. public function changeColor(newColor:Number = 0x000000):void { currentColor = newColor; for each(var avatar:MovieClip in _directionArray){ var avatarColor:ColorTransform = new ColorTransform(); avatarColor.color = newColor; avatar.head.color_area.transform.colorTransform = avatarColor; } } We modified the color by using color transform and used timeline to style the avatar style. Every frame in the head movie clip represents a style with its color tint area. We display the new style by changing the current frame of the avatar movie clip. It is also necessary to change the color again after switching the style because every style contains its own color area. public function changeStyle(styleNumber:int):void { for each(var avatar:MovieClip in _directionArray){ /* display the giving style in all parts of avatar*/ avatar.head.gotoAndStop(styleNumber); avatar.body.gotoAndStop(styleNumber); avatar.lefthand.gotoAndStop(styleNumber); avatar.righthand.gotoAndStop(styleNumber); /* need to apply the color again after changing the style */ var avatarColor:ColorTransform = new ColorTransform(); avatarColor.color = currentColor; avatar.head.color_area.transform.colorTransform = avatarColor; } currentStyle = styleNumber; } The purpose of the avatar class is to control the appearance of the avatar. We just implemented the direction, color, and style switching methods and it is now ready for customization panel to use. Designing a customization panel Avatars in virtual worlds and games often provide players with different kinds of customization. Some games allow users to customize the whole body with lots of options while some games may only provide two to three basic customizations. The layout design of the customization panel is often based on the number of options. There are two common customization panel layouts in the market. One layout displays arrows for a user to select next and previous styles. The other one displays a thumbnail view of the options within the same category. The arrows selection layout is suitable for an avatar that contains limited parts for customization. There may be only two to four categories and not many options in each category. Players can easily loop through different style combinations and choose their favorite one using this layout. The following avatar customization screenshot from the 2D Online RPG called Dragon Fable uses the arrows selection layout: The thumbnail view layout is suitable for avatars that can be highly customized. There are often many categories to customize and each category provides a lot of options for players to choose. Some virtual worlds even provide micro modification so that players can adjust details on the chosen style such as the distance between the eyes. Players do not need to iterate the large amount of styles and can quickly choose a style option among them with the thumbnail view. The following screenshot is an online Mii editor. Mii is the avatar system in the Nintendo Wii console. This is an online clone of the Mii avatar customization. It allows a large amount of avatar customization by the thumbnail view layout with extended features such as scaling and moving the elements.
Read more
  • 0
  • 0
  • 2739

article-image-flash-multiplayer-virtual-world-setting-smartfoxserver-third-party-http-and-database-s
Packt
17 Aug 2010
7 min read
Save for later

Flash Multiplayer Virtual World: Setting up SmartFoxServer with Third-party HTTP and Database Server

Packt
17 Aug 2010
7 min read
(For more resources on Flash, see here.) We are going to download and install Apache and MySQL server package. These kinds of server package features have easy install that auto-configures most of the server settings. It will also install some essential tool for beginners to manage the server easily, such as GUI server administration panel. Installing WAMP on Windows WampServer is an open source HTTP and database server solution on Windows. WAMP stands for Windows, Apache, MySQL, and PHP package. Go to http://www.wampserver.com/en/download.php. Click on Download WampServer to download the installer. Run the installer with all default settings. The server is configured and ready. The WampServer can run by launching from Start | Programs | WampServer | Start WampServer. It will be in the task bar and the server management operation can be found by clicking the WampServer icon. We can start the server by putting the server online in the menu. Installing MAMP on Mac OSX Similar to WampServer, MAMP is the one package web server solution that stands for Mac, Apache, MySQL, and PHP package. The MAMP package can be downloaded at http://www.mamp.info/. Download the MAMP package from the official website. Double-click on the downloaded MAMP dmg file to mount it. Drag the MAMP folder into the Applications folder. To run the MAMP server, go to Applications | MAMP and double-click on the MAMP.app. Installing LAMP on Linux As the same naming convention, the "L" stands for Linux here. Different Linux distributions use different ways to install applications. There may not be a oneclick install method on some Linux branch which requires us to install the Apache and MySQL individually. Some Linux may provide graphic user interface to install LAMP by just selecting it in the applications list. We will use Ubuntu to demonstrate the installation of LAMP. Launch terminal from Applications | Accessories | Terminal. Type following command to install LAMP. sudo tasksel install lamp-server The installer will progress and configure different modules. A dialog will prompt several times asking for a new MySQL root password. You can set your own MySQL password, while in the example we will leave the root password blank. After the completion of the installation, the MySQL server is set up as service in the system. It runs automatically and we do not need to manually launch it to use it. Connecting SmartFoxServer and MySQL server SmartFoxServer is a Java application and Java database connection driver is needed to connect from SmartFoxServer to MySQL database. Downloading JDBC Driver for MySQL JDBC is a Java database connection driver that we need to establish connections between the Java-based SmartFoxServer and the MySQL server. The JDBC driver for MySQL is called Connector/J. We are going to install it to enable MySQL connection from SmartFoxServer. Go to http://dev.mysql.com/downloads/connector/j/5.1.html in web browser. Download the Platform Independent Zip Archive. It may ask you to log in to MySQL.com account. Click on No thanks, just take me to the downloads! to bypass the login step. Choose a mirror to download by clicking on HTTP. Setting up the JDBC driver The MySQL Java connector comes with a bunch of files. We only need two among them. Extract the mysql-connector-java-5.1.10.zip file to a temporary folder. Open the folder and find the mysql-connector-java-5.1.10-bin.jar file. Copy that jar file into SmartFoxServer installation directory | jre | lib | ext. Go into the src directory of the extracted directory and copy the org directory to SmartFoxServer installation directory | jre | lib | ext. Configuring the server settings The configuration file of SmartFoxServer is an XML file that allows us to configure many server settings. It can configure the initial zone or room creation, server address, admin authorization, value tuning for performance, and a lot more. We are going to set the database connection for testing our setup in this article (core settings are out of scope of this article). The configuration file is called config.xml and is located in the SmartFoxServer installation directory under the Server directory. Configuring MySQL server connection in SmartFoxServer Open the config.xml in your favorite text editor. Go to line 203 of the config.xml. This line should be within the structure of a Zone tag with name as dbZone. Change the lines 203-218 from the config.xml: Original code: <DatabaseManager active="false"> <Driver>sun.jdbc.odbc.JdbcOdbcDriver</Driver> <ConnectionString>jdbc:odbc:sfsTest</ConnectionString> <!-- Example connecting to MySQL <Driver>org.gjt.mm.mysql.Driver</Driver> <ConnectionString>jdbc:mysql://192.168.0.1:3306/sfsTest </ConnectionString> --> <UserName>yourname</UserName> <Password>yourpassword</Password> <TestSQL><![CDATA[SELECT COUNT(*) FROM contacts]]></TestSQL> Replace the code in lines 203-218 with the following code: <DatabaseManager active="true"> <Driver>org.gjt.mm.mysql.Driver</Driver> <ConnectionString>jdbc:mysql://127.0.0.1:3306/mysql </ConnectionString> <UserName>root</UserName> <Password></Password> <TestSQL><![CDATA[SELECT NOW()]]></TestSQL> The new setting activates the DatabaseManager and configures the JDBC driver to the MySQL connector that we just downloaded. We also changed the user name and password of the connection to the database to "root" and empty password. We will use the empty password through out the development process but it is strongly recommended to set your own database user password. There is a TestSQL setting where we can write a simple database query so that the SmartFoxServer will try to run it to test if the database connection is correct. As we have not created any new databases for the virtual world, we will test the database connection by querying the current server time. Restarting the server We’ve just set up the connection between SmartFoxServer and third-party database. It is time to test the new setting by restarting the SmartFoxServer. To stop the SmartFoxServer in Windows and Linux, press Ctrl + C. To stop it in Mac OS X, click on the Cancel button in the SmartFoxServer log window. There is a log that appears as usual after we start up the server again. It is important to check the log carefully every time the config.xml is changed. The logfile can provide details of any errors that occur when it tries to load the configure file. For example, if we configure the database connection just now but forget to activate the DatabaseManager, the server will start up correctly. Then you may spend a lot of time debugging why the database connection is not working until you find that the DatabaseManager is not active at all. This happened to me several times while I was developing my first flash virtual world. If the server is running with the new database connection settings, the following lines will be appearing in the log. There can be different database manager settings for each zone. When checking the log, we should be aware which zone the log is referring to. We are configuring the database manager of dbZone zone now. DB Manager Activated ( org.gjt.mm.mysql.Driver ) Zone: dbZone If we forget to activate the DatabaseManager, we will not see the DB Manager Activated wording. Instead, the following message may appear in the log: DB Manager is not active in this Zone! Moreover, if the SmartFoxServer faces some fatal error on start up, it will terminate itself with more detailed error logs. The following lines are an example for error logs that appear when the MySQL connector file is missing: Can’t load db driver: org.gjt.mm.mysql.Driver [ Servre ] > DbManager could not retrive a connection. Java.sql.SQLException: Configuration file not found DbManagerException: The Test SQL statement failed! Please check your configuration. These lines state that the testing SQL failed to run, which we just set to test the connection. It also describes what exception has caused this error to help the debugging.
Read more
  • 0
  • 0
  • 2589
article-image-ordering-buildings-flash-virtual-worlds
Packt
16 Aug 2010
2 min read
Save for later

Ordering the Buildings in Flash Virtual Worlds

Packt
16 Aug 2010
2 min read
(For more resources on Flash, see here.) Ordering the buildings The buildings are not well placed on the map. They overlap with each other in a very strange way. That is because we are now viewing the 3D isometric world in 2D screen with wrong ordering. When we view the 3D perspective in the following way, the closer objects should block the view of the objects behind. The buildings in the preceding image do not obey this real-world rule and cause some strange overlapping. We are going to solve this problem in the next section. Ordering the movie clips in Flash In Flash, every movie clip has its own depth. The depth is called z-order or the z-index of the movie clip. A movie clip with bigger z-order number is higher and covers the others with lower z-order when overlapping. By swapping their z-order, we can rearrange the movie clips on how they overlap and create the correct ordering of isometric buildings. Determining an object's location and view According to our tile-based isometric map, the object that locates in larger number of the x and y axis is in front of the object that locates in smaller number of the x and y axis. We can thus compare the isometric x and y coordinate to determine which object is in front. There is a special case when all shapes of the buildings occupy square shapes. In this situation, the order of the movie clip's z order can be easily determined by comparing their y position.
Read more
  • 0
  • 0
  • 1754

article-image-flash-multiplayer-virtual-world-smartfoxserver-using-embedded-web-server-and-database
Packt
16 Aug 2010
4 min read
Save for later

Flash Multiplayer Virtual World with SmartFoxServer Using Embedded Web Server and Database

Packt
16 Aug 2010
4 min read
(For more resources on Flash, see here.) Unlike a deployment environment, it is common to have just once machine acting both as server and client in a development environment. The machine will have SmartFoxServer, web server, and database installed. In this case, there are no noticeable differences between using the embedded or third-party web server and database. It is a good habit to simulate the deployment environment as much as possible in development stage. As we are going to use a third-party web server and database, we will set up a development environment that also uses the third-party server instead of the embedded web server and database in the third part of this article series. Installing Java Development Kit The Java Development Kit includes the essential development tools (JDK) and the Java Runtime Environment (JRE). The development tool compiles the Java source code into byte codes and the JRE is the response to execute the byte codes. We will need several Java compilations in later chapters. SmartFoxServer is build on the Java environment and we need the JRE to start up the server. The JDK and JRE may be pre-installed in some OSs. Installing JDK On Windows The steps for installing JDK on Windows are as follows: Go to http://java.sun.com/javase/downloads/. Click on the Download button of Java. It will lead to the Java SE Downloads page. Select Windows (or Windows x64 for 64-bits Windows) in Platform. Click on Download. If it prompts an optional login request, we can click the Skip this Step to bypass it. Launch the installer after the download. Install the Java Development Kit with all default settings. The Java environment is ready after installation completes. Installing JDK on Mac OSX The Mac OSX comes with its own set of Java environment. We can check the JDK and JRE version by following steps: Launch terminal from Applications | Utilities | Terminal. Type the following and press the Enter key: javac -version The command will output the currently installed version of the Java in the Mac OSX. In my case, it outputs: javac 1.6.0_17. The current version of SmartFoxServer at the time of writing recommends the version 1.6. If the Java is not updated, we can update it via Apple Menu | Software Update. The software update will check for any updates for your existing Mac software, including the Java environment. Installing JDK on Linux We can use the general method to download and install the JDK or use the system specific method to install the package. We will show the general method and the Ubuntu method. Installing for General Linux Go to http://java.sun.com/javase/downloads/index.jsp in browser. Click on the Download button. The platform Linux should be selected automatically. Otherwise, select Linux (or Linux x64 for 64-bit Linux). Click on Continue. If it prompts for login, click on Skip this Step to bypass it. For Redhat or Fedora Linux, choose the rpm-bin file to download. For other Linux, choose the .bin file to download. Launch terminal via Applications | Accessories | Terminal after the download completes. Change the directory to the folder that contains the downloaded package. The download destination varies from different profile settings. In my case, it is in Downloads folder. cd ~/Downloads/ The version is Java 6 Update 20 at the time of writing and the filename is jdk-6u20-linux-i586.bin or jdk-6u20-linux-i586-rpm.bin. Then we make it executable and launch the installer by the following commands: chmod a+x jdk-6u20-linux-i586.bin./jdk-6u20-linux-i586.bin The installer displays the license agreement. Type Yes at the end to agree and continue installation. Press the Enter key after the file’s extraction to end the installation. Installing for Ubuntu Linux Ubuntu users can install the JDK via the apt-get command. We will search for the latest package name of the JDK by the following command: apt-cache search --names-only sun-java.*-jdk The result shows the available JDK packet names. At the time of writing, it is JDK6: sun-java6-jdk - Sun Java(TM) Development Kit (JDK) 6 We use the apt-get command to install the JDK: sudo apt-get install sun-java6-jdk Type in the user password because it requires user’s password and the privilege to use apt-get.
Read more
  • 0
  • 0
  • 1700