12,065,204 members (42,723 online)
Those Magnificent Men, previously called "The Catalyst" and "Island Hopper" is a 2D RPG based around aircraft. You play as young pilot designing your own airframe and running errands between towns and cities across the islands trading, buying/selling stock, hiring crew and dogfighting.
The game is written in AGK (App Game Kit) which is a multi-platform language. It has two tiers of implementation, a high level, BASIC-style language (Tier 1), and a higher level, native language (Tier 2). Both tiers enable the developer to export the compiled code to a number of platforms such as Windows, iOS, Android, Blackberry, etc. See the AGK website here for more information on specifics of the development environment itself.
AGK was selected for Those Magnificent Men, for many reasons including, my familiarity with the code, the potential ability to export the completed game to other platforms and also because accessing the dedicated UltrabookTM stimuli, such as the GPS, accelerometers and touch-screen, was very easy.
Set in the 1920s over a small collection of islands where aircraft are the only logical choice of transport, four races of men (vampires, werewolves, merman and shadow people) are vying for political control.
The Earth was once populated by a wide variety of men; Vampires, Werewolves, Mermen, etc. but the vast number of Humans have forced them to occupy a small group of Islands in the Pacific ocean, known as Tresto. The Islands are the last safe-place on Earth for all these mythical men, but the limited space and resources have caused these Mythical people distrust each other and they co-exist in a state of pending-war.
The player is one of the small number of humans on these islands, although the other races can be unlocked with progress.
You pilot between towns and cities doing jobs and trading stock while avoiding dog fights with pirates and enemy factions.
Islands generated randomly (seeded by alpha-numeric string entered manually, or taken from GPS location) or drawn manually by the player (manual drawing is not in the current Demo).
1000 individually named locations (all place names created by a human!).
Buy stock at one town and sell for a profit at another location across the islands.
Take on jobs for groups and political parties (for cash and technology bonus rewards, as well as shaping who controls the islands).
Upgrade your wings to boost your chance in dogfights.
Take on crew that provide you with additional bonuses.
This will be a Win 8 Desktop App.
The latest demo version can be down loaded via IndieDB/gamefront:
I should point out that IndieDB is being used to host the demos only during the development of the game. The quick authorization process enables de-bugging feedback to be performed much quicker than hosting via AppUp. I should also point out that the final version will be available via the Intel AppUp store.
Originally the game offered four distinct airframes to chose from, each specializing in a different area (cargo, passengers, weaponry and speed). I felt this was a little frustrating to those player that wanted to execute an intermediate strategy so I have enable players to create their own aircraft by joining together airframe parts. This allows the player to customize their airframe to their particular strategy.
The player cannot start the game by building the very best aircraft. Aircraft can only be built based on the number of build points the player has accumulated through previous games. Initially you can only build a simple mono-plane, but a few games in and you can progress to bi and tri-planes.
[Aircraft Designer Screen]
The latest demo, [r006] of the game introduces some new parts to use in the designer; a delta tail and a bat-style wing.
[New airframe parts available]
Once the airframe has been created, the game takes a screen shot of the airframe and generates the side profile for use in the main game.
Three aspects of the code for the airframe designer that people interested in are:
The parts available in the designer screen are generated by reading the airframeparts.txt file. The code is contained within a single custom function, which is called as part of the screen set-up.
function SetupUpAirframeParts() // loads all available airframe parts into blue print mode row = 0 col = 0 AirframePartID = 0 AvailableParts = 0 PartsFileID = opentoread("airframeparts.txt")
A sample of the txt file is shown here:
newpart tail_small_01.png tail_small_01s.png CoGx=70.0 CoGy=50.0 Fuel=1000 Mass=35.0 Lift=1.0 Liftx=30.0 Lifty=50.0 PartType=1 SizeLeft=99 SizeRight=1 Strength=30 Value=900 endpart
The txt file is opened is each line is read until it detects the keyword "newpart". At this point it resets all the airframe part parameters to zero.
The line following "newpart" is always the image of the part as viewed from above and the second image is always the image of the part viewed from the side. The first image is used directly in the designer screen and while flying the aircraft. The second image is only used while landing. The images are processed as follows:
//TOP IMAGE & SPRITE TopImageFile$ = readline(PartsFileID) AvailableAirframePart[AirframePartID].imageid = loadimage(TopImageFile$) PartSpriteID = createsprite(AvailableAirframePart[AirframePartID].imageid) AvailableAirframePart[AirframePartID].spriteid = PartSpriteID if getspritewidth(PartSpriteID)>getspriteheight(PartSpriteID) setspritescale(PartSpriteID,90/getspritewidth(PartSpriteID),90/getspritewidth(PartSpriteID)) else setspritescale(PartSpriteID,90/getspriteheight(PartSpriteID),90/getspriteheight(PartSpriteID)) endif setspritevisible(PartSpriteID,1) setspritedepth(PartSpriteID,2) fixspritetoscreen(PartSpriteID,1) setspritex(PartSpriteID,810+((getspritewidth(AvailableAirframePart.spriteid )+25)*col)) setspritey(PartSpriteID,100+((getspritewidth(AvailableAirframePart.spriteid )+25)*row))
To aid the creator, text is displayed with the part to identify the key stats of the part. The text is generated as follows
// part stats DisplayText$ = "" repeat CompleteLine$ = readline(PartsFileID) if lower(CompleteLine$)<>"endpart" and lower(CompleteLine$)<>"none" stat$ = lower(GetStringToken(CompleteLine$,"=",1)) value$ = GetStringToken(CompleteLine$,"=",2) select stat$ case "cargo" AvailableAirframePart[AirframePartID].cargo = val(value$) if DisplayText$="" DisplayText$ = DisplayText$+value$+" Cargo" else DisplayText$ = DisplayText$+chr(10)+value$+" Cargo" endif endcase case "cogx" AvailableAirframePart[AirframePartID].cogx = valfloat(value$) endcase
Not all part stats are added to the display text, for example the "cogx" parameter, the position of the Centre of Gravity for the part is not indicated in text, but the number of cargo units is.
The airframe design screen code is set-up in a similar way to all the other screens in the game where the user can drag items from one area of the screen and drop them in another area.
Initially all the media for the screen is generated - here is an example:
// DESIGN AIRFRAME _DesignAirframe: // clear background setspritevisible(titlesprite,0) setspritevisible(titlesprite,0) setspritevisible(titlesprite,0) setspritevisible(titlesprite,0) setspritevisible(MapFoldsSpt,1) BlueprintImage = loadimage("blueprintback.png") BlueprintSprite = createsprite(BlueprintImage) setspritevisible(BlueprintSprite,1) fixspritetoscreen(BlueprintSprite,1) setspritedepth(BlueprintSprite,11) setspritex(BlueprintSprite,40) setspritey(BlueprintSprite,75)
Then the main loop is executed checking for user interaction. Specifically when the pointer is first pressed, is being held or has just been released. The following code shows the complete loop showing the interact code, but with the meat of the part and sprite handling removed to help reading.
ButtonID = 0 ActionID = 0 repeat // Back button pressed if getvirtualbuttonreleased(2)=1 then ActionID=2 if getpointerpressed()=1 //GRABED PART newselectedpart = -1 oldselectedpart = -1 returningsprite = 0 sliderstarty = 0 //new part for partid=0 to AvailableParts-1 spriteid = AvailableAirframePart[partid].spriteid //CODE TO HANDLE NEW PARTS HERE next partid //existing part if newselectedpart=-1 for partid=0 to 39 spriteid = customairframepart[partid].spriteid //CODE TO HANDLE EXISTING PARTS HERE next partid endif // slider control if getpointerx()>794 and newselectedpart=-1 and oldselectedpart=-1 sliderstarty=getpointery() endif endif if getpointerstate()=1 //DRAGGING PART if (newselectedpart>-1 or oldselectedpart>-1) and returningsprite=0 and getspriteexists(clonedsprite)=1 //move sprite //snap to closest part endif //SLIDER DRAGGING if (newselectedpart=-1 and oldselectedpart=-1 and returningsprite=0 and getspriteexists(clonedsprite)=0) slidervalue = slidervalue+getpointery()-sliderstarty sliderstarty = getpointery() UpdateAirframeParts(slidervalue) endif endif if getpointerreleased()=1 // add to airframe if clonedsprite>0 and newselectedpart>-1 if getpointerx()<792 //ADD PART TO AIRFRAME else // remove part endif endif //remove part if clonedsprite>0 and oldselectedpart>-1 and newselectedpart<0 if getpointerx()>792 //Removed part else // just moving endif endif // DONE if getpointerx()>getspritex(DoneButSpt) and getpointerx()<getspritex(DoneButSpt)+getspritewidth(DoneButSpt) and clonedsprite=0 if getpointery()>getspritey(DoneButSpt) and getpointery()<getspritey(DoneButSpt)+getspriteheight(DoneButSpt) // aircraft checks if AllGood=1 then ButtonID = 2 endif endif // CLEAR ALL if getpointerx()>getspritex(ClearButSpt) and getpointerx()<getspritex(ClearButSpt)+getspritewidth(ClearButSpt) and clonedsprite=0 if getpointery()>getspritey(ClearButSpt) and getpointery()<getspritey(ClearButSpt)+getspriteheight(ClearButSpt) ClearAirframeParts() endif endif endif sync() until getrawkeypressed(13)=1 or ButtonID=2 or ActionID=2
When the airframe has been successfully designed the game takes 3 screen-shot images that are later used by the game. That way the game only needs to handle a single image on screen, rather than all the individual part images.
Screen shots are performed in AGK by individually calling the update(), render() and swap() functions, normally automatically called when using the sync() function. Using the GetImage(x,y,w,h) function after render() stores a section of the screen as a dedicated image that can then be saved to disk using SaveImage().
The code below shows the first images being captured and stored. This image is the main, top-down image of the aircraft using during the flying scenes.
//Save NEW Airframe IMAGE update(0) render() FileName$ = geteditboxtext(AirframeNameBox)+".png" AFx = getspritex(BlueprintSprite) AFy = getspritey(BlueprintSprite) AFw = getspritewidth(BlueprintSprite) AFh = getspriteheight(BlueprintSprite) NewAirframeImage = getimage(AFx,AFy,AFw,AFh) saveimage(NewAirframeImage,FileName$) swap()
The second image is created for using within the hangar so that the airframe can be purchased, again using the top-down view. This time an additional masking sprite "SellingBackSpt" is made visible and the aircraft name is displayed before the screen shot is taken.
// Save NEW Airframe Selling IMAGE setspritevisible(SellingBackSpt,1) //title textsize = 80 settextsize(gametext.airframe,textsize) settextstring(gametext.airframe,geteditboxtext(AirframeNameBox)) settextx(gametext.airframe,getspritex(BlueprintSprite)+(getspritewidth(BlueprintSprite)/2)) settexty(gametext.airframe,getspritey(BlueprintSprite)+(0.1*getspriteheight(BlueprintSprite))) //re-size text if needed if gettexttotalwidth(gametext.airframe)>getspritewidth(BlueprintSprite) textsize = textsize-1 settextsize(gametext.airframe,textsize) endif randomcolour = random(0,5) select randomcolour case 0: //red settextcolor(gametext.airframe,200,0,0,255) endcase case 1: //green settextcolor(gametext.airframe,0,200,0,255) endcase case 2: //blue settextcolor(gametext.airframe,0,0,200,255) endcase case 3: //magenta settextcolor(gametext.airframe,200,0,200,255) endcase case 4: //cyan settextcolor(gametext.airframe,0,200,200,255) endcase case 5: //orange settextcolor(gametext.airframe,200,200,0,255) endcase endselect settextvisible(gametext.airframe,1) update(0) render() a=1 repeat FileName$ = "Airframe"+str(a)+".png" a = a+1 until getfileexists(FileName$)=0 AFx = getspritex(SellingBackSpt) AFy = getspritey(SellingBackSpt) AFw = getspritewidth(SellingBackSpt) AFh = getspriteheight(SellingBackSpt) NewAirframeImage = getimage(AFx,AFy,AFw,AFh) saveimage(NewAirframeImage,FileName$) swap()
Finally the side-view of the airframe is drawn using a custom function called
DrawLandingSprite() which swaps all the top-down part images for the side profile images.
It also draws the wing-struts and places the landing wheel in the correct location.
setspritevisible(SellingBackSpt,0) settextvisible(gametext.airframe,0) // Save NEW Airframe Landing IMAGE DrawLandingSprite() FileName$ = geteditboxtext(AirframeNameBox)+"_land.png" update(0) render() AFx = getspritex(BlueprintSprite) AFy = getspritey(BlueprintSprite) AFw = getspritewidth(BlueprintSprite) AFh = getspriteheight(BlueprintSprite) NewAirframeImage = getimage(AFx,AFy,AFw,AFh) saveimage(NewAirframeImage,FileName$) swap()
Finally all the aircraft stats, such as speed, number of passengers, gun mounts, etc. are stored to binary file with the custom suffic *.afd.
//Save NEW Airframe DATA FileName$ = geteditboxtext(AirframeNameBox)+".afd" SaveAirframeData(FileName$)
RANDOM MAP GENERATOR
The islands can either be generated by random walks of varying length based on a seed value supplied by the player, taken from the system clock or taken from the player's location if their Ultrabook has its GPS turned ON.
[Map Drawing Choice]
Three sizes of maps will be available (small medium and large) with the larger sizes simply increasing the playable area, number of locations and random walks as well as the walk length. Alternatively if the player has chosen to draw their own map, then the map size limits the total number of 'blocks' that can be drawn on screen.
A separate function then draws a coastline around the random walks to improve the presentation.
[Random Map Generated with Airfield Locations]
Alternatively the player can choose to draw their own map.
[The player can draw their own map]
Flying between locations is performed top-down looking at a map in the style of ordnance survey. The aircraft can yaw by either the arrow keys (left/right),A & D keys, or a virtual joystick on the tough screen. The throttle can also be adjusted by the arrow keys (up/down), W & S keys, or again via the touch screen.
[Flying between airfield locations]
Occasionally flocks of birds or other passive aircraft will cross the player's path which must be avoided or they will cause damage. The player will also encounter enemy aircraft on their journey that will attempt to shoot you down. You can either attempt to shoot them down first or make a run for it. Less threateningly are cloud which also appear randomly and obscure the map, the birds and other aircraft.
[Cloud Obscuring View while flying]
When arriving at a location a separate landing game is started where the player must successfully land on the runway. The arrow keys (left/right), A/D keys, or the virtual joystick adjust the pitch of the aircraft which increases or reduces the lift of the aircraft. Again the throttle is adjusted by the arrow keys (up/down), W/S keys or the touch-screen changes the aircraft speed.
If the player lands too hard, damage is done to the airframe. Landing too short will incur an additional charge based the distance from the runway. If the runway is over shot, the player gets another go to land, but gets charged for a missed landing.
The landing screen is also displayed if the player is shot-down, runs out of fuel or collides with birds/aircraft and takes too much damage. The main difference being is that this is the end of the game for the player - they will have no control over their aircraft as it merrily plummets into the ground.
The game is about 90% complete with basic game functionality and navigation working. Most of the images are currently work-in-progress as I concentrate on the mechanics.
A video of the game play can be seen below or visit this link.
[Change log for r005]
# ALL SHINY & NEW
# TWEAKED, ADJUSTED or POLISHED A BIT
# REPAIRED or PATCHED UP
I developed the original idea for this game as a table-top board game, but never completed development. Now having got to grips with coding, I'm able to expand on my original idea and develop this to completion.