Introduction
The Mothernode is a new game where up to four players compete against each other, racing through a maze of random storage boxes to reach the safety node in the center of the room. As they make their way towards the center the players receive bonuses that they can use to help themselves and to hinder the progress of others.
The game is designed to be used on the Levono Horizon All-In-One PC and is a Round 2 Finalist within the "Games" category for the Intel® App Innovation Contest 2013.
Update
[17th Nov 2013] Round 2 entry submitted, wish me luck.
PROMOTIONAL VIDEO for ROUND 2
[This is a promotional video showing the various features of the game]
Update
[18th Oct 2013] New demo available to download and test.
DOWNLOAD CURRENT DEMO [r02]
[This download will also work on a non-touch-screen PC, but only in single player mode]
VIDEO OF THE DEMO IN ACTION
[This video shows three rooms being played on EASY mode]
Here are some screen shots from the latest demo with some explanations about what has changed.
A back image has been added to make the title screen more interesting. Having now tested on the AIO, there is a LOT of space to fill for the intro screen. A back button has been added, together with a settings menu to change the difficulty. The tutorial button has been added, but the actual tutorial functionality is still being worked on.
The hidden boxes sometimes take there colour from tiny 30x16 pixel images. The one shown above shows my face. This does absolutely nothing, but I felt it made the screen more interesting. The invincible red block are also now hidden until they are in the line of sight of a player so make the screen more appealing.
The end of level trigger has been made more exciting with the use of pyrotechnics! The image above shows the yellow raider triggering all the box traps by reaching the Safety Node. All the other players will be damaged as the wave of death reaches them.
The sequence been rooms have been changed to look prettier. It now shows the unlocked bonus for each room more clearly, it shows the winning colour for that room and it plays a little animation of the raiders walking from one room to the next.
Summary
The game has been designed to take full advantage of the Lenovo Horizon All-In-One's magnificent 27" display, its high quality audio and its multi-tough features.
The game is naturally optimised for four players to battle together, but the game also works with the AIO in desktop mode for single player experiences using the mouse.
A short video of one round of the game can be found in the follwoing link. The video shows the game running on a Windows8 Ultrabook:
VIDEO LINK
The image below provides a quick overview of how every square inch of the 27" screen is used to produce a simple, competitive and thoroughly engaging experience.
The Gameplay
The Mothenode gameplay consists of a number of simple tasks, the basics of which are explained below.
The Objective/Goal
Each round starts with your raider in one of the four corners of the screen and your aim is to guide your raider to the safety zone in the center of the screen before any of the other raiders get there.
Blocking your way is a large grid of storage boxes. The only boxes you can see at the start are the red invincible boxes and the two boxes adjacent to your raider.
Movement
The game is played in real-time so you will need to guide your raider immediately. To move your raider towards the safety zone your raider needs to break open the boxes in their path. Boxes are targeted to be broken by touching them on the screen.
As boxes are broken open, some of them grant the player a bonus. All the bonuses collected by the player sit along side the raider's start zone.
Bonuses
There are two types of bonuses the raider can collect and use: One-Shots and Decayers.
One-Shot bonuses are simply that, bonuses you can use once such as:
- Medipac (replenishes health),
- Destroy 3-in-a-row (instantly destroys 3 containers in a line),
- Block 3-in-a-row (sets 3 containers to invinciple, to nicely prevent your enemes from taking the easy route),
- Set-Trap (makes the intended container a trap)
Decayer bonuses last for 30 seconds. Sample Decayer bonuses are:
- Strength Boost (increases the damage inflicted on the containers)
- Trap Sense (shades trapped containes red, the colour fades with use)
- Beyond Sight (shows the the type of containers beyond the current line of sight helpful for route planning - the distance seen reduces with use)
- Gas Mask (reduces the damage taken due to gas)
The bonuses are used in different ways. Decayer bonuses are activated by tapping the bonus and the activated bonus then appears in the activated bonus area. The image below shows the "Trap Sense" decayer bonus active and it also shows how trapped boxes are identified when this bonus is active.
One-Shot bonuses are used by dragging them to specific boxes in the grid. The image below shows the "3 in-a-row Destroy" bonus being dragged from the collected bonus area to the target box.
Once armed, the 3 in-a-row bonus is dragged to a second target and released to activate.
Boobytraps
As well as bonuses, some boxes also contain traps. Explosion traps cause immediate injury to the raider and can also destroy adjacent boxes. Poison gas traps are permanent traps that slowly poison the rider if they stand in the poisoned zone.
End of Round Feedback
Eventually a raider will reach the safety zone and trigger the end of the round. When this happens, play stops and the players are given some feedback on their performance.
Game Rounds
The game types are briefly described below, but they all consist of 2 phases:
Phase 1: Get to the Safety Node
As explained above, players direct their raider by breaking boxes in their raider's path to the Safety none.
Raiders can use their bonuses during the level by tapping and/or dragging them from the collected bonuses area to their target.
Multi-touch is essential for this game as there will be many players taping and dragging from all four corners of the screen simultaneously.
This phase ends when a raider reaches the Safety node.
Phase 2: Trade your bonuses for a head-start
After the room is cleared, the players get 10 seconds in which to trade any unused bonuses for a 5.0 second head-start over the other players, trade 2 bonuses and get a 10.0 second head-start and so forth. The unwanted bonuses are flicked into the center of the screen.
This feature could be ideally combined with the AIO Striker, in a manner similar to that of dragging the winning chips in roulette or grabbing the balls in Hungry Hippos.
This phase ends when the timer runs out. and the game restarts at phase 1.
Game Types
There are also five variations of the game planned for the final version, although only "Last Man Standing" will be available in the demo:
- Last Man Standing - The players make it through warehouse after warehouse until only one raider remains alive.
- All For One - Unlike Last Man Standing players can only progress if everyone makes it to the Safenode.
- Clear Out - A variation of Last Man Standing, but The players must clear a set % of the containers in order to progress.
- Time Of Your Life - Another variation of Last Man Standing, but player must reach the Safenode before the time runs out.
- Of Sentinels - The warehouse also contains some simple sentinels that attack the riaders if they are spotted. Like Last Man Standing again, but with added threat.
Game Story
Legend has it that the Champanova, the flagship of the once mighty Galactic Trading Corp (GTC), was filled with half the world’s wealth when it vanished from known space 50 years ago. So when the ship mysteriously drifted back into the Solar System, apparently abandoned, there was a mass panic by the Earth's population to capture the craft and claim the treasure as their own.
You play as one of the many raiding individuals trying to reach the Mothernode – the control centre of the Champanova that will grant to access to the unimagineable wealth the ship contains. The location of the Mothernode is not known, lost in history as the databanks of the GTC were wiped as it went into financial meltdown and the few that knew the details were tortured to death .
Raiders start at the docking bay of the Champanova and have to navigate their way through a series of connected warehouses. Access to the adjoining warehouses is controlled by a safety node in the middle of the storage area and has completely surrounded by storage containers. The safety node grants the user access to one of the connecting storage areas, but also activates the internal security systems which destroys all the remaining storage containers.
To get to the safety node, raiders break open the storage containers in their path. Some containers are harder to break than others (wooden crates are easier than metal cases) and some are impossible to break. Containers can contain good and bad surprises. Some containers grant the raider bonuses (extra speed, extra health, cash, etc.) some causes problems (explosions, release toxic gas, etc.) which the raider either needs to flee from, or use protection against.
The game is aimed at young adults and teenagers. Although there is no gore and there are no offensive weaponry, the tone of the game and its style is aimed at a more mature audience.
Development
The game is being developed using the App Game Kit (AGK) v108 from The Game Creators (TGC). I chose this environment as I have previously developed a number of games using AGK and I find the language very easy to use and it provides some great functions to access the features of the AIO.
The example function below shows how the touch interaction is handled.
<span style="font-size: 12px; white-space: pre;">function DetermineTouchInput()
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> beingtouched = getrawfirsttouchevent(1)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> while beingtouched>0</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if DebugON>0
</span><span style="font-size: 12px; white-space: pre;"> px# = screentoworldx(getrawtouchlastx(beingtouched))
</span><span style="font-size: 12px; white-space: pre;"> py# = screentoworldy(getrawtouchlasty(beingtouched))
</span><span style="font-size: 12px; white-space: pre;"> setspritepositionbyoffset(TouchCrossSpt,px#,py#)
</span><span style="font-size: 12px; white-space: pre;"> setspritevisible(TouchCrossSpt,1)
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;"> setspritevisible(TouchCrossSpt,0)
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if getrawtouchvalue(beingtouched)>0
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if getrawtouchreleased(beingtouched)=1
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> usprite = getrawtouchvalue(beingtouched)
</span><span style="font-size: 12px; white-space: pre;"> for p=0 to 3
</span><span style="font-size: 12px; white-space: pre;"> for b=1 to TotalBonusTypes
</span><span style="font-size: 12px; white-space: pre;"> if PlayerBonus[p,b].count > 0
</span><span style="font-size: 12px; white-space: pre;"> if PlayerBonus[p,b].UsingSprite = usprite
</span><span style="font-size: 12px; white-space: pre;"> pid = p
</span><span style="font-size: 12px; white-space: pre;"> bid = b</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> p = 3
</span><span style="font-size: 12px; white-space: pre;"> b = TotalBonusTypes
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> next b
</span><span style="font-size: 12px; white-space: pre;"> next p</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if bonus[bid].NeedsArm = 1
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> px# = screentoworldx(getrawtouchlastx(beingtouched))
</span><span style="font-size: 12px; white-space: pre;"> py# = screentoworldy(getrawtouchlasty(beingtouched))
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> xtile = trunc((px#+32)/64)
</span><span style="font-size: 12px; white-space: pre;"> ytile = trunc((py#+32)/64)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> ArmBonus(pid, bid, Xtile, Ytile)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> TriggerBonus(pid, bid, 0, 0, 0, 0)
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> usprite = getrawtouchvalue(beingtouched)
</span><span style="font-size: 12px; white-space: pre;"> if getspriteexists(usprite)=1 then deletesprite(usprite)
</span><span style="font-size: 12px; white-space: pre;"> setrawtouchvalue(beingtouched,0)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> usprite = getrawtouchvalue(beingtouched)
</span><span style="font-size: 12px; white-space: pre;"> px# = screentoworldx(getrawtouchcurrentx(beingtouched))
</span><span style="font-size: 12px; white-space: pre;"> py# = screentoworldy(getrawtouchcurrenty(beingtouched))
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> setspritepositionbyoffset(usprite,px#,py#)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if getrawtouchreleased(beingtouched)=1
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> px# = screentoworldx(getrawtouchstartx(beingtouched))
</span><span style="font-size: 12px; white-space: pre;"> py# = screentoworldy(getrawtouchstarty(beingtouched))
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> xtile = trunc((px#+32)/64)
</span><span style="font-size: 12px; white-space: pre;"> ytile = trunc((py#+32)/64)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if StorageArea[xtile,ytile].armbonusid>0
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> xend# = screentoworldx(getrawtouchlastx(beingtouched))
</span><span style="font-size: 12px; white-space: pre;"> yend# = screentoworldy(getrawtouchlasty(beingtouched))
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> xetile = trunc((xend#+32)/64)
</span><span style="font-size: 12px; white-space: pre;"> yetile = trunc((yend#+32)/64)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> dext = trunc(xetile - xtile)
</span><span style="font-size: 12px; white-space: pre;"> deyt = trunc(yetile - ytile)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if StorageArea[xtile,ytile].armbonusid=1 or StorageArea[xtile,ytile].armbonusid=2
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if abs(dext)>2.0 or abs(deyt)>2.0
</span><span style="font-size: 12px; white-space: pre;"> p = StorageArea[xtile,ytile].armplayerid
</span><span style="font-size: 12px; white-space: pre;"> b = StorageArea[xtile,ytile].armbonusid</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if abs(dext)>abs(deyt)
</span><span style="font-size: 12px; white-space: pre;"> if dext>0
</span><span style="font-size: 12px; white-space: pre;"> dext = xtile+2
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;"> dext = xtile
</span><span style="font-size: 12px; white-space: pre;"> xtile = xtile-2
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> deyt = ytile
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;"> dext = xtile
</span><span style="font-size: 12px; white-space: pre;"> if deyt>0
</span><span style="font-size: 12px; white-space: pre;"> deyt = ytile+2
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;"> deyt = ytile
</span><span style="font-size: 12px; white-space: pre;"> ytile = ytile-2
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> TriggerBonus(p, b, xtile, ytile, dext, deyt)
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if StorageArea[xtile,ytile].armbonusid=5 or StorageArea[xtile,ytile].armbonusid=12
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if abs(dext)>1.0 and abs(deyt)>1.0
</span><span style="font-size: 12px; white-space: pre;"> p = StorageArea[xtile,ytile].armplayerid
</span><span style="font-size: 12px; white-space: pre;"> b = StorageArea[xtile,ytile].armbonusid</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if dext>0.0
</span><span style="font-size: 12px; white-space: pre;"> dext = xtile+1
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;"> dext = xtile
</span><span style="font-size: 12px; white-space: pre;"> xtile = xtile-1
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if deyt>0.0
</span><span style="font-size: 12px; white-space: pre;"> deyt = ytile+1
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;"> deyt = ytile
</span><span style="font-size: 12px; white-space: pre;"> ytile = ytile-1
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> TriggerBonus(p, b, xtile, ytile, dext, deyt)
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if StorageArea[xtile,ytile].armbonusid=6 or StorageArea[xtile,ytile].armbonusid=11
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> p = StorageArea[xtile,ytile].armplayerid
</span><span style="font-size: 12px; white-space: pre;"> b = StorageArea[xtile,ytile].armbonusid</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> TriggerBonus(p, b, xtile, ytile, xtile, ytile)
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> StorageArea[xtile,ytile].armbonusid = 0</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> tsprite = StorageArea[xtile,ytile].ShroudSpriteID
</span><span style="font-size: 12px; white-space: pre;"> class = StorageArea[xtile,ytile].class
</span><span style="font-size: 12px; white-space: pre;"> if getspriteexists(tsprite)=0 and class>0 and xtile>1 and xtile<areamaxx and ytile>1 and ytile<areamaxy
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> for p=0 to 3
</span><span style="font-size: 12px; white-space: pre;"> if player[p].health>0
</span><span style="font-size: 12px; white-space: pre;"> psx# = getspritexbyoffset(Player[p].spriteid)
</span><span style="font-size: 12px; white-space: pre;"> psy# = getspriteybyoffset(Player[p].spriteid)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> tdist# = sqrt(((psx#-px#)^2)+((psy#-py#)^2))</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if dist#=0.0
</span><span style="font-size: 12px; white-space: pre;"> dist# = tdist#
</span><span style="font-size: 12px; white-space: pre;"> selectedplayer = p
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;"> if tdist#<dist#
</span><span style="font-size: 12px; white-space: pre;"> dist# = tdist#
</span><span style="font-size: 12px; white-space: pre;"> selectedplayer = p
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;"> spriteid = Player[p].TargetSpriteID
</span><span style="font-size: 12px; white-space: pre;"> setspritevisible(spriteid,0)
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> next p</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> spriteid = Player[selectedplayer].TargetSpriteID
</span><span style="font-size: 12px; white-space: pre;"> setspritevisible(spriteid,1)
</span><span style="font-size: 12px; white-space: pre;"> setspritepositionbyoffset(spriteid,xtile*64,ytile*64)
</span><span style="font-size: 12px; white-space: pre;"> Player[selectedplayer].TargetX = getspritexbyoffset(spriteid)
</span><span style="font-size: 12px; white-space: pre;"> Player[selectedplayer].TargetY = getspriteybyoffset(spriteid)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> px# = screentoworldx(getrawtouchstartx(beingtouched))
</span><span style="font-size: 12px; white-space: pre;"> py# = screentoworldy(getrawtouchstarty(beingtouched))
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> xtile = trunc((px#+32)/64)
</span><span style="font-size: 12px; white-space: pre;"> ytile = trunc((py#+32)/64)</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> if StorageArea[xtile,ytile].armbonusid>0
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> lx# = (64.0*xtile)-32.0
</span><span style="font-size: 12px; white-space: pre;"> ly# = (64.0*ytile)-32.0</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> ex# = screentoworldx(getrawtouchcurrentx(beingtouched))-32.0
</span><span style="font-size: 12px; white-space: pre;"> ey# = screentoworldy(getrawtouchcurrenty(beingtouched))-32.0</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> DrawLine( lx#, ly#, ex#, ey#, 255, 0, 0 )
</span><span style="font-size: 12px; white-space: pre;"> else
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> for p=0 to 3
</span><span style="font-size: 12px; white-space: pre;"> for b=1 to TotalBonusTypes
</span><span style="font-size: 12px; white-space: pre;"> if PlayerBonus[p,b].count > 0
</span><span style="font-size: 12px; white-space: pre;"> bspriteid = PlayerBonus[p,b].spriteid
</span><span style="font-size: 12px; white-space: pre;"> if getspritehittest(bspriteid,px#,py#)=1
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> usprite = clonesprite(bspriteid)
</span><span style="font-size: 12px; white-space: pre;"> setspritedepth(usprite,1)
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> PlayerBonus[p,b].UsingSprite = usprite
</span><span style="font-size: 12px; white-space: pre;"> setrawtouchvalue(beingtouched,usprite)
</span><span style="font-size: 12px; white-space: pre;"> p = 3
</span><span style="font-size: 12px; white-space: pre;"> b = TotalBonusTypes
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> next b
</span><span style="font-size: 12px; white-space: pre;"> next p
</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> endif</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> endif
</span><span style="font-size: 12px; white-space: pre;"> beingtouched = getrawnexttouchevent()</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;"> endwhile</span><span style="font-size: 12px; white-space: pre;">
</span><span style="font-size: 12px; white-space: pre;">endfunction</span> <span style="color: black; font-family: Consolas, 'Courier New', Courier, mono; font-size: 9pt; white-space: pre;"> </span>
The code above is reasonably complicated to follow, but it captures ALL of the touch commands within the game. These commands include:
- Setting the raider's target,
- Activating a decayer bonus,
- Dragging a one-shot bonus to arm a box,
- Dragging a one-shot bonus from an armed box,
What makes these commands more complicated is the fact that any one of four players could be making them, at the same time. Luckily the AGK language makes this possible with commands such as:
beingtouched = getrawfirsttouchevent(1)
The environment automatically detects the touch events and stores them in a list. The touch events are also catagorized into "short", "long", "drag" and "unknown" types. The command getrawfirsttouchevent(1) extracts the first touch event from this list. The parameter "1" allows all touch events, including the "unknown" types to be return.
The following parameters can be extracted, once the touch event ID has been returned:
- Start co-ordinates,
- Current co-ordinates,
- Last co-ordinates (kept for touch events that have been released)
- Released status,
- Duration of touch.
These features of the BASIC language enable me to develop the game quickly.
The entire loop to control each round is shown below:
repeat
FrameTime = (getframetime()*1000)
SecondCounter = SecondCounter-FrameTime
CheckTraps()
DetermineTouchInput()
if HumanPlayers<4
for p=0 to 3
if player[p].Human < 1 and player[p].health>0
MoveAI(p)
endif
next p
endif
MovePlayers()
AnimatePlayers()
MoveNewBonuses()
ManageActiveBonuses()
if SecondCounter<=0
for p=0 to 3
PlayerLevelStats[p].TimeTaken = PlayerLevelStats[p].TimeTaken +1
next p
SecondCounter = SecondCounter+1000
endif
if getrawkeyreleased(13)=1 then FakeExit = 1
sync()
until InNodeZone>3000 or FakeExit = 1
The AGK IDE compiles the source code into byte code which an optimised "player" runs. The player utilises Open GL and has been specifically developed to maintain a high frame rate when handing a large number of sprites.
The game started development in early August and has already reached a playable mature alpha-state, as the video link shows and which can be downloaded here. To ensure compatibility of the game with the AIO PC, the game is being developed and tested on a Windows8 Ultrabook. An Ultrabook is being used primarily since this device also has a touch-screen interface and has the same operating system as the AIO. Although the screen size and overall power of the Ultrabook is inferior to the AIO, these restrictions ensure a high level of performance will be possible on the AIO and development on a second machine ensures the development environment does not influence the installation of the game.
Points of Interest
The Lenovo All-In-One PC is ideal for running multi-player borard-games such as the Mothernode. The Mothernode game takes full advantage of the AIO's large 27" screen, its 10-point multi-touch feature and it's Striker accessories to give the players a real-time multi-player board game experience like no other.