The Process
Transcription
The Process
TANKER Flash Game Design with ActionScript 3.0 by Xai Lao Introduction Tanker is a 2D single player flash game demo coded in ActionScript 3.0. The gamepaly in terms of movement is based around a floor-tile-layout system. In other words, the player is able to only move the hero character accordingly to floor tiles shown on each level. To give a better idea of the game, Tanker is not a Mario game in which a player can pick up and learn how to play in seconds. Unlike Mario where movement plays a lot with physics, the movement in Tanker is more similar to the classic “Frogger game” (Fig 1.0). A player uses the four arrow keys on the keyboard to move the hero avatar (Fig 1.1). In Tanker, a player may only move up, down, left, and right. And unlike Mario, where the player can defeat enemies by jumping on top of them, Tanker requires the player to carefully time and press the attack button to deplete an enemy’s health points down to zero at a rate that constantly changes from enemy to enemy. The details of how health points work and how to defeat an enemy in Tanker will later be explain. Fig 1.1 Frog Fig 1.0 But before I explain about my game any further, I want to first get the reader familiarize with Role Playing Games (RPG) and what they are because Tanker is influenced by the RPG style. In a typical RPG, a player will be role-playing a game avatar or hero that mimics real life in a way. The hero has health points to be aware of as it will usually determine whether the game should continue or not. The hero also has clothes or gears it can wear and which when worn, will increase/ decrease defense armor. The armor plays a role in reducing incoming damages from enemy attacks. Furthermore, the hero has some sort of weapon, like a sword, club, or knife to wield with. Without a weapon, the hero would not be able to attack and even if the hero can attack without a weapon, the game would be quite boring if a player could only attack by relying on hero’s bare hands throughout the entire game. So this is why in RPG games, a game hero needs to carry a weapon and make use of its power to help the player attack. Then there are enemies the hero has to engage epic battles with in a RPG game. Without enemies to fight, the game would be pointless when there is a hero that carries a weapon. RPG games does not end there. Each enemy also carries a certain amount of health points that a player needs to deplete in order to defeat or kill it. If the term “health points” is still confusing, think of simple mathematics. RPGs use a lot of point adding and subtracting which require a player to understand basic math in order to understand how the point system works. Of course however, different RPG games will use different formulas to calculate health points and such. Here is a simple mathematic scenario (Fig 1.2) that is apply in most RPGs. A hero has 50 health points. If the hero gets attack by an enemy and takes in 25 damage, the hero will now have 25 health points Fig 1.2 remaining. If the hero were to take another incoming 26 damage from an enemy, the hero would now have -1 health points. The game would end as soon as the health point reaches 0 or less than 0. The above scenario works with enemies as well too. Each enemy has its own health points and when the hero depletes an enemy’s health points to zero, the hero defeats the enemy. And upon a successful enemy defeat or kill, the enemy will randomly drop an item, which the hero can then keep and put it into its inventory to use later on as the hero progresses further through the game. This explains the complexity of RPG games and that is why games like these become a challenge to learn if you want to enjoy RPGs. Furthermore in most RPG games, a player is given a game avatar to journey throughout the game world while interacting with computer controlled characters. While a player journeys across the game world, a player will often come across random missions or game story missions that connects to the game’s main storyline. And when that happens the player would simply take on the missions by accepting it. Whether the missions ask the player to find something, to deliver an item, or to defeat a foe, upon a mission’s success the player is awarded with gold or some type of money to be used with the game’s monetary system. Players may even be awarded a type of item or weapon, which that can be equip onto their game avatar to help them advance further into the game. The above explainations almost matches how Tanker works and is why my game falls under one of the “hard fun” genre as defined by Nicole Lazarro that would require a little patience before a player can really start to enjoy all the aspects the game offers. Tanker would not fit for a player who only wants to play games like Mario. Although I’m not saying Tanker isn’t a fast pace game, it actually is once you learn the basics of a typical RPG. Tanker is also similar in a way to one of today’s modern Massive Multiplayer Online Role Playing Games (MMORPG) like World of Warcraft, Star Craft, Final Fantasy XI (Fig 2.0), or Diablo due to the similar attributes my game incorporates. MMORPG games usually can take players anywhere from months or to even years to beat. Sometimes an RPG game is never won but instead the storyline ends and the player is welcome to continue and explore the world until they are satisfy. The big difference between the mentioned MMORPG games and my Tanker game is that it is just a single player RPG game and can be completed within a 30-minute timeframe at the max. The reason I’ve decided to keep the game short is because I will be building a demo version rather than a fully developed RPG game. The main reason why I’ve brought up MMOPRG is because my game will incorporate some attributes and game-play-styles from MMORPG such as health points, attack power, attack speed, weapon, and etc. This is why I believe RPG games can be challenging but at the same time fun to play once you get the hang of it. The whole RPG concept about combats stytems, selling/buying items, equipping items; and the list can go on forever, are what that inspired me to create this game. Although RPG game styles are more complicated to play for newcomers, most people have come to love RPGs after understanding the game flow. Fig 2.0 MMORPG Highlights Common Functions - Over 1000 players per individual game server - Many game servers - Spawning Enemy - Day & Night Time - Team/Party Battles Intensive Attribtues - Gears/Armor/Clothes - Defense Armor Points - Weapons - Elemental Attack Status - Different Class/Race - Human, Eleves, Orcs - Health & Magic Bar The images sources are from http://ffxi.allakhazam.com Pre-initial Game Plans and Ideas Before I began the journey to create and program this game, I was forced to really think about my experiences and capabilities. I knew I had experience with Flash and was quite familiar with actionscript 3.0. But what I didn’t have much knowledge in was the fact that I didn’t know much about game development, especially when it comes to professional game development. However I do not have intentions to compare my game against games like Call of Duty, Mario, or World of Warcraft. I am aware that professional games have many people working together as a team. Although knowing most of the time I will be working alone, I didn’t want this to stop me from creating a RPG game in flash using actionscript 3.0 due to my passion to learn. With all that being said, I am not going to be making a full functioning RPG game that will have a complete storyline with zero technical issues. Although it will try to have some kind of a story, the story will be brief and broad just so that I can program my game around a story. Again with the amount of teamwork I have, my initial plans will be to create a short demo rather than a full version. The demo version will still try to incorporate as much elements from an RPG game as possible and in doing so I want to challenge myself as much as I can. Attributes I want to incorporate into the game are health points, energy points, attack power, speed attack, and gold. Although not every attribute will be fully implemented I will try my best to include them so users can get a better grasp at the idea of my game. Health points will play against the player determining if a hero/enemy has been defeated or not. Energy points will allow a player to unleash special attacks that will do more damage then normal attacks. Attack power serves as the damage point that will be dealt to either the hero or the enemy to deplete health points. Speed attack serves for the purpose of how fast a game character can attack during battle. Without speed attack in the game, each player or enemy would be able to spam attacks which would ruin the game. Then lastly I want to incorporate gold as the foundation of keeping track of the player’s score points. Gold can be looked at as an achievement earned by the player throughout the game. Other functions I will want to include will be text dialogues. These text will be loaded from an external XML data file in flash as it will be easier to correct and add changes to. I also want to be able to load external fonts and use them rather than embedding fonts straight into the flash game file. The game will evolve around my own flash game engine as I will at the same time create from scratch as I program the game. Since I will want many elements to be random into the scene, such as floor tiles, enemies, points, and etc., I will depend on the flash’s random script function with some minor modifications. As for graphics for my hero, enemies, and backgrounds, I will plan to import the graphics straight into flash file since I know I probably won’t be having a lot of characters in the game. Equipping and switching items is one of the main things I will want to explore and implement in this game. I want the user to be able to find a weapon by defeating an enemy or monster and equip the weapon. The weapon should help the user become strong as it attack stronger enemies with larger health points. Although I have many things I want to incorporate into the game, I know I will probably have time to implement so many, but these will be the main ideas I want to implement first before implementing anything additional to the game. Tanker - Story Synopsis Tanker is a warrior who has just returned from a long journey. The hero comes back home to find only that his village is in chaos. Not only is his village being overthrown by some evil force, but eventually finds out his entire world is at stake too. If nothing is done this will be the last of his world. The hero will then be led by a Shine Guardian who communicates to the hero through telepathy. The Shine Guardian is one of the last survivors to survive the village attack. The Shine Guardian will serve as the guide to the player and explain how the game works. Tanker’s job is go find whoever is causing this chaos in his village and stop it before it is too late. When the game ends, the player will learn more of the secrets behind the story line such as that the Hero’s name is actually Faith. Tanker is actually a title given to high class warriors whom have completed difficult missions. Characters Character designs by Nou Chee Her Bomblister A dark green creature that lives inside a golden shell. They can spit red acid to its prey disabling vision temporarily if caught in the eyes. Though slow, they bring disaster to an oponent if is engaged in battle (see Appendix A.3). Psycho Sensei These little creatures have a strange behavior. They constantly gaggle noises and walk in funny patterns. When engaged in battly, they become furiuos little foes that go beserk. Tanker A young warrior who seeks to find the truth and destroy all evil. He lives in a small village call Shamals hidden within two large mountains. He doesn’t speak much but rather tends to get straight to the point in conversations. Tuskom These powerful beast can do serious damage with a single blow from their horns. They are easily provoked and when mad will confront their oponent with a ragging stempede force. They are known to travel in herds of 200 or more at a time. Mad Bunny A These creatures come out at night to hunt. Their red eyes glow and helps them see in the dark. Although they are not strong creatures, they are quick and fast. Squwi Although little, they can easily navigate around their oponent with ease by bouncing with maximum precision and speed. They are usually found in the day time around tall grasses. Breathom These are one of the most feared creatures. Anyone who contacts with these should avoid being seen. They have a form of a dragon but are without wings. It is believe they are part of the evil act that is causing chaos throughout the world. There is currently a total of six enemies in Tanker, however not all the characters will be seen in the game for demo purposes. Character Setup In Flash Each character is made up of three or more frames that were created in flash. The purpose of having three frames per character is to simulate the attack phase during combat in the game. Fig 3.0 shows how the layers were set up in Flash for the hero. Fig 3.1 shows the layer setup for the enemies. Fig 3.0 Fig 3.1 Collision Detection The collision detection I decided to go with is a hidden point detection. Each object in the game that will be used for collision will have an invisible square with a opacity of 0%. This invisible square will be used to detect if it is hitting another invisible square. The Main Actionscript Classes TankerEngine.as - The engine is built for a decent performance. This means modification can be easily done to some extent without having to re-write or delete an entire code. In other words, the engine is dynamic and flexible. The Tanker engine is written in actionscript 3.0. It is the main class file that is called in the beginning of the game during startup. The engine will load all fonts, graphics, classes at game assets. The engine has one EnterFrame function that runs every movement in the game such as characters movements down to a ticking clock timer (see Appendix A28.0). TankerPreloader.as - The pre-loader helps load all necessary items before the game can load itself. It basically calls all the classes and prepares them for the game (see Appendix A30.0). TankerStartMenu.as - Once the pre-loader is done loading, the start menu loads and displays a simple graphic interface for the player to click start to play the game (see Appendix 31.0). Hero.as - The hero class controls the main hero in the game. It provides the foundation of how the hero can move and what it can interact with (see Appendix A14.0). M0001.as - The monster classes are name coded so that future monsters can be easily incorporated into the game engine when creating new monsters. The idea is to name all monster classes in this manner: M0001, M0002, ..., M0023, and so on rather than naming the each monster class by the monster’s name. This is purposely for good programming practices (see Appendix A4.0). W0001.as - The weapon classes are name coded so that future weapons can be easily incorporated into the game engine when creating new weapons. The idea is to name all weapon classes in this manner: W0001, W0002, ..., W0101, and so on rather than naming the each weapon class by the weapon’s name. This is purposely for good programming practices (see Appendix A33.0). HelpMenu.as - The help menu is available for the player at the top right of the game screen. It describes the game play and will give the player information on the attributes in the game (see Appendix A13.0). IFStat.as - The stat interface will be located on the left side of the screen and give the player real-time updates on their stats. It will display health points, equipment, and weapon stats to the player (see Appendix A16). IFStatEquip.as - The equipment interface will display the player’s current items/weapons that they have collected from defeating foes. The player is allow to browse through the equipment slots and equip whatever is selected (see Appendix A17.0). There is a total of over 50 actionscript classes in Tanker. Start Menu The start menu has simply one button that allows the player to start the game once they click on the “Start” button. Starting The Game Once the game has started, the game interface will open. On the left side, there are the stats information about the player. On the right is the game stage that the player can move around in and is where enemies will randomly spawn. The Help Menu The help menu is design to help players understand the game. It is located in the upper right hand corner of the screen. The Dialogue Box The dialogue box will pop up every so often to help guide the player in the game on what to do. It plays as a major role in the game to display game character dialogues. The RPG Battle System When the player attacks an enemy, numbers will come flying above the enemy and will dissapear after a few seconds. These numbers indicate the amount of damage that the hero is dealing to the enemy. The stronger the weapon the player has equip, the higher these damage numbers will increase. In other words, strong weapons will make defeating enemies easier. Once the player starts attacking an enemy, enemies will start to attack back. Each enemy carries a speed attack bar just like the hero on its right side. Each attack will deplete the speed attack bar and will automatically fill up gradually depending on their speed recovery stats of the enemy. When this bar fills up, the enemy is allow to attack the player again. This attacking process will repeat until the enemy is either killed or the player disengages in battle. A player can run away from battle moving to the another floor tile where there is no enemy occupying it. The battle system works similar to other RPGs. In order to initiate an attack, the player must move into an enemy’s location. Once inside, the player will have to continuously press the attack button to attack an enemy. Players will only be able to attack when the attack speed bar fills up (indicated by the blue bar on the left of the hero. This is to prevent spaming and will make the game more challenging. The green bar on the right indicates the enemy’s health points. Once the health point is depleted, then the enemy will be consider destroyed and the player will automatically recieve gold and if lucky an item, which is base off a random math expression. Battle Close Up View How A Player Can Get Better Speed: Fast Strength: Easy Speed: Slow Strength: Medium Speed: Slow Strength: Medium Speed: Slow Strength: Hard Speed: Fast Strength: Hard Speed: Slow Strength: Hard Learning how to analyze each enemy is the key to winning Gold Gold is the score a player gets each them they defeat an enemy. The amount of gold depends on the type and difficulty of the enemy. The future plan is to use gold for buying and selling items in the game monetary system. Health Health is the player’s life bar. When it reaches zero the player will be penalize. The little scouts that wander the plain will come take away the player if their life bar depletes. In other words, the game demo will end. Energy Energy is the player’s extra power. Each time the player moves across a floor tile, they will collect the indicated amount of energy on that specific tile. When the player has collect enough and their energy fills up, they can unleash a powerful attack that does more damage then your normal attack. Attack Attack is the player’s attack power. The strong attack power, the faster the player can take down an enemy. If the hero is equipped with a weapon, their attack will be modify. Take advantage of equiping weapons whenever possible. There are two numbers that represents a player’s attack power. Each attack to the eneymy will be randomed between the two numbers. So every attack may have a different damage. Atk Spd ATK SPD is short for attack speed. This is a number in miliseconds. The higher the number, the longer the interval between each attack. It controls the rate at which the player can attack. Item Sack The item sack holds all the items that drop from defeated enemies. A player can only carry 6 items at a time. Future update will allow players to switch items around in the sack and also delete items so new items can be collected. The item slot allows a player to toggle around their items and read the effects an item has. Item Numbers Each item or weapon has a level number. The upper left hand corner of an item is where the level number is located. There is a maximum of 3 levels, [0-3]. The higher the level the stronger the item. For example if two weapons of the same name is obtained and one is level 0 while the other is level 3, the level 3 weapon will have a higher attack power. Summary Creating simple games flash has been a hobby of mine since I picked up actionscript 3.0. I wanted to create a flash game and put it on the web for others to play and enjoy. However, the more I got into programing flash games, the more I realize I would have to have a team of two or more, especially if I’m going to tackle an RPG game style. Through out my process of creating Tanker from scratch, I have learned a lot about actionscript 3.0 and have improve my understanding of creating flash games. It didn’t take long to notice that in order to run a complex game, I was going to need a game engine. But I didn’t know how complex my game was going to be so I decided not to go with a pre-existing game engine created by others. Instead I created my own game engine, specifically just for Tanker. I coded the engine from scratch following basic tutorials on lynda.com and flash forum sites. I got help mostly from the online flash forum sites however. Fortunately, I already learned java and c++ programming skills from my other computer science classes. Without those classes, I don’t think I would have been able to create the Tanker game demo. By the time I figure I was close to finishing the game demo, I realized I have already wrote over 50 classes. I was surprise I wrote all of those classes by myself, but of course with a little help here and there from the online flash forum sites. I was also able to incorporate programing methods such as polymorphism and creating interface classes in my game as well. I am really grateful I took the time grasp these concepts well during my computer science classes. Without these methods, I wouldn’t have been able to make my enemy classes inherit attributes from preexisting ones and would have ended up with a lot more complicated unorganized classes. The more I coded, I started to appreciate math, algorithms, and expressions. I used a lot of these to generate things such as the random spawning, drop rate percentage of each enemy, and much more. I believe the more random a game is, the more exciting it’ll be for the players. If everything is too linear the game would be boring and was why I tried to incorporate a random game environment for the players. Although I ran out of time to incorporate everything I was planning to, I will definitely finish up this game demo with the things I’ve planned. Because what makes an RPG game fun is the way how it tries to mimic real life in a way. There are so much things I could’ve included but I could only do so much. Therefore when creating complex games, teamwork and a smooth system workflow between team members is the key. Overall, I enjoyed the challenge of learning actionscript 3.0 and programming an RPG game. The experience has definitely uplifted my coding and programing abilities. I’ve gained a higher respect for all programers who codes day to day to invent games for the public. In the future I wouldn’t mind programing another game like this, but one thing for sure is that I would make sure I have a bigger team to work with. The game can be played at www.xaiLao.com/tanker.php However, the game is only available for a time period. Credits Game Design Programmer Xai Lao Character and Game Design Artist Nou Chee Her UW-Stout Faculty Advisor Uttam Kokil APPENDIX Appendix A1.0 Clock.as package com.Lao.tanker { /* created by Xai Lao - free to use and modify This is a clock dependent on the game’s main enterframe You must change the gameFrameRate variable to match your game’s FPS for this clock to be accurate */ import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFormat; import flash.events.Event; public class Clock extends ClockWeekend { private var hr:int=0, min:int=0, sec:int=0; private var tHr:String=”00”, tMin:String=”00”, tSec:String=”00”; private var MAXHR:int = 23, MAXMIN:int = 59, MAXSEC:int = 59; private var amPm:String = “AM”; // CHANGE gameFrameRate to match your game’s fps private var gameFrameRate:int = 30; private var counter:int; private var tTxt:TextField = new TextField(); private var f:TextFormat = new TextFormat(); private var tColor:uint = 0xffffff; public function Clock(h:int, m:int, s:int, fr:int, startDay:int, rand:Boolean) { super(startDay, rand); // if rand is true, super will generate the startDay, else startDay will be use hr = h; min = m; sec = s; gameFrameRate = fr; addEventListener(Event.ADDED_TO_STAGE, loadClock ); } // initial values and displays private function loadClock(e:Event){ f.size = 16; f.color = tColor; tTxt.defaultTextFormat = f; tTxt.border = false; tTxt.selectable = false; tTxt.width = 120; tTxt.height = 20; tTxt.text = “00:00:00 am”; addChild(tTxt) removeEventListener(Event.ADDED_TO_STAGE, loadClock Appendix ); } // The main enterframe should call this public function updateClock(){ counter++; if(counter%gameFrameRate == 0){ sec++; // increment sec every time the last max FPS is hit if(sec > MAXSEC){ // reset sec and increment min min++; sec = 0; } if(min > MAXMIN){ // reset min and increment hr hr++; min = 0; } if(hr > MAXHR){ // reset hr base on a 24 hour clock hr = 0; changeDay(); } // modify the sec, min, hr if they are below 10 // mod sec if(sec < 10){ tSec = “0”+ sec; }else{ tSec = String(sec); } // mod min if(min < 10){ tMin = “0”+ min; }else{ tMin= String(min); } // mod hr if(hr < 10){ tHr = “0”+ hr; }else{ tHr = String(hr); } // AM PM if(hr < 13){ amPm = “AM”; }else{ amPm = “PM”; } Appendix A1.1 Clock.as // ----- end of modification // display the current time tTxt.text = “”+tHr + “:” + tMin + “:” + tSec + “ “+ amPm; counter = 0; } } // getters public function getTime():String{ return tTxt.text; } public function getHr():int{ return hr; } public function getMin():int{ return min; } public function getSec():int{ return sec; } } } Appendix Appendix A2.0 Clock2.as package com.Lao.tanker { /* created by Xai Lao - free to use and modify This is a clock2 dependent on the game’s main enterframe This clock extrends ClockWeekend if you want the weekend name otherwise this class can extends Sprite instead Clock2 is a modify version of Clock.as. For game time purposes a real time clock would be too slow. So Clock 2 makes every sec a minute and every minute an hour. If you want a real time 24 hr clock with sec, use Clock1.as Other objects can use this class to check: - getDayTime:Boolean --> isDayTime - getTime - getHr - getMin */ import flash.display.Sprite; import flash.display.Graphics; import flash.text.TextField; import flash.text.TextFormat; import flash.events.Event; public class Clock2 extends ClockWeekend { private var hr:int=0, min:int=0; private var tHr:String=”00”, tMin:String=”00”; private var MAXHR:int = 23, MAXMIN:int = 59; private var amPm:String = “AM”; // controls graphic // at 6 and until 18, game is consider daylight time // these two numbers control the graphic if moon should appear or sun private var dayTimeStart:int = 6, dayTimeEnd:int = 18; private var dayTimeCounter:int = 0; // when dayTimeCounter hits dayTimeStart or dayTimeEnd MINUS 1, then turns on canCreateSunMoon private var canCreateSunMoon:Boolean = true; public var isDayTime:Boolean = true; // make sure you crate this class passing the correct game framerate of your game private var gameFrameRate:int = 24; private var counter:int; private var tTxt:TextField; private var f:TextFormat; private var tColor:uint = 0xffffff; Appendix public function Clock2(h:int, m:int, fr:int, startDay:int, rand:Boolean) { // hour, min, frameRate super(startDay, rand); hr = h; min = m; gameFrameRate = fr; addEventListener(Event.ADDED_TO_STAGE, loadClock ); } // initial values and displays private function loadClock(e:Event){ tTxt = new TextField(); f = new TextFormat(“Segoeb”); f.size = 16; f.color = tColor; tTxt.defaultTextFormat = f; tTxt.embedFonts = true; tTxt.border = false; tTxt.selectable = false; tTxt.width = 120; tTxt.height = 20; tTxt.x = 50; addChild(tTxt) var s:Sprite = new Sprite(); C_Holder.push(s); // index 1 C_Holder[1].x = tTxt.width + 40; C_Holder[1].y = 5; addChild(s); //createMoon(false); removeEventListener(Event.ADDED_TO_STAGE, loadClock); } private function createMoon(moon:Boolean){ if(moon){ C_Holder[1].graphics.clear(); C_Holder[1].graphics.lineStyle(1, 0x00ccff); C_Holder[1].graphics.beginFill(0xffffff); C_Holder[1].graphics.lineTo(0,0); C_Holder[1].graphics.curveTo(10,10, 0, 15); C_Holder[1].graphics.curveTo(5, 10, 0, 0); C_Holder[1].graphics.endFill(); }else{ C_Holder[1].graphics.clear(); C_Holder[1].graphics.lineStyle(2, 0xffffff); C_Holder[1].graphics.beginFill(0xffff00); C_Holder[1].graphics.drawCircle(0,8, 8); C_Holder[1].graphics.endFill(); } Appendix A2.1 Clock2.as } // The main enterframe should call this public function updateClock(){ counter++; if(counter%gameFrameRate == 0){ min++; // increment sec every time the last max FPS is hit if(min > MAXMIN){ // reset min and increment hr hr++; dayTimeCounter = hr; canCreateSunMoon = true; min = 0; } if(hr > MAXHR){ // reset hr base on a 24 hour clock hr = 0; changeDay(); } // create sun or moon depending on time if(hr >= dayTimeStart && hr < dayTimeEnd && canCreateSunMoon ){ createMoon(false); canCreateSunMoon = false; isDayTime = false; }else if(canCreateSunMoon){ createMoon(true); canCreateSunMoon = false; isDayTime = true; } // modify the min, hr if they are below 10 // mod min if(min < 10){ tMin = “0”+ min; }else{ tMin= String(min); } // mod hr if(hr < 10){ tHr = “0”+ hr; }else{ tHr = String(hr); } // AM PM if(hr < 12){ Appendix amPm = “AM”; }else{ amPm = “PM”; } // ----- end of modification // display the current time tTxt.text = “”+tHr + “:” + tMin + “ “+ amPm; counter = 0; } } // getters public function getTime():String{ return tTxt.text; } public function getHr():int{ return hr; } public function getMin():int{ return min; } public function getDayTime():Boolean{ return isDayTime; } /* public function setWoldName():void{ var worldTxt:TextField = new TextField; C_Holder.push(woldTxt); }*/ } } Appendix A3.0 ClockWeekend.as package com.Lao.tanker { /* created by Xai Lao - free to use and modify This is a clock dependent on the game’s main enterframe You must change the gameFrameRate variable to match your game’s FPS for this clock to be accurate */ import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFormat; import flash.events.Event; public class ClockWeekend extends Sprite { public var C_Holder:Array = new Array(); private var day:Array = new Array(“MON”, “TUE”, “WED”, “THU”, “FRI”, “SAT”, “SUN”); public function ClockWeekend(startDay:int, rand:Boolean) { //super(h,m,s); if(rand){ // if use wants to start this clock with a random day generated or not counterDay = Math.floor(Math.random() * day. length); }else{ counterDay = startDay; // otherwise use the given startng day } addEventListener(Event.ADDED_TO_STAGE, loadDay ); } // initial values and displays private function loadDay(e:Event){ var f:TextFormat = new TextFormat(“Segoeb”); var tTxt:TextField = new TextField(); f.size = 16; f.color = 0xffffff; tTxt.defaultTextFormat = f; tTxt.embedFonts = true; tTxt.border = false; tTxt.selectable = false; tTxt.width = 120; tTxt.height = 20; tTxt.text = day[counterDay]; //tTxt.x = 100; C_Holder.push(tTxt); addChild(tTxt) removeEventListener(Event.ADDED_TO_STAGE, loadDay ); } private var counterDay:int = 0; protected function changeDay(){ counterDay++; if(counterDay > 6){ counterDay = 0; } C_Holder[0].text = day[counterDay]; } } } Appendix Appendix A4.0 M0001.as package com.Lao.tanker.enemy { import com.Lao.tanker.Monster; import com.Lao.tanker.IItem; import com.Lao.tanker.weapon.*; public class M0001 extends Monster { // attributes private var hp:int = 10; private var minGold:int = 1; private var maxGold:int = 3; private var atkSpd:int = 2000; private var minAtk:int = 3; private var maxAtk:int = 5; private var itemDropPercent:Number = 1; // 30% chance drop an item // constructor public function M0001(num:int) { super(hp, minGold, maxGold, atkSpd, minAtk, maxAtk, itemDropPercent); } override public function dropItem():IItem{ var par = parent; var rand:Number = Math.floor(Math.random()*10); if( rand > 8){ par.parent.parent.summonTutorial(“Weapon”); return new W0001(2); // drop a bone club }else if(rand > 5){ par.parent.parent.summonTutorial(“Weapon”); return new W0001(1); }else{ par.parent.parent.summonTutorial(“Weapon”); return new W0001(0); } } // end of dropItem } // end of class } Appendix Appendix A5.0 M0002.as package com.Lao.tanker.enemy { import com.Lao.tanker.IItem; import com.Lao.tanker.Monster; import com.Lao.tanker.weapon.*; // Rabbit public class M0002 extends Monster { // attributes private var mname:String = “Dull Rabbit”; private var hp:int = 50; private var minGold:int = 1; private var maxGold:int = 3; private var atkSpd:int = 2000; private var minAtk:int = 3; private var maxAtk:int = 5; private var itemDropPercent:Number = .5; // 30% chance drop an item // constructor public function M0002(num:int) { super(hp, minGold, maxGold, atkSpd, minAtk, maxAtk, itemDropPercent); } override public function dropItem():IItem{ var par = parent; var rand:Number = Math.floor(Math.random()*10); if( rand > 8){ return new W0001(2); // drop a bone club }else if(rand > 5){ return new W0001(1); }else{ return new W0001(0); } } // end of dropItem } // end of class } Appendix Appendix A6.0 M0003.as package com.Lao.tanker.enemy { import com.Lao.tanker.Monster; import com.Lao.tanker.IItem; import com.Lao.tanker.weapon.*; public class M0003 extends Monster { // attributes private var mName:String = “Dull Turtle”; private var hp:int = 100; private var minGold:int = 5; private var maxGold:int = 8; private var atkSpd:int = 3000; private var minAtk:int = 3; private var maxAtk:int = 5; private var itemDropPercent:Number = .50; // 30% chance drop an item // constructor public function M0003(num:int) { super(hp, minGold, maxGold, atkSpd, minAtk, maxAtk, itemDropPercent); } override public function dropItem():IItem{ var rand:Number = Math.floor(Math.random()*10); if( rand > 8){ return new W0002(2); // drop a bone club }else if(rand > 5){ return new W0002(1); }else{ return new W0001(1); } } // end of dropItem } // end of class } Appendix Appendix A7.0 FloorTiles.as package com.Lao.tanker { import flash.display.Sprite; import flash.display.Graphics; public class FloorTiles extends Sprite { // data tile private var dataTile:Tile; private var C_AI:Array; public var C_Holder:Array = new Array(); // data tile public var C_Holder2:Array = new Array(); // floor tile private var availableTiles:Array = new Array(); //Enemy private var MAX_ENEMY:int = 5; // loop variables private var i:int=0; private var tile:Sprite; private var MAX_TILES:int = 50; private var MAX_TILE_PER_LINE:int = 10; private var limitReachCounter:int = 0; // tile appearence private var tColor = 0x733345; private var tBorderThickness = 1; private var tRoundness = 15; // tile demensions and spacing private var wid:int = 50; private var hei:int = 50; private var COL_GAP:int = 9; // column gap between each block private var ROW_GAP:int = 9; // gap between rows private var xReset:int = 0; private var xOffset:int = 140; // each tile starts with this x offset so it doesn’t overlap any menus private var yOffset:int = 45;// each tile starts with this x offset so it doesn’t overlap any menus // border attribute private var border_X_offset:int = 180; private var bLineThickness:int = 1; private var bColor = 0x733345; // border color private var bWid:Number = 600; private var bHei:Number = 370; private var bRoundCorner:Number = 15; Appendix public function FloorTiles(C_AI_sub:Array) { C_AI = C_AI_sub; // create top banner createTopBanner(); // create tiles for(i=0; i<MAX_TILES; i++){ createTile(i); } // create border for tiles createBorder(); // populate level (enemies, items, etc) createEnemies(); } private function createTopBanner(){ tile = new Sprite(); tile.graphics.beginFill(tColor); tile.graphics.drawRoundRect(10,10,bWid, 20, bRoundCorner, bRoundCorner); tile.graphics.endFill(); addChild(tile); tile.x = border_X_offset; // fix block tile = new Sprite(); tile.graphics.beginFill(tColor); tile.graphics.drawRect(10,18,bWid, 20); tile.graphics.endFill(); addChild(tile); tile.x = border_X_offset; } private function createTile(tileCount:int){ if( (tileCount % MAX_TILE_PER_LINE) == 0 && tileCount != 0){ // detect whenever the limit tile is reach limitReachCounter ++; // counts every time the limit is reach xReset = 0; // reset the x offset so tiles get lay down on most left again } tile = new Sprite(); xReset ++; //tile.graphics.beginFill(0x987878); //tile.graphics.drawRoundRect(10,10,wid,hei,15,15); //tile.graphics.endFill(); tile.graphics.lineStyle(tBorderThickness, tColor); tile.graphics.drawRoundRect(0,0,wid,hei,tRoundness, tRoundness); // data tile dataTile = new Tile(); // create a new data Appendix A7.1 FloorTiles.as tile C_Holder.push(dataTile); // Main array holder for this class tile.addChild(dataTile); // for each tile created, nest a new data tile inside each tile C_Holder2.push(tile); addChild(tile); // add tile to class to be diplay tile.x = xOffset + ((wid+COL_GAP)*xReset); tile.y = yOffset + ((hei+ROW_GAP) * limitReachCounter ) ; } private function createBorder(){ tile = new Sprite(); tile.graphics.lineStyle(bLineThickness, bColor); tile.graphics.drawRoundRect(10,10,bWid,bHei,bRoundC orner,bRoundCorner); addChild(tile); tile.x = border_X_offset; } private function createEnemies(){ // -------------------------- // // Enemies - populate each enemy onto each floor tiles, two enemies can’t be on same floor tile // -------------------------- // // push all floor tiles into array, like powerballs being put inside a plastic bubbles for(i=0; i<if_floorTiles.C_Holder2.length; i++){ availableTiles.push(i); } availableTiles.splice(0,1); // to prevent enemy from spawning on the first tile where hero is also on //populate enemey onto level for(i=0; i<MAX_ENEMY; i++){ // pick one random number from the array randomNum = Math.floor(Math.random() * availableTiles.length ); // note: if array length is 50, you can’t get random # 50, random max would be 49 e1 = new Rabbit(i); // availableTiles[randomTile] tankerWorld.addChild(e1); C_AI.push(e1); } } } } Appendix Appendix A8.0 Font001.as package com.Lao.tanker { import import import import flash.display.Loader; flash.events.Event; flash.text.TextField; flash.text.TextFormat; import import import import import import import flash.display.Sprite; flash.text.TextField; flash.text.TextFormat; flash.text.Font; flash.text.TextFieldAutoSize; flash.text.AntiAliasType; flash.utils.getDefinitionByName; public class Font001 extends Sprite{ public function Font001() { var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event. INIT, fontLoaded); loader.load(new URLRequest(“Font001.swf”)); // method 3 - works but is not for run time /* var myFont:Font1 = new Font1(); var f:TextFormat = new TextFormat(); f.font = myFont.fontName; f.size = 24; var myTextField:TextField = new TextField(); myTextField.autoSize = TextFieldAutoSize.LEFT; myTextField.antiAliasType = AntiAliasType.ADVANCED; myTextField.defaultTextFormat = f; myTextField.embedFonts = true; myTextField.text = “The quick brown fox jumped over the lazy dog.”; addChild(myTextField) */ } private function fontLoaded(e:Event){ var txt:TextField = new TextField(); txt.width = 600; txt.embedFonts = true; var f:TextFormat = new TextFormat(“Segoe”); f.size = 24; f.color = 0x00ff00; txt.defaultTextFormat = f; txt.text = “RUNTIME FONTkS oh yeah 123 baby”; addChild(txt); } } } Appendix Appendix A9.0 FontLoader.as package com.Lao.tanker { /* This class loads all the fonts for the applications */ import flash.display.Loader; import flash.events.Event; import flash.display.Sprite; import flash.net.URLRequest; /* import import import import import import */ public flash.text.TextField; flash.text.TextFormat; flash.text.Font; flash.text.TextFieldAutoSize; flash.text.AntiAliasType; flash.utils.getDefinitionByName; class FontLoader extends Sprite{ private var isReady:Boolean = false; private var loader:Loader = new Loader(); public function FontLoader() { loader.contentLoaderInfo.addEventListener(Event. INIT, fontLoaded); loader.load(new URLRequest(“Font001.swf”)); // method 3 - works but is not for run time fonts /* var myFont:Font1 = new Font1(); var f:TextFormat = new TextFormat(); f.font = myFont.fontName; f.size = 24; var myTextField:TextField = new TextField(); myTextField.autoSize = TextFieldAutoSize.LEFT; myTextField.antiAliasType = AntiAliasType.ADVANCED; myTextField.defaultTextFormat = f; myTextField.embedFonts = true; myTextField.text = “The quick brown fox jumped over the lazy dog.”; addChild(myTextField) */ } private function fontLoaded(e:Event):void{ dispatchEvent(new Event(“loadComplete”)); // make sure any class that use this class listens to loadComplete before you start // making textFields with thiese fonts loader.contentLoaderInfo.removeEventListener(Event. INIT, fontLoaded); } } } Appendix Appendix A10.0 FontLoader.as package com.Lao.tanker { /* This class loads all the fonts for the applications */ import flash.display.Loader; import flash.events.Event; import flash.display.Sprite; import flash.net.URLRequest; /* import import import import import import */ public flash.text.TextField; flash.text.TextFormat; flash.text.Font; flash.text.TextFieldAutoSize; flash.text.AntiAliasType; flash.utils.getDefinitionByName; class FontLoader extends Sprite{ private var isReady:Boolean = false; private var loader:Loader = new Loader(); public function FontLoader() { loader.contentLoaderInfo.addEventListener(Event. INIT, fontLoaded); loader.load(new URLRequest(“Font001.swf”)); // method 3 - works but is not for run time fonts /* var myFont:Font1 = new Font1(); var f:TextFormat = new TextFormat(); f.font = myFont.fontName; f.size = 24; var myTextField:TextField = new TextField(); myTextField.autoSize = TextFieldAutoSize.LEFT; myTextField.antiAliasType = AntiAliasType.ADVANCED; myTextField.defaultTextFormat = f; myTextField.embedFonts = true; myTextField.text = “The quick brown fox jumped over the lazy dog.”; addChild(myTextField) */ } private function fontLoaded(e:Event):void{ dispatchEvent(new Event(“loadComplete”)); // make sure any class that use this class listens to loadComplete before you start // making textFields with thiese fonts loader.contentLoaderInfo.removeEventListener(Event. INIT, fontLoaded); } } } Appendix Appendix A11.0 FramerateTracker.as package com.Lao.tanker { // This class is a textarea that displays the fps /* // framerate tracker - copy and paste this comment code in .fla where it is created var fr:FramerateTracker = new FramerateTracker(); fr.x = 10; fr.y =10; fr.scaleX = 2; fr.scaleY = 2; stage.addChild(fr); */ import flash.utils.getTimer; import flash.events.Event; import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFormat; public class FramerateTracker extends Sprite { // vars private var time:int; private var prevTime:int = 0; private var fps:int; private var fps_txt:TextField; private var avg_fps_txt:TextField; private var myFormat:TextFormat; private var avg_fps:int = 0; public var counter:int = 0; private var max_frame:int = 30; // constructor public function FramerateTracker() { // myFormat = new TextFormat(); myFormat.size = 15; fps_txt = new TextField(); fps_txt.defaultTextFormat = myFormat; avg_fps_txt = new TextField(); avg_fps_txt.defaultTextFormat = myFormat; fps_txt.x = 0; fps_txt.y = 0; addChild(fps_txt); // add textfield to this class only, not to yet to stage avg_fps_txt.x = 0; avg_fps_txt.y = 20; addChild(avg_fps_txt);// add textfield to this Appendix class, note that the class still needs // to be added to stage when the class is created // //addEventListener(Event.ENTER_FRAME, getFps); } // methods public function getFps():void { // time = getTimer(); fps = 1000 / (time - prevTime); // fps_txt.text = “fps: “ + fps; avg_fps += fps; // prevTime = getTimer(); // update avg_fps counter++; if(counter % max_frame == 0){ avg_fps_txt.text = “avg_fps: “ + (avg_fps / max_frame).toFixed(2); avg_fps = 0; } } } // end class } // end package Appendix A12.0 GaugeBar.as package com.Lao.tanker { import flash.display.Graphics; import flash.display.Shape; import flash.display.Sprite; public class GaugeBar extends Sprite { public var C_Holder:Array = new Array(); private var wid:int = 4; private var hei:int = 40; private var barC = 0x33FF00; private var borderThick = 1; private var borderC = 0x999999; private var rot:int = 180; // to trick the registration point so height can shrink down public function GaugeBar(rotat:int, colr:uint, w:int, h:int, border:Boolean) { rot = rotat; barC = colr; wid = w; hei = h; // constructor code var s:Shape= new Shape(); C_Holder.push(s); s.graphics.beginFill(barC); s.graphics.drawRect(0,0, wid, hei); s.graphics.endFill(); //s.x = 50; s.y = 50; s.rotation = rot; addChild(s); s = null; if(border){ var t:Shape = new Shape(); t.graphics.lineStyle(borderThick,borderC); t.graphics.drawRect(0,0, wid, hei); //t.x = 50; t.y = 50; t.rotation = rot; addChild(t); t = null; } } public function updateBar(num:Number){ C_Holder[0].scaleY = num; } } } Appendix Appendix A13.0 HelpMenu.as package com.Lao.tanker { /* This class loads the help menu list so users can read help infomation. */ import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFormat; import flash.events.Event; import flash.events.MouseEvent; import flash.text.AntiAliasType; // xml import flash.net.URLLoader; import flash.net.URLRequest; import flash.text.TextFieldType; public class HelpMenu extends Sprite{ private var C_Holder:Array = new Array(); // holds the menu list private var C_Holder2:Array = new Array(); // holds the description text box field, just 1 element for now // help var - use xml for this private var xmlLoader:URLLoader = new URLLoader(); private var help1:Array = new Array(); private var help2:Array = new Array(); private var maxList:int = 0; private var S_Holder:Sprite = new Sprite(); public function HelpMenu() { // constructor code xmlLoader.addEventListener(Event.COMPLETE, showXML); xmlLoader.load(new URLRequest(“xml/help.xml”)); } private function showXML(e:Event):void { XML.ignoreWhitespace = false; var helpList:XML = new XML(e.target.data); //trace(helpList.list.title.length());//Result is 4 var i:Number; maxList = helpList.list.title.length(); // for use with textFields for (i=0; i < helpList.list.title.length(); i++) { help1.push( helpList.list.title[i].text() ); help2.push( helpList.list.desc[i].text() ); Appendix } createMenuButton(); createMenuLists(); } private function createMenuButton():void{ var s:Sprite = new Sprite(); var txt:TextField = new TextField(); var f:TextFormat = new TextFormat(“Segoeb”); s.graphics.beginFill(0xffffff, 0); // turn alpha zero for now s.graphics.drawRect(0,0,200,20); s.graphics.endFill(); f.size = 16; f.color = 0xffffff; txt.defaultTextFormat = f; txt.embedFonts = true; // so it can use embeded fonts txt.text = “HELP”; txt.selectable = false; txt.width = 100; txt.height = 30; txt.x = 50; txt.y = 0; s.addChild(txt); s.x = 30; addChild(s); s.addEventListener(MouseEvent.CLICK, showMenu); } private function showMenu(e:Event):void{ if(S_Holder.visible == true){ S_Holder.visible = false; }else{ S_Holder.visible = true; } } private function createMenuLists():void{ var f:TextFormat = new TextFormat(“Segoe”); // frank var txt:TextField; var s:Sprite; var wid:int = 200; var hei:int = 20; //format f.size = 12; f.color = 0x333333; for(var i:int=0; i<maxList; i++){ // block Appendix A13.1 HelpMenu.as s = new Sprite(); s.graphics.lineStyle(1, 0x666666); s.graphics.beginFill(0xffffff, .9); s.graphics.drawRect(0,0, wid, hei); s.graphics.endFill(); s.y = 30+(hei*i); // txt txt = new TextField(); txt.defaultTextFormat = f; txt.embedFonts = true; txt.width = wid-6; txt.height = hei-3; txt.text = “”+help1[i]; txt.border = false; txt.selectable = false; txt.mouseEnabled = false; // so mouse can’t affect it since bg is mouseclickable txt.condenseWhite = true; txt.x = 3; txt.y = 1; txt.doubleClickEnabled = false; // add s.addChild(txt); C_Holder.push(s); S_Holder.addChild(s); s.addEventListener(MouseEvent.CLICK, loadDesc); } // ------------------------- // description box textfield var dWid:int = 380; var dHei:int = 290; f = new TextFormat(“Frank”); f.size = 12; f.color = 0x333333; txt = new TextField(); txt.embedFonts = true; txt.antiAliasType = AntiAliasType.ADVANCED; txt.defaultTextFormat = f; txt.selectable = false; txt.mouseEnabled = false; txt.width = dWid-6; txt.height = dHei-6; txt.wordWrap = true; txt.border = false; //txt.condenseWhite = true; // only works when setting text with txt.htmlText = “this is html text”; txt.htmlText = “Choose a topic on the right to read description”; txt.x = 3; txt.y = 3; // Appendix s = new Sprite(); s.graphics.lineStyle(1, 0x666666); s.graphics.beginFill(0xffffff, 1); s.graphics.drawRect(0,0, dWid, dHei); s.graphics.endFill(); // C_Holder2.push(txt); s.addChild(txt); s.x = -390; s.y = 30; S_Holder.addChild(s); addChild(S_Holder); S_Holder.x = 30; S_Holder.visible = false; } private function loadDesc(e:MouseEvent):void{ var newStr:String = help2[C_Holder.indexOf(e.target)]; //newStr = newStr.split(“bb”).; C_Holder2[0].text = newStr; //trace(num); } } } Appendix A14.0 Hero.as package com.Lao.tanker { // imports import flash.display.Sprite; import flash.display.MovieClip; /* import flash.display.BitmapData; import flash.display.Bitmap; */ import flash.events.Event; import flash.events.KeyboardEvent; import flash.display.Stage; import flash.ui.Keyboard; public class Hero extends MovieClip { public var C_Holder:Array = new Array(); // holds speed attack bar created from stage. // reason why spdAtkBar is not added here is becuase hero will be flipped around using move arrows // we don’t want speed bar to be fliped as well //private var hero:HeroA; // call bitmapdata from library //public var bmpHero:Bitmap; // to put hero bitmapdata into //Hero Controls private var left:Number = 37, right:Number = 39, up:Number = 38, down:Number = 40; //Hero stage boundary for a 10x5 stage private var MAX_RIGHT:int = 9; private var MAX_DOWN:int = 4; private var r_count:int = 0; private var d_count:int = 0; //Hero Stats private var speed:int = 59; // default 59 public function Hero(xPos:int, yPos:int) { /* hero = new HeroA(); bmpHero = new Bitmap(hero); bmpHero.x = xPos; bmpHero.y = yPos; addChild(bmpHero); */ this.x = xPos; this.y = yPos; Appendix // add bmpHero to be displayed in this class //stage.addEventListener(KeyboardEvent.KEY_DOWN, moveHero); //addEventListener(Event.ENTER_FRAME, moveHero); } public function moveHero(e:KeyboardEvent):Boolean{ // trace(“Hero button”); //bmpHero.x ++; var par:* = parent; if(e.keyCode == left){ if(r_count != 0){ r_count--; //bmpHero.x -= speed; //this.x -= speed; gotoAndStop(2); // switch controls on engine class par.parent.parent.startPosX = x; par.parent.parent.heroCanMove = true; par.parent.parent.goLeft = true; //scaleY *= -1; return true; } return false; } if(e.keyCode == right){ if(r_count != MAX_RIGHT){ r_count++; //bmpHero.x += speed; //this.x += speed; gotoAndStop(1); // switch controls on engine class par.parent.parent.startPosX = x; par.parent.parent.heroCanMove = true; par.parent.parent.goRight = true; return true; } return false; } if(e.keyCode == up){ if(d_count != 0){ d_count--; //bmpHero.y -= speed; //this.y -= speed; Appendix A14.1 Hero.as // switch controls on engine class par.parent.parent.startPosY = y; par.parent.parent.heroCanMove = true; par.parent.parent.goUp = true; return true; } return false; } if(e.keyCode == down){ if(d_count != MAX_DOWN){ d_count++; //bmpHero.y += speed; //this.y += speed; // switch controls on engine class par.parent.parent.startPosY = y; par.parent.parent.heroCanMove = true; par.parent.parent.goDown = true; return true; } return false; } return false; // if other non-registered keys are press return false and do nothing // trace(“”+e.keyCode); } public function updateSpdAtkBar(refreshPercent:Number){ // updates the display spdAtkBar C_Holder[0].updateBar(refreshPercent) } // removes the damage display when the hero attacks public function removeStatusWindow(dmgWindow:Sprite){ removeChild(dmgWindow); } } } Appendix Appendix A15.0 IFStart.as package com.Lao.tanker { /* this is the start menu it puts a textfield “Start” non-selectable inside a block sprite. The block is then given an addEventListener(MouseEvent.CLICK) on click the user will be able to proceed to play the game or start the game. The game logo is inserted underneath the Start Button */ //imports import flash.display.Graphics; import flash.display.Sprite; import flash.events.MouseEvent; import flash.text.TextField; import flash.text.*; import flash.display.BitmapData; // to represent logo bitmapdata import flash.display.Bitmap; // to put logo bitmapdata into in order to display the logo import flash.events.Event; public class IFStart extends Sprite{ //public var startButton:Sprite; public var C_Holder:Array = new Array(); // display objects using addChild private var C_Holder2:Array = new Array(); // non-display objects public function IFStart(xPos:int, yPos:int) { // addEventListener(Event.REMOVED, clearOutAllContents, false, 0, true); // constructor code var wid:int = 300; var hei:int = 100; var startButton:Sprite = new Sprite(); C_Holder.push(startButton); startButton.graphics.beginFill(0x666666); startButton.graphics.drawRoundRect(0,0, wid, hei, 20, 20); startButton.graphics.endFill(); var myFormat:TextFormat = new TextFormat(“Segoeb”); C_Holder2.push(myFormat); myFormat.size = 50; myFormat.color = 0xffffff; myFormat.align = “center”; var myT:TextField = new TextField(); myT.embedFonts = true; C_Holder2.push(myT); myT.defaultTextFormat = myFormat; Appendix myT.selectable = false; myT.text = “START”; myT.width = wid; myT.height = hei; myT.y = 10; startButton.addChild(myT); addChild(startButton); startButton.x = xPos-(startButton.width/2); startButton.y = yPos; // startButton.addEventListener(MouseEvent.CLICK, startGame); // display logo on start menu as well var logo:Logo = new Logo(0,0); C_Holder2.push(logo); var logoBitmap:Bitmap = new Bitmap(logo); C_Holder.push(logoBitmap); logoBitmap.x = xPos-(logoBitmap.width/2); logoBitmap.y = 200; addChild(logoBitmap); } private function clearOutAllContents(){ // remove display objects in this class for(var i:int=0; i< this.C_Holder.length; i++){ //removeChild(C_Holder[i]); C_Holder[i] = null; } C_Holder.splice(0) C_Holder = null; for(var k:int=0; k< C_Holder2.length; k++){ this.C_Holder2[k] = null; } C_Holder2.splice(0); C_Holder2 = null; //removeEventListener(Event.REMOVED, clearOutAllContents); } } } Appendix A16.0 IFStat.as package com.Lao.tanker { //imports here in this class doesn’t need to be imported in the parent class // for these imports to work, unless the parent class also creates objects // that require these imports import flash.display.Sprite; import flash.display.Shape; import flash.text.*; import flash.events.Event; import flash.display.Stage; import flash.display.Graphics; import flash.display.Bitmap; import flash.display.BitmapData; import flash.utils.Timer; import flash.events.TimerEvent; import flash.utils.getTimer; public class IFStat extends Sprite { // Holders public var C_Holder:Array = new Array(); the data as hero plays the game public var C_Holder2:Array = new Array(); ence the textField data public var C_Holder3:Array = new Array(); pement slot interface public var C_Holder4:Array = new Array(); sual shrinking bars private var valHolder:int = 0; // Parent Target References private var par; // display classes private var logo:Logo; mapData class from library private var logoBitmap:Bitmap; private var bgBdata:BgIMG; private var bgBitmap:Bitmap; /* private var statBdata:StatIMG; in library class private var statBitmap:Bitmap; bitmapdata private var stat1Bdata:Stat1IMG; in library class private var stat1Bitmap:Bitmap; bitmapdata */ // to change // to refer// hold equi// hold vi- // logo bit- // bitmapData // to hold // bitmapData // to hold Appendix private var block:Sprite; private var block1:Sprite; private var blockArr:Array = new Array(); private var attr:Array = new Array(“HEALTH”, “ENERGY”, “ATTACK”, “ATK SPD”, “GOLD”); // adding or subtracting will affect height of menu // hero stats private var maxHp:int = 50; private var hp:int = maxHp; private var maxEnergy:int = 25; private var energy:int = 0; // start with zero energy private var minAtk:int = 1; private var maxAtk:int = 3; private var def:int = 1; private var atkSpd:int = 3000; private var gold:int = 0; private var timer:Timer = new Timer(atkSpd,1); private var spdAtkBarUpdateTimer:Timer = new Timer(100); // controls the frame rate at which hero // spdAtkBar updates, 100 is decent private var startTime; // display spacing private var MAX:int = attr.length; private var wid:int = 170; private var hei:int = 23; private var lineGap:int = 25;// space between the blocks private var startX:int = 20; private var startY:int = 30; // colors private var headerColor = 0xB03535; // redTan private var subColor = 0xECF5FF; // yellowOrange 0xFDC68F private var menuBorderColor = 0x733345; // maroon private var attrColor = 0xffffff; // white private var bHei = 370; // border height // text private var attrNameTxt:TextField; // titles and sub menu titles private var formatTitle:TextFormat; // text formatter private var formatSub:TextFormat; // text formatter private var myFont:Font; // constructor code public function IFStat() { //addEventListener(Event.REMOVED, cleanOutAllCon- Appendix A16.1 IFStat.as tents, false, 0, true); // empty this class and clear upon removal addEventListener(Event.ADDED_TO_STAGE, loadIFStatAssets, false, 0, true); // true = use weak reference addEventListener(Event.REMOVED_FROM_STAGE, isRemoved, false, 0, true); } public function loadIFStatAssets(e:Event){ par = parent; // reference parent createBG(); createBlock(); // lay out the blocks for hp, atk, def, etc..’ C_Holder[0].alpha = 1;// turn this off if you want to see the number display of HP again C_Holder[1].alpha = 1;// turn this off if you want to see the number display of ENERGY again createEquipments(); // lay out equipment blocks //createBorder(); // put border around stats interface //createLogo(); // put logo below stat menu createVisualHP_ENGY_Bar(); timer.addEventListener(TimerEvent.TIMER, toggleAtkOn, false, 0, true); spdAtkBarUpdateTimer.addEventListener(TimerEvent. TIMER, updateSpdAtkBar, false, 0, true); removeEventListener(Event.ADDED_TO_STAGE, loadIFStatAssets); } private function createVisualHP_ENGY_Bar():void{ var hei:int = 10; var wid:int = 100; var i:int = 0; var xOffset:int = 90; // -----// HP Bar // ----- // small squares for(i=0; i<hei; i++){ var bgBar:Shape = new Shape(); bgBar.graphics.lineStyle(1, 0x2A2E3B); bgBar.graphics.drawRect(0,0, hei,hei); bgBar.x = xOffset+(i*hei); bgBar.y = 52; addChildAt(bgBar, 1); } // visual bar var hpBar:RectGaugeBar = new RectGaugeBar(270, Appendix 0x52C24C, hei, wid, false); // (rotate degree, bgColor, height, wid) C_Holder4.push(hpBar); hpBar.x = xOffset; hpBar.y = 62; addChildAt(hpBar, 1); // background bgBar = new Shape(); bgBar.graphics.beginFill(0x52c24c, .5); bgBar.graphics.drawRect(0,0, wid, hei); bgBar.x = xOffset; bgBar.y = 52; addChildAt(bgBar, 1); // ---------- // Energy Bar // ---------- // small squares for(i=0; i<hei; i++){ bgBar = new Shape(); bgBar.graphics.lineStyle(1, 0x2A2E3B); bgBar.graphics.drawRect(0,0, hei,hei); bgBar.x = 90+(i*hei); bgBar.y = 78; addChildAt(bgBar, 1); } // visual energy bar hpBar = new RectGaugeBar(270, 0x46ACDC, hei, wid, false);// (rotate degree, bgColor, height, wid) C_Holder4.push(hpBar); hpBar.x = 90; hpBar.y = 88; addChildAt(hpBar, 1); hpBar.updateBar(0); // cause hero starts with zero energy // background bgBar = new Shape(); bgBar.graphics.beginFill(0x46ACDC, .5); bgBar.graphics.drawRect(0,0, wid, hei); bgBar.x = 90; bgBar.y = 78; addChildAt(bgBar, 1); } private function createBlock(){ var i:int = 0; // create blocks and define colors shapes for(i=0; i<MAX; i++){ block = new Sprite(); // block.graphics.lineStyle(2, 0xFDC68F); block.graphics.drawRect(0,0, wid,hei); block.graphics.beginFill(subColor, 0); // invis for now block.graphics.drawRect(0,0, wid, hei); block.graphics.endFill(); // text inside blocks attrNameTxt = new TextField(); Appendix A16.2 IFStat.as //attrNameTxt.border = true; formatSub = new TextFormat(“Segoeb”); // set font family //myFont = new Font1(); // embedded font in library, not run-time font //formatSub.font = myFont.fontName; formatSub.size = 12; formatSub.color = 0xffffff; attrNameTxt.defaultTextFormat = formatSub; // have to use before inserting text into textfield attrNameTxt.embedFonts = true; // to display the custom font correctly //attrNameTxt.embedFonts = true; //attrNameTxt.antiAliasType = AntiAliasType.ADVANCED; attrNameTxt.height = 15; attrNameTxt.width = 80; attrNameTxt.border = false; attrNameTxt.selectable = false; switch(i){ case 0: attrNameTxt.text = attr[i]; break; case 1: attrNameTxt.text = attr[i]; //”ENERGY”; break; case 2: attrNameTxt.text = attr[i]; // “DEF”; break; case 3: attrNameTxt.text = attr[i];// “ATK”; break; case 4: attrNameTxt.text = attr[i];// “ATK”; break; } //attrNameTxt.text = “”+i; attrNameTxt.x = 5; attrNameTxt.y = 5; block.addChild(attrNameTxt); // add attribute name block.addChild(loadAttrDisplay()); // add attribute visual data display, will return a block:sprite addChild(block); blockArr.push(block); //trace(“i’m here”); } // end of for loop //position title “Stats” block Appendix block = new Sprite(); block.graphics.beginFill(headerColor, 0); block.graphics.drawRoundRect(10,10,170,20,15,15); block.graphics.endFill(); addChild(block); block = new Sprite(); block.graphics.beginFill(headerColor, 0); // invis for now block.graphics.drawRect(0,0, wid, hei-10); block.graphics.endFill(); block.x = startX; block.y = startY; attrNameTxt = new TextField(); attrNameTxt.border = false; attrNameTxt.width = 160; attrNameTxt.height = 30; formatTitle = new TextFormat(“Segoeb”); formatTitle.size = 20; formatTitle.color = 0xffffff; formatTitle.align = TextFormatAlign.LEFT; attrNameTxt.defaultTextFormat = formatTitle; attrNameTxt.embedFonts = true; attrNameTxt.selectable = false; attrNameTxt.text = “HERO STATS”; // attrNameTxt.setTextFormat(format, -1);// = format; // can only setTextFormat after text has been inserted attrNameTxt.x = 5; attrNameTxt.y = -16; block.addChild(attrNameTxt); // add text to block addChild(block); // position sub-Stats blocks for(var k:int=0; k<blockArr.length; k++){ blockArr[k].x = startX // ((wid+10)*k) + 50; blockArr[k].y = startY+13+lineGap*k; } } // attribute text fields that displays the hero stats private function loadAttrDisplay(){ var myW:int = 80; var myH:int = 15; var xOffset:int = 85; var yOffset:int = 4; block1 = new Sprite(); // block.graphics.lineStyle(2, 0xFDC68F); //block1.graphics.drawRect(0,0, myW,myH); Appendix A16.3 IFStat.as block1.graphics.beginFill(attrColor,0); // block1.graphics.drawRoundRect(0,0, myW, myH, 10, 10); block1.graphics.drawRect(0,0, myW, myH); block1.graphics.endFill(); block1.x = xOffset; block1.y = yOffset; var tf:TextFormat = new TextFormat(“Segoe”); tf.size = 12; tf.color = 0xffffff; attrNameTxt = new TextField(); attrNameTxt.defaultTextFormat = tf; attrNameTxt.embedFonts = true; attrNameTxt.width = 80; attrNameTxt.height = 15; attrNameTxt.border = false; attrNameTxt.selectable = false; attrNameTxt.text = “Not Set”; attrNameTxt.x = 5; C_Holder.push(attrNameTxt); block1.addChild(attrNameTxt); return block1; } private function createEquipments(){ var equipBox:IfStatEquip = new IfStatEquip(); addChild(equipBox); C_Holder3.push(equipBox); //trace(C_Holder3[0].x); equipBox.x = 40; equipBox.y = 200; equipBox = null; } private function createBorder(){ // create border around left side menu block = new Sprite(); block.graphics.lineStyle(1, menuBorderColor); block.graphics.drawRoundRect(10,10,170,bHei,15,15); // *MAX addChild(block); //trace(“IFStat border loaded”); } private function createBG():void{ bgBdata = new BgIMG(0,0); bgBitmap = new Bitmap(bgBdata); bgBitmap.x = -20; bgBitmap.y = -25; addChild(bgBitmap); /* statBdata = new StatIMG(0,0); Appendix statBitmap = new Bitmap(statBdata); statBitmap.x = 0; statBitmap.y = 0; addChild(statBitmap); stat1Bdata = new Stat1IMG(0,0); //C_Holder4.push(bgBdata); stat1Bitmap = new Bitmap(stat1Bdata); stat1Bitmap.x = 3; stat1Bitmap.y = 180; addChild(stat1Bitmap); */ } private function createLogo(){ logo = new Logo(0,0); C_Holder2.push(logo); logoBitmap = new Bitmap(logo) C_Holder2.push(logoBitmap); logoBitmap.x = 0; logoBitmap.y = 300; addChild(logoBitmap); } // setters - exact set // ------------------------------------------- public function setHP(num:int){ maxHp = num; hp = num; C_ Holder[0].text = hp; } // HP public function setEnergy(num:int){ energy = num; C_Holder[1].text = energy; }// Energy public function setAtk(min:int, max:int){ minAtk = min; maxAtk = max; C_Holder[2].text = “”+minAtk + “ - “ + maxAtk; }// atk public function setAtkSpd(num:int){ atkSpd = num; C_Holder[3].text = atkSpd; } public function setDef(num:int){def = num; C_Holder[3]. text = def;} // Def public function setGold(num:int){ gold = num; C_Holder[4]. text = gold; } // Gold public function checkEnergy():int{ return energy; } public function checkHP():int{ return hp; } // setters - modifiers // ---------------------------------------- public function changeHP(num:int){ hp += num; if(hp <=0) hp = 0;// can’t be negative C_Holder[0].text = hp; Appendix A16.4 IFStat.as // update visual hp bar C_Holder4[0].updateBar( hp/maxHp ); } public function changeEnergy(num:int){ // taking damage or gaining damage energy += num; if(energy <=0){ energy = 0; // can’t be negative } if(energy > maxEnergy){ energy = maxEnergy; // can’t go above maxEnergy } C_Holder[1].text = energy; // update visual energy bar C_Holder4[1].updateBar( energy/maxEnergy ); } public function changeGold(num:int){ // taking damage or gaining damage gold += num; C_Holder[4].text = gold; } public function changeAtkSpd(num:int){ atkSpd += num; C_Holder[3].text = atkSpd; } // When Hero Attack Functions // --------------------------------------- public function getAtkSpd(){ return atkSpd; } public function getHeroAtk():int{ atk_is_ready = false; // hero can no longer attack until ready again // start attack delay timer timer.delay = atkSpd; timer.start(); // start the spdAtk bar timer spdAtkBarUpdateTimer.start(); startTime = getTimer(); //return Math.floor(Math.random()* (maxAtk-minAtk) ) + minAtk; // normal random var atkNum = Math.floor(Math.random()* ( (maxAtk+1)minAtk ) ) + (minAtk); // +1 so if atk range is 12-15, 15 can be generated Appendix return atkNum; } private var atk_is_ready = true; // starts hero with allow to attack public function checkHeroAtkStatus(){// called from main engine return atk_is_ready; } private function toggleAtkOn(e:TimerEvent){ atk_is_ready = true; timer.reset(); //timer.removeEventListener(TimerEvent.Timer, toggleAtkOn); //timer = null; } private function updateSpdAtkBar(e:TimerEvent){ // update the spd display bar on hero //par.parent.C_Holder[0].updateBar(); if(atk_is_ready == false){ var newTime = getTimer(); var curTime = newTime - startTime; newTime = null; par.parent.C_Interface[1].C_Holder3[0]. updateSpdAtkBar(curTime/atkSpd); curTime = null; //trace(par.parent.C_Interface[1].C_Holder3[0]); }else{ spdAtkBarUpdateTimer.reset(); par.parent.C_Interface[1].C_Holder3[0].updateSpdAtkBar(1) // fill up the spdAtkBar to full } } // ifStatEquip.as calls this function when user tries to equip an empty slot, goes to default barehands public function useBareHands(){ setAtk(1,2); setAtkSpd(800); } private function isRemoved(e:Event){ timer.removeEventListener(TimerEvent.TIMER, toggleAtkOn); spdAtkBarUpdateTimer. removeEventListener(TimerEvent.TIMER, updateSpdAtkBar); removeEventListener(Event.REMOVED_FROM_STAGE, isRemoved); } Appendix A16.5 IFStat.as // For Garbage Collection purposes clear out all variables public function cleanOutAllContents(){ var i:int = 0; for(i=0; i<C_Holder.length; i++){ C_Holder[i] = null; } C_Holder.splice(0); C_Holder = null; // other array ref for(i=0; i<blockArr.length; i++){ blockArr[i] = null; } blockArr.splice(0); blockArr = null; for(i=0; i<attr.length; i++){ attr[i] = null; } attr.splice(0); attr = null; for(i=0; i<C_Holder2.length; i++){ C_Holder2[i] = null; } C_Holder2.splice(0); C_Holder2 = null; removeChild(C_Holder3[0]); for(i=0; i<C_Holder3.length; i++){ C_Holder3[i] = null; } C_Holder3.splice(0); C_Holder3 = null; } } } Appendix Appendix A17.0 IfStatEquip.as package com.Lao.tanker { /* This class gets called from IFStat.as to be placed inside of it This class are the equipment/item slots below the hero stats */ import import import import import import flash.display.Sprite; flash.display.Graphics; flash.events.Event; flash.text.TextField; flash.text.TextFormat; flash.display.Shape; public class IfStatEquip extends Sprite{ private var C_Holder:Array = new Array(); // holds slot boxes private var C_Holder2:Array = new Array(); // holds items dropped and items picked up private var C_Holder3:Array = new Array(); // holds text display items - reads item private var availableSlots:Array = new Array(); private var occupySlots:Array = new Array(); // display var //private var mColor = 0x00033f; // dark blue //private var mColor2 = 0xffffff; // white //private var mColor3 = 0xff99ff; private var selectC = 0xECF5FF; // lightGreen 33CCFF private var equipC = 0x00033f; // blue 0x00033f private var unSelectC = 0xD6D6D6; // grey 0xD6D6D6 private var selectBorderC = 0xffffff; // 0x777777 private var selectBorderThick = 2; private var wid:int = 42; private var hei:int = 42; private var corner:int = 10; private var bC = 0x000000; private var bThick = 1; // layout - how the slots will be layed out private var MAX_SLOTS:int = 6; private var MAX_SLOTS_PER_LINE:int = 3; private var limitReachCounter:int = 0; private var xReset:int = 0; private var COL_GAP:int = 10; private var ROW_GAP:int = 10; //interactive slot selection var private var counter:int = 0; private var equip:int = 0; Appendix public function IfStatEquip() { addEventListener(Event.REMOVED, cleanOutAllContents, false, 0, true); // if this class if removed, clear it’s contents // text box createTextBox(); // will display item names // constructor code for(var i:int=0;i<MAX_SLOTS;i++){ createSlot(i);// pass the count } for(var j:int=0; j<C_Holder.length; j++){ // extract all slots availableSlots.push(j); // populate available slots, like powerball } // then go back and set the first slot to be highlighted //C_Holder[0].alpha = transE; markSlotAsEquip(0); } private function createTextBox(){ var s:Shape = new Shape(); s.graphics.beginFill(0xECF5FF, 0); // light blue s.graphics.drawRect(0,0,169,95); s.graphics.endFill(); addChild(s); s.graphics.beginFill(0xECF5FF,0); // light blue s.graphics.drawRoundRect(0,0,169,95,15,15); s.graphics.endFill(); addChild(s); s.y = 100; s.x = -10; var txt:TextField = new TextField(); var f:TextFormat = new TextFormat(“Segoeb”); f.size = 12; f.color = 0xffffff; txt.defaultTextFormat = f; txt.embedFonts = true; txt.width = 150; txt.height = 15; txt.border = false; txt.selectable = false; txt.text = “No Item Selected”; C_Holder3.push(txt); addChild(txt); txt.x = -10; Appendix A17.1 IfStatEquip.as txt.y = 95; // box 2 for item description -- is turned off for now, alpha 0 txt = new TextField(); f = new TextFormat(“Segoe”); f.size = 10; f.color = 0xffffff; txt.embedFonts = true; txt.defaultTextFormat = f; txt.border = false; txt.selectable = false; txt.width = 150; txt.height = 50; txt.text = “Item Description”; txt.wordWrap = true; txt.alpha = 0; addChild(txt); C_Holder3.push(txt); txt.y = 105; // box 2 for item description txt = new TextField(); txt.embedFonts = true; f.size = 9; f.leading = 2; txt.defaultTextFormat = f; txt.border = false; txt.selectable = false; txt.width = 200; txt.height = 100; txt.text = “Attributes”; txt.wordWrap = true; txt.x = -10; addChild(txt); C_Holder3.push(txt); txt.y = C_Holder3[1].y + 15; txt = null; f = null; } private function createSlot(slotCount:int){ if( (slotCount % MAX_SLOTS_PER_LINE) == 0 && slotCount != 0){ // detect whenever the limit tile is reach limitReachCounter ++; // counts every time the limit is reach xReset = 0; // reset the x offset so tiles get lay down on most left again } var block:Sprite = new Sprite(); block.graphics.beginFill(unSelectC); block.graphics.drawRoundRect(0,0,wid,hei,corner,cor ner); Appendix C_Holder.push(block); addChild(block); block.x = ((wid+COL_GAP)*xReset); block.y = ((hei+ROW_GAP) * limitReachCounter ); block = null; // GC xReset ++; // xReset is like the counter so each loop gives the counter ++ } // used when this class is removed private function cleanOutAllContents(e:Event){ for(var i:int=0;i<C_Holder.length;i++){ C_Holder[i] = null; }C_Holder = null; removeEventListener(Event.REMOVED, cleanOutAllContents); } // change slot public function changeSlot(){ counter++; // reset counter so if counter is at 6 or MAX_ SlotS, make it 0 if(counter >= MAX_SLOTS){ counter = 0; } // read selected item if there’s anything under selection updateItemName(); // put all other slots into unselected mode for(var k:int=0;k<C_Holder.length;k++){ if(k != equip){ C_Holder[k].graphics.clear(); C_Holder[k].graphics. beginFill(unSelectC); C_Holder[k].graphics.drawRoundRect(0 ,0,wid,hei,corner,corner); //C_Holder[k].alpha = trans; } } // highlight selected slot if(counter == equip){ C_Holder[counter].graphics.clear(); C_Holder[counter].graphics. lineStyle(2,unSelectC,1, true); C_Holder[counter].graphics.drawRoundRect(0, 0,wid,hei,corner,corner); Appendix A17.2 IfStatEquip.as C_Holder[counter].graphics. beginFill(selectC); C_Holder[counter].graphics.drawRoundRect(0, 0,wid,hei,corner,corner); C_Holder[counter].graphics.endFill(); }else if(counter != equip){ // put equip slot back to normal C_Holder[equip].graphics.clear(); C_Holder[equip].graphics. lineStyle(2,equipC, 1, true); //var k:Sprite = newSprite(); //k.graphics.lineStyle(1, 0x000000, 1, false, “normal”, null, null, 1); C_Holder[equip].graphics.drawRoundRect(0,0, wid,hei,corner,corner); C_Holder[equip].graphics. beginFill(selectC); C_Holder[equip].graphics.drawRoundRect(0,0, wid,hei,corner,corner); C_Holder[equip].graphics.endFill(); // change next selected slot C_Holder[counter].graphics.clear(); C_Holder[counter].graphics. beginFill(unSelectC); C_Holder[counter].graphics.drawRoundRect(0, 0,wid,hei,corner,corner); C_Holder[counter].graphics.endFill(); C_Holder[counter].graphics.lineStyle(select BorderThick,selectBorderC, 1, true); C_Holder[counter].graphics.drawRoundRect(0, 0,wid,hei,corner,corner); } } // update textField to display item info upon selection change private function updateItemName(){ var par:* = parent; if(C_Holder2.length != 0){ // if not empty //trace(C_Holder2[counter]); if(C_Holder2[counter] is IItem){ C_Holder3[0].text = C_ Holder2[counter].getName(); C_Holder3[1].text = C_ Holder2[counter].getDesc(); C_Holder3[2].text = C_ Holder2[counter].getDesc2(); }else{ C_Holder3[0].text = “No Item Selected”; C_Holder3[1].text = “Item Descrip- Appendix tion”; C_Holder3[2].text = “Attributes”; } }else{ C_Holder3[0].text = “No Item Selected”; C_Holder3[1].text = “Item Description”; C_Holder3[2].text = “Attributes”; } } // display previous selected slot as un-equipped // then display selected slot as an equipped slot public function equipItem():void{ // change previous equipped slot back to unequip display status // currently only 1 item can be equipped at a time C_Holder[equip].graphics.clear(); C_Holder[equip].graphics.beginFill(unSelectC); C_Holder[equip].graphics.drawRoundRect(0,0,wid,hei, corner,corner); C_Holder[equip].graphics.endFill(); // target the new selected slot and prepare it to be equipped equip = counter; // display selected slot as equipped C_Holder[equip].graphics.clear(); C_Holder[equip].graphics.lineStyle(2,equipC); C_Holder[equip].graphics.drawRoundRect(0,0,wid,hei, corner,corner); C_Holder[equip].graphics.beginFill(selectC); C_Holder[equip].graphics.drawRoundRect(0,0,wid,hei, corner,corner); C_Holder[equip].graphics.endFill(); /* C_Holder[counter].graphics.lineStyle(2,equipC); C_Holder[counter].graphics.drawRoundRect(0,0,wid,he i,corner,corner); C_Holder[counter].graphics.beginFill(selectC); C_Holder[counter].graphics.drawRoundRect(0,0,wid,he i,corner,corner); C_Holder[counter].graphics.endFill(); */ // transfer this item’s stats to hero’s stats for equipping this item or using it var par:* = parent; if(C_Holder2.length != 0){ // if not empty if(C_Holder2[equip] is IWeapon){ par.setAtk( C_Holder2[equip].getMinAtk(), C_Holder2[equip].getMaxAtk()); Appendix A17.3 IfStatEquip.as par.setAtkSpd( C_Holder2[equip].getAtkSpd() ); }else{ //do nothing par.useBareHands(); // if no items unser selection go back to bare hands //setAtk(1,3); } }else{ par.useBareHands(); //setAtk(1,3); } } private function markSlotAsEquip(slotNum:int){ C_Holder[slotNum].graphics.clear(); C_Holder[slotNum].graphics.lineStyle(2,unSelectC, 1, true); C_Holder[slotNum].graphics.drawRoundRect(0,0,wid,he i,corner,corner); //fill C_Holder[slotNum].graphics.beginFill(selectC); C_Holder[slotNum].graphics.drawRoundRect(0,0,wid,he i,corner,corner); C_Holder[slotNum].graphics.endFill(); } // add item to open slots from left to right when enemy drops item, // else if slots full, queue item for a certain time period before deposing it public function addItem(item:IItem):void{ if(availableSlots.length != 0){ // if there is an open slots //pop an open slot var openSlot = availableSlots[0]; // store open slot occupySlots.push( availableSlots. splice(0,1)); // use up slot and make open slot now occupy //addChild(DisplayObject(item); //Sprite(item).x = 10; Sprite(item).y = 10; // need to cast sprite in order to target item C_Holder[openSlot].addChild(item); C_Holder2.push(item); // push item into holder 2 // we may not have to cast Sprite when using addChild by doing Sprite(item) // although item is implementing from Weapon Interface: IWeapon // sometimes we need to have Appendix cast Sprite to display the object using addChild // sometimes you may not have to cast MovieClip, Bitmap, depending on what object it is // when implementing an object is an interface openSlot = null; //read item name when item is put into sack updateItemName() } } } } Appendix A18.0 IFTopMenu.as package com.Lao.tanker { import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFormat; public class IFTopMenu extends Sprite{ public var C_Holder:Array = new Array(); public function IFTopMenu() { createWorldName(); createTimeClock(); createHelpMenu(); } // ----------------- // CREATE // ----------------- private function createWorldName():void{ var f:TextFormat = new TextFormat(“Segoeb”); var txt:TextField = new TextField(); f.size = 16; f.color = 0xffffff; txt.defaultTextFormat = f; txt.embedFonts = true; txt.width = 140; txt.height = 20; txt.border = false; txt.text = “No Name”; txt.selectable = true; addChild(txt); C_Holder.push(txt); } private function createTimeClock():void{ var clock:Clock2 = new Clock2(5,50,30, 6, true); // (hr, min, gameframerate, startDay betwen 0-6, random a startDay?); addChild(clock); clock.x = 100; C_Holder.push(clock); } private function createHelpMenu():void{ var menuList:HelpMenu = new HelpMenu(); menuList.x = 350; addChild(menuList); C_Holder.push(menuList); } public function cleanOutAllContents():void{ for(var i:int=0;i<C_Holder.length; i++){ } } } } Appendix removeChild(C_Holder[i]); C_Holder.splice(0); Appendix A19.0 IItem.as package com.Lao.tanker { // Interfaces that extends this interface // IWeapon, ISupply, IArmor public interface IItem { // you don’t define public, private, protected // but classes must implement these functions as public only function getName():String; function getDesc():String; function setGold(g:int):void; function drawLetter(n:String):void // weapon: lvl 0,1,2,3,R // Craft: LQ, MQ, HQ // Potion: S, M, L //function getDesc2():String; } } Appendix Appendix A20.0 IMonster.as package com.Lao.tanker { /* Interface Class * You have to list all public methods that will be common for the classes that implements this interface; * You do so by writing the definition of the function, its name, its parameters and its return type; * You don’t have to open and close curly braces after the method definition * You don’t specify if the method is private, public or protected (that’s kind of obvious but I did that mistake) * But any class that use this interface must implement the functions as “PUBLIC” only, not private * interface can only extend other interfaces * a class can implement more than one interface An interface is for the purpose of polymorphism, so that a var interface can hold an object of that interface Also an interface helps all your classes that implements an interface, keep a structure or else an error will generate var m:FruitInterface = new Orange(); var m:FruitInterface = new Apple(); function getCalorie(fruit:FruitInterface); // it can accept can fruit as a parameter */ import flash.display.Sprite; import flash.events.Event; public interface IMonster { // you don’t define public, private, protected, but these functions below should only be used in class // as public //function takeHit(heroAtkDmg:int, enemyID:int); function getGold():int; function dropItem():IItem; function setDropPercent(num:Number):void; function animate(); } } Appendix Appendix A21.0 IStage.as package com.Lao.tanker { /* Interface Class * You have to list all public methods that will be common for the classes that implements this interface; * You do so by writing the definition of the function, its name, its parameters and its return type; * You don’t have to open and close curly braces after the method definition * You don’t specify if the method is private, public or protected (that’s kind of obvious but I did that mistake) * interface can only extend other interfaces * a class can implement more than one interface An interface is for the purpose of polymorphism, so that a var interface can hold an object of that interface Also an interface helps all your classes that implements an interface, keep a structure or else an error will generate var m:FruitInterface = new Orange(); var m:FruitInterface = new Apple(); function getCalorie(fruit:FruitInterface); // it can accept can fruit as a parameter */ public interface IStage { // you don’t define public, private, protected //function createTopBanner(); //function createTile(tileCount:int):void; } } Appendix Appendix A22.0 IWeapon.as package com.Lao.tanker { /* Interface Class * You have to list all public methods that will be common for the classes that implements this interface; * You do so by writing the definition of the function, its name, its parameters and its return type; * You don’t have to open and close curly braces after the method definition * You don’t specify if the method is private, public or protected (that’s kind of obvious but I did that mistake) * interface can only extend other interfaces * a class can implement more than one interface An interface is for the purpose of polymorphism, so that a var interface can hold an object of that interface Also an interface helps all your classes that implements an interface, keep a structure or else an error will generate var m:FruitInterface = new Orange(); var m:FruitInterface = new Apple(); function getCalorie(fruit:FruitInterface); // it can accept can fruit as a parameter */ public interface IWeapon extends IItem { // you don’t define public, private, protected function setAtk(min:int,max:int):void; function getMinAtk():int; function getMaxAtk():int; //function setGold():void; } } Appendix Appendix A23.0 Monster.as package com.Lao.tanker { import flash.events.Event; import flash.display.MovieClip; import flash.display.Sprite; import com.Lao.tanker.weapon.*; import flash.utils.Timer; import flash.events.TimerEvent; import flash.utils.getTimer; public class Monster extends MovieClip implements IMonster{ // array holder public var C_Holder:Array = new Array(); // holds hp bar and spdAtkBar public var C_Holder2:Array = new Array(); // holds the pop-up window displaying attack dmg public var hitBox:Sprite; // attributes private var maxHp:int = 0; private var hp:int = 0; private var gold:int = 0; // attacks private var atkSpd:int = 3000; // default value private var minAtk:int = 1; // default value private var maxAtk:int = 1; // default value // drops private var itemDropPercent:Number = 0.0; // item drop percentage // targets //private var par:* = parent; // target parent variable private var par; private var stageLvl; private var I_stat; // stat interface private var I_stat_slot; // slot interface private var timer:Timer; private var spdTimer:Timer; private var startTime; public function Monster(health:int, minG:int, maxG:int, atkS:int, minA:int, maxA:int, dropPer:Number) { addEventListener(Event.ADDED_TO_STAGE, build); addEventListener(Event.REMOVED_FROM_STAGE, isRemoved); //addEventListener(Event.ENTER_FRAME, updateSpdAtkBar, false, 0, true); maxHp = health; hp = maxHp; // hp gold = Math.floor(Math.random()* (maxG-minG) ) + minG; // gold Appendix atkSpd = atkS; minAtk = minA; maxAtk = maxA; itemDropPercent = dropPer; // create health bar createHPBar(); // create atkSpd bar createSpdAtkBar(); // create hitBox so hero can hit this enemey createHitBox(); // create timer for attacking hero timer = new Timer(atkSpd,1); // atks hero according to speed timer.addEventListener(TimerEvent.TIMER, atkHero, false, 0, true); spdTimer = new Timer(100); // updates the spdBar display every 100 miliseconds spdTimer.addEventListener(TimerEvent.TIMER, updateSpdAtkBar); } private function build(e:Event){ par = parent; // target parent variable stageLvl = par; I_stat = par.parent.parent.C_Interface[0]; I_stat_slot = par.parent.parent.C_Interface[0].C_ Holder3[0]; gotoAndStop(1); // start all monster in frame 1 state removeEventListener(Event.ADDED_TO_STAGE, build); } private function isRemoved(e:Event){ timer.removeEventListener(TimerEvent.TIMER, atkHero); spdTimer.removeEventListener(TimerEvent.TIMER, updateSpdAtkBar); removeEventListener(Event.REMOVED_FROM_STAGE, isRemoved); } // life bar public function createHPBar(){ // add life bar display var lifeBar:RectGaugeBar = new RectGaugeBar(180, 0x00ff00,4, 40, true);// lifebar rotation C_Holder.push(lifeBar); lifeBar.alpha = 0; Appendix A23.1 Monster.as lifeBar.x = 44; lifeBar.y = 35; addChild(lifeBar); lifeBar = null; } public function createSpdAtkBar(){ var spBar:RectGaugeBar = new RectGaugeBar(180, 0x99CCFF, 3, 40, true); // lifebar rotation C_Holder.push(spBar); spBar.alpha = 0; spBar.x = 39; spBar.y = 35; addChild(spBar); spBar = null; } private function createHitBox(){ hitBox = new Sprite(); hitBox.graphics.beginFill(0x00ff22, 0); hitBox.graphics.drawRect(0,0,30,30); hitBox.graphics.endFill(); addChild(hitBox); } private function updateSpdAtkBar(e:TimerEvent){ var newTime = getTimer(); var cur = newTime - startTime; newTime = null; C_Holder[1].updateBar(Math.floor((cur/atkSpd)*100)/100 ); //trace(time); } // TakeHite private var atkInitiated = false; // (dmg from hero, enemy’s id so it can be removed from parent stage1) public function takeHit(heroAtkDmg:int){ // start monster timer so monster can start attacking hero timer.start(); spdTimer.start(); toggleDisplay(1); // turn on visibility for the hp and spdAtk bar if(!atkInitiated){ // only get startTime once if enemy hasn’t started attacking yet startTime = getTimer(); atkInitiated = true; } hp -= heroAtkDmg; Appendix C_Holder[0].updateBar(hp/maxHp); // update lifebar if(hp <=0){ // check if enemy is dead //var par:* = parent; //par.parent.parent.C_Interface[0].changeGold( getGold() ); // reward gold //par.parent.parent.C_Interface[0].C_Holder3[0].addItem( dropItem() ); // reward item //par.removeEnemy(enemyID); // call stage1 to remove this enemey because it is a child of stage1 I_stat.changeGold( getGold() ); // reward gold if( itemDrop() ){ // check if monster dropped any item when killed I_stat_slot.addItem( dropItem() ); // then return a randomed dropped item } //par.removeEnemy(enemyID); // call stage1 to remove this enemey because it is a child of stage1 par.removeEnemy(this);// call stage1 to remove this enemey because it is a child of stage1 } } private function toggleDisplay(alphaNum:Number){ C_Holder[0].alpha = alphaNum; C_Holder[1].alpha = alphaNum; } public function getGold():int{ return gold; } // percent that this mob will drop an item when killed protected function itemDrop():Boolean{ var randN:Number = Math.round(Math.random()*100)/100; if( randN <= itemDropPercent){ return true; } return false; } // drop item - many monsters will override this method public function dropItem():IItem{ var rand:Number = Math.floor(Math.random()*10); if( rand > 5){ return new W0001(2); // drop a bone club }else if(rand > 5){ return new W0001(1); }else{ return new W0001(0); } Appendix A23.2 Monster.as } // modify drop percent public function setDropPercent(num:Number):void{ itemDropPercent = num; } // movement - not in use at the moment public function animate(){ /* if(currentFrame == 1) gotoAndStop(2); else if(currentFrame == 2) gotoAndStop(1); */ } private function atkHero(e:TimerEvent){ var par = parent; if( par.parent.parent.game_is_ready){// if main engine is ready startTime = getTimer(); // generate monster’s attack, the minAtk # and maxAtk # is a possibile random in this formula below var randAtk = Math.floor(Math.random()* ( (maxAtk+1)-minAtk ) ) + (minAtk) I_stat.changeHP( randAtk * -1); // send data to stat interface and update gotoAndPlay(“atk”); // display atk dmg - calls parent or the stage level’s function to display dmg atk par.displayAtkDmg(this.x, this.y, String(randAtk)); // this below will determine if monster should keep attacking hero or not canAtkHero(); }else{ // end of game_is_ready - reset the timers so the monsters stop attacking if they are already timer.reset(); spdTimer.reset(); atkInitiated = false; toggleDisplay(0); }// end of game_is_ready else } private function canAtkHero(){ if(par.heroIsStillHere() ){ // call stage to see if hero is still next to recent attacked enemy ever go up to infinite can keep attacking }else{ ible } } } } Appendix timer.reset();// reset timer so it doesn’t timer.start();// start timer so monster spdTimer.reset(); spdTimer.start(); timer.reset(); spdTimer.reset(); atkInitiated = false; toggleDisplay(0); // make window invis- Appendix A24.0 RectGaugeBar.as package com.Lao.tanker { public class RectGaugeBar extends GaugeBar { public function RectGaugeBar(rotateDegree:int, colr:uint, wid:int, hei:int, border:Boolean) { super(rotateDegree, colr, wid, hei, border); } } } Appendix Appendix A25.0 Stage1.as package com.Lao.tanker { import flash.display.MovieClip; import flash.display.Sprite; import flash.display.Graphics; import flash.display.MovieClip; import flash.text.TextField; import flash.events.Event; import com.Lao.tanker.enemy.*; public class Stage1 extends Sprite implements IStage{ // Floor Tile private var dataTile:Tile; // Array Reference Holder public var C_Holder:Array = new Array(); // floor tile public var C_Holder2:Array = new Array(); // data tile public var C_Holder3:Array = new Array(); // enemies and hero public var C_Holder4:Array = new Array(); // atk dmg display - holds all the displays so it can be reuse public var C_Holder5:Array = new Array(); private var availableTiles:Array = new Array(); // stagename private var worldName:String = “WORLD 1”; // Hero Variables private var hero:Hero; //Enemy variables private var MAX_ENEMY:int = 6; private var randomNum:int = 0; // hold random generator private var tilePick:int = 0; private var xPos:Number; // temp x position holder private var yPos:Number; // temp y posistion holder // Loop variables private var i:int=0; // Floor tile layout control var private var tile:Sprite; private var MAX_TILES:int = 50; private var MAX_TILE_PER_LINE:int = 10; private var limitReachCounter:int = 0; // Individual tile appearence Appendix private var tColor = 0x733345; private var tBorderThickness = 1; private var tRoundness = 15; // Individual tile demensions and spacing private var wid:int = 50; private var hei:int = 50; private var COL_GAP:int = 9; // column gap between each block left and right side private var ROW_GAP:int = 9; // gap between rows - above and below each tile private var xReset:int = 0; // reset all new tile’s x pos at the begining of each new row private var xOffset:int = 140; // each tile starts with this x offset so it doesn’t overlap any menus private var yOffset:int = 45;// each tile starts with this x offset so it doesn’t overlap any menus // Stage main border attribute private var border_X_offset:int = 180; private var bLineThickness:int = 1; private var bColor = 0x733345; // border color private var bWid:Number = 600; private var bHei:Number = 370; private var bRoundCorner:Number = 15; public function Stage1() { //addEventListener(Event.REMOVED, cleanOutAllContents, false, 0, true); // create top banner //createTopBanner(); // create floor tiles for(i=0; i<MAX_TILES; i++){ createTile(i); } // create stage border for tiles //createBorder(); // populate level with stuff (enemies, items, etc) createEnemies(); // load hero createHero(); // create atk dmg display (not only atk but other status upon attack) // these are pre-made windows to display atk dmg, they will be hidden offstage when not in use createAtkDmgDisplays(8); // pass the Appendix A25.1 Stage1.as amount of max windows you would like to create // 5-8 is usually a good number } private function createTopBanner(){ tile = new Sprite(); tile.graphics.beginFill(tColor); tile.graphics.drawRoundRect(10,10,bWid, 20, bRoundCorner, bRoundCorner); tile.graphics.endFill(); addChild(tile); tile.x = border_X_offset; // fix block tile = new Sprite(); tile.graphics.beginFill(tColor); tile.graphics.drawRect(10,18,bWid, 20); tile.graphics.endFill(); addChild(tile); tile.x = border_X_offset; tile = null; } private function createTile(tileCount:int):void{ if( (tileCount % MAX_TILE_PER_LINE) == 0 && tileCount != 0){ // detect whenever the limit tile is reach limitReachCounter ++; // counts every time the limit is reach xReset = 0; // reset the x offset so tiles get lay down on most left again } tile = new Sprite(); xReset ++; //tile.graphics.beginFill(0x987878); //tile.graphics.drawRoundRect(10,10,wid,hei,15,15); //tile.graphics.endFill(); //tile.graphics.lineStyle(tBorderThickness, tColor); //tile.graphics.drawRoundRect(0,0,wid,hei,tRoundnes s,tRoundness); // data tile dataTile = new Tile(1); // create a new data tile, these tiles have values and info in them C_Holder.push(dataTile); // Main array holder for this class tile.addChild(dataTile); // for each tile created, nest a new data tile inside each tile C_Holder2.push(tile); Appendix addChild(tile); // add tile to class to be diplay tile.x = xOffset + ((wid+COL_GAP)*xReset); tile.y = yOffset + ((hei+ROW_GAP) * limitReachCounter ) ; tile = null; } private function createBorder(){ tile = new Sprite(); tile.graphics.lineStyle(bLineThickness, bColor); tile.graphics.drawRoundRect(10,10,bWid,bHei,bRoundC orner,bRoundCorner); addChild(tile); tile.x = border_X_offset; } private function createEnemies(){ // POWERBALL PICK METHOD // -------------------------- // // Enemies - populate each enemy onto each floor tiles, two enemies can’t be on same floor tile // -------------------------- // // extract all floor tiles on this stage into a new array // then like the powerball game, randomly select each tile once // to hold an enemy or item for(i=0; i<C_Holder2.length; i++){ // extract all stage tiles availableTiles.push(i); // into array } // this next line is important, it takes out the first tile as a possibility when randomming tiles // to prevent enemy from spawning on the first tile where hero is also on availableTiles.splice(0,1); // set so one tutorial monster is created var enemyTutorialCount:int = 0; //populate enemey onto stage layout for(i=0; i<MAX_ENEMY; i++){ // the percentage of what enemies get spawn // you look at 100% bar and 2 levels deep // each monster has a % of being spawn // var e1; // method 1 for spawning enemies Appendix A25.2 Stage1.as var randNum = Math.floor(Math.random()*10); // turn random spawn off for not if(randNum < 8){ if(enemyTutorialCount==0){ e1 = new M0001(i); //80% of being spawn }else{ e1 = new M0002(i); // dull rabbit } enemyTutorialCount++; }else if(randNum < 9){ e1 = new M0002(i); }else{ e1 = new M0003(i); // 20% of being spawn } // method 2 for spawning enemies /* if( Math.floor(Math.random()*2) == 0){ e1 = new Rabbit(i); // availableTiles[randomTile] }else{ e1 = new Turtle(i); } */ addChild(e1); // add enemy to this class, not the tankerWorld C_Holder3.push(e1); // Put each enemy on random tiles // pick one random number from the array randomNum = Math.floor(Math.random() * availableTiles.length ); // note: if array length is 50, you can’t get random # 50, random max would be 49 tilePick = availableTiles[randomNum]; availableTiles.splice(randomNum,1); // take out each tile number as it gets selected //position enemies xPos = C_Holder2[tilePick].x;// store x pos yPos = C_Holder2[tilePick].y;// store y pos Appendix e1.x = xPos+10; e1.y = yPos+10; } // end of for loop } // end of createEnemies // create hero and spdAtkBar private function createHero(){ hero = new Hero(200,61); addChild(hero); // add hero to the world C_Holder3.splice(0,0,hero); // (start at index, remove amount, insert object) // create spdBar gauge bar attach it inside hero var spBar:RectGaugeBar = new RectGaugeBar(180, 0x99CCFF, 3, 40, true); // lifebar rotation hero.C_Holder.push(spBar); spBar.x = 3; spBar.y = 30; hero.addChild(spBar); spBar = null; } public function detectEnergyCost():int{ for (var n:int=0; n < C_Holder.length; n++) { if (C_Holder[n].hitTestObject(C_Holder3[0]) ){ // tile against hero object //if (C_Holder[i].hitTestPoint(C_ Holder3[0].x,C_Holder3[0].y, true)){ // tile against hero point return C_Holder[n].getVal(); // energy value } } // end of hit test for loop return 0; } public function detectBoxID():int{ for (i=0; i < C_Holder.length; i++) { //if (C_Interface[2].C_Holder[i]. hitTestPoint(hero.x, hero.y)){ if (C_Holder[i].hitTestPoint(C_ Holder3[0].x,C_Holder3[0].y, true)){ // tile agains hero point return i; // box value } } // end of hit test for loop return 0; Appendix A25.3 Stage1.as } // makes hero atk enmey or pick up items if there’s item public function checkHeroCollision(){// is only checked when action button is pressed // run through enemy and item array to see if hero collided with anything for (i=1; i < C_Holder3.length; i++) { if ( C_Holder3[i].hitBox.hitTestObject(C_ Holder3[0]) ){// check for collision with enemies // C_Holder3[0] is hero reference, [1] and up are enemies and items var par:* = parent; // target parent //1. if collision, what type is the collision? enemy or item? if( C_Holder3[i] is IMonster){ par.parent. summonTutorial(“Attack”); // Get Hero AtkDmg and store it C_Holder3[0]. gotoAndPlay(“attack”); var heroAtk:int = par. parent.C_Interface[0].getHeroAtk(); // DISPLAY ATK DMG // important - display atk dmg before you call the takeHit // because if enemy is remove, enemy array decrease will // cause in targeting wrong enemy x,y coordinate // display atk dmg done by hero, pass in monster’s x and y coord and hero atk displayAtkDmg( C_ Holder3[i].x + 20, C_Holder3[i].y, String(heroAtk) ); C_Holder3[i].takeHit( heroAtk ); // enemy take hit }else if(C_Holder3[i] is IItem){ trace(“item interface found”); } Appendix } // end if hittest } // end for loop //return null; } public function heroIsStillHere():Boolean{ // monster who just got attack calls this each time after it attacks to see if they should keep attacking hero for (var i:int=1; i < C_Holder3.length; i++) { if(C_Holder3[i].hitBox.hitTestObject(C_ Holder3[0]) ){ return true; } } return false; } public function removeEnemy(enemy:MovieClip){ C_Holder3.splice(C_Holder3.indexOf(enemy),1); // take out of enemylist removeChild(enemy); // remove child or enemey } // -----------------// // Atk Dmg Display // // -----------------// // these displays are like bullets that will get re-use over and over again private var atkWinX:int = 850, atkWinY:int = 300; private var counter:int = 0; private function createAtkDmgDisplays(MAX_WINDOW:int){ for(var i:int=0; i<MAX_WINDOW; i++){ var atkWindow:StatusWindow = new StatusWindow(“100”); C_Holder4.push(atkWindow); // put these off stage to the right var par = parent; atkWindow.x = atkWinX; atkWindow.y = atkWinY; addChild(atkWindow); } } public function displayAtkDmg(newX:int, newY:int, newAtkDmgNumber:String){ C_Holder4[counter].y = newY; C_Holder4[counter].x = newX; C_Holder4[counter].turnOn( newAtkDmgNumber ); counter++; // increase counter Appendix A25.4 Stage1.as so next bullet can be used if(counter > C_Holder4.length-1){ counter = 0; // reset counter } } // does not actually removeChild but insted puts the window offstage public function removeWindow(obj:Sprite){ C_Holder4[C_Holder4.indexOf(obj)].y = atkWinY; C_Holder4[C_Holder4.indexOf(obj)].x = atkWinX; } public function getWorldName():String{ return worldName; } // ----------------------// Garbage Collection // -------------------- public function cleanOutAllContents(){ var i:int=0; for(i=0; i<C_Holder4.length; i++){ display windows //removeChild(C_Holder3[i]); C_Holder4[i] = null; reference all objects null } C_Holder4.splice(0); C_Holder4 = null; for(i=0; i<C_Holder3.length; i++){ emies and hero //removeChild(C_Holder3[i]); C_Holder3[i] = null; reference all objects null } C_Holder3.splice(0); C_Holder3 = null; for(i=0;i<C_Holder2.length; i++){ data tiles //removeChild(C_Holder2[i]); C_Holder2[i] = null; // turn all references to null for GC } C_Holder2.splice(0); C_Holder2 = null; for(i=0; i<C_Holder.length; i++){ //removeChild(C_Holder[i]); C_Holder[i] = null; // remove atk // // remove en- // // remove Appendix } C_Holder.splice(0); C_Holder = null; //removeEventListener(Event.REMOVED, cleanOutAllContents); } } } Appendix A26.0 StatContainer.as package com.Lao.tanker { import import import import import import import flash.display.MovieClip; flash.display.Sprite; flash.text.TextField; flash.text.TextFormat; flash.display.Graphics; flash.display.Stage; flash.events.Event; public class StatContainer extends MovieClip { // Left Side Menu // define blocks private var statContainer:Sprite; private var block:Sprite; private var blockArr:Array = new Array(); private var MAX:int = 4; private var wid:int = 170; private var hei:int = 23; private var lineGap:int = 25; private var startX:int = 10; private var startY:int = 25; private var headerColor = 0xB03535; // redTan private var subColor = 0xFDC68F; // yellowOrange private var menuBorderColor = 0x733345; // maroon public function StatContainer() { // constructor code addEventListener(Event.ADDED, loadMenu); } public function loadMenu(e:Event){ trace(“menu added”); //text var countTxt:TextField; var format:TextFormat = new TextFormat(); format.size = 20; format.color = 0xffffff; // create blocks and define colors shapes for(var i:int=0; i<MAX; i++){ block = new Sprite(); // block.graphics.lineStyle(2, 0xFDC68F); block.graphics.drawRect(0,0, wid,hei); block.graphics.beginFill(subColor); block.graphics.drawRect(0,0, wid, hei); block.graphics.endFill(); // text countTxt = new TextField(); countTxt.selectable = false; Appendix switch(i){ case 0: countTxt.text = “HP”; break; case 1: countTxt.text = “ENERGY”; break; case 2: countTxt.text = “DEF”; break; case 3: countTxt.text = “ATK”; break; } //countTxt.text = “”+i; countTxt.x = 5; countTxt.y = 5; block.addChild(countTxt); statContainer.addChild(block); blockArr.push(block); } //position title “Stats” block block = new Sprite(); block.graphics.beginFill(headerColor); block.graphics.drawRoundRect(10,10,170,20,15,15); block.graphics.endFill(); statContainer.addChild(block); block = new Sprite(); block.graphics.beginFill(headerColor); block.graphics.drawRect(0,0, wid, hei-10); block.graphics.endFill(); block.x = startX; block.y = startY; countTxt = new TextField(); countTxt.selectable = false; countTxt.text = “Hero Stats”; countTxt.setTextFormat(format, -1);// = format; countTxt.x = 5; countTxt.y = -10; block.addChild(countTxt);// add text to block statContainer.addChild(block); // position sub-Stats blocks for(var k:int=0; k<blockArr.length; k++){ blockArr[k].x = startX // ((wid+10)*k) + 50; blockArr[k].y = startY+13+lineGap*k; } Appendix A26.1 StatContainer.as // create border var b1:Sprite = new Sprite(); b1.graphics.lineStyle(1, menuBorderColor); b1.graphics.drawRoundRect(10,10,170,200,15,15); statContainer = new Sprite(); statContainer.addChild(b1); addChild(statContainer); } } } Appendix Appendix A27.0 StatusWindow.as package com.Lao.tanker { /* Like bullets, instead of creating new bullets each time anything attcks This class uses a pool method to lower memory leaks, like bullets in a pool this class displays the damage using textField when hero or enemy attacks When the class moves a certain distance, this class should be moved off stage and be reused once the last bullet is used */ import flash.display.Sprite; import flash.text.TextField; import flash.events.Event; import flash.display.Graphics; import flash.display.Shape; import flash.text.TextFormat; public class StatusWindow extends Sprite { private var C_Holder:Array = new Array(); private var txt:TextField; private var distLimit:int = 40; private var origY:int = 0; private var isActive:Boolean = false;// this class starts with the off trigger public function StatusWindow(stat:String) { // constructor code txt = new TextField(); var f:TextFormat = new TextFormat(“Segoe”); txt.defaultTextFormat = f; txt.embedFonts = true; txt.width = 50; txt.height = 20; txt.selectable = false; txt.border = false; txt.text = “5”; C_Holder.push(txt); addChild(txt); addEventListener(Event.ADDED_TO_STAGE, added); //addEventListener(Event.REMOVED_FROM_STAGE, isRemoved); } // Event added private function added(e:Event){ origY = this.y; // record start position upon creation or when added //trace(this.y); Appendix removeEventListener(Event.ADDED_TO_STAGE, added); } // Enterframe // ----------- Main engine enterframe calls this function if this class is in use public function updatePos(){ this.y --; // move this class obj up the stage // once this obj moves a certain distance, call parent to move it offstage (not removeChild) if( Math.abs(this.y-origY) > distLimit){ var par:* = parent; par.removeWindow(this); isActive = false; } } // constant checker - called from main engine public function isUse():Boolean{ return isActive; } // reuses an old attack window but displays the new atk dmg // this class only cares about the y coordinate it ignores x coord public function turnOn(newDmg:String){ C_Holder[0].text = newDmg; origY = this.y; // record new y start pos so it can calculate distance travel again isActive = true; // allow main enterframe to update this class } } } Appendix A28.0 TankerEngine.as Appendix package com.Lao.tanker { /* Tanker Engine - specifically design to run the Tanker RPG game */ /* INDEX c1.0 ................... Imports c1.1 ................... Main class c1.2 ................... Main public/private variables c1.3 ................... Class Constructor c1.4 ................... Test objects and variables c1.5 ................... EnterFrame update - game ticker c1.6 ................... Keyboard update - game ticker c1.7 ................... Pre-loader complete - Load game interface c1.8 ................... Return to menu button functions c1.9 ................... Top Menu Bar [WorldName, Clock, Help Menu] c1.91 ................... Window Popper C3.0 ................... Garbage Collection */ // c1.0 import com.asgamer.snipergame.ThePreloader; import flash.display.MovieClip; import flash.display.BitmapData; import flash.display.Bitmap; import flash.display.Stage; import flash.display.Sprite; import flash.text.TextField; //sound import flash.media.Sound; import flash.media.SoundLoaderContext; import flash.media.SoundChannel; import flash.net.URLRequest; import flash.system.System; import flash.events.Event; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.utils.setTimeout; // c1.1 public class TankerEngine extends MovieClip { // private var fr:FramerateTracker; // for fps testing ///private var testTxt:TextField = new TextField(); // for memory testing private var testArr:Array = new Array(); // hold the testing objects // var // test variables // c1.3 // ---------------- // --------------- // GAME BUTTON CONTROLS & TRIGGER STATES // --------------- private var btn_quit = 81; // ‘Q’ key private var btn_slot = 16; // “SHIFT” key private var btn_equip = 90; // ‘Z’ key private var btn2_equip = 191;// ‘/’ key private var btn_atk = 65; // ‘a’ key private var btn_action = 32; // ‘spacebar’ key // Senital Values public var game_is_ready:Boolean = false; public var user_input = false; // For simple “Yes” “No” window pop ups - holds user input // --------------- // GAME WORLD // --------------- public var tankerWorld:MovieClip = new MovieClip(); // holds all types of display in the game // --------------- // TURN ON / OFF variables // --------------- private var allowGameTestDisplays:Boolean = false; // show test objects (FPS, game objects, etc) // --------------- // The Main Array - references all interface so you can access all other contents in the game public var C_Interface:Array = new Array(); // to reference and hold all the interface objects // Note* each interface will have a public var C_ Holder array // C_Holder references editable objects so you can access child’s contents // index // 0 = preloader // 0 = IFStat [replace preloader] // 1 = stage level // 2 = window pop up // 3 = time menu [time clock, help menu] Appendix A28.1 TankerEngine.as // CONSTRUCTOR // --------------- public function TankerEngine() { // the main stage/canvas addChild(tankerWorld);// container that holds all display objects in this game // load preloader var preloader = new ThePreloader(474, this.loaderInfo); C_Interface.push(preloader); // reference preloader tankerWorld.addChild(preloader); // display preloader preloader.addEventListener(“loadComplete”, loadAssets, false, 0, true); // about eventListener: // use true for weak reference so Garbage Coolection will collect it when not being referenced preloader.addEventListener(“preloaderFinished”, loadAllFonts, false, 0, true); // GAME ENGINE UPDATE FUNCTIONS addEventListener(Event.ENTER_FRAME, updateGameTicker, false, 0, true); // enterFrame updater // use weak reference because every time you run this flash game, memory will be reset stage.addEventListener(KeyboardEvent.KEY_DOWN, updateGameKeyboard, false, 0, true); // keyboard updater : must add keyboardEvent to stage // make sure to not allow key inputs till eveyrthing is loaded, including hero //c1.4 if(allowGameTestDisplays){ // turn it off/false when game is finalize var i:int = 0; // framerate tracker var fr:FramerateTracker = new FramerateTracker(); addChild(fr); // add class object to stage testArr.push(fr); fr = null; // delete one reference testArr[0].x = stage.stageWidth-120; // position in far left corner testArr[0].y = 5; // memory tracker var extraTestItems:int = 7; for(i = 1; i<extraTestItems; i++){ var testTxt:TextField = new TextField(); // create text tester Appendix testArr.push(testTxt); testTxt = null; testArr[i].width = 200; addChild(testArr[i]); testArr[i].x = stage.stageWidth-120; // auto re-position each tester text field below the previous testArr[i].y = 30+(20*i);//50 } } } // c1.5 // ------------------------------------------------------// ------------------------------------------------------// ENTER FRAME FUNCTION // ------------------------------------------------------// ------------------------------------------------------// // // // so use it wisely ----------------------------------------------Game Update - 1 - 30fps ticker ----------------------------------------------this function updates the game at 30fps consecutively - public var heroCanMove:Boolean, goLeft:Boolean, goRight:Boolean, goUp:Boolean, goDown:Boolean; public var startPosX; public var startPosY; private var spd:int = 4; private var maxDistance:int = 59; // amount of distance hero can move private var animateCounter:int = 0; private function updateGameTicker(e:Event){ updateGameTestDisplays(); // turn off when not needed // Hero movement update - the initiator is in the Hero.as class if(game_is_ready){ //C_Interface[1].C_Holder5[0].updateClock(); C_Interface[3].C_Holder[1].updateClock(); updateHeroMovement(); checkHp(); updateAtkDmgDisplays(); Appendix A28.2 TankerEngine.as } // end of gameIsReady } // ENTERFRAME UPDATE FUNCTIONS private function updateGameTestDisplays(){ //tankerWorld.hero.x -= speed; // update Game Test Data if turned on if(allowGameTestDisplays){ testArr[0].getFps(); testArr[1].text = “MEM USE: “ + Number(System.totalMemory/1024).toFixed(2); testArr[2].text = “C_Interface: “ + C_Interface.length; testArr[3].text = “tankerWorld: “ + tankerWorld.numChildren; if(game_is_ready){ // to prevent errors for var that don’t exist till game is fully running testArr[4].text = “Hero & ENEMY: “ + C_ Interface[1].C_Holder3.length; } } } private function updateHeroMovement():void{ if(heroCanMove){ // go right if(goRight){ C_Interface[1].C_Holder3[0].x += spd; if( Math.abs( C_Interface[1].C_Holder3[0].x startPosX ) >= maxDistance){ goRight = false; heroCanMove = false; C_Interface[1].C_Holder3[0].x --; // to offset hero slightly back into position performUpdate(); } // go left }else if(goLeft){ C_Interface[1].C_Holder3[0].x -= spd; if( Math.abs( C_Interface[1].C_Holder3[0].x startPosX ) >= maxDistance){ goLeft = false; heroCanMove = false; C_Interface[1].C_Holder3[0].x ++; // to offset hero slightly back into position performUpdate(); } // go up }else if(goUp){ C_Interface[1].C_Holder3[0].y -= spd; if( Math.abs( C_Interface[1].C_Holder3[0].y startPosY ) >= maxDistance){ // stop once max distance reach goUp = false; Appendix heroCanMove = false; C_Interface[1].C_Holder3[0].y ++; // to offset hero slightly back into position performUpdate(); } // go down }else if(goDown){ C_Interface[1].C_Holder3[0].y += spd; if( Math.abs( C_Interface[1].C_Holder3[0].y startPosY ) >= maxDistance){ goDown = false; heroCanMove = false; C_Interface[1].C_Holder3[0].y --; // to offset hero slightly back into position performUpdate(); } } } // end of heroCanMove } private function updateAtkDmgDisplays():void{ //update Attack Dmg Windows - targets the stage level class then targets atkDmg Windows if(C_Interface[1].C_Holder4.length != 0){ for(var i:int =0; i<C_Interface[1].C_Holder4.length; i++){ if(C_Interface[1].C_Holder4[i].isUse()){ C_Interface[1].C_Holder4[i].updatePos(); } } } } private function checkHp(){ if( C_Interface[0].checkHP() <= 20){ summonTutorial(“LowHealth”); } if( C_Interface[0].checkHP() <= 0){ summonTutorial(“Health”); // finish implementing the HP zero penalty } } // perfrom heroUpdate after hero moves - look at code above inside updateHeroMovement // such as energy loss private function performUpdate(){ var eCost = C_Interface[1].detectEnergyCost(); // times negative to indicate neg # C_Interface[0].changeEnergy( eCost ); // test display if(allowGameTestDisplays){ Appendix A28.3 TankerEngine.as testArr[5].text = “Energy Val: “+ eCost;//C_Holder[i].getVal();// turn off when done testing testArr[6].text = “Box “ + C_Interface[1].detectBoxID();// turn off when done testing } } // ------------------------------------------------------// ------------------------------------------------------// END OF ENTER FRAME FUNCTION // ------------------------------------------------------// ------------------------------------------------------// c1.6 // ----------------------------------------------// GAME UPDATE - 2 - Keyboard // ----------------------------------------------// this function will update the game only when a button is press private function updateGameKeyboard(e:KeyboardEvent){ if(game_is_ready){ // only if game is ready and everything is loaded will it enable keyboard detection // start first tutorial summonTutorial(“Intro”); // hero move detection if( !heroCanMove ){ // only if hero is not currently moving can user press move btn // returns true false upon movement C_Interface[1].C_Holder3[0]. moveHero(e); if( C_Interface[0].checkEnergy() >= 1){ summonTutorial(“Energy”); } // attack if( C_Interface[0].checkHeroAtkStatus() ){ // if hero atk is ready if(e.keyCode == btn_ atk){ // can only atk or pick items once hero is not moving C_Interface[1].checkHeroCollision();// does everything from minus hp, to kill, get gold, etc. } } }else{ Appendix // do nothing if hero cannot move, it is probably on the map’s edge } // Game interactive button controls if(e.keyCode == btn_slot){ // browse through equipments C_Interface[0].C_Holder3[0].changeSlot(); //trace(e.keyCode); } if(e.keyCode == btn_equip || e.keyCode == btn2_equip){ // equip current selected equipment C_Interface[0].C_Holder3[0].equipItem(); //trace(e.keyCode); } // ------------------------------------------------------- // important to put goToStartMenu controls last // or error will occur // // because above functions may still some var needed to run before the var gets set to null // GAME MENU CONTROLS -- see above for controls re-mapping if(e.keyCode == btn_quit){ // Q button --> Start Menu returnToStartMenu(); } //trace(e.keyCode); } //trace(windowTut1_energy.status); startGCCycle(); // call Garbage Collect every time game button is press to free memory //trace(e.keyCode); } // c1.7 // ----------------------------------------------// ----------------------------------------------// THE MAIN LOADER // ---------------------------------------------- // load all assests - will help the preloader load correctly private function loadAssets(e:Event) : void{ this.play(); C_Interface[0].removeEventListener(“loadComplete”, loadAssets); } // Game is done loading all assets, load start menu private function loadAllFonts(e:Event) : void{ // remove event Appendix A28.4 TankerEngine.as C_Interface[0].removeEventListener(“preloaderFinish ed”, loadAllFonts); // remove preloader tankerWorld.removeChild(C_Interface[0]); C_Interface[0] = null; C_Interface.pop(); // remove first item and clear C_Interface again // load all text fonts for the game var FL:FontLoader = new FontLoader(); // will load a invisible external font swf // you can now use the text fonts FL.addEventListener(“loadComplete”, beginStartMenu, false, 0, true); // when safe to use font, begin startMenu } private function beginStartMenu(e:Event){ startMenu(); //e.target.removeEventListener(“loadComplete”, beginStartMenu); //remove //e.removeEventListener(“loadComplete”, beginStartMenu); } // Start Menu private function startMenu(){ var middle:int = stage.stageWidth/2; var if_start = new IFStart(middle,100); // TankerStartMenu(x,y) tankerWorld.addChild(if_start); C_Interface.push(if_start); // 1st statMenu item C_Interface[0].C_Holder[0]. addEventListener(MouseEvent.CLICK, playGame, false, 0, true); } // Play Game public function playGame(e:MouseEvent){ // remove event C_Interface[0].C_Holder[0]. removeEventListener(MouseEvent.CLICK, playGame); tankerWorld.removeChild(C_Interface[0]); // remove start menu //C_Interface[0].clearOutAllContents(); C_Interface[0] = null; C_Interface.splice(0,1); // remove from array //trace(“Game Loaded, now loading interface”); Appendix // load user game interface loadGameInterface(); } private function loadGameInterface(){ // -------------------------- // // The Hero Stat Menu // -------------------------- // var if_stat = new IFStat(); // consider passing in hero stats tankerWorld.addChild(if_stat); C_Interface.push(if_stat); // interface 1 // set stats if_stat.setHP(50); if_stat.setEnergy(0); if_stat.setAtk(1,2); if_stat.setAtkSpd(800); //if_stat.setDef(5); if_stat.setGold(0); // -------------------------- // // Load Stage1 // -------------------------- // //C_Interface[1] = new FloorTiles(C_AI); // consider calling this class a level name, so you can do differen lvls var if_stage1 = new Stage1();// consider calling this class a level name, so you can do differen lvls if_stage1.x = 20; if_stage1.y = 13; tankerWorld.addChild(if_stage1); C_Interface.push(if_stage1); // C_Interface[1] if_stage1 = null; stage.focus = this; // to help force focus the stage so buttons can work // target stage levels by using the C_Interface[1] name // because each time a new stage is load // it will be given C_Interface[1] as a reference over writting the old stage // ------------------------- // Load PopWindow - a textfield displaying user with info upon triggering an event // ------------------------- createPopWindow() // C_Interface[2] // ------------------------ // Load assets on top of stage banner - (clock and world name and help menu) Appendix A28.5 TankerEngine.as // ------------------------ createTopAssets(); // C_Interface[3] // music test //loadSound(); game_is_ready = true; // after all contents loads, set game_is_ready marker to true } /* -- Music Sound private var soundClip:Sound, sndChannel:SoundChannel; private function loadSound():void{ //Create an instance of the Sound class soundClip=new Sound(); //Create a new SoundChannel Object sndChannel=new SoundChannel(); //Load sound using URLRequest soundClip.load(new URLRequest(“sound/theme.mp3”)); //Create an event listener that wll update once sound has finished loading soundClip.addEventListener(Event.COMPLETE, playSound,false,0,true); } private function playSound(evt:Event):void { //Play loaded sound sndChannel=soundClip.play(0,999); } */ // c1.8 // --------------------------------// Return To Menu Buttons // ------------------------------- public function returnToStartMenu(){ game_is_ready = false; //unload all interfaces (if_stat, if_start, if_money, ...) for(var i:int=0; i<C_Interface.length; i++){ C_Interface[i].cleanOutAllContents();// every interface class should have this function tankerWorld.removeChild(C_Interface[i]); C_Interface[i] = null;// null all referenced objects for GC (garbage collection) } C_Interface.splice(0);// clear entire array starting with index 0 to end of array // no not null C_Interface because this var get’s used even when user goes back to start menu again Appendix // load startMenu startMenu(); } // // // // c1.9 ----------------------------------------------top assests that goes ontop of stage display ---------------------------------------------- private function createTopAssets():void{ var ifTopMenu:IFTopMenu = new IFTopMenu(); tankerWorld.addChild(ifTopMenu); ifTopMenu.x = 225; ifTopMenu.y = 20; C_Interface.push(ifTopMenu); // C_Interface is now index 3, index 2 is the window poper holder getStageName(); // world name } private function getStageName():void{ C_Interface[3].C_Holder[0].text = C_Interface[1].getWorldName(); // index 3 } // c1.91 // ---------------------------------------// Window Popers that pop up warnings upon an event trigger // ----------------------------------------public var windowCount:int = 0; // doesn’t really do anthing at the moment private function createPopWindow():void{ // prepare it and set it invisible at start of game var win:WindowTutorial = new WindowTutorial(); win.x = 198; win.y = 134; tankerWorld.addChild(win); C_Interface.push(win); // this object should now be in the 2nd index of C_Interface } // whenever you want to call upon a tutorial, use thi function public function summonTutorial(tutorial:String):void{ // 1. find the tutorial you want to use, referencing the <title> in the getIndex() // - look in the tutorial.xml to know what tutorial reference var newIndex:int = C_Interface[2].tutTitle. getIndex(tutorial); Appendix A28.6 TankerEngine.as if(newIndex == -1){ throw new Error(“No such tutorial exist yet. Add \’”+ tutorial+”\’ to the tutorial.xml first”); } if(C_Interface[2].C_Holder2[newIndex].status){ // check if window should still run again game_is_ready = false; C_Interface[2].popWindow(C_Interface[2]. tutDesc[newIndex], newIndex); } } // any class can utilize the engine’s popWindow() /* public function popWindow(newTxt:String, windowRef:Object):void{ if( C_Interface[2] is Window){ // check if is Window object C_Interface[2].setText(newTxt); C_Interface[2].visible = true; C_Interface[2].setWindowRef(windowRef); windowCount++; // max out the window so only 1 window can pop up at a time }else{ throw new Error(“C_Interface[2] is either not a window, is null, or does not exist inside engine.as”); } } */ // c2.0 // --------// prototype functions // search for a value in an array and return that index Array.prototype.getIndex = function(data) { for (var i:int=0; i<this.length; ++i) { if (this[i] == data) { return i; } } return -1; }; // c3.0 // --------------------------------------// Manual Garabage Collection Function // -------------------------- private var gcCount:int; private function startGCCycle():void{ gcCount = 0; addEventListener(Event.ENTER_FRAME, doGC); } Appendix private function doGC(evt:Event):void{ flash.system.System.gc(); // first time will only sweep for references if(++gcCount > 1){ removeEventListener(Event.ENTER_FRAME, doGC); // 2nd time will free memory //setTimeout(lastGC, 40); // seem to create memory leak, turn it off for now } } /*private function lastGC():void{ flash.system.System.gc(); }*/ } } Appendix A29.0 TankerFont.as package com.Lao.tanker { import import import import import import flash.display.Sprite; flash.text.TextField; flash.text.TextFormat; flash.text.Font; flash.text.TextFieldAutoSize; flash.text.AntiAliasType; public class TankerFont extends Sprite{ public function TankerFont() { // constructor code var myFont:Font1 = new Font1(); var f:TextFormat = new TextFormat(); f.font = myFont.fontName; f.size = 24; var myTextField:TextField = new TextField(); myTextField.autoSize = TextFieldAutoSize.LEFT; myTextField.antiAliasType = AntiAliasType.ADVANCED; myTextField.defaultTextFormat = f; myTextField.embedFonts = true; myTextField.text = “The quick brown fox jumped over the lazy dog.”; addChild(myTextField) } } } Appendix Appendix A30.0 TankerPreloader.as package com.Lao.tanker { /* This class is Tanker game engine It runs all the other classes together to make the game run */ //imports // import com.Lao.IFStat; // don’t need to include this import because IFStat is already // under com.Lao the package url import com.asgamer.snipergame.ThePreloader; import flash.display.MovieClip; import flash.events.Event; import flash.display.Stage; public class TankerPreloader extends MovieClip { //var private var preloader:ThePreloader; private var target:Stage; public function TankerPreloader() { // constructor code // load preloader preloader = new ThePreloader(474, this.loaderInfo); stage.addChild(preloader); preloader.addEventListener(“loadComplete”, loadAssets); preloader.addEventListener(“preloaderFinished”, loadGame); } private function loadAssets(e:Event) : void { this.play(); } private function loadGame(e:Event) : void { stage.removeChild(preloader); trace(“Game Loaded, now loading interface”); loadGameInterface(); } private function loadGameInterface(){ // left side stat menu var ifStat:IFStat = new IFStat(target); addChild(ifStat); } } } Appendix Appendix A31.0 TankerStartMenu.as package com.Lao.tanker { /* this is the start menu it puts a textfield “Start” non-selectable inside a block sprite. The block is then given an addEventListener(MouseEvent.CLICK) on click the user will be able to proceed to play the game or start the game. The game logo is inserted underneath the Start Button */ //imports import flash.display.Graphics; import flash.display.Sprite; import flash.events.MouseEvent; import flash.text.TextField; import flash.text.*; import flash.display.BitmapData; // to represent logo bitmapdata import flash.display.Bitmap; // to put logo bitmapdata into in order to display the logo public class TankerStartMenu extends Sprite{ public var startButton:Sprite; // put this var here so other calss can access this button public function TankerStartMenu(xPos:int, yPos:int) { // constructor code var wid:int = 300; var hei:int = 100; startButton = new Sprite(); startButton.graphics.beginFill(0x666666); startButton.graphics.drawRoundRect(0,0, wid, hei, 20, 20); startButton.graphics.endFill(); var myFormat:TextFormat = new TextFormat(); myFormat.size = 50; myFormat.color = 0xffffff; myFormat.align = “center”; var myT:TextField = new TextField(); myT.defaultTextFormat = myFormat; myT.selectable = false; myT.text = “START”; myT.width = wid; myT.height = hei; myT.y = 30; startButton.addChild(myT); addChild(startButton); startButton.x = xPos-(startButton.width/2); startButton.y = yPos; // startButton.addEventListener(MouseEvent.CLICK, Appendix startGame); // display logo on start menu as well var logo:Logo = new Logo(0,0); var logoBitmap:Bitmap = new Bitmap(logo) logoBitmap.x = xPos-(logoBitmap.width/2); logoBitmap.y = 200; addChild(logoBitmap); } } } Appendix A32.0 Tile.as package com.Lao.tanker { /* This class is the data tile that get’s nested inside the FloorTiles.as class. This class holds the individual unique data for each tile when hero contacts tile. */ import flash.display.Sprite; import flash.display.Graphics; import flash.text.TextField; import flash.text.TextFormat; public class Tile extends Sprite { private var tile:Sprite; // tile appearence private var tColor = 0xFDC68F; private var tBorderThickness = 1; private var tRoundness = 10; // tile demensions and spacing private var wid:int = 40; private var hei:int = 40; private var energyValue:int = 0; public function Tile(maxEnergy:int) { tile = new Sprite(); tile.graphics.beginFill(tColor, 0); tile.graphics.drawRoundRect(5,5,wid,hei,tRoundness, tRoundness); tile.graphics.endFill(); // create text var txt:TextField = new TextField(); var f:TextFormat = new TextFormat(“Segoe”); txt.defaultTextFormat = f; txt.embedFonts = true; txt.width = 40; // width and height will affect parent sprite’s size txt.height = 20; // set heigh and width as it will auto give each txtfield 100x100 pixel //txt.border = true; // good to turn on when testing to see how big textfield is txt.selectable = false; // 90 means it’ll random from 0-90 and math.floor will make whole numbers // so 5.55 will be 5 and 5.87 will still be 5 Appendix energyValue = Math.floor(Math.random() * maxEnergy); // random text number txt.text = “”+energyValue; txt.x = 5; txt.y = 0; tile.addChild(txt); // add text field to tile addChild(tile); // add tile to be display in this class } public function getVal(){ return energyValue; } } } Appendix A33.0 W0001.as package com.Lao.tanker.weapon { import com.Lao.tanker.Weapon; //import com.Lao.tanker.Weapon; // not necessary to import this class is in same directory as Weapon /* In an inherited class, W0002 will have all properties and methods of it’s parent So you can call a parent’s function without needing the “super” in front of the function But if you override a function of a parent (meaning a child has the same name method as parent) you must use “public override method1” then use super.method1() child can call parent’s method, but parent cannot call child’s method */ public class W0001 extends Weapon{ private var wName:String = “Bone Club”; private var desc:String = “A heavy collar bone commonly found on large animals.”; private var minAtk:int = 2; private var maxAtk:int = 5; private var atkSpd:int = 1000; private var gold:int = 20; public function W0001(lvl:int) { // pass in 0,1,2, or 3 for lvl // # greater than 0 will enhance default weapon attribute and gold super(wName, desc, gold, lvl, minAtk, maxAtk, atkSpd); } } } Appendix Appendix A34.0 W0002.as package com.Lao.tanker.weapon { import com.Lao.tanker.Weapon; //import com.Lao.tanker.Weapon; // not necessary to import this class is in same directory as Weapon /* In an inherited class, W0002 will have all properties and methods of it’s parent So you can call a parent’s function without needing the “super” in front of the function But if you override a function of a parent (meaning a child has the same name method as parent) you must use “public override method1” then use super.method1() child can call parent’s method, but parent cannot call child’s method */ public class W0002 extends Weapon{ private var wName:String = “Sharp Shell”; private var desc:String = “A rare hard piece of shell broken off from a giant turtle.” private var minAtk:int = 2; private var maxAtk:int = 10; private var atkSpd:int = 2500; private var gold:int = 100; public function W0002(lvl:int) { // pass in 0,1,2, or 3 for lvl // # greater than 0 will enhance default weapon attribute and gold super(wName, desc, gold, lvl, minAtk, maxAtk, atkSpd); } } } Appendix Appendix A35.0 Weapon.as package com.Lao.tanker { // This is the parent class for weapons import flash.display.Graphics; import flash.display.Sprite; import flash.text.TextField; import flash.text.TextFormat; public class Weapon extends Sprite implements IWeapon{ // IWeapon extends IItem private var type:String = “Weapon”; private var wName:String = “parent Weapon”; private var desc:String = “parent description”; private var minAtk:int = 0; private var maxAtk:int = 0; private var atkSpd:int = 0; private var gold:int = 0; private var defaultGold:int = 0; // holds the initial gold value of default weapon’s gold // atk power mod increase per lvl private var level:int = 0; private var lvl1:Number = 1.2, lvl2:Number = 1.4, lvl3:Number = 1.8; private var RARE:String = “R”; // spd atk mod increase per lvl private var sp1:Number=1.05, sp2:Number=1.1, sp3:Number=1.15; // letter box display size to display weapon lvl power or indicate RARE private var bg:Sprite = new Sprite(); private var wid:int = 14; private var corn:int = 5; /* public function setAtk(min:int,max:int):void; public function getInformation(); */ public function Weapon(n:String, d1:String, g:int, lvl:int, min:int, max:int, atkSp:int){ wName = n; desc = d1; defaultGold = g; gold = defaultGold; minAtk = min; maxAtk = max; atkSpd = atkSp; level = lvl; levelMod(lvl); } public function levelMod(lvl:int){ // so weapon can be Appendix upgraded // upon weapon creation, a lvl number should always be passed switch(lvl){ case 0: // no modification if lvl 0 take default weapon attribute drawLetter( String(lvl) ); break; case 1: setAtk( Math.floor(minAtk*lvl1), Math.floor(maxAtk*lvl1) ); setAtkSpd( atkSpd - ( Math. floor(atkSpd*sp1) - atkSpd ) ); drawLetter( String(lvl) ); setGold(defaultGold*2); break; case 2: setAtk( Math.floor(minAtk*lvl2), Math.floor(maxAtk*lvl2) ); setAtkSpd( atkSpd - ( Math. floor(atkSpd*sp2) - atkSpd ) ); drawLetter( String(lvl) ); setGold(defaultGold*3); break; case 3: setAtk( Math.floor(minAtk*lvl3), Math.floor(maxAtk*lvl3) ); setAtkSpd( atkSpd - ( Math. floor(atkSpd*sp3) - atkSpd ) ); drawLetter( RARE ); setGold(defaultGold*4); break; default: // do nothing } } // IWeapon public function setAtk(min:int, max:int):void{ minAtk = min; maxAtk = max; } public function setAtkSpd(sp:int){ atkSpd = sp; } public function setGold(g:int):void{ gold = g; } public function getMinAtk():int{ return minAtk; } public function getMaxAtk():int{ return maxAtk; Appendix A35.1 Weapon.as } public function getAtkSpd():Number{ return Number(atkSpd); } // IItem public function getName():String{ return wName; //+super.getInfo(subName)); } public function getDesc():String{ return desc; } public function getDesc2():String{ return “[Type] “+ type + “ [Speed] “+atkSpd + “\n[Effect] Atk “+ minAtk + “ - “ + maxAtk + “\n[Gold] “ + gold; } public function drawLetter(n:String):void{ bg.graphics.clear(); bg.graphics.beginFill(0x000000); bg.graphics.drawRoundRect(0,0,wid,wid,corn,corn); bg.graphics.endFill(); var txt:TextField = new TextField(); var f:TextFormat = new TextFormat(); f.size = 10; f.color = 0xffffff; txt.defaultTextFormat = f; txt.width = 20; txt.height = 20; txt.text = n; txt.selectable = false; bg.addChild(txt); addChild(bg); txt = null; bg = null; } } } Appendix Appendix A36.0 WeaponInterface.as package com.Lao.tanker { /* Interface Class * You have to list all public methods that will be common for the classes that implements this interface; * You do so by writing the definition of the function, its name, its parameters and its return type; * You don’t have to open and close curly braces after the method definition * You don’t specify if the method is private, public or protected (that’s kind of obvious but I did that mistake) * interface can only extend other interfaces * a class can implement more than one interface An interface is for the purpose of polymorphism, so that a var interface can hold an object of that interface Also an interface helps all your classes that implements an interface, keep a structure or else an error will generate var m:FruitInterface = new Orange(); var m:FruitInterface = new Apple(); function getCalorie(fruit:FruitInterface); // it can accept can fruit as a parameter */ public interface WeaponInterface { // you don’t define public, private, protected function setAtk(min:int,max:int):void; function getInformation():void; } } Appendix Appendix A37.0 Window.as package com.Lao.tanker{ import flash.display.Sprite; import flash.text.TextFormat; import flash.text.TextField; import flash.text.AntiAliasType; import flash.display.Graphics; import flash.events.Event; import flash.events.MouseEvent; public class Window extends Sprite{ public var C_Holder:Array = new Array(); private var myTxt:String = “string not defined”; private var wid:int = 400; private var hei:int = 200; private var corner:int = 15; private var bgColor = 0xEAF7FF; private var bColor = 0x000000; private var txtColor = 0x333333; public function Window(newTxt:String, w:int, h:int) { wid = w; hei = h; // constructor code myTxt = newTxt; createWindow(); } private function createWindow(){ var block:Sprite = new Sprite(); block.graphics.lineStyle(2, bColor, .9); block.graphics.drawRoundRect(0,0, wid,hei,corner,corner); block.graphics.beginFill(bgColor, .95); block.graphics.drawRoundRect(0,0, wid, hei, corner,corner); block.graphics.endFill(); addChild(block); //create main textfield var format:TextFormat = new TextFormat(“Frank”); // Segoe, Segoeb, Footlight format.size = 16; format.color = txtColor; var txt:TextField = new TextField(); txt.embedFonts = true; txt.antiAliasType = AntiAliasType.ADVANCED; txt.defaultTextFormat = format; Appendix txt.wordWrap = true; txt.border = false; txt.htmlText = myTxt; txt.width = wid-12; txt.height = hei-50; txt.x = 6; txt.y = 6; C_Holder.push(txt); addChild(C_Holder[0]); } // change the text box to the incoming new text public function setText(newTxt:String):void{ //newTxt = newTxt.split(“-b”).join(“<b>”); C_Holder[0].htmlText = newTxt; } // turn the visibility of this window off/on public function setVisible(Switch:Boolean){ this.visible = Switch; var par:* = parent; par.game_is_ready = !Switch; } public function cleanOutAllContents():void{ for(var i:int = 0; i<C_Holder.length; i++){ removeChild(C_Holder[i]); C_Holder[i] = null; C_Holder.splice(0); } } } } Appendix A38.0 WindowNotice.as package com.Lao.tanker{ /* Will be use to pop up tutorials by the Shine Gaurdian - includes a prev, next, and okay button - okay btn will not become visible untill the maxPage is reach - parent:Window is what that displays the the text */ import flash.display.Sprite; import flash.text.TextFormat; import flash.text.TextField; import flash.display.Graphics; import flash.events.Event; import flash.events.MouseEvent; public class WindowNotice extends Window{ //public var C_Holder:Array = new Array(); private var myTxt:String = “string not defined”; private var wid:int = 400; private var hei:int = 300; private var corner:int = 15; private var bgColor = 0xEAF7FF; private var bColor = 0x000000; private var txtColor = 0xff0066; private var windowRef:Object;// when set to false, that window will not get trigger again public function WindowNotice(newTxt:String, wid:int, hei:int) { super(newTxt, wid, hei); // constructor code createButton(); createNextBackButton(); } private function createButton(){ // buttons var block:Sprite = new Sprite(); C_Holder.push(block); // in parent block.graphics.beginFill(0x000033); block.graphics.drawRoundRect(0,0,100,30, corner, corner); block.graphics.endFill(); var txt:TextField = new TextField(); var format:TextFormat = new TextFormat(“Segoeb”); format.size = 12; format.color = 0xffffff; txt.defaultTextFormat = format; txt.embedFonts = true; Appendix txt.x = 6; txt.y = 6; txt.selectable = false; txt.text = “OKAY”; txt.width = 100; txt.height = 30; block.addChild(txt); addChild(block); block.x = 10; block.y = 160; C_Holder[1].addEventListener(MouseEvent.CLICK, passAnswer, false, 0, true); } private var C_Holder2:Array= new Array(); // to hold page text field private function createNextBackButton():void{ for(var i:int=0; i<2; i++){ var block:Sprite = new Sprite(); C_Holder.push(block); // in parent block.graphics.beginFill(0x000033); block.graphics.drawRoundRect(0,0,50,30, corner, corner); block.graphics.endFill(); var txt:TextField = new TextField(); var format:TextFormat = new TextFormat(“Segoeb”); format.size = 12; format.color = 0xffffff; txt.defaultTextFormat = format; txt.embedFonts = true; txt.border = false; txt.x = 6; txt.y = 6; txt.selectable = false; switch(i){ case 0: txt.text = “Back”; break; case 1: txt.text = “Next”; break } txt.width = 40; txt.height = 25; block.addChild(txt); addChild(block); block.x = C_Holder[0].width-160+(i*110); block.y = 160; } C_Holder[2].addEventListener(MouseEvent.CLICK, go- Appendix A38.1 WindowNotice.as Back, false, 0, true); C_Holder[3].addEventListener(MouseEvent.CLICK, goNext, false, 0, true); // creat page txt = new TextField(); format = new TextFormat(“Segoeb”); format.size = 14; format.color = 0x000033; txt.defaultTextFormat = format; txt.embedFonts = true; txt.border = false; txt.x = C_Holder[0].width-100; txt.y = 160; txt.selectable = false; txt.text = “1/1”; txt.width = 50; txt.height = 25; C_Holder2.push(txt); addChild(txt); } public function passAnswer(e:MouseEvent){ //trace(this.parent.parent); var par:* = parent; // to call the parent’s parent, you use a 2nd var // okay press if(e.currentTarget.x == C_Holder[1].x){ // almost don’t need this if you just have one button turnOff(); } } private function turnOff(){ this.visible = false; var par:* = parent; par.parent.parent.windowCount --; // engine << windowTutorial << WindowNotice par.parent.parent.game_is_ready = true; windowRef.status = false; pages.splice(0); // clean array } public function setWindowRef(newWindowRef:Object){ windowRef = newWindowRef; } public function setMaxPage(count:int):void{ maxPage = count; currPage = 0; // determine if okay button should be visible or Appendix not if there’s only one page to browse through if( currPage+1 == maxPage){ C_Holder[1].visible = true; }else{ C_Holder[1].visible = false; } C_Holder2[0].text = “”+(currPage+1)+”/”+maxPage; } // set pages private var pages:Array = new Array(); public function setPageStr(pageArr:Array):void{ pages = pageArr; } // previous page private var currPage:int =0, maxPage:int=0; private function goBack(e:MouseEvent):void{ currPage--; if(currPage <=0){ // can’t go below zero currPage=0; } C_Holder2[0].text = “”+(currPage+1)+”/”+maxPage; // update current page number display // not yet working, a way to format the text to bold using css /* var str:String = pages[currPage]; // modify string str = str.split(“-b”).join(“<b>”); // find bold str = str.split(“--b”).join(“</b>”); // find end of bold */ // update text setText(pages[currPage]); // display current page text } // next page private function goNext(e:MouseEvent):void{ currPage++; if(currPage >= maxPage-1){ // can’t go above max page currPage=maxPage-1; } // display the okay button once user is on last page. if( currPage+1 >= maxPage){ Appendix A38.2 WindowNotice.as C_Holder[1].visible = true; } C_Holder2[0].text = “”+(currPage+1)+”/”+maxPage; // update page number setText(pages[currPage]); // display current page text } /* public function answerNo(e:MouseEvent){ //trace(this.parent.parent); C_Holder[2].removeEventListener(MouseEvent.CLICK, answerNo); C_Holder[1].removeEventListener(MouseEvent.CLICK, answerYes); for(var i:int=0; i<C_Holder.length; i++){ removeChild(C_Holder[i]); C_Holder[i] = null; } C_Holder.splice(0); C_Holder = null; trace(“no : “ + e.currentTarget); var par:* = parent; par.parent.userNo(this); // re //par.parent.tankerWorld.removeChild(this); } */ } } Appendix Appendix A39.0 WindowTutorial.as package com.Lao.tanker { /* This class is made up of WindowNotice (extends Window), XML tutorials */ import flash.display.Sprite; // xml import flash.net.URLLoader; import flash.net.URLRequest; import flash.events.Event; public class WindowTutorial extends Sprite{ public var C_Holder:Array = new Array(); holds WindowNotice, currently just one item public var C_Holder2:Array = new Array(); holds boolean tutorial objects, so the tutorial won’t repeat private var xmlLoader:URLLoader = new URLLoader(); public var tutTitle:Array = new Array(); public var tutDesc:Array = new Array(); // // public function WindowTutorial() { // load windowNotice createWindowNotice(); // load xml xmlLoader.addEventListener(Event.COMPLETE, populateXML); xmlLoader.load(new URLRequest(“xml/tutorial.xml”)); // create back forward buttons to flip through text createForwardBackButton(); } private function createWindowNotice():void{ // prepare it and set it invisible at start of game var win:WindowNotice = new WindowNotice(“nothing”, 400, 200); addChild(win); C_Holder.push(win); // this object should now be in the 2nd index of C_Interface win.visible = false; // this window starts off invisible till trigger } private function populateXML(e:Event):void{ XML.ignoreWhitespace = false; var tutXML:XML = new XML(e.target.data); //trace(helpList.list.title.length());//Result is 4 var i:Number; for (i=0; i < tutXML.list.title.length(); i++) { Appendix tutTitle.push( tutXML.list.title[i].text() ); tutDesc.push( tutXML.list.desc[i].text() ); } // create the boolean objects, they have to be objects in order to use pass by reference // just in case these booleans needs to be pass by reference outside of this class var count:int = tutXML.list.title.length(); // to know how many objects to create for(i=0; i<count; i++){ var winBooleanObj = {status:true}; C_Holder2.push(winBooleanObj); } /*public var windowTut1_energy = {status:true}, windowTut2_hp = {status:true}, windowTut3_weapon = {status:true}, windowTut4_intro = {status:true}; */ } // pop window test public function popWindow(oldTxt:String, winIndex:int):void{ if( C_Holder[0] is Window){ // check if is Window object // split string into sections var strArr:Array = oldTxt.split(“//”); var pageCount:int = strArr.length; // get the page count C_Holder[0].setMaxPage(pageCount); // set the max page count in windowNotice C_Holder[0].setPageStr(strArr); // send all the pages in an array var newTxt:String = strArr[0]; C_Holder[0].setText(newTxt); C_Holder[0].visible = true; C_Holder[0].setWindowRef(C_ Holder2[winIndex]); //windowCount++; // max out the window so only 1 window can pop up at a time }else{ throw new Error(“C_Interface[2] is either not a window, is null, or does not exist inside engine.as”); } } private function createForwardBackButton():void{ } Appendix A39.1 WindowTutorial.as // GC public function cleanOutAllContents():void{ for(var i:int=0;i<C_Holder.length; i++){ removeChild(C_Holder[i]); C_Holder.splice(0); } } } } Appendix