Quantcast
Channel: Envato Tuts+ Game Development
Viewing all 728 articles
Browse latest View live

20 Cinematic Music Tracks to Inspire and Excite Your Next Video

$
0
0

Your choice of music can be everything when it comes to your video project. We've put together some of our favourite pieces, loosely categorised to make it easy for you to find what you want.

emotional
Photograph via Photodune

Melodic and Emotional Audio Tracks

Inspiring Piano And Emotional Orchestra

A beautiful and inspiring melodic piano piece, which kicks into rousing orchestra – perfect for films, presentations or YouTube videos that are ready to tug on the heartstrings.

Inspiring Moments

This track download comes with three versions of differing lengths to suit your project. It’s relaxing and emotional throughout.

Piano Trailer

Suitable for cinematic scenes, inspiring projects slow motion videos and much more, the Piano Trailer download comes with 5 versions

Dreams

A light, magical and inspiring piece, this track is based on grand piano and an airy soundscape of electronic and acoustic instruments.

dramatic
Image via Photodune

Powerful and Dramatic Audio Tracks

Hybrid Trailer

A modern Hollywood Marvel inspired trailer cue with an intense build up and dramatic, cinematic impacts.

Inspiring Cinematic Trailer

Motivational, powerful and inspiring cinematic orchestral music with a bright, triumphant and adventurous atmosphere.

The Cinematic

With 5 versions to choose from, The Cinematic is a powerful and intense piece, great for use in game trailers, film openers and much more.

Epic

A motivational orchestral piece featuring strings, horns and percussion. A calm introduction builds, calms, builds and finally calms again into a soft piano finish.

Epic Inspirational

Including three versions, this Epic Inspirational track is a powerful one for your video, commercial or media project.

Emotional Cinematic Trailer

With a straight build, to an epic climax, this track covers everything in order to cater to every need. It’s especially good for montage projects.

Uplifting
Image via Photodune

Uplifting and Inspirational Audio Tracks

Uplifting & Inspiring Emotional Adventure Trailer

With a longer and shorter version included in the download, the Uplifting and Inspiring Emotional Adventure Trailer piece will have you scaling the greatest of heights. Metaphorically of course.

Uplifting Indie Rock

An uplifting, cool, driving indie rock track. This piece carries the spirit of progress and positivity, in a very chill rock ‘n’ roll kind of way.

Inspiring

Inspiring is a strong, moving and emotional cinematic piece. Create a great atmosphere for your film, trailer, presentations and much more

Majestic Orchestra

This majestic, powerful and uplifting orchestral piece is the perfect fit for movies, games, trailers and more.

Gravity's Rainbow

Gravity’s Rainbow is powerful, melodic dubstep track with a catchy uplifting chorus. It contains multiple and different emotional builds.

Timeless City

Timeless City is a track that shares characteristics from different genres like downtempo, chill step, uplifting trance and chill out, all combined in a unique way.

Open The Sky

Open the Sky is a dreamy dubstep track featuring beautiful pads, deep bass sounds and includes an instrumental version without the vocals.

Absorbed by Space

 Absorbed by Space begins with piercing, clear sounds, full of mystery. Sounds in this piece are varied, but the tones are rounded and polished in a way that resembles fluidity.

Hip-Hop Background Beat

A usefully looping track, Hip-Hop Background Beat is a light hip-hop track with a deliberately young, urban sound. 

Coda

If you're as emotionally wrung out as we are after listening to so many pieces of wonderful music, then take a few minutes to look at these other articles to help you to nail your film project's music.


Making Healing Fun

$
0
0

What is best in games? To crush your enemies, see them driven before you, and get cool weapon upgrades? Sadly, the alternative answer—"to heal the sick, bring people together, and make everyone happy"—never really took off. 

This is the heart of most games. As designers, we spend hours upon hours designing unique weapons and devious traps, but when it comes to healing, we mostly just say, "Oh, and we'll throw in some health packs." Healing isn't cool.

But why does it have to be like this? Why is it that no one ever wants to be the healer? Is it even possible to make healing fun? Lets look a bit more into how healing works, and examine why things are like this.

Quake Image
In the original Quake, healthpacks such as this were scattered through the landscape.

What Is Health?

First, we need to understand the purpose health serves in a game. 

The most fundamental purpose of health is to provide a win/lose system for the player. In almost any game with combat, be it roleplaying games, beat-em-ups, or even card games, the goal is simple: make their health hit zero first. 

Generally speaking, health is an all-or-nothing attribute—it has no impact on the game until you run out. Some games do try to make health a bit more nuanced by implementing "pain", where your crosshair wobbles a bit or you limp, but generally, these are minor inconveniences at best.

But because health is something the player can control to an extent, it's also a resource. Players will often make decisions based on the amount of health they have left, and will often be willing to "trade" health for other benefits. 

At a basic level, this includes things like rocket jumping or running through heavy fire to secure an objective, but also includes more complex concepts like using low health to bait enemies into an ambush.

You might ask, "What about health in other games, like Surgeon Simulator or Trauma Centre?" Yes, there is a sort of health system, but these games are puzzle games, and the health concept is really just a thematic way of giving the player a timer. Conversely, there are games which use "health in disguise", such as shields, hunger, or fatigue. As a general rule, if you die when it hits zero, it's health.

Sleepwalker
In Sleepwalker, the player controls an invincible dog named Ralph. However, the player can lose if Lee (the human) wakes up. At the top of the screen is the "sleep bar".

So Why Do We Heal? 

Why is it important to heal? Simply, because healing allows us to progress through the game. A traditional RPG might have the players encounter several groups of goblins before a big boss fight. If the player wasn't allowed to heal, then minor wounds sustained during the adventure might make the boss fight impossible. 

Healing allows the players to treat each fight as a separate combat, and means that the final boss fight can feel like a properly epic clash, rather than forcing the players to use cheap tactics because everyone arrived on 1 hitpoint. Most combat games follow the same idea, allowing players a brief respite and a chance to heal between skirmishes.

For most fighting games, healing is less important. In a game like Street Fighter or Mortal Kombat, the player only has one fight. In a campaign/story mode, the player starts each fight on full health, negating the need for healing (although some characters might have special moves which restore a minor amount of health). We don't really need a healing mechanic because our health is automatically reset each fight.

The resetting of health is a massively important concept to keeping the player engaged in the game. We've talked before about frustrating the player, and how important it is to keep the player engaged. Imagine playing a game where you finish a large combat, only to stroll into the next room and be instantly killed by the weakest enemy in the game. 

Worse, imagine finishing that fight and knowing that the next room will kill you. What do you do? In order to progress the game, your only option is to walk forward into certain death? Locking a player into an unwinnable situation is massively frustrating.

Super Smash Bros Melee
Smash Brothers Melee's "Endless Mode". A never-ending stream of wireframes attack you, and the challenge is to last as long as possible. A trophy is awarded for beating 100.

Then Why Is Healing Bad?

The problem we have is that when a player is healing, they're not really taking part in the game. Wandering around looking for healthpacks isn't exciting, and if there are no healthpacks available then the player might find themselves stuck in an unwinnable situation. This is one of the reasons the original Halo did so well, being arguably the first mainstream FPS to utilise a regenerating health.

The existence of healthpacks also pose another problem: sudden health spikes. Because health bars act as a sort of "goal", players can use enemy health as a progress bar. It can be frustrating for you to reduce an enemy to 3 hitpoints, only to have them run over a healthpack and be restored to full health. Healing potions are often guilty of this as well, as players can stock up before battle, ensuring victory is given to the player who simply brought the most potions to the fight.

The solution to all this is reasonably simple: allow players to heal as much as they want, once combat has finished. There are a few ways do go about this:

  • Regenerating health (or shields), used in games like Halo.
  • Food and drink, as used in games like World of Warcraft, which is really just a slightly fancier out-of-combat regeneration health option. Players must take a few moments to sit down and replenish their health and mana reserves. The benefit with food and drink is that it feels slightly more "sensible" than health magically regenerating, and forcing the player to sit down while they heal can be considered a good way to set a calm, resting feeling.
  • Return to base: popular with MOBAs like League of Legends, where returning to your home fountain will very rapidly heal you up. 
  • Potions which slowly regenerate health, rather than ones which cause health spikes.
  • Healing points: special map points which heal players inside. These healing stations can be put as objectives for players to fight over, or simply deployed as "forward bases" for wounded players to retreat to. 
Archon Ultra
In Archon Ultra, the game is played on a chess-like field, which switches to an overhead combat minigame when combat is initiated. Healing squares on the main board will be present in the minigame.

So What About the Medic?

The existence of healers provides a whole new range of problems for most games. The healer is one of the "holy trinity" of class design (tank-damage-healer), so most games with some sort of role selection have at least one healer.

The biggest issue is that if a game has healer, then self-healing players render the healer redundant. Some games have decided that only the healer can restore health—which then means that the healer is, ultimately, the only class which is 100% mandatory. 

Sadly, the healer is also frequently the least interesting class to play, meaning that the healer role becomes something that players need to play (in order to win), rather than something they want to play. In Team Fortress 2, the medic is by far and away the least popular class, as can be seen in this graph.

This isn't unique to Team Fortress 2, however, as pretty much any game which features a "support" role will struggle to find players who want to play that role. There are several reasons for this: 

  • Support classes tend to have less of a visible impact on the game, which feels unrewarding.
  • They tend not to be the ones to score kills and objectives (which, once again, feels less rewarding).
  • Games tend to verbally/visually reward players for killstreaks and multi-kills, but very rarely for a "heal streak" or "well-timed shield"—once again, less rewarding.
  • Playing a support class is effectively sacrificing personal power for team power, which rewards those playing non-support classes.
  • Playing a healer often means following other players around, effectively putting the player on a leash, removing their agency.
  • And, for many online games, being a healer means being blamed by other players. 

For the most part, there is an obvious theme here. A large part of the problem comes from the fact that while a player is supporting, they're not really playing the game. A healer needs to spend all their time healing, not hitting objectives and shooting bombs. The choices a player makes are minimal, and they don't get the same level of satisfaction from doing well. For most players, being the healer means sacrificing fun to win.

League of Legends Image
For League of Legends players, few things are more coveted than the legendary "pentakill"—when a single player kills all five members of the enemy team. While the rest of the team may help, the glory goes to the one that scores the kills. Image taken from match  "TSM vs IMT NA LCS 2016".

Keeping Healers Involved

Most of these problems come from traditional views of how a healer should be designed. There's nothing necessarily wrong with the idea of a healer class, but the "pure healer" approach to design is often flawed. As we mentioned earlier, in many games, having a healer in the team is necessary for success. Because of this, healers are often kept out of danger—and out of the action. 

One option for this is to remove the healer class and allow players to deal with healing themselves. If everyone has access to regenerating health, for example, then the use of a healer becomes more of a choice. Healers can still exist, but their skillset can be geared towards combat healing and allowing them to participate in the action.

It's also possible to make combat-capable healers—or, at least, make healers that don't have to focus exclusively on healing. Here are some examples of games that tried to make healing a little more interesting:

In the now defunct Warhammer Online, there were six different healer classes, with a variety of abilities. Most notably, the human and dark elf healers gained healing power for being in melee combat, making them effective front-line healers and rewarding them for getting into combat. Similarly, goblin shamans had a sort of yin/yang design for damage and healing, which meant that casting a spell of one type would give a boost to the other. Effective play meant that the player had to cast a mix of healing and damage spells.

In Paladins, classes are given specific roles, but all roles are expected to be engaged in combat. The healer classes are all capable combatants, and healing is often a "fire and forget" affair. 

As an example, Grohk can simply drop a totem which has an ongoing AOE heal effect, and Pip can throw a "healing bomb" which heals everyone within a short area. Grover, a tanky frontline healer, has a passive healing aura—everyone near him will slowly regenerate health, meaning his presence is all that's required for a healing boost.

Finally, in Dystopia, players can choose one of three classes: light, medium, or heavy. Each class can be outfitted with a variety of abilities (implants), such as stealth, leg boosters, or thermal vision. 

The light and medium classes can be equipped with a mediplant, which passively uses energy to heal nearby wounded allies. This ability can be turned off to save energy, but the fact that the healing is automatic means the healer is free to concentrate on combat rather than wounded teammates.

All three of these games utilise a similar approach to the healer—namely, that the healer should be engaged in gameplay, and not hiding in the back lines babysitting allies who find themselves caught out of position. Players are still expected to participate in objective pushes and combat, and players who do attempt to sit back and heal people will not be a great asset to the team.  

Dystopia Image
In Dystopia, healers are noted by having a First Aid cross above their heads. Stand near one to automatically receive medical attention.

Making Healing Fun

But what if we want to make a traditional healing class? There's nothing wrong with that, but it's important to understand why healing roles traditionally fail.

The biggest issue is the idea of choice. As we've talked about in previous articles, choice is one of the most fundamental aspects of game design. Since the role of the healer is largely limited to "follow me and keep healing", the options they have tend to be very limited. In order to fix this, we simply need to give the player more options.

World of Warcraft manages this to a degree: healing classes have a range of spells, and balancing these spells is essential to maximising combat effectiveness. These spells will generally include:

  • a general purpose healing spell
  • a mana-intensive fast heal for emergencies
  • a slow but efficient heal-over-time spell
  • an area-of-effect heal for groups
  • a "one-use" extra powerful heal with a significant cooldown

By giving the healer a variety of heals, it allows them a lot more variation than simply clicking the same "heal" button over and over. Healing requires a balance of using heal spells effectively as well as making sure they don't draw aggro from the tank.

An alternative to this is giving the player a mixture of defensive spells, and letting them figure out which is the best. While this might not be suitable for all games, it's an option which can be considered. Imagine, for example, the following spells: 

  • Heal: Heals for 10% of health.
  • Rewind: Heal all damage from last attack.
  • Shield: Provides a health bonus equal to 20% for five seconds.
  • Resist: Halves all damage for three seconds.
  • Vampirism: Buff which gives health back for attacking enemies.

A variety of spells means the player needs to be able to react to specific situations better, rather than simply hitting the heal button over and over. There are a multitude of ways to make spells more interesting than simply "heal someone", and these are just some basic ideas. 

On top of this, if players are able to self-heal, then a healer doesn't even need to heal—they can throw buffs and debuffs around, protecting allies with shields and slowing enemies with curses. The core gameplay element is the same, but the player now has different options.

World of Warcraft image
Healers in World of Warcraft get powerful spells and fancy robes.

Rewarding the Healer

This is a small point, but worth bringing up again. Because game objectives traditionally revolve around scoring kills and securing objectives, healing can often feel unrewarding. To make matters worse, some games reward players that score kills with points, experience, or gold, whereas the healer might only get a fraction of that reward.

Make sure your healers feel as if they're contributing. If a healer does well, reward them. If your game has a scoreboard, make sure your healers and supports earn points for doing their job. If your only metric for success is having a positive kill:death ratio, then of course the healers are going to feel undervalued. 

If your healer throws up that shield at the right time, or gives you a speed boost so you can catch the wounded enemy, then they deserve the kill as much as you do. Statistics like lives saved, wards placed, 

Additionally, ensure that the healer feels rewarding to play. Many players don't notice healing—they only notice when they die—so the effect of healing can go unnoticed. Psychologically, players tend to favour big, splashy effects over subtle ones, even if the subtle effect is better. Compare a skill which continually heals all teammates nearby for a small amount, vs. a skill which provides an invulnerability shield for a few seconds. 

Even though constant healing is much better in any sort of extended fight, the invulnerability shield allows for clutch moments where a player is saved with a sliver of health. Team Fortress 2 allows medics to heal with the ubercharge, a powerful shield which provides eight seconds of invulnerability to the medic and a friend. It can be argued that the medics' true power lies in the ubercharge, which can be used to break stalemates or push important objectives.

As a word of warning, however, be aware that powerful healers can create very stagnant gameplay, which is why many games shy away from the idea. This was common in the early days of World of Warcraft, where druids generally had low damage, but high defence and healing power—meaning a duel between two druids would literally last forever, as they could simply outheal everything thrown at them. 

Its not unreasonable for a healer to desire the same sort of game-changing power that a mage or warrior might have, but if the healer is able to "lock the game down", then it's unlikely to be much fun for the opposing side.

Meet the medic image
From Team Fortress 2's video "Meet the medic".

Putting It All Together

At the end of the day, all of this depends on the type of game you're trying to make. Regenerating health isn't some sort of instant fix that automatically makes games good—in fact, sometimes it's important to not let the players heal. In an RPG setting, the players might have to go through several fights without being allowed to heal. 

This can increase tension, allow pacing to be maintained, and force the players to either retreat or approach combat in a more tactical way than "kill everything that moves".

Similarly, restricting access to healing can provide additional challenge. In a fighting game, the player might find be good at fighting 1v1, but what if they weren't allowed to heal between fights? Suddenly, combat changes—the player needs to be more aware of their environment, and combat becomes more of a risk. This concept is often used in survival games, where running away from enemies is as important as engaging.

It's also worth noting that many of these ideas are simple to apply to other concepts in game design as well. Ammo, mana, and even gold coins are limited resources. If the player finds themselves stuck in an unwinnable situation, then you need to look at giving them ways to get back into the game.

Ultimately, your game is your game, and there is no right and wrong way to do healing. What matters is making the game fun and keeping your players entertained. Like many other aspects of game design, these concepts are to be used or discarded at your leisure. 

If your gameplay revolves around pressing the same button over and over, then it's not likely to be very engaging. But if you can give your players a variety of choices and keep them on their toes, then it's much more likely that they'll have a good time.

Introducing SpriteKit

$
0
0

SpriteKit is Apple's 2D game engine—a rendering engine built on top of OpenGL. It was introduced with iOS 7, and each subsequent release has brought great additions to the framework. With the use of textured sprites, a built-in physics engine, and the very powerful SKAction class, you can very quickly build functional 2D games.

SpriteKit has built-in editors for scenes and particles, a camera node since the release of iOS9, and built-in support for tilesets since the release of iOS 10. With these new additions, SpriteKit is quickly becoming a powerhouse for creating 2D games.

Below is an image of the built-in scene editor, with a label, a colored sprite, and a textured sprite.

Scene Editor

Rendering Loop

SpriteKit, like most game engines, uses a rendering loop to render and update the screen. The rendering loop goes through the following steps in rendering each scene:

  1. Update the scene and its objects
  2. Evaluate actions
  3. Simulate physics
  4. Apply constraints
  5. Render the scene

Each of these steps has a corresponding method you can hook into to apply additional logic. The render loop methods are as follows:

  1. update
  2. didEvaluateActions
  3. didSimulatePhysics
  4. didApplyConstraints
  5. didFinishUpdate

For example, if you wanted to manually move objects in your scene, then the update method would be what you would use. Or if you had objects that were being affected by actions or physics, you could tie into the corresponding methods to make sure those actions and the physics simulation are applied before whatever changes you make.

SKNode

The SKNode class is the fundamental building block of SpriteKit. All of your onscreen assets will be an SKNode or subclass thereof.

The SKNode class does not draw any visual assets itself. Its primary role is to provide baseline behavior that other classes implement. For example, the SKScene class is the root node in a tree of SKNode instances and is used to hold sprites and other content that needs to be rendered. 

The rendering and animation are done by an SKView instance. The view is placed inside a window and an SKScene instance is added to it, and that scene will be rendered and animated as long as the view is active. You can use a single SKView instance in your window and switch between different scenes at any time.

The framework defines a number of other SKNode subclasses. The most common one used within a scene is the SKSpriteNode class. The SKSpriteNode class can be drawn either as a rectangle with an image mapped onto it with SKTexture, to create a sprite, or as a colored, untextured rectangle. You'll most often use textured sprites, because this is how you will bring your game's artwork to life. 

Other important types of nodes include:

  • SKShapeNode, which renders a shape defined by a Core Graphics path
  • SKVideo, which displays video content
  • SKLabel, which displays a text label

We'll look at several of these subclasses of SKNode later in this series.

SKAction

The SKAction class is a very powerful class that is used to bring your nodes to life. SKAction can change your node's properties over time, for example by moving, scaling, or rotating them. You can chain actions together in a sequence, execute many actions together as a group, and repeat them in a loop. You can also use SKAction to run a custom block of code. For example, suppose you wanted to print out the coordinates of a node after it has moved. You could run a custom block of code within the SKAction to do just that.

SpriteKit Features

Physics

SpriteKit has a built-in physics engine that makes handling complex physics scenarios a breeze. Built on top of the popular Box2D framework, it allows you to respond to collisions and contact events, apply forces and gravity, and build very complex physics simulations using joints, such as pins and springs. You can use the scene editor to visually add physics to the nodes, or you can add physics programmatically.

Coordinate System

In SpriteKit, the coordinate (0,0) is located at the bottom left of the screen instead of the top left, which you may be used to if you've worked with Flash, Corona, HTML5 Canvas, and many other game frameworks. Having the origin at the bottom left is an OpenGL convention, and SpriteKit follows it because SpriteKit uses OpenGL under the hood.

Particle System

SpriteKit has a very powerful particle engine which can be used to simulate particle systems such as fire and smoke. There is also a built-in particle editor where you can visually lay out particle systems. If you prefer to stick with code, you can program these systems from the ground up using nothing but code.

Below is an image of the particle editor with a fire-like particle system.

Particle Editor

Tiles

SpriteKit has a number of classes dedicated to building tiled layouts. Using tilemaps offers better memory usage than using a very large single image. The tiles can be arranged in rectangular, hexagonal, or isometric grids.

Below is an image of a tile map node using a rectangular grid.

Tile Map Node

Conclusion

These are a few of the highlights of the SpriteKit engine. I would suggest reading the SpriteKit overview to learn more about what it has to offer. To learn more about how to get started with SpriteKit, you should also check out Davis Allie's post here on Envato Tuts+.

Also, check out our SpriteKit courses! These will take you through all the steps of building your first SpriteKit game for iOS, even if you've never coded with SpriteKit before.

An Updated Primer for Creating Isometric Worlds, Part 1

$
0
0
Final product image
What You'll Be Creating

We have all played our fair share of amazing isometric games, be it the original Diablo, or Age of Empires or Commandos. The first time you came across an isometric game, you may have wondered if it was a 2D game or a 3D game or something completely different. The world of isometric games has its mystical attraction for game developers as well. Let us try to unravel the mystery of isometric projection and try to create a simple isometric world in this tutorial.

This tutorial is an updated version of my existing tutorial on creating isometric worlds. The original tutorial used Flash with ActionScript and is still relevant for Flash or OpenFL developers. In this new tutorial I have decided to use Phaser with JS code, thereby creating interactive HTML5 output instead of SWF output. 

Please be advised that this is not a Phaser development tutorial, but we are just using Phaser to easily communicate the core concepts of creating an isometric scene. Besides, there are much better and easier ways to create isometric content in Phaser, such as the Phaser Isometric Plugin

For the sake of simplicity, we will use the tile-based approach to create our isometric scene.

1. Tile-Based Games

In 2D games using the tile-based approach, each visual element is broken down into smaller pieces, called tiles, of a standard size. These tiles will be arranged to form the game world according to pre-determined level data—usually a two-dimensional array.

Related Posts

Usually tile-based games use either a top-down view or a side view for the game scene. Let us consider a standard top-down 2D view with two tiles—a grass tile and a wall tile—as shown here:

Green and Maroon tiles

Both of these tiles are square images of the same size, hence the tile height and tile width are the same. Let us consider a game level which is a grassland enclosed on all sides by walls. In such a case, the level data represented with a two-dimensional array will look like this:

Here, 0 denotes a grass tile and 1 denotes a wall tile. Arranging the tiles according to the level data will produce our walled grassland as shown in the image below:

Top view level - grass area surrounded by walls

We can go a bit further by adding corner tiles and separate vertical and horizontal wall tiles, requiring five additional tiles, which leads us to our updated level data:

Check out the image below, where I have marked the tiles with their corresponding tile numbers in the level data:

Better top view level with corner tiles and tile numbers

Now that we have understood the concept of the tile-based approach, let me show you how we can use a straightforward 2D grid pseudo code to render our level:

If we use the above tile images then the tile width and tile height are equal (and the same for all tiles), and will match the tile images' dimensions. So the tile width and tile height for this example are both 50 px, which makes up the total level size of 300 x 300 px—that is, six rows and six columns of tiles measuring 50 x 50 px each.

As discussed earlier, in a normal tile-based approach, we either implement a top-down view or a side view; for an isometric view, we need to implement the isometric projection.

2. Isometric Projection

The best technical explanation of what isometric projection means, as far as I'm aware, is from this article by Clint Bellanger:

We angle our camera along two axes (swing the camera 45 degrees to one side, then 30 degrees down). This creates a diamond (rhombus) shaped grid where the grid spaces are twice as wide as they are tall. This style was popularized by strategy games and action RPGs. If we look at a cube in this view, three sides are visible (top and two facing sides).

Although it sounds a bit complicated, actually implementing this view is very easy. What we need to understand is the relation between 2D space and the isometric space—that is, the relation between the level data and the view; the transformation from top-down Cartesian coordinates to isometric coordinates. The image below shows the visual transformation:

Side by side view of top down and isometric grids

Placing Isometric Tiles

Let me try to simplify the relationship between level data stored as a 2D array and the isometric view—that is, how we transform Cartesian coordinates into isometric coordinates. We will try to create the isometric view for our now-famous walled grassland. The 2D view implementation of the level was a straightforward iteration with two loops, placing square tiles offsetting each with the fixed tile height and tile width values. For the isometric view, the pseudo code remains the same, but the placeTile() function changes.

The original function just draws the tile images at the provided coordinates x and y, but for an isometric view we need to calculate the corresponding isometric coordinates. The equations to do this are as follows, where isoX and isoY represent isometric x- and y-coordinates, and cartX and cartY represent Cartesian x- and y-coordinates:

Yes, that is it. These simple equations are the magic behind isometric projection. Here are Phaser helper functions which can be used to convert from one system to another using the very convenient Point class:

So we can use the cartesianToIsometric helper method to convert the incoming 2D coordinates into isometric coordinates inside the placeTile method. Apart from this, the rendering code remains the same, but we need to have new images for the tiles. We cannot use the old square tiles used for our top-down rendering. The image below shows the new isometric grass and wall tiles along with the rendered isometric level:

Isometric level walled grassland along with the isometric tiles used

Unbelievable, isn't it? Let's see how a typical 2D position gets converted to an isometric position:

Similarly, an input of [0, 0] will result in [0, 0], and [10, 5] will give [5, 7.5].

For our walled grassland, we can determine a walkable area by checking whether the array element is 0 at that coordinate, thereby indicating grass. For this we need to determine the array coordinates. We can find the tile's coordinates in the level data from its Cartesian coordinates using this function:

(Here, we essentially assume that tile height and tile width are equal, as in most cases.) 

Hence, from a pair of screen (isometric) coordinates, we can find tile coordinates by calling:

This screen point could be, say, a mouse click position or a pick-up position.

Registration Points

In Flash, we could set arbitrary points for a graphic as its centre point or [0,0]. The Phaser equivalent is Pivot. When you place the graphic at say [10,20], then this Pivot point will get aligned with [10,20]. By default, the top left corner of a graphic is considered its [0,0] or Pivot. If you try to create the above level using the code provided, then you will not get the displayed result. Instead, you will get a flat land without the walls, like below:

The issue with wall tiles when rendered normally

This is because the tile images are of different sizes and we are not addressing the height attribute of the wall tile. The below image shows the different tile images that we use with their bounding boxes and a white circle where their default [0,0] is:

How to properly align the different tiles along with their registration points

See how the hero gets misaligned when drawing using the default pivots. Also notice how we lose the height of the wall tile if drawn using default pivots. The image on the right shows how they need to be properly aligned so that the wall tile gets its height and the hero gets placed in the middle of the grass tile. This issue can be solved in different ways.

  1. Make all tiles in the same image size with the graphic aligned properly within the image. This creates a lot of empty areas within each tile graphic.
  2. Set pivot points manually for each tile so that they align properly.
  3. Draw tiles with specific offsets so that they align properly.

For this tutorial, I have chosen to use the third method so that this works even with a framework without the ability to set pivot points.

3. Moving in Isometric Coordinates

We will never try to move our character or projectile in isometric coordinates directly. Instead, we will manipulate our game world data in Cartesian coordinates and just use the above functions for updating those on the screen. For example, if you want to move a character forward in the positive y-direction, you can simply increment its y property in 2D coordinates and then convert the resulting position to isometric coordinates:

This will be a good time to review all the new concepts that we have learned so far and to try and create a working example of something moving in an isometric world. You can find the necessary image assets in the assets folder of the source git repository.

Depth Sorting

If you tried to move the ball image in our walled garden then you would come across the problems with depth sorting. In addition to normal placement, we will need to take care of depth sorting for drawing the isometric world, if there are moving elements. Proper depth sorting makes sure that items closer to the screen are drawn on top of items farther away.

The simplest depth sorting method is simply to use the Cartesian y-coordinate value, as mentioned in this Quick Tip: the further up the screen the object is, the earlier it should be drawn. This may work well for very simple isometric scenes, but a better way will be to redraw the isometric scene once a movement happens, according to the tile's array coordinates. Let me explain this concept in detail with our pseudo code for level drawing:

Imagine our item or character is on the tile [1,1]—that is, the topmost green tile in the isometric view. In order to properly draw the level, the character needs to be drawn after drawing the corner wall tile, both the left and right wall tiles, and the ground tile, like below:

Hero standing on the corner tile

If we follow our draw loop as per the pseudo code above, we will draw the middle corner wall first, and then will continue to draw all the walls in the top right section until it reaches the right corner. 

Then, in the next loop, it will draw the wall on the left of the character, and then the grass tile on which the character is standing. Once we determine this is the tile which occupies our character, we will draw the character after drawing the grass tile. This way, if there were walls on the three free grass tiles connected to the one on which the character is standing, those walls will overlap the character, resulting in proper depth sorted rendering.

4. Creating the Art

Isometric art can be pixel art, but it doesn't have to be. When dealing with isometric pixel art, RhysD's guide tells you almost everything you need to know. Some theory can be found on Wikipedia as well.

When creating isometric art, the general rules are:

  • Start with a blank isometric grid and adhere to pixel-perfect precision.
  • Try to break art into single isometric tile images.
  • Try to make sure that each tile is either walkable or non-walkable. It will be complicated if we need to accommodate a single tile that contains both walkable and non-walkable areas.
  • Most tiles will need to seamlessly tile in one or more directions.
  • Shadows can be tricky to implement, unless we use a layered approach where we draw shadows on the ground layer and then draw the hero (or trees, or other objects) on the top layer. If the approach you use is not multi-layered, make sure shadows fall to the front so that they won't fall on, say, the hero when he stands behind a tree.
  • In case you need to use a tile image larger than the standard isometric tile size, try to use a dimension which is a multiple of the iso tile size. It is better to have a layered approach in such cases, where we can split the art into different pieces based on its height. For example, a tree can be split into three pieces: the root, the trunk, and the foliage. This makes it easier to sort depths as we can draw pieces in corresponding layers which correspond with their heights.

Isometric tiles that are larger than the single tile dimensions will create issues with depth sorting. Some of the issues are discussed in these links:

Related Posts

5. Isometric Characters

First we will need to fix how many directions of motion are permitted in our game—usually, games will provide four-way movement or eight-way movement. Check out the image below to understand the correlation between the 2D space and isometric space:

The directions of motion in top view and isometric view

Please note that a character would be moving vertically up when we press the up arrow key in a top-down game, but for an isometric game the character will move at a 45-degree angle towards the top right corner. 

For a top-down view, we could create one set of character animations facing in one direction, and simply rotate them for all the others. For isometric character art, we need to re-render each animation in each of the permitted directions—so for eight-way motion, we need to create eight animations for each action. 

For ease of understanding, we usually denote the directions as North, North-West, West, South-West, South, South-East, East, and North-East. The character frames below show idle frames starting from South-East and going clockwise:

The different frames of the character facing the different directions

We will place characters in the same way that we placed tiles. The movement of a character is accomplished by calculating the movement in Cartesian coordinates and then converting to isometric coordinates. Let us assume we are using the keyboard to control the character.

We will set two variables, dX and dY, based on the directional keys pressed. By default, these variables will be 0 and will be updated as per the chart below, where UDR, and L denote the UpDownRight, and Left arrow keys, respectively. A value of 1 under a key represents that the key is being pressed; 0 implies that the key is not being pressed.

Now, using the values of dX and dY, we can update the Cartesian coordinates like so:

So dX and dY stand for the change in the x- and y-positions of the character, based on the keys pressed. We can easily calculate the new isometric coordinates, as we've already discussed:

Once we have the new isometric position, we need to move the character to this position. Based on the values we have for dX and dY, we can decide which direction the character is facing and use the corresponding character art. Once the character is moved, please don't forget to repaint the level with the proper depth sorting as the tile coordinates of the character may have changed.

Collision Detection

Collision detection is done by checking whether the tile at the newly calculated position is a non-walkable tile. So, once we find the new position, we don't immediately move the character there, but first check to see what tile occupies that space.

In the function isWalkable(), we check whether the level data array value at the given coordinate is a walkable tile or not. We must take care to update the direction in which the character is facing—even if he does not move, as in the case of him hitting a non-walkable tile.

Now this may sound like a proper solution, but it will only work for items without volume. This is because we are only considering a single point, which is the midpoint of the character, to calculate collision. What we really need to do is to find all the four corners of the character from its available 2D midpoint coordinate and calculate collisions for all of those. If any corner is falling inside a non-walkable tile, then we should not move the character.

Depth Sorting With Characters

Consider a character and a tree tile in the isometric world, and they both have the same image sizes, however unrealistic that sounds.

To properly understand depth sorting, we must understand that whenever the character's x- and y-coordinates are less than those of the tree, the tree overlaps the character. Whenever the character's x- and y-coordinates are greater than that of the tree, the character overlaps the tree. When they have the same x-coordinate, then we decide based on the y-coordinate alone: whichever has the higher y-coordinate overlaps the other. When they have the same y-coordinate then we decide based on the x-coordinate alone: whichever has the higher x-coordinate overlaps the other.

As explained earlier, a simplified version of this is to just sequentially draw the levels starting from the farthest tile—that is, tile[0][0]—and then draw all the tiles in each row one by one. If a character occupies a tile, we draw the ground tile first and then render the character tile. This will work fine, because the character cannot occupy a wall tile.

6. Demo Time!

This is a demo in Phaser. Click to focus on the interactive area and use your arrow keys to move the character. You may use two arrow keys to move in the diagonal directions.

You can find the complete source for the demo in the source repository for this tutorial.

Updated Primer for Creating Isometric Worlds, Part 2

$
0
0
Final product image
What You'll Be Creating

In this final part of the tutorial series, we'll build on the first tutorial and learn about implementing pickups, triggers, level swapping, path finding, path following, level scrolling, isometric height, and isometric projectiles.

1. Pickups

Pickups are items that can be collected within the level, normally by simply walking over them—for example, coins, gems, cash, ammo, etc.

Pickup data can be accommodated right into our level data as below:

In this level data, we use 8 to denote a pickup on a grass tile (1 and 0 represent walls and walkable tiles respectively, as before). This could be a single tile image with a grass tile overlaid with the pickup image. Going by this logic, we will need two different tile states for every tile which has a pickup, i.e. one with pickup and one without to be shown after the pickup gets collected.

Typical isometric art will have multiple walkable tiles—suppose we have 30. The above approach means that if we have N pickups, we will need N x 30 tiles in addition to the 30 original tiles, as each tile will need to have one version with pickups and one without. This is not very efficient; instead, we should try to dynamically create these combinations. 

To solve this, we could use the same method we used to place the hero in the first tutorial. Whenever we come across a pickup tile, we will place a grass tile first and then place the pickup on top of the grass tile. This way, we just need N pickup tiles in addition to 30 walkable tiles, but we would need number values to represent each combination in the level data. To solve the need for N x 30 representation values, we can keep a separate pickupArray to exclusively store the pickup data apart from the levelData. The completed level with the pickup is shown below:

Isometric level with coin pickup

For our example, I am keeping things simple and not using an additional array for pickups.

Picking Up Pickups

Detecting pickups is done in the same way as detecting collision tiles, but after moving the character.

In the function onPickupTile(), we check whether the levelData array value at the heroMapTile coordinate is a pickup tile or not. The number in the levelData array at that tile coordinate denotes the type of pickup. We check for collisions before moving the character but need to check for pickups afterwards, because in the case of collisions the character should not occupy the spot if it is already occupied by the collision tile, but in case of pickups the character is free to move over it.

Another thing to note is that the collision data usually never changes, but the pickup data changes whenever we pick up an item. (This usually just involves changing the value in the levelData array from, say, 8 to 0.)

This leads to a problem: what happens when we need to restart the level, and thus reset all pickups back to their original positions? We do not have the information to do this, as the levelData array has been changed as the player picked up items. The solution is to use a duplicate array for the level while in play and to keep the original levelData array intact. For instance, we use levelData and levelDataLive[], clone the latter from the former at the start of the level, and only change levelDataLive[] during play.

For the example, I am spawning a random pickup on a vacant grass tile after each pickup and incrementing the pickupCount. The pickupItem function looks like this.

You should notice that we check for pickups whenever the character is on that tile. This can happen multiple times within a second (we check only when the user moves, but we may go round and round within a tile), but the above logic won't fail; since we set the levelData array data to 0 the first time we detect a pickup, all subsequent onPickupTile() checks will return false for that tile. Check out the interactive example below:

2. Trigger Tiles

As the name suggests, trigger tiles cause something to happen when the player steps on them or presses a key when on them. They might teleport the player to a different location, open a gate, or spawn an enemy, to give a few examples. In a sense, pickups are just a special form of trigger tiles: when the player steps on a tile containing a coin, the coin disappears and their coin counter increases.

Let's look at how we could implement a door that takes the player to a different level. The tile next to the door will be a trigger tile; when the player presses the x key, they'll proceed to the next level.

Isometric level with doors  trigger tiles

To change levels, all we need to do is swap the current levelData array with that of the new level, and set the new heroMapTile position and direction for the hero character. Suppose there are two levels with doors to allow passing between them. Since the ground tile next to the door will be the trigger tile in both levels, we can use this as the new position for the character when they appear in the level.

The implementation logic here is the same as for pickups, and again we use the levelData array to store trigger values. For our example, 2 denotes a door tile, and the value beside it is the trigger. I have used 101 and 102 with the basic convention that any tile with a value greater than 100 is a trigger tile and the value minus 100 can be the level which it leads to:

The code for checking for a trigger event is shown below:

The function triggerListener() checks whether the trigger data array value at the given coordinate is greater than 100. If so, we find which level we need to switch to by subtracting 100 from the tile value. The function finds the trigger tile in the new levelData, which will be the spawn position for our hero. I have made the trigger to be activated when x is released; if we just listen for the key being pressed then we end up in a loop where we swap between levels as long as the key is held down, since the character always spawns in the new level on top of a trigger tile.

Here is a working demo. Try picking up items by walking over them and swapping levels by standing next to doors and hitting x.

3. Projectiles

projectile is something that moves in a particular direction with a particular speed, like a bullet, a magic spell, a ball, etc. Everything about the projectile is the same as the hero character, apart from the height: rather than rolling along the ground, projectiles often float above it at a certain height. A bullet will travel above the waist level of the character, and even a ball may need to bounce around.

One interesting thing to note is that isometric height is the same as height in a 2D side view, although smaller in value. There are no complicated conversions involved. If a ball is 10 pixels above the ground in Cartesian coordinates, it could be 10 or 6 pixels above the ground in isometric coordinates. (In our case, the relevant axis is the y-axis.)

Let's try to implement a ball bouncing in our walled grassland. As a touch of realism, we'll add a shadow for the ball. All we need to do is to add the bounce height value to the isometric Y value of our ball. The jump height value will change from frame to frame depending on the gravity, and once the ball hits the ground we'll flip the current velocity along the y-axis.

Before we tackle bouncing in an isometric system, we'll see how we can implement it in a 2D Cartesian system. Let's represent the jump power of the ball with a variable zValue. Imagine that, to begin with, the ball has a jump power of 100, so zValue = 100

We'll use two more variables: incrementValue, which starts at 0, and gravity, which has a value of -1. Each frame, we subtract incrementValue from zValue, and subtract gravity from incrementValue in order to create a dampening effect. When zValue reaches 0, it means the ball has reached the ground; at this point, we flip the sign of incrementValue by multiplying it by -1, turning it into a positive number. This means that the ball will move upwards from the next frame, thus bouncing.

Here's how that looks in code:

The code remains the same for the isometric view as well, with the slight difference that you can use a lower value for zValue to start with. See below how the zValue is added to the isometric y value of the ball while rendering.

Check out the interactive example below:

Do understand that the role played by the shadow is a very important one which adds to the realism of this illusion. Also, note that we're now using the two screen coordinates (x and y) to represent three dimensions in isometric coordinates—the y-axis in screen coordinates is also the z-axis in isometric coordinates. This can be confusing!

4. Finding and Following a Path

Path finding and path following are fairly complicated processes. There are various approaches using different algorithms for finding the path between two points, but as our levelData is a 2D array, things are easier than they might otherwise be. We have well-defined and unique nodes which the player can occupy, and we can easily check whether they are walkable.

Related Posts

A detailed overview of pathfinding algorithms is outside of the scope of this article, but I will try to explain the most common way it works: the shortest path algorithm, of which A* and Dijkstra's algorithms are famous implementations.

We aim to find nodes connecting a starting node and an ending node. From the starting node, we visit all eight neighbouring nodes and mark them all as visited; this core process is repeated for each newly visited node, recursively. 

Each thread tracks the nodes visited. When jumping to neighbouring nodes, nodes that have already been visited are skipped (the recursion stops); otherwise, the process continues until we reach the ending node, where the recursion ends and the full path followed is returned as a node array. Sometimes the end node is never reached, in which case the path finding fails. We usually end up finding multiple paths between the two nodes, in which case we take the one with the smallest number of nodes.

Path Finding

It is unwise to reinvent the wheel when it comes to well-defined algorithms, so we would use existing solutions for our path-finding purposes. To use Phaser, we need a JavaScript solution, and the one I have chosen is EasyStarJS. We initialise the path-finding engine as below.

As our levelData has only 0 and 1, we can directly pass it in as the node array. We set the value of 0 as the walkable node. We enable diagonal walking capability but disable this when walking close to the corners of non-walkable tiles. 

This is because, if enabled, the hero may cut into the non-walkable tile while doing a diagonal walk. In such a case, our collision detection will not allow the hero to pass through. Also, please be advised that in the example I have completely removed the collision detection as that is no longer necessary for an AI-based walk example. 

We will detect the tap on any free tile inside the level and calculate the path using the findPath function. The callback method plotAndMove receives the node array of the resulting path. We mark the minimap with the newly found path.

Isometric level with the newly found path highlighted in minimap

Path Following

Once we have the path as a node array, we need to make the character follow it.

Say we want to make the character walk to a tile that we click on. We first need to look for a path between the node that the character currently occupies and the node where we clicked. If a successful path is found, then we need to move the character to the first node in the node array by setting it as the destination. Once we get to the destination node, we check whether there are any more nodes in the node array and, if so, set the next node as the destination—and so on until we reach the final node.

We will also change the direction of the player based on the current node and the new destination node each time we reach a node. Between nodes, we just walk in the required direction until we reach the destination node. This is a very simple AI, and in the example this is done in the method aiWalk shown partially below.

We do need to filter out valid click points by determining whether we've clicked within the walkable area, rather than a wall tile or other non-walkable tile.

Another interesting point for coding the AI: we do not want the character to turn to face the next tile in the node array as soon as he has arrived in the current one, as such an immediate turn results in our character walking on the borders of tiles. Instead, we should wait until the character is a few steps inside the tile before we look for the next destination. It is also better to manually place the hero in the middle of the current tile just before we turn, to make it all feel perfect.

Check out the working demo below:

5. Isometric Scrolling

When the level area is much larger than the available screen area, we will need to make it scroll.

Isometric level with 12x12 visible area

The visible screen area can be considered as a smaller rectangle within the larger rectangle of the complete level area. Scrolling is, essentially, just moving the inner rectangle inside the larger one. Usually, when such scrolling happens, the position of the hero remains the same with respect to the screen rectangle, commonly at the screen center. Interestingly, all we need to implement scrolling is to track the corner point of the inner rectangle.

This corner point, which we represent in Cartesian coordinates, will fall within a tile in the level data. For scrolling, we increment the x- and y-position of the corner point in Cartesian coordinates. Now we can convert this point to isometric coordinates and use it to draw the screen. 

The newly converted values, in isometric space, need to be the corner of our screen too, which means they are the new (0, 0). So, while parsing and drawing the level data, we subtract this value from the isometric position of each tile, and can determine if the tile's new position falls within the screen. 

Alternatively, we can decide we are going to draw only an X x Y isometric tile grid on screen to make the drawing loop efficient for larger levels. 

We can express this in steps as so:

  • Update Cartesian corner point's x- and y-coordinates.
  • Convert this to isometric space.
  • Subtract this value from the isometric draw position of each tile.
  • Draw only a limited predefined number of tiles on screen starting from this new corner.
  • Optional: Draw the tile only if the new isometric draw position falls within the screen.

Please note that the corner point is incremented in the opposite direction to the hero's position update as he moves. This makes sure that the hero stays where he is with respect to the screen. Check out this example (use arrows to scroll, tap to increase the visible grid).

A couple of notes:

  • While scrolling, we may need to draw additional tiles at the screen borders, or else we may see tiles disappearing and appearing at the screen extremes.
  • If you have tiles that take up more than one space, then you will need to draw more tiles at the borders. For example, if the largest tile in the whole set measures X by Y, then you will need to draw X more tiles to the left and right and Y more tiles to the top and bottom. This makes sure that the corners of the bigger tile will still be visible when scrolling in or out of the screen.
  • We still need to make sure that we don't have blank areas on the screen while we are drawing near the borders of the level.
  • The level should only scroll until the most extreme tile gets drawn at the corresponding screen extreme—after this, the character should continue moving in screen space without the level scrolling. For this, we will need to track all four corners of the inner screen rectangle, and throttle the scrolling and player movement logic accordingly. Are you up for the challenge to try implementing that for yourself?

Conclusion

This series is particularly aimed at beginners trying to explore isometric game worlds. Many of the concepts explained have alternate approaches which are a bit more complicated, and I have deliberately chosen the easiest ones. 

They may not fulfil most of the scenarios you may encounter, but the knowledge gained can be used to build upon these concepts to create more complicated solutions. For example, the simple depth sorting implemented will break when we have multi-storied levels and platform tiles moving from one story to the other. 

But that is a tutorial for another time. 

Tips and Tricks for Augmented Reality With Unity and Vuforia

$
0
0

Hello, Augmented Reality traveller! In this post, I'll show you some cool features of Vuforia that make it possible to create engaging AR apps. We'll take a look at Cube and Cylinder Targets, Smart Terrain, VuMarks, and more. We won't dive deep into any of those subjects, but I'll try to cover enough to get you started.

If you aren't familiar with Vuforia's main concepts, check out some of my earlier posts. They'll get you started building your first app with Vuforia, right from scratch.

1. Setting Up Vuforia on Unity

This section is just a review for those who have used Vuforia in the past. If you're already familiar with the process of preparing a Unity project for Vuforia, feel free to skip this section. 

Before using any of Vuforia’s resources on Unity, you’ll have to get the framework set up. First of all, you’ll have to download and import the Vuforia package for Unity.

Then you’ll need to create a License Key for the project in Vuforia's License Manager. Once it's created, you’ll take the key and insert it on an ARCamera prefab, and that’s it. Now you can start playing around with Vuforia.

I cover this process in depth with my tutorial Create a Pokémon GO Style Augmented Reality Game With Vuforia.

2. Designing an ImageTarget

There are multiple ways to create Augmented Reality experiences on Vuforia, and almost all of them rely on some kind of Target that must be recognized by Vuforia's algorithm to start the augmentation process. You can design a target yourself and submit it to Vuforia's Target Manager, making it recognizable by the system. However, this design must conform to some guidelines, otherwise the target won't be tracked easily, or it might not even be recognized at all.

You especially need to know how to design an ImageTarget. That's because a lot of other kinds of Vuforia targets are composed of multiple ImageTargets arranged in some specific position and order with a MultiTarget.

There are three main rules that an ImageTarget must comply with:

  1. It must be rich in detail.
  2. It must have a good contrast, with bright and dark regions.
  3. No repetitive patterns can be present.
An example image

In the background, Vuforia creates an arrangement of the image using its features, and then the algorithm can find such patterns and track the targets. Roughly, a feature in an image is a sharpened angle, like a box corner or the tip of a star. The quantity of features in an image is directly connected to its 'trackability'.

The edges of an image

However, it's important to understand that even hundreds of features in an image won't help if those features are arranged in a pattern. The ImageTargets need some grade of randomness and chaos to be properly recognized.

Patterns on ImageTarges

If you keep those rules in mind, you'll be able to create excellent ImageTargets, but if you need to know a little more, read the documentation.

3. Using MultiTarget

Also known as Cuboid Target, the MultiTarget consists of a series of ImageTargets in a defined geometric arrangement. This arrangement allows Vuforia's algorithm to track the targets at the same time, creating a volumetric reference. MultiTarget can be very useful in marketing campaigns to promote consumer interaction with product packages and so on.

3.1 Designing a MultiTarget

Basically, a MultiTarget design must conform to the same rules as an ImageTarget, adding two other concerns: the Depth of the box and its Geometric consistency

The box's Depth should be at least half of its width. This is only a recommendation, and it will work if it's a little smaller than that, but it's interesting to keep that in mind.

Also, Vuforia's algorithm expects consistency on all parts of the MultiTarget. That means that all of the sides of the box are expected to be in place. If this isn't possible, it would be possible to keep the removable part blank when creating the target in Target Manager. A cereal box lid, for example, could be left blank, otherwise once the lid was open it could generate inconsistencies during the augmentation.

3.2 Creating a MultiTarget

The first step is to add or select a database in Vuforia’s Target Manager. Select the database and click on Add Target, selecting the Cuboid option and setting its Width, Height, Length, andName.

Adding a Cuboid Target

After the MultiTarget has been created, select it and set its ImageTargets. As I mentioned, a MultiTarget is composed of a series of ImageTargets adjusted in a specific position. Each part of the cuboid must contain an image, and each image should comply with the cuboid’s proportion, defined when the target was created.

 

When the Cuboid is set, you’ll be ready to go. Just download the database and import it to Unity. To use it, drag a MultiTarget prefab to the stage, and select the downloaded database and Cuboid Target. To learn more about MultiTarget, take a look at the documentation.

4. Cylinder Targets

According to the Vuforia documentation, “CylinderTargets enable you to detect and track images rolled into cylindrical and conical shapes.” You can use this kind of interaction to create engagement with product packages, like soda cans or any other cylindrical product.

 

4.1 Designing a Cylinder Target

A CylinderTarget is also based on the ImageTarget, hence its design should conform to those rules. The top and bottom of the cylinder must be square images that will be marked by the Target Manager system. As with MultiTarget, you should consider the target's consistency, meaning that if a part of the object can be removed, it would be helpful to leave it blank on the manager.

4.2 Creating a Cylinder Target

This kind of target is created in two steps. The first one is toAdd or Select a database in Vuforia’s Target Manager, add a new Target, selecting the Cylinder option, and set its Dimensions and Name.

Adding a Cylinder Target

Next, you’ll need to select the CylinderTarget you created and upload images to it. You can upload one image for the side, one for the bottom, and one for the top. Just click on the desired section and upload the image.

Adding a cylinder target

However, the image must respect the cylinder’s ratio. It’s possible that your first attempt won’t work. But fear not, the Vuforia system will give you the correct ratio, and you can adjust your image proportions accordingly. For example, for a cylinder with width of 1 and height of 2, the ratio is 1.571. On a target side, the image’s height is equal to the width divided by the ratio. Once the ratio is correct, your upload will succeed.

Cylinder ratio error

Once the CylinderTarget is defined, you can use it. You’ll only have to download and import the database to Unity, and then drag a Vuforia CylinderTarget prefab to your scene, and you’re ready to go.

5. Smart Terrain

TheSmartTerrain is a feature exclusive to Unity that enables you to reconstruct and augment your physical environment. The feature reconstructs, recognizes, and tracks physical objects and surfaces. Those recognized objects can be used as terrain in Unity, opening up interesting possibilities for games and experiences.

The experience is started when some kind of Vuforia target is tracked. It could start when the device tracks an ImageTarget , a CylinderTarget, or any other type of target. 

Once started, the system will recognize objects distributed around the target and set the game stage considering those objects tracked. The terrain is then virtually projected over the scanned objects, and the experience begins.

Smart Terrain can recognize simple objects like boxes and cylinders, as long as they conform to Vuforia standards, putting those objects directly on the game stage and using them as part of the scene. 

Those kinds of objects are called Props by the SmartTerrain system, and their size can be as small as a soup can or as big as a large cereal box. Transparent objects such as glass are not supported.

SmartTerrain works in three phases:

  • Staging:the user distributes the target and the props.
  • Scanning:the stage and props used in the setting are captured and reconstructed by the Smart Terrain tracker.
  • Tracking:the terrain is augmented in real time by the Unity scene you've developed.

The creation process of a SmartTerrain experience is straightforward, but it takes a lot of steps. Since the Vuforia team provides us with an excellent step-by-step guide to creating a Smart Terrain experience in Unity, we won't dive into the creation process here. 

If you want to give it a try, follow the guide, and you shouldn’t have any problems. However, keep in mind that the SmartTerrain has certain limitations, especially concerning hardware and system requirements. You can find out more about the system in its documentation.

6. VuMark

A VuMark is a kind of target that can be fully customized. It can reflect specific design choices or a brand personality. It’s also extremely recognizable by the Vuforia tracking system, and it can start AR experiences or encode data.

VuMark examples

Before you start to play around with VuMark, it's good to understand that the creation process isn’t the simplest. The Vuforia team has put together a pretty good guide and some helpful tools, but I would recommend this solution only for specific situations where the design of the marker is of utmost importance.

I won't go into all the VuMark requirements and design processes. Instead, I'll just give you a general idea of the process and, if you decide to design your own VuMarker, you’ll probably need to read Vuforia’s guides first.

6.1 VuMark Design

It's vital to understand some architecture and design rules for VuMark, otherwise the target won't work properly.

A VuMark is composed of five parts:

  1. Contour: The contour isn’t actually drawn on the VuMark; it's defined by the contrast between the border and the clear space. It's the part that the Vuforia’s algorithm first detects.

  2. Border: The most identifiable and defining shape of the VuMark. It's made of straight lines, with at least four angles located at the outermost edge of the design.

  3. Clear Space: A mandatory blank area that appears adjacent to the border. It guarantees there is enough contrast for the algorithm to detect the contour.

  4. Code / Elements: The visual representation of the target’s ID. This is composed of elements with high contrast, which represent two states, dark and light. The number of elements present is defined when creating the VuMark Template in Illustrator using the tools provided by Vuforia. (More on this in the next section.)

  5. Background / Design Area: This area is a blank canvas that will be ignored by the algorithm. You can design freely on this space.

VuMark parts

To find out more about the design requirements, read the VuMarkDesign Guide.

6.2 Creating a VuMark

A VuMark is created using Adobe Illustrator and the VuMark Design Tools that are available for download on Vuforia’s site. The tools are comprised of three Illustrator scripts, which come with some examples and a detailed PDF guide.

Before starting a VuMark, you should design its concept, considering all the guidelines proposed by Vuforia. Once the design is complete, you’ll start to break it down into parts, obeying VuMark’s architecture.

The first step is to create a new VuMark template, using the VuMark-Setup.jsx illustrated script. In the VuMark Template Setup window, you can choose the mark’s name, ID type, and length. The number of characters encoded in the mark will define how many elements it must contain.

VuMark Template Design Window

Once the template is created, you must copy your design concept and break it down using the layers created by the script. Each layer represents an architectural part and has its own rule. You’ll use the VuMark-Verify.jsx script to check if your design is correct. The script will give you advice on how to fix the design to conform to VuMark standards.

VuMark Verify Window

After breaking down your design and verifying that it conforms to VuMark standards, it's time to export the target. To export the design, you must run the VuMark-Export.jsx script. It will create a new file in Illustrator and move the contents from your VuMark template. It will then prompt you to save your VuMark template as an SVG file. 

Finally, your marker will be ready, and you can upload the target file to a new database in Vuforia’s Target Manager. Then you just need to download the database and use it like any other target.

7. Exploring Other Cool Features

It's been a long journey into the Vuforia system and the possibilities for Augmented Reality. As you can see, the Vuforia system has a lot of cool features. This was my fifth post on Vuforia, and yet I still couldn’t cover all its features. However, I’m confident that you have enough knowledge to explore those resources by yourself now.

Here are some pointers to other features that are worth exploring:

  • User Defined Targets: works like ImageTarget, but the user can define the targets on the go using the device’s camera.
  • Cloud Recognition: exclusive to enterprise accounts. It's a kind of target database that lives in the cloud, allowing you to upload and synchronize newImageTargets with the app on the fly.
  • Object Recognition: This is an experimental feature that allows the recognition of an object, after it's been scanned using a special tool provided by Vuforia.

While you're here, check out some of our other posts on AR and mobile development!

Or to learn more about Augmented Reality with Vuforia and Unity, check out our video course here on Envato Tuts+!

SpriteKit Basics: Nodes

$
0
0

SpriteKit is Apple's 2D game engine—a rendering engine built on top of OpenGL. It was introduced with iOS 7, and each subsequent release has brought great additions to the framework. With the use of textured sprites, a built-in physics engine, and the very powerful SKAction class, you can very quickly build functional 2D games.

SpriteKit has built-in editors for scenes and particles, a camera node since the release of iOS9, and built-in support for tilesets since the release of iOS 10. With these new additions, SpriteKit is quickly becoming a powerhouse for creating 2D games.

To follow along with this tutorial, just download the accompanying GitHub repo. It has a folder called ExampleProject Starter. Open the project in that folder in Xcode, and you're ready to go!

Nodes

Nodes are the fundamental building blocks of SpriteKit, and SKNode is the base class of all nodes. All of your onscreen assets will be an SKNode or a subclass thereof. SKNodes by themselves do not provide any visual content, however. All visual content is drawn using one of a number of predefined SKNode subclasses. SKNodes and its subclasses share several properties you can alter. Some of the more important ones are as follows.

  • position (CGPoint): the node's position within its parent's coordinate system
  • xScale (CGFloat): scales the width of a node by a multiplier
  • yScale(CGFloat): scales the height of a node by a multiplier
  • alpha (CGFloat): the transparency of the node
  • zRotation (CGFloat): the Euler rotation about the z axis (in radians)

One of the most important SKNodes is the SKScene. This is the root node to which all other nodes are added. By itself, SKScene does not provide any visual elements, but it displays the nodes which are added to it.

Scene Nodes

SKScenes are the root nodes to which all other nodes are added. The scene animates and renders the content from its child nodes. To display a scene, you add it to an SKView (which is a subclass of UIView and therefore has many of the same properties as UIView).

In the SpriteKit starter project, the initial scene is showing when the project loads. For now, this is just a blank black screen. It is shown when the GameViewController invokes presentScene(_:) on the view instance, passing in the scene as a parameter:

Don't worry about the other options for now; I'll explain them later in this series.

Creating a Scene

Many games have more than one screen or scene, so we will create a new scene from scratch and then show it from our initial scene.

Select File> New> File from Xcode's menu, and choose Cocoa Touch Class.

Choose the Cocoa Touch Class template

Make sure Class is set to NewScene and that Subclass of is set to SKScene. Press Next and then Create, making sure the main target is checked. Below is the code for the NewScene.swift.

Now we have two scenes in our project, and neither has any visual content. Let's add an SKLabelNode (like all nodes, this is a subclass of SKNode). The SKLabelNode's sole purpose is to display a text label.

Label Nodes

Label nodes, implemented in the SKLabelNode class, are used to show text within your game. You can use custom fonts if you wish, but for our purposes we will just stick to the default, which displays white text and is set to Helvetica Neue Ultra Light, 32 point.

Add the following inside the didMove(to:) method within GameScene.swift. This method is called immediately after a scene is presented by a view. Generally, this is where you would set up any of your game's assets and add them to the scene.

Here we create an SKLabelNode using the convenience initializer init(text:), which takes as a parameter a string of text.

Adding and Removing Nodes

Just initializing nodes will not show them in the scene. To get the nodes to show, you have to invoke the addChild(_:) method on the receiving node, passing the SKNode that you wish to add as a parameter.

Add the following within the didMove(to:) method.

The addChild(_:) method is not exclusive to SKScenes, but is a method of SKNode. This allows you to build a complex hierarchy of nodes—known as the "node tree". For example, suppose you have a game character and you wanted to move its arms and legs separately. You could create an SKNode instance and then add each individual part as a child of that SKNode (the containing node is known as the parent node). This would give you the benefit of being able to move the character as a whole unit by moving the parent SKNode, but also allow you to move each individual part individually.

Another important method for adding nodes is the insertChild(_:at:) method, which inserts a child into a specific position within the receiver node's list of children. When you add a child to a node, the node maintains an ordered list of children which is referenced by reading the node's children property. It is important when adding multiple nodes to a parent node to take this into consideration, as the order in which you add the nodes affects some of the aspects of scene processing, including hit testing and rendering.

To remove a node, you invoke the removeFromParent() method on the node you wish to remove.

Now that we have covered adding and removing nodes, we can move our focus back to the example project. If you recall, we had just added an SKLabelNode to the GameScene. If you test now, you will see just half of the text off to the bottom left of the screen.

Test showing blank screen with text half off to the bottom left of the screen

Why is only half the text showing, though? Now would be a good time to talk about SpriteKit's coordinate and positioning system.

Positioning and Coordinates

By default, SpriteKit's coordinate system places (0,0) at the bottom left of the screen. Also by default, SpriteKit places nodes so they are positioned at (0,0). Still, though... why are we only seeing half of the text? This is because by default the text label is centered horizontally on the label node's origin, which is (0,0). Below is an image that shows how a node's coordinate system works.

A nodes x and y coordinates

Node's origins are at (0,0), and a positive x coordinate moves to the right and a positive y coordinate goes up the screen. Remember that an SKScene is a node, and therefore its origin is also (0,0).

Setting a Node's Position

Now that we have learned SpriteKit's coordinate system works and how it places nodes, we can move the SKLabelNode to a different position so we can see all of the text. Add the following to the didMove(to:) method within GameScene.swift.

Here we position the label to the center of the scene. The position property is of type CGPoint, which has x and y values that represent a single point within the scene.

If you test now, you should see the label has been positioned in the center of the scene.

Test with label positioned in centre of screen

Switching Between Scenes

As it currently stands, NewScene is just a blank scene. Let's also add a label to it, and then we can learn how to switch between scenes. Here's a challenge: before you read ahead, try to add a label to NewScene that says, "Go Back". My solution is below.

The first thing we need to do is add the didMove(to:) method. Add the following to NewScene.swift.

Next, we need to add the label. Add the following within the didMove(to:) method that you added above.

This adds a label to  NewScene with the text "Go Back". Next, we'll implement the functionality this label suggests—we'll respond to touch events by switching scenes.

Responding to Touch

Nearly all mobile games will be interacted with using touch. In this step, you will learn how to respond to touch events within your game.

To register touch event handlers within your game, you must implement the view's touchesBegan(_:with:) method. Add the following to GameScene.swift:

If you want to test this now, you will see YOU TOUCHED printed to the console when you touch on the screen. What we usually need, however, is to be able to tell when a specific node has been touched. To do this, we need some way to find and identify the nodes. We will learn how to accomplish this, and then come back and finish the touchesBegan(_:with:) method.

Searching the Node Tree

To be able to identify a node, you use the node's name property and the search the node tree for a node with that name. The node's name property takes an alphanumeric string without any punctuation. 

There are a couple of methods to search for a node by its name property. If you already have a reference to the node, you can just check its name property directly, which is what we will do in the touchesBegan(_:with:) method. However, it is important to know how to search the node tree for a particular node by name, or to search for a group of nodes with the same name.

The childNode(withName:) method searches the children of a node for the specific name passed in as a parameter.

The enumerateChildNodes(withName:using:) method searches a node's children and calls the block once for each matching node it finds. You use this method when you want to find all nodes that share the same name.

The subscript(_:) method returns an array of nodes that match the name parameter.

You can also search for nodes using an advanced searching syntax that allows you to search the entire scene tree, or search for a pattern rather than an exact name, for example. This advanced searching capability is beyond the scope of this tutorial. However, if you wish to learn more, you can read about in the SKNode programming reference.

Now that we know how to search for nodes within the node tree, let's give our labels a name.

Add the following within the didMove(to:) method within GameScene.swift.

Here, we set startGameLabel's name property to startgame.

We also need to set the label's name within NewScene. Add the following with the didMove(to:) method within NewScene.swift.

We set the name property to goback.

Detecting Which Node Is Touched

Add the following within the touchesBegan(_:with:) method within GameScene.swift.

The multiTouchEnabled property of the scene's view is set to false by default, which means the view only receives the first touch of a multitouch sequence. With this property disabled, you can retrieve the touch by using the first computed property of the touches set, since there is only one object in the set.

We can get the touchLocation within the scene from the location property of the touch. We can then figure out which node was touched by invoking atPoint(_:) and passing in the touchLocation.

We check if the touchedNode's name property is equal to "startgame", and if it is, we know that the user has touched the label. We then create an instance of NewScene and set its scalemode property to be the same as the current scene—this ensures the scene acts the same across different devices. Finally, we create an SKTransition and invoke the presentScene(_:transition:) method, which will present the scene along with the transition.

The SKTransition class has many class methods that you can invoke to show different transitions between scenes instead of immediately showing the scene. This provides a bit of "eye candy" for the end user, and makes showing a new scene seem less abrupt. To see all of the available transition types, check out the SKTransition class in the reference guide.

I'm not going to implement the touchesBegan(_:with:) method in NewScene. Why don't you try doing that on your own and have the label transition back to the GameScene using a different transition type? The code will closely resemble what we have above, only remember we named the SKLabelNode"goback".

Conclusion

We have learned a good bit about nodes so far using scenes, and you've seen how to use a label node as a generic example to learn some of the characteristics of nodes. We've studied their coordinate systems, how to locate them within the node tree, how to position them, and how to respond to touch events. 

There are several other kinds of nodes available, and we'll take a look at them in the next tutorial—starting with SKSpriteNode!

To learn more about how to get started with SpriteKit, you should also check out Davis Allie's post here on Envato Tuts+.

Also, check out our SpriteKit courses! These will take you through all the steps of building your first SpriteKit game for iOS, even if you've never coded with SpriteKit before.

SpriteKit Basics: Sprites

$
0
0

In this series, we're learning how to use SpriteKit to build 2D games for iOS. In this post, we'll continue our exploration of SpriteKit nodes, and learn about a special kind of node called a "sprite"—an SKSpriteNode.

To follow along with this tutorial, just download the accompanying GitHub repo. It has a folder called ExampleProject Starter. Open the project in that folder in Xcode, and you're ready to go!

Sprite Nodes

An SKSpriteNode is drawn either as a rectangle with a texture mapped onto it, or as a colored untextured rectangle. Creating a SKSpriteNode with a texture mapped onto it is the most common, as this is how you bring your game's artwork to life.

Add the following to the didMove(to:) method within GameScene.swift.

Here we are using the convenience intiailizer init(color:size:) which will draw a rectangular sprite with the color and size you pass in as parameters. If you test the project now, you will see half of the red square showing.

red sprite

You might be wondering why only half of the sprite is showing since we already determined that SKNode's origins are at (0,0). This because the SKSpriteNode's frame and therefore its texture is centered on its position. To change this behaviour, you can change the sprite's anchorPoint property, which determines the point at which the frame is positioned. The diagram below shows how the anchorPoint works.

Diagram showing the anchorPoint property within a coordinate system

The anchorPoint is specified in the unit coordinate system, which places (0,0) at the bottom left and (1,1) at the top right corner of the frame. The default for SKSpriteNodes is (0.5,0.5).

Go ahead and change the anchorPoint property to (0,0) and notice the difference it makes.

Now, if you test, you will see that the sprite is lined up perfectly with the bottom left of the scene.

red sprite aligned bottom left

Now let's move it to the top center of the scene by changing its position property. Replace your didMove(to:) function with the following:

Notice how we had to subtract from both the x and y values to center the sprite. If we had left the anchorPoint at its default then it would already have been centered on the x axis. It is important to remember that when you change the anchor point, you may have to make some adjustments in your positioning.

red sprite centered top

Textured Sprites

That red box is good for practice with positioning, but you'll usually want to texture your sprite with artwork for your game. 

Let's create a textured SKSpriteNode. Add the following code at the bottom of the didMove(to:) method.

Here we use the convenience initializer init(imageNamed:), which takes as a parameter the name of an image without the extension. This is the easiest way to create a textured sprite as it creates the texture for you from the image you pass in. 

The other way to create a textured SKSpriteNode is to create an SKTexture beforehand, and use one of the intializers that take a texture as a parameter.

textured sprite

Let's create a couple more SKSpriteNodes and change some of their properties. Again, add these to the bottom of your didMove(to:) function.

Here we create two SKSpriteNodes, enemy1 and enemy2. We set the xScale on enemy1 to 2 and change the zRotation on enemy2 to rotate it by 90 degrees. (The zRotation property takes it values in radians, and a positive value indicates a counterclockwise rotation.) 

We've experimented with changing a few properties on a sprite. Take a look at the documentation for SKNodes and SKSpriteNodes and try changing a few of the other properties to see the effects they have.

textured sprite properties changed

Sprite nodes are good for basic rectangles and textures, but sometimes a more complex shape will be needed. The SKShapeNode has you covered in those cases. We'll take a look at shape nodes next.

Shape Nodes

Another useful node is the SKShapeNode. This node renders a shape defined by a Core Graphics path. SKShapeNodes are useful for content that cannot be easily realized with an SKSpriteNode. This class is more memory intensive and has lower performance than using an SKSpriteNode, so you should try to use it sparingly.

To assign a shape to SKShapeNode, you can set a CGPath to the node's path property. However, there are a few initializers that offer predefined shapes such as rectangles, circles, and ellipses. Let's create a circle using the convenience initializer init(circleOfRadius:).

Then, add the following to the bottom of the didMove(to:) method.

We change a few properties on the shape node, position it, and add it to the scene. It is very easy to use the predefined shape initializers. However, creating a complex CGPath manually takes a considerable amount of time and is not for the faint of heart as it usually involves some complex math. 

Thankfully, there is a tool that lets you draw shapes visually and export their CGPath as Swift code. Check out PaintCode if you want to learn more.

shape node

Sprite Nodes and Shape Nodes will cover most cases, but sometimes you may wish to display video in your apps. The SKVideoNode, which we'll take a look at next, has you covered.

Video Nodes

The last node we will be taking a look at is the SKVideoNode. As the name implies, this node allows you to play video within your games.

There are a few different ways to create an SKVideoNode. One uses an instance of an AVPlayer, another just uses the name of a video file that is stored in the app bundle, and the third way is to use a URL.

One thing to keep in mind is that the video's size property will initially be the same as the size of the target video. You can change this size property, though, and the video will be stretched to the new size.

Another thing to be aware of is that the SKVideoNode offers play() and pause() methods only. If you wanted more control over your videos, you would initialize an SKVideoNode with an existing AVPlayer and use that to control your videos.

Let's use the simplest method to create an SKVideoNode. Add the following to the bottom of the didMove(to:) method.

Here we used the intiailizer init(fileNamed:) to create a video. You pass in the video's name along with the extension. I have not included a video along with the project's source code, but if you want to see this work, you can add a video named "video.mov" to your project.

Conclusion

This completes our study on nodes. After reading this post and the previous one, you should have a good understanding of SKNodes and their subclasses. In the next part of this series, we will take a look at SKActions and using physics within our games. Thanks for reading, and I will see you there!

In the meantime, check out some of our other great courses and tutorials on creating iOS apps with Swift and SpriteKit.

Also, check out our SpriteKit courses! These will take you through all the steps of building your first SpriteKit game for iOS, even if you've never coded with SpriteKit before.

 

Unity Terrain Engine Tools

$
0
0
Final product image
What You'll Be Creating

Unity is a multi-platform game engine developed by Unity Technologies and is used to create video games and applications for a multitude of devices (PC, consoles, mobile devices, and even websites). Unity's core advantages are its robustness and portability; Unity targets several known APIs such as Direct3D, OpenGL, OpenGL ES, and the recent Vulkan.

Due to the aforementioned characteristics, Unity has become more and more popular among AAA software development houses and aspiring game programmers.

Unity supports several technologies and components. One of the key components is the terrain engine system. Unity's terrain system allows you to create vast landscapes for your games or applications. You can use a selection of tools available to create terrains easily and quickly.

This tutorial will focus on explaining how terrain engine tools work, and how to use them to create vast and rich terrain environments.

Prerequisites

First, ensure you have the latest version of Unity. In this tutorial we're using version 5.6. Make sure that you are using the latest Unity version; otherwise you may find small differences following the tutorial and using the physics joints.

For this tutorial, you will not use any starter file. The goal is to create a new project and perform the tutorial from there.

The Terrain Tools

The first step is to create a new Unity project. Now add a new scene (File > New Scene). The new scene has been created with two game objects, the Main Camera and a Directional Light (Unity 5 will automatically add a skybox into the scene).

Now, in order to add a terrain game object, go to the GameObject menu, and select 3D Object > Terrain. This will add a flat plane (called Terrain) into your scene. This plane is the mesh that we are going to sculpt in order to create your level terrain.

Terrain Tools - New Terrain

If you check your Assets directory (bottom part of Unity), you will see that a New Terrain file was created.

Select the Terrain and look at the Inspector tab. You will see that the terrain has three components: Transform, the Terrain script, and the Terrain Collider component.

Terrain Tools - Terrain Inspector

The terrain component provides you the tools you need to edit your terrain. All the tools on the toolbar, with the exception of the tree placement tool and the settings panel, provide a set of "brushes" and settings for brush size and opacity, just like painting tools from a normal image editor. This allows you to sculpt your terrain similarly to a painting tool.

If you select any brush under the Terrain component and mouse over the terrain, you will see a blue area projected on the terrain. This lets you know the area of the terrain that your brush will affect.

As you may have already realised, the Terrain is quite big. To navigate through the Scene, you can use the mouse and keyboard. Inside the Scene tab, press and hold your Right mouse button (the cursor should change to an eye).

While holding the mouse button:

  • You can change the angle of your view by moving the mouse.
  • Use the W, S, A, D keys to move around the 3D scene.

Before you start exploring the terrain tools, let’s take a look at the Terrain properties. The last button on the Terrain component (inside the Inspector) will show you the base parameters of the terrain.

Terrain Tools - Terrain Properties

The properties are divided into sections:

  • Base Terrain
  • Tree & Detail Objects
  • Wind Settings for Grass
  • Resolution
  • Heightmap

Inside the first section Base Terrain, you will find several properties and parameters.

The Draw option toggles the rendering of the terrain on or off. The Pixel Error represents the accuracy value of the mapping between the terrain maps (for example textures, heightmaps, and generated terrain). Higher values represent lower accuracy, and lower values will result in rendering overhead. It is your responsibility to balance this value in order to create a nice, rich environment.

The Base Map dist. is the maximum distance at which terrain textures will be displayed at full resolution. You can set shadows on or off by selecting Cast Shadows.

Next, we have Material. Here you set the material that is going to be used to render the terrain. This will affect how the color channels of a terrain texture are interpreted. You can select:

  • Built In Standard represents the Physically-Based Rendering material that was introduced in Unity 5. If you select this option, for each splat layer, you can use one texture for albedo and smoothness, one texture for normal, and one scalar value to tweak the metalness. Keep in mind that if "Overwrite Smoothness" is checked, instead of reading from texture maps, the smoothness of the entire terrain will be controlled only by the Smoothness value.
  • Built In Legacy Diffuse represents the legacy built-in terrain material from previous Unity releases (Unity 4 and backwards). It uses a Lambert lighting model and has optional normal map support.
  • Built In Legacy Specular uses the Blinn-Phong lighting model (please consult this previous Unity 5 lightning tutorial), and has optional normal map support. This option also allows you to specify the overall specular color and shininess for the terrain.
  • Custom option uses a custom material of your choice to render the terrain. This material should be a shader that is orientated for terrain rendering. This is an option that I only recommend to advanced users. However, if you want to give it a try, take a look at the source code of some of the built-in terrain shaders and make modifications on top of them.

You can also set Reflection Probes for some materials, but they will only be used when you’re using a built-in standard material or a custom material which supports rendering with reflection. The options for reflection probes are:

  • Off: Reflection probes are disabled, and only the skybox will be used for reflection.
  • Blend Probes: Reflection probes are enabled. The blending occurs only between probes. Default reflection will be used if there are no reflection probes nearby, but there will be no blending between default reflection and probe.
  • Blend Probes And Skybox: Reflection probes are enabled. Blending occurs between probes or probes and default reflection.
  • Simple: Reflection probes are enabled, but no blending will occur between probes when there are two overlapping volumes.

Finally, the last parameter in this section is Thickness. This value specifies how much the terrain collision volume should extend along the negative Y-axis. Objects are considered colliding with the terrain from the surface to a depth equal to the thickness. This helps to prevent high-speed moving objects from penetrating into the terrain without using expensive continuous collision detection.

The next settings section is Tree & Detail Objects.

The first option is Draw. Here, you can set the draw of the details on or off. Basically, it tells the engine if you want trees and grass to be drawn or not. Next, you have Bake Light Probes for trees. If you enable this option, Unity will create light probes at the position of each tree. The probes will then be applied to the rendering of the trees. If you disable this option, trees will still be affected by light group probes. Take note that this option is only available for trees that have light probes enabled on their prefabs.

The Detail Distance is the distance from the camera beyond which details will be culled. Detail Density represents the number of detail objects in a given unit of area. Tree Distance represents the distance from the camera beyond which trees will be culled. The Billboard Start is the distance from the camera at which 3D tree objects will be replaced by billboard images. The Fade Length represents the distance over which trees will transition between 3D objects and billboards. Finally, the Max Mesh Trees is the maximum number of visible trees that will be represented as solid 3D meshes.

Moving on, you'll see the Wind Settings for Grass section.

Speed defines the speed of the wind as it blows grass. The Size represents the ripple size on grassy areas. Bendinglets you define the degree to which grass objects are bent by the wind. Grass Tint lets you select the overall color tint applied to grass objects.

Inside the Resolution section you will find several resolution properties, namely the Terrain Width, Length, and Height. All three are very explicit of their meaning. The Heightmap Resolution is the pixel resolution of the terrain’s height map. It should be a power of 2 plus 1, for example, 513, where 512 is a power of 2, and you add 1.

Detail Resolution lets you define the resolution of the map. Higher resolutions will give you smaller and more detailed grass patches. The Detail Resolution per Patch sets the length and width of the square of patches rendered on a single draw call. The Control Texture Resolution is the resolution of the splat map that controls the blending of the different terrain textures. Finally, the Base Texture Resolution sets the resolution of the composite texture used on the terrain when viewed from a distance superior to the base map distance.

The last section is Heightmap. Here you can import a heightmap raw file or export your current terrain into a heightmap raw file. This can be very useful if you want to use external third-party software to interact with your application or game.

Height Tools

Before you move on to the height tools, remember that you must set the resolution settings first. Otherwise, if you try to change them later, all of the sculpting of the terrain will be lost.

The first three tools on the Terrain Inspector toolbar are the height tools. These tools are used to paint height changes onto the terrain.

Height Tools - Terrain Options

They provide a set of "brushes" with settings for Brush Size and Opacity; these tools are very similar to painting tools from any image editor. This allows you to paint detail in the terrain, as if you were painting an image.

Height Tools - Brushes options

If you move your cursor to the Scene tab, you will see a blue area projected on the terrain. This lets you know the area of the terrain that your brush will affect.

Height Tools - Cursor on the floor

The first tool is Raise / Lower Height. When painting with this tool, the height of the terrain will be increased as you sweep the mouse over it. If you hold the mouse in one particular area, the height will accumulate. Such an effect can be visualized in the following image.

Height Tools - Raising the terrain

To lower the terrain, just hold the Shift key while painting with the tool, and this will lower the height of your terrain.

The second tool on the terrain editor is Paint Height. This tool is used to set a specific height for an area of the terrain.

Height Tools - Selection of STAR brush

It works in a similar way to the Raise/Lower tool, but it has an additional property to set the target Height. You can select the desired Height by changing the value of the Height parameter. The Flatten button next to the height property will level the whole terrain to the chosen Height.

Height Tools - Selection of STAR brush - Lowering terrain

Finally, the third tool is Smooth Height. This tool will not drastically increase or decrease the height of the terrain; instead, it will soften the landscape and reduce the appearance of abrupt changes. This tool is particularly useful when you have painted detail using one of the noisier brushes, since these brushes tend to create sharp, jagged rocks in the landscape, and you can use this tool to soften them.

Height Tools - Soften tool

It is now time to take some time and create your own sculpted terrain. Try to use the aforementioned three tools to create a nice mountain terrain.

Paint Texture Tool

With the terrain sculpted, is now time to texture it.

Paint Texture - Texturing the terrain

Before moving on, you need to import the environment assets that are available with Unity 5. To do that, select Assets > Import Package, and select Environment. Click Import to import all environmental assets.

Terrain Tools - Importing Assets

Unity allows you to paint your terrains with textures. You can paint your terrain with different textures in different areas. For example, you can have a texture for rock, another for sand, and another for grass. The textures can be applied with different transparency, which means that you can have smooth transitions between two textures. In order to achieve the best results, you should paint your terrain with seamless textures.

As you may have noticed on the Inspector tab, the Paint Texture tool has several brushes, and lets you change the Brush Size, the Opacity, and the Target Strength.

Paint Texture - Texturing with brushes

The first time you use the paint Texture Tool, there won’t be any textures to choose from. The first thing you need to do is to add a new texture into your pallet. To do this, click on the Edit Textures button and select Add Texture. A new window will appear.

Texture Tool - New Texture

As you can see, on this window you can Select the texture you want to use and its normal map, if you have one. Click on the square under texture and select your texture. A window will pop up to let you select the texture. Select the SandAlbedo texture and click Add.

Texture Tools - Selecting the SandAlbedo Texture

Your terrain should now have a sand look. Note that you can always modify it on the edit texture option, or remove it. 

Paint Texture - Textures

The first texture you create should always be the base texture for the terrain. The complete list of textures used in this example are:

  1. SandAlbedo
  2. GrassHillAlbedo
  3. GrassRockAlbedo
  4. MudRockyAlbedo
  5. CliffAlbedo

All of them are part of the environmental imported assets and can be found in the same way as the SandAbedo texture. Go ahead and import them all.

Paint Texture - Multiple textures types

When you have all the textures imported, it is now time to texture your terrain as you want. Select a texture and paint the desired environment. An example of a textured map is the following.

Paint Texture - Preliminary textured terrain

When you are satisfied with the result, move on to the next section.

Paint Tree Tool

Now that you have your terrain painted, it’s time to add some trees to it. Unity 3D allows you to put trees on your terrain in the same way as you painted the textures. Using billboarding settings for distant trees, Unity maintains a good rendering performance, allowing you to have dense forests with thousands of trees.

To start painting trees, select your Terrain from the Hierarchy tab, and on the Inspector tab, select the fifth button.

Paint Tree - Paint tree tool

Similar to textures, you also need to add the trees. Click on Edit Trees > Add Tree.

Unity will ask you for the prefab of the tree you want to use. Click on the small circle, and another window will show up. This time, it will show you all the prefabs you have in your project.

Trees - Select the prefab

Select the Broadleaf_desktop tree prefab and click Add. This will close the prefab window and add the selected tree into the project.

Paint Tree - Trees selection

You can now select the palm tree to paint it onto your terrain.

Under the Settings, you will find several parameters that you can adjust while you are placing trees in your scene. Brush Size defines the area you will paint, while Tree Density defines the number of trees you will have in the painted area. High values will mean more trees. Tree Height will allow you to define how the height changes. You can set it to random and use an interval of values, or you can set a specific value. You can Lock Width to Height of the trees, in order to make them have the same aspect ratio. You can also randomize the tree rotation orientation using the Random Tree Rotation option. Also, the tree rotation can be set to random.

Inside the Lighting section you can set how the lightmaps are generated for your trees.

Paint Tree - Baked lightmaps

In order to paint the trees in the terrain, move the mouse over into your scene view. The blue area represents the brush. With a tree type selected, press the left mousebutton on the terrain and start creating trees.

Paint Tree - Example of trees on terrain

To erase trees from a certain area, hold Shift and use the left mouse button. This will clear all trees in the brush area. If you just want to erase a certain type of tree, hold Control instead of Shift. This will clear just the selected tree type.

You can always change or delete a type of tree by selecting it and clicking on the edit tree button. To modify a tree, click on edit, and to delete it, click on remove.

Finally, you will notice that inside the Terrain Collider component, you have a field named Enable Tree Colliders. By selection this option, you are enabling collisions between other game objects and the trees.

Paint Tree - Terrain Collider

If you don’t want to paint the trees manually, you can use the Mass Place Trees button. If you click there, a new window will pop up. Unity will then ask you for a number of trees to create. Set the Number of Trees and click on Place. Unity will then randomly place the trees in your terrain.

Paint Tree - Mass Place Trees

The next step is being creative and populating your terrain with trees. In order to create different trees, you can also add new trees like the Palm_Desktop, Broadleaf_Mobile and Conifer_Desktop. For that, use the option Edit Trees under the Trees menu (inside Inspector). 

You can create something like the following image (or something completely different).

Paint Tree - Preliminary terrain with trees

When you are ready, you can move on to the next step.

Paint Details Tool

Unity allows the terrains to have grass clumps and other small objects, such as rocks, covering its surface. The grass is rendered using 2D images, while other objects are usually standard meshes.

To add details to the terrain, select your terrain object from the hierarchy. Inside the Inspector tab, click on the sixth button, the one with the flowers.

Paint Details Tools

As you can see, you now have a similar interface to the Height Tools. Here you also have a set of brushes that you can choose from in order to paint a list of details.

Since you don't have any object details selected, let's add them by clicking on Edit Details > Add Grass Texture.

This will open a window where you can set several properties for your grass. Detail Texture lets you define the texture that you will use for your grass. You can also define several properties like Max Width, Min Width, Max HeightMin Height, Noise Spread, Healthy Color, Dry Color, and Billboard. All these properties will define how your grass will look.

For this tutorial, you can leave the default options or change them at your will.

Click on the circle in front of the Detail Texture field. This will open a new window. Search for the GrassFrond01AlbedoAlpha, select it, and click Add.

Paint Details - Grass tools

Just like for the trees, you can use several brushes to paint the grass. You can set different Brush Sizes and change the brush Opacity and the Target Strength.

It is now time to be creative and paint grass onto the terrain.

Paint Details - Grass details

If you want to add a mesh to paint detail on your terrain, for example rocks, you need the repeat the same process you did with importing the grass. However, this time, when you click on Edit Details, choose Add Detail Mesh. This will open a window where you can specify several parameters of the detail mesh, very similar to the one you used to import the grass. 

Unfortunately, the environment assets do not include any rock prefab, so you will not be able to paint rocks directly. However, you can search for some rocks over at the Unity Asset Store, since it is a great place to find free assets.

Conclusion

This concludes the tutorial about Unity Terrain Tools. You learned about several terrain tools and configurations. With this knowledge, you can now create, modify and improve current or new terrains for your next cutting-edge game or application.

Unity has an active economy. There are many other products that help you build out your project. The nature of the platform also makes it a great option from which you can improve your skills. Whatever the case, you can see everything we have available in the Envato Marketplace.

If you have further questions or comments, as always, feel free to drop a line in the comments section.

Creating a Hexagonal Minesweeper

$
0
0
Final product image
What You'll Be Creating

In this tutorial, I will try to introduce the interesting world of hexagonal tile-based games using the easiest of approaches. You will learn how to convert a two-dimensional array data to a corresponding hexagonal level layout on screen and vice versa. Using the information gained, we will be creating a hexagonal minesweeper game in two different hexagonal layouts.

This will get you started with exploring simple hexagonal board games and puzzle games and will be a good starting point to learn more complicated approaches like the axial or cubic hexagonal coordinate systems.

1. Hexagonal Tiles and Layouts

In the current generation of casual gaming, we don't see many games which use a hexagonal tile-based approach. Those we come across are usually puzzle games, board games, or strategy games. Also, most of our requirements are met by the square grid approach or isometric approach. This leads to the natural question: "Why do we need a different and obviously complicated hexagonal approach?" Let's find out.

Advantages of the Hexagonal Approach

So what makes the hexagonal tile-based approach relevant, since we already have other approaches learned and perfected? Let me list some of the reasons.

  • Smaller number of neighbour tiles: When compared to a square grid, which will have eight neighbour tiles, a hexagonal tile will only have six neighbours. This reduces computations for complicated algorithms.
  • All neighbour tiles are at the same distance: For a square grid, the four diagonal neighbours are far away when compared to the horizontal or vertical neighbours. Neighbours being at equal distances is a great relief when we are calculating heuristics and reduces the overhead of using two different methods to calculate something depending on the neighbour.
  • Uniqueness: These days, millions of casual games are coming out and are competing for the player's time. Great games are failing to get an audience, and one thing that can be guaranteed to grab a player's attention is uniqueness. A game using a hexagonal approach will visually stand out from the rest, and the game will seem more interesting to a crowd who are bored with all the conventional gameplay mechanics. 

I would say the last reason should be enough for you to master this new approach. Adding that unique gameplay element over your game logic could make all the difference and enable you to make a great game. 

The other reasons are purely technical and would only come into effect once you are dealing with complicated algorithms or larger tile sets. There are many other aspects also which can be listed as advantages of the hexagonal approach, but most of them will depend on the player's personal interest.

Layouts

A hexagon is a polygon with six sides, and a hexagon with all sides having the same length is called a regular hexagon. For theory purposes, we will consider our hexagonal tiles to be regular hexagons, but they could be squashed or elongated in practice. 

The interesting thing is that a hexagon can be placed in two different ways: the pointy corners could be aligned vertically or horizontally. When pointy tops are aligned vertically, it is called a horizontal layout, and when they are aligned horizontally, it is called a vertical layout. You may think that the names are misnomers with respect to the explanation provided. This is not the case as the naming is not done based on the pointy corners but the way a grid of tiles gets laid out. The image below shows the different tile alignments and corresponding layouts.

The vertical and horizontal hexagonal tile grid layout

The choice of layout entirely depends on your game's visuals and gameplay. Yet your choice does not end here as each of these layouts could be implemented in two different ways.

Let's consider a horizontal hexagonal grid layout. Alternative rows of the grid would need to be horizontally offset by hexTileWidth/2. This means we could choose to offset either the odd rows or the even rows. If we also display the corresponding row, column values, these variants would look like the image below.

Horizontal hexagonal layout with even  odd offsets

Similarly, the vertical layout could be implemented in two variations while offsetting alternative columns by hexTileHeight/2 as shown below.

Vertical hexagonal layout showing even  odd variations

2. Implementing Hexagonal Layouts

From here on onwards, please start referring to the source code provided along with this tutorial for better understanding

The images above, with the rows and columns displayed, make it easier to visualise a direct correlation with a two-dimensional array which stores the level data. Let's say we have a simple two-dimensional array levelData as below.

To make it easier to visualise, I will show the intended result here in both vertical and horizontal variations.

simple hexagonal grid based on level data array

Let's start with horizontal layout, which is the image on the left side. In each row, if taken individually, the neighbour tiles are horizontally offset by hexTileWidth. Alternative rows are horizontally offset by a value of hexTileWidth/2. The vertical height difference between each row is hexTileHeight*3/4

To understand how we arrived at such a value for the height offset, we need to consider the fact that the top and bottom triangular portions of a horizontally laid out hexagon are exactly hexTileHeight/4

This means that the hexagon has a rectangular hexTileHeight/2 portion in the middle, a triangular hexTileHeight/4 portion on top, and an inverted triangular hexTileHeight/4 portion on the bottom. This information is enough to create the code necessary to lay out the hexagonal grid on screen.

With the HexTile prototype, I have added some additional functionalities to the Phaser.Sprite prototype which enables it to display the i and j values. The code essentially places a new hexagonal tile Sprite at startX and startY. This code can be changed to display the even offset variant just by removing an operator in the if condition like this: if(i%2===0).

For a vertical layout (the image on the right half), neighbour tiles in every column are vertically offset by hexTileHeight. Each alternate column is vertically offset by hexTileHeight/2. Applying the logic which we applied for vertical offset for the horizontal layout, we can see that the horizontal offset for the vertical layout between neighbour tiles in a row is hexTileWidth*3/4. The corresponding code is below.

In the same way as with the horizontal layout, we can switch to the even offset variant just by removing the ! operator in the top if condition. I am using a Phaser Group to collect all the hexTiles named hexGrid. For simplicity, I am using the centre point of the hexagonal tile image as an anchor, or else we would need to consider the image offsets as well. 

One thing to notice is that the tile width and tile height values in the horizontal layout are not equal to the tile width and tile height values in the vertical layout. But when using the same image for both layouts, we could just rotate the tile image 90 degrees and swap the values of tile width and tile height.

3. Finding the Array Index of a Hexagonal Tile

The array to screen placement logic was interestingly straightforward, but the reverse is not so easy. Consider that we need to find the array index of the hexagonal tile on which we have tapped. The code to achieve this is not pretty, and it is usually arrived at by some trial and error. 

If we consider the horizontal layout, it may seem that the middle rectangular portion of the hexagonal tile can easily help us figure out the j value as it is just a matter of dividing the x value by hexTileWidth and taking the integer value. But unless we know the i value, we don't know if we are on an odd or even row. An approximate value of i can be found by dividing the y value by hexTileHeight*3/4

Now come the complicated parts of the hexagonal tile: the top and bottom triangular portions. The image below will help us understand the problem at hand.

a horizontally laid hexagonal tile split into regions

The regions 2, 3, 5, 6, 8, and 9 together form one tile. The most complicated part is to find if the tapped position is in 1/2 or 3/4 or 7/8 or 9/10. For this, we need to consider all the individual triangular regions and check against them using the slope of the slanted edge. 

This slope can be found from the height and width of each triangular region, which respectively are hexTileHeight/4 and hexTileWidth/2. Let me show you the function which does this.

First, we find xVal and yVal the same way we would do for a square grid. Then we find the remaining horizontal (dX) and vertical (dY) values after removing the tile multiplier offset. Using these values, we try to figure out if the point is within any of the complicated triangular regions. 

If found, we make corresponding changes to the initial values of xVal and yVal. As I have said earlier, the code is not pretty and not straightforward. The easiest way to understand this would be to call findHexTile on mouse move, and then put console.log inside each of those conditions and move the mouse over various regions within one hexagonal tile. This way, you can see how each intra-hexagonal region is handled.

The code changes for the vertical layout are shown below.

4. Finding Neighbours

Now that we've found the tile on which we have tapped, let's find all six neighbouring tiles. This is a very easy problem to solve once we visually analyse the grid. Let's consider the horizontal layout.

odd and even rows of horizontal layout when a middle tile has ij set to 0

The image above shows the odd and even rows of a horizontally laid out hexagonal grid when a middle tile has the value of 0 for both i and j. From the image, it becomes clear that if the row is odd, then for a tile at i,j the neighbours are i, j-1, i-1,j-1, i-1,j, i,j+1, i+1,j, and i+1,j-1. When the row is even, then for a tile at i,j the neighbours are i, j-1i-1,ji-1,j+1i,j+1i+1,j+1, and i+1,j. This could be manually calculated easily.

Let's analyse a similar image for the odd and even columns of a vertically aligned hexagonal grid.

odd and even columns of vertical layout when a middle tile has ij set to 0

When we have an odd column, a tile at i,j will have i,j-1i-1,j-1, i-1,j, i-1,j+1, i,j+1, and i+1,j as neighbours. Similarly, for an even column, the neighbours are i+1,j-1, i,j-1, i-1,j, i,j+1, i+1,j+1, and i+1,j

5. Hexagonal Minesweeper

With the above knowledge, we can try to make a hexagonal minesweeper game in the two different layouts. Let's break down the features of a minesweeper game.

  1. There will be N number of mines hidden inside the grid.
  2. If we tap on a tile with a mine, the game is over.
  3. If we tap on a tile which has a neighbouring mine, it will display the number of mines immediately around it.
  4. If we tap on a mine without any neighbouring mines, it would lead to the revealing of all the connected tiles which do not have mines.
  5. We can tap and hold to mark a tile as a mine.
  6. The game is finished when we reveal all tiles without mines.

We can easily store a value in the levelData array to indicate a mine. The same method can be used to populate the value of nearby mines on the neighbouring tiles' array index. 

On game start, we will randomly populate the levelData array with N number of mines. After this, we will update the values for all the neighbouring tiles. We will use a recursive method to chain reveal all the connected blank tiles when the player taps on a tile which doesn't have a mine as neighbour.

Level Data

We need to create a nice looking hexagonal grid, as shown in the image below.

horizontal hexagonal minesweeper grid

This can be done by only displaying a portion of the levelData array. If we use -1 as the value for a non-usable tile and 0 as the value for a usable tile, then our levelData for achieving the above result will look like this.

While looping through the array, we would only add hexagonal tiles when the levelData has a value of 0. For the vertical alignment, the same levelData can be used, but we would need to transpose the array. Here is a nifty method which can do this for you.

Adding Mines and Updating Neighbours

By default, our levelData has only two values, -1 and 0, of which we would be using only the area with 0. To indicate that a tile contains a mine, we can use the value of 10

A blank hexagonal tile can have a maximum of six mines near it as it has six neighbouring tiles. We can store this information also in the levelData once we have added all the mines. Essentially, a levelData index having a value of 10 has a mine, and if it contains any values from 0 to 6, that indicates the number of neighbouring mines. After populating mines and updating neighbours, if an array element is still 0, it indicates that it is a blank tile without any neighbouring mines. 

We can use the following methods for our purposes.

For every mine added in addMines, we are incrementing the array value stored in all of its neighbours. The getNeighbors method won't return a tile which is outside our effective area or if it contains a mine.

Tap Logic

When the player taps on a tile, we need to find the corresponding array element using the findHexTile method explained earlier. If the tile index is within our effective area, then we just compare the value at the array index to find if it is a mine or blank tile.

We keep track of the total number of blank tiles using the variable blankTiles and the number of tiles revealed using revealedTiles. Once they are equal, we have won the game. 

When we tap on a tile with an array value of 0, we need to recursively reveal the region with all the connected blank tiles. This is done by the function recursiveReveal, which receives the tile indices of the tapped tile.

In this function, we find the neighbours of each tile and reveal that tile's value, meanwhile adding neighbour tiles to an array. We keep repeating this with the next element in the array until the array is empty. The recursion stops when we meet array elements containing a mine, which is ensured by the fact that getNeighbors won't return a tile with a mine.

Marking and Revealing Tiles

You must have noticed that I am using hexTile.reveal(), which is made possible by creating a HexTile prototype which keeps most of the attributes related to our hexagonal tile. I use the reveal function to display the tile value text and set the tile's colour. Similarly, the toggleMark function is used to mark the tile as a mine when we tap and hold. HexTile also has a revealed attribute which tracks whether it is tapped and revealed or not.

Check out the hexagonal minesweeper with horizontal orientation below. Tap to reveal tiles, and tap-hold to mark mines. There is no game over as of now, but if you reveal a value of 10, then it is hasta la vista baby!

Changes for the Vertical Version

As I am using the same image of hexagonal tile for both orientations, I rotate the Sprite for the vertical alignment. The below code in the HexTile prototype does this.

The minesweeper logic remains the same for the vertically aligned hexagonal grid with the difference for findHextile and getNeighbors logic which now need to accommodate the alignment difference. As mentioned earlier, we also need to use the transpose of the level array with corresponding layout loop.

Check out the vertical version below.

The rest of the code in the source is simple and straightforward. I would like you to try and add the missing restart, game win, and game over functionality.

Conclusion

This approach of a hexagonal tile-based game using a two-dimensional array is more of a layman's approach. More interesting and functional approaches involve altering the coordinate system to different types using equations. 

The most important ones are axial coordinates and cubic coordinates. There will be a follow-up tutorial series which will discuss these approaches. Meanwhile, I would recommend reading Amit's incredibly thorough article on hexagonal grids

The Smoke & Mirrors of Good Countdowns, Part 1

$
0
0
Final product image
What You'll Be Creating

Countdowns are simple elements that appear in a lot of games, yet their design can be easily overlooked.

With a few simple additions, though, a regular timer can be made much more engaging and fitting the universe of the game presented, and thus greatly enhance the player's experience.

A lot of these elements are inspired by the talk "Juice it or lose it" by Martin Jonasson and Petri Purho on how to make your game "juicier". The bottom line is that it is not enough to just present the information in its most base form; you also need to enhance and accentuate what is happening with color, sounds and movement, which will make the entire experience much more engaging. I totally recommend watching that talk to also learn about other applications.

In this two-part series, we will go through these elements and then implement them in a simple Unity project, for which you will need the newest version. In the upcoming part 2, we will look at more detailed and nuanced elements.

Ready? Let's go!

The Purpose of Countdowns

Timers in games can serve different purposes, which have not necessarily overlapping applications. These are:

  1. You have X amount of time to accomplish a task.
  2. You need to survive for X amount of time.

The design of a timer can change between those two, as the information necessary for the player changes in its application.

When you are given five minutes to defuse a bomb in Metal Gear Solid 2, you need to know the exact amount of time you have, as every second becomes vital to the overall progress and planning. The timer needs to convey to the player how much is left, and to alert them if that amount is becoming critically low.

When you have to hold out for a certain amount of time, that element of exactitude becomes less important. While it would of course be nice to know the exact amount of time in seconds you need to survive, the game can also work without that information. It could even be improved, as a piece of information like "you need to hold out for just a few seconds more!" is more easily understood in a stressful situation than "please read this number readout in the corner of the screen", and can enhance the immersion within the gameworld.

How to Improve Countdowns

Now let's take a look at elements that will make countdowns and timers more interesting and engaging.

1: Create Your Own Timer That Doesn't Rely on Numbers and Embed the Timer Into the World

Instead of just putting a number somewhere, you can create your own countdown graphic which will tell the user roughly how much time is left.

A graphical, 2D implementation will require some finesse, as you need to make sure the player can correctly intuit and read the idea of "time is running out and you've got roughly X seconds left".

Non-numerical countdown from Star Trek Generations The exact time is not readily readable but the graphic lets a viewer easily deduce that a countdown is happening and time is running out
Non-numerical countdown from Star Trek Generations. The exact time is not readily readable, but the graphic lets a viewer easily deduce that a countdown is happening, and time is running out

This works very well if you use environmental indicators to show the progress, and have in-game voices tell you how much is left. A number pasted on top of the screen can feel non-diegetic and might very well take some players out of the game.

In Half Life 2, for example, you need to defend a position until a teleporter has charged. At the beginning, a full charge is displayed, which then has to be refilled again.

Full charge for a teleport in Half Life 2 The element is highly visible inside the otherwise sparsely decorated room
Full charge for a teleport in Half Life 2. The element is highly visible inside the otherwise sparsely decorated room.

The charging is shown by elements of the machine lighting up and starting to spin, giving you a rudimentary clock that conveys how much longer you have to hold out.

After being used the teleport needs to recharge The elements slowly light up again giving the player an indication how much longer they have to hold out from Half-Life 2
After being used, the teleport needs to recharge. The elements slowly light up again, giving the player an indication how much longer they have to hold out (from Half-Life 2)

The teleporter charge is also a good example of an embedded display, which is directly in the gameworld. These are useful as they keep the player focussed on the world itself, while a timer on a GUI layer would be on top of the gameworld.

An oxygen-timer in Metro Last Light directly inside the gameworld
An oxygen timer in Metro: Last Light, directly inside the gameworld

2: Make the Numbers Look Like Numbers

Get a cool font for your countdowns! Certain fonts like this Digital Display Font emulate older lightup displays, which were mostly used for numbers in old "digital" displays.

Digital Display Font Example

The player will already associate these fonts with timers and countdowns, and it will make reading it much simpler, as if it were in something like Arial or Times New Roman.

Basic readability and text composition also apply. Do not stack the numbers vertically, do not use Roman numerals, etc.

3: Give the Player the Amount in Seconds, Not in Minutes

The Metal Gear Solid series does this wonderful trick where they say "you only have 500 seconds left!" and then display a number that reads as "5:00".

When I played it for the first time, my mind auto-completed this to read as "5 minutes", but it was tricked. "500 seconds" is an uncommon yet correct format for time, and people in general are not trained to correctly pick up on this.

The effect is that players will think they only have 5 minutes, while in actuality it is 8 minutes and 20 seconds.

Optional mini-missions in Metal Gear Solid V The Phantom Pain Time is given in seconds obscuring the amount in minutes
Optional mini-missions in Metal Gear Solid V: The Phantom Pain. Time is given in seconds, obscuring the amount in minutes

This usually has no drawbacks, as they will be spurred by the tight time limit and concentrate on accomplishing the task (in Metal Gear Solid 2: defusing bombs), which will distract them from the fact that five minutes may have passed, and there is still time.

4: Make a "Minute" 100 Seconds Long

This goes hand in hand with telling the player the amount of time left in seconds.

A recurring element in the MGS2 countdowns is that they do not have 60-second turnovers, but 100-second "turnovers". This is not actually a minute turning over to the next, but the seconds being listed. So instead of 01:00 becoming 00:59, it is 0100 that becomes 0099. You need to just get the value itself, which makes a countdown actually easier to create, as you can skip the minute calculation.

A countdown used in Metal Gear Solid 2 Sons of Liberty Note the numbers being displayed again in total seconds but in a way that resembles minute-and-second counters While the second-symbol  is also shown the young target demographic is possibly not familiar with it
A countdown used in Metal Gear Solid 2: Sons of Liberty. Note the numbers being displayed again in total seconds, but in a way that resembles minute-and-second counters. While the second symbol (") is also shown, the young target demographic is possibly not familiar with it.

5: Using Milliseconds and Fractions to Add Tension

Having milliseconds displayed after the main number makes it much more interesting!

This is rather easy, as time can be stored in a float already. Two to three floating point numbers are a good amount that is still readable and potentially useful to the player.

6: Use Color to Your Advantage!

When the timer reaches a certain low amount, color the text differently. Making it yellow works well, as it makes the timer stand out more.

Once it reaches its final seconds, make it red, bigger, and flash. Now the low amount cannot be ignored, and it creates tension in the player.

Red countdown from Metal Gear Solid V The Phantom Pain
Red countdown from Metal Gear Solid V: The Phantom Pain

Let's Build a Simple Timer With These Things!

Now let's get started on how to improve a timer via code. We will turn this:

A basic timer-display
A basic timer display

Into this:

Our improved timer-display
Our improved timer display

We will use a few special assets you can quickly get or create yourself, or get from the source files you can download on the upper right of this article.

Ready? Let's go!

Setup & Basic Timer

Start up Unity and create a new project.

Then create an empty gameobject, place it in front of the camera, and add a textMesh via Component > Mesh > TextMesh to it. This will be the display for the timer in the gameworld.

We'll use the 3d-textmesh for now, but this will also work on other areas, like the basic Unity interface. For now, the 3d-text also has the benefit that it can be inside the gameworld, as mentioned before, and not on top of the world inside a GUI-layer.

Our new 3d-text will not be displayed immediately; we need to alter a few values.

Changing some values for our timer

Set the character size to 0.1, the anchor to middle left, the alignment to center, and the font size to 80. Also add some placeholder text into the "text" field. This is just so we have something to look at in the editor; during actual gameplay, this will be directly adapted via code. 00:00 will do nicely.

Then create a new file called Countdown.cs, add it to our timer-object, and add this code to it:

We have a variable named timer, which will hold the time that is counting down. Right now it is at 120 seconds, or 2 minutes. Then in the Update function, which is called every frame, we deduct Time.deltaTime. This is a shortcut to get the actually elapsed time in there. Following that, we get the textMesh component from the object and adapt its text value to be the timer, turned into a string.

When you now run the game, the textmesh will show the number decreasing. Congratulations! You have built a rudimentary timer.

But it is far from being engaging yet. Also, it shows 4 to 5 numbers after the decimal point, and it will continue to go into negative values after reaching zero.

Have It Stop at Zero

A negative timer will look broken, so let's make sure that doesn't happen. Adapt the Update function to look like this:

This will only decrease the timer if it is actually positive. Should it turn negative anyway (which could happen when it subtracts the elapsed time), it will be set to zero.

Get Nicer Numbers

Remember that cool Digital Display Font I mentioned above? Go get it and add it to your project!

The textmesh section in the inspector has a field for the font, so drag the font from your assets there.

And now our timer will look much neater!

A much cleaner timer

Fix the Amount of Numerals

Right now the amount of numbers after the decimal point varies, which makes the timer fluctuate wildly. Fix that by adapting the line that applies the value to the text to look like this:

This will automatically cut off everything after two numbers, constantly showing you tens and hundredths of seconds.

Removing extraneous numbers

Make the Color Change

Let's add some adaptive coloring! Adapt the Update function to look like this:

And the timer will turn yellow when less than 20 seconds are remaining, and red when less than 10 seconds are remaining.

The timer will turn yellow when less than 20 seconds

The entire Countdown.cs file should look like this:

And that's it! We now have a much more engaging and interesting countdown.

You can also look at the complete project in the source files on the upper right of this article.

Conclusion

We took a look at several elements that will improve timers in games, the lessons of which can also be applied to a lot of other elements. In addition, the timer we built can be easily adapted and slotted into any sort of game, and will be an interesting element without you having to develop its contents again.

But there's more! In the next part of this series, we will look at even more elements and continue to improve our timer.

The Smoke & Mirrors of Good Countdowns, Part 2

$
0
0
Final product image
What You'll Be Creating

Last time, we looked at countdowns in games, how they are set up, and what elements you can use to make them more engaging. There are much more than will fit in a single article, though!

This will continue from Part 1, which is why we will start at number seven.

Ready? Let's go!

7: Have a Different Constant Ticking Speed

This is a simple trick that does not even necessitate you lying to the player. You just say "when the timer runs out" and show a ticking clock. What you do not mention is the unit that is shown.

If you show a "10", the player will intuit this is 10 seconds, but the number can decrease slower than seconds would. If you modify the value with a 0.5 multiplier, for example, it will run out after 20seconds instead of just 10.

You can look at how this works in my Ludum-Dare game, Every Ten Seconds a Kitten Drowns.

A timer in Every Ten Seconds a Kitten Drowns
A timer in Every Ten Seconds a Kitten Drowns. The timer is slow enough to give the player a fair amount of time while still appearing very low

The theme of the jam necessitated that 10 seconds are used, but 10 actual seconds are a much-too-low amount of time to accomplish something meaningful.

8: Adapt the Ticking Speed During Gameplay

This also works better if time units are not mentioned and the player is just given a rough idea of "until this happens".

If you have a series of panels that light up to show timer progress, you do not need to activate them at the same rate. In fact, it will become more intense if the first few light up quickly, and the latter ones have more time between them. In the heat of action-packed gameplay, the player will not realize this and will have a much more intense experience.

This should not be employed with actual time units, as players might feel cheated and lied to. Do not break the player's trust in your system.

This can be seen in one level of Starfox 64, where the player has to defend a position against an approaching giant ship.

Minimap in Starfox 64
Minimap in Starfox 64. The attacking mothership (the black circle) is moving towards the base in the middle, giving the player a rough ticking clock of how much time is left to destroy it

On the first glance, you get a rough idea of how much time is left, but the ship itself appears to move at different speeds and not in a straight line.

The timer is in essence being adapted on the fly, the process of which is hidden behind smoke and mirrors.

9: Use Sounds

Countdowns do not have to be purely optical! A beep sound every few seconds will greatly enhance immersion.

Once you have that, you can also adapt the frequency once a certain amount of time has passed. If the beep occurs every five seconds, in the last 30 seconds of the timer the player will be notified without having to look at the number and mentally calculate how much is left.

Similarly,  it also helps if a character comments on the progress. Having someone say "We are halfway done!" gives you a well-framed piece of information that is much easier to understand than parsing it from a readout.

10: Use Scaling Visuals

This works very well when the counter is nearing its end. Whenever another second elapses, scale up the entire counter for half a second.

In addition to color and sound, this will make it much juicier.

11: Do Something When It Reaches Zero

Make sure a timer never goes negative—this will be confusing to a lot of people and seem like a bug, as bugged, badly-created timers tend to do that.

Having it flash would be a nice touch, as it again underlines the point of it having just run out.

If you have a positive timer, it is a fun element to just let it keep running and use that element as a high-score. The game Devil Daggers does a similar thing, where the main goal is "Survive 500 seconds".

Gameplay from Devil Daggers
Gameplay from Devil Daggers

What Not to Do That Would Break the Player's Trust

Once the rules of a timer have been established, they should remain roughly consistent, with more leeway being allowed the less exact a timer is. The main question should be, "How is this hidden rule benefitting the experience?"

When you slow down a timer in the last three seconds, it will make the situation more tense and give the player a few more actual seconds to accomplish things. Randomly slowing it down in the middle, or speeding it up, will only break the player's trust in your rules.

Let's Build It

This will continue with the code-base from the last tutorial and build on it. If you haven't checked it out yet, do so now! You can also download the finished source on the upper right of this article.

When we last left our timer, it looked like this:

Our time when we last left it

Now, new additions will make it behave more interestingly. We will continue with the countdown.cs-script, which should look like this:

Make It Beep

Let's make our timer beep every second, so that the player will know it is decreasing even without looking at it.

First,  we need a nice blip sound effect. You can find an audio file in the source files, or create a nice one using the free tool BFXR. Once you have one, copy it into your asset folder.

Add an AudioSource component to your countdown object via Component > Audio > AudioSource. Add this variable to the countdown script:

You also need to assign the sound file to the soundBlip variable:

Select Blip01

And add this block to the Update function:

This will check whether the timer is at the full second mark, and if so play the sound file.

The actual workings of this code are a bit more complicated. What it does is first round the floating-point timer to two decimal points, then divide it by 1, and see if there is a remainder. If the remainder is zero, it means the timer has reached a full second, and the blip sound can be played.

If we do not do this, the system might trigger much more often, which will not be fun and conducive to a good timer.

Different Speed

This will add a multiplier which will reduce or accelerate the speed of the ticking clock. Add this variable at the beginning:

Now find the line that reduces the timer—it's this one:

And adapt it to look like this:

If the multiplier is below 1.0 the timer will now run slower, and if it's above 1.0 it will run quicker. Setting it at 1.0 will do nothing.

Try to experiment to find a good value! I feel a slightly lower speed, like 0.85f, will make the player feel the ticking clock more.

Slow Down When Low

Now that we have a multiplier component, we can change it during gameplay!

Go to the color-changing block of code:

Here we already have the conditions where a change in ticking speed would be appropriate, so we can just add it!

When the timer turns yellow at 20 seconds, it will now tick with 80% speed. Once it turns red, it will go down to 60% regular speed. Otherwise, it will be set to 100% speed.

Scaling When Low

Another great way to make a timer running out of time stand out more is to scale it up every passing second when low. Since we already have code that gets triggered every second, we can adapt it further!

First, we need a function to increase and decrease the size of our display. Add this function:

This is an IEnumerator, which is a type of function that can contain wait commands. We need the isBlinking variable to make sure we do not call it multiple times.

Once initiated, it will scale up the size of the object by the factor of 1.4f, wait 0.3 seconds, and then scale down again to the original size.

We call it using this special code:

An IEnumerator needs to be initiated by calling it via StartCoroutine, otherwise it will not work.

The entire block will be called when a second passes, at which point we can check if the timer is low enough to make it blink.

Blink at Zero

Let's do something when the timer runs out. Having it just sit there at zero can be boring, so let's make it blink.

First, we'll need another IEnumerator function:

This will turn the timer on and off in 1.5-second intervals. Trigger it in the block that already checks if the timer is zero.

Before running it, we need to disable the beeping and blinking at zero itself, otherwise that will collide behaviors.

Adapt the conditions in the block to check if a second has passed and also to check if the current time is more than zero:

This will make sure regular blinking and zero blinking work without interfering with each other.

The entire countdown script should look like this:

This will get the job done. You can, of course, make it more elegant and combine the commands into a more efficient code.

Conclusion

Our standard little countdown has become much more interesting and engaging. If you build this once, you can use it and plug it into any project you make, no matter how small.

Now go and put it in a game!

Now Available on Envato Elements: Unlimited Stock Photos

$
0
0

Welcome to unlimited stock photos on Envato Elements!

If you're already an Elements subscriber, you'll now see that, along with all the graphics, fonts, web templates, 3D models and everything else you've been used to downloading, you have unlimited access to over 240,000 high-quality stock images. Enjoy!

If you're not an Elements subscriber, here's how it works. For a single monthly subscription of US$29, you get unlimited downloads from a broad and highly curated selection of:

  • graphics (vectors, icons, patterns, textures, illustrations and more)
  • add-ons (think Photoshop and Illustrator actions, Lightroom presets, etc.)
  • fonts
  • graphic templates (logos, infographics, product mockups, etc.)
  • presentation templates (Keynote and PowerPoint)
  • web templates (landing pages, full websites, email newsletters, etc.)
  • CMS templates (Shopify, Magento, OpenCart, and a lot more)
  • 3D models

Oh, and you also get free access to over 1,000 courses and 170 eBooks here on Envato Tuts+, as well as free AND CO membership to help you with invoicing and contracts. 

And because all of that just wasn't enough, now you get almost a quarter of a million stock photos too.

Stock photo on Envato Elements
Workplace image from Envato Elements

Why Envato Elements?

Of course, there are loads of stock photo sites out there already, both free and paid. So why should you bother with Envato Elements? Here are a few reasons:

1. Get Premium Quality

On some other stock photo sites, the emphasis is on quantity: thousands of people uploading millions of images, with little quality control. On Envato Elements, the collection is carefully curated to make sure you have access to the very best images, without having to wade through tons of mediocre ones.

Photography image on Envato Elements
Photography image on Envato Elements

2. Get Broad Commercial Rights

No matter whether you're using photos for a website, an artwork, a client project or a professional document, you need to know that you have the right to use those images and won't get sued for copyright infringement. All the items on Envato Elements come with a simple, easy-to-understand commercial license, so that you can use them in your projects with confidence—and without having to squint at a mass of small print.

Happy couple image on Envato Elements
Happy couple image on Envato Elements

3. Find Exactly What You Need

Elements offers some useful filters to help you find what you need quickly and effectively. You can search by subject, of course, but you can also filter for image orientation (landscape, portrait, or square) and for the predominant colours in the image. So you can find images that not only convey the right message, but also fit seamlessly with your overall design.

Image of Tuscany from Envato Elements
Image of Tuscany from Envato Elements

4. Get a Lot of Other Stuff Too

As I mentioned above, you get a ton of other useful things bundled with an Elements subscription. There are no usage limits, no credits to keep track of. You just use as many photos, templates, fonts and graphics as you need for the projects you're working on. So whether you're a web designer, a developer, an artist a businessperson or a freelancer in a number of creative fields, you'll be able to get good value out of an Elements subscription.

Food image on Envato Elements
Food image on Envato Elements

What to Do Next

To learn more about the new selection of photos, head over to Envato Elements. You can browse the full selection of items even if you don't have an account, so take a look around to get an idea of what's on offer and decide whether it would be useful for you.

Keep in mind that Envato Elements is expanding all the time, both in terms of the number of categories being offered and the number of items in each category. So this is a subscription that's only going to get more valuable over time.

How to Create a Low Poly Floating Island in C4D

$
0
0
Final product image
What You'll Be Creating

Learn Cinema 4D quickly and easily by creating a Floating Island Landscape. Follow this tutorial step by step for use in video games, graphic design and illustration projects.

You can use the popular low poly style for this project. Some of the skills you'll learn will include creating basic 3D shapes, manipulating them, and using basic lighting and rendering. 

1. How to Create Low Poly Sphere

Step 1

Open Cinema 4D and take a look at the top menu bar of the screen. You'll find almost all the tools that you will need to create the floating island. 

Primary-Click and Hold on the blue Add Cube Object button. This reveals a sub menu where you can click to create more objects. Select the Sphere tool by clicking on it.

Choosing a Sphere from the menu
Choosing a Sphere from the menu

Step 2

Once the sphere has been created, change the properties of the sphere in the lower right-hand corner of the screen. 

Under the Object tab, scale the sphere up from 100cm to 250cm. For this tutorial, I've changed the Segments to 100 and the sphere type to Octahedron.

Editing the Sphere parameters in the object options
Editing the Sphere parameters in the object options

Step 3

Untick Render Perfect and remove the Phong Tag. Do this by clicking on it to select it and then pressing Delete or Backspace on the keyboard. This allows us to render the sphere in the low poly style (otherwise it will appear smooth when it is rendered).

Deleting the Phong Tag and unticking Render Perfect
Deleting the Phong Tag and unticking Render Perfect

Step 4

Primary-Click and Hold on the blue Bend button. This reveals a sub menu where you can click to create more objects. Select Polygon Reduction.

Choosing Polygon Reduction from the menu
Choosing Polygon Reduction from the menu

Step 5

Now click and drag the Polygon Reduction so that it is under Sphere. Now go to the Options tab, and place the Reduction Strength at around 92%.

Click and drag the Polygon Reduction
Click and drag the Polygon Reduction

Step 6

Primary-Click and Hold on the blue Bend button to select Displacer. 

Choosing Displacer from the menu
Choosing Displacer from the menu

Step 7

Click and drag Displacer so that it is situated above Polygon Reduction.

Click and drag Displacer
Click and drag Displacer

Step 8

With Displacer selected, go to the Shading Tab. Here you will be able to select Shader > Noise.

Editing Shading tab
Editing Shading tab

Step 9

Go to the Object Tab and play about with the settings here until you come up with a shape that you like. For this tutorial I have put the value at 30cm Height.

Editing Object tab
Editing Object tab

Step 10

Go to the top menu bar and select MoGraph > Effector > Random. Place Random in the Sphere Object with the others (above Displacer) and select the Deformer tab.

From there select Polygon. You can then go to the Parameter tab and the play about with the options there until you are happy with the shape. 

Editing Deformer tab
Editing Deformer tab

2. How to Model a Floating Island

Step 1

In order to make any further changes to the sphere, I will need to make it editable. To do this, ensure the sphere is selected and click on the Make Editable button in the top right of the screen. 

Once you do this, you will not have access to some of the previous options such as radius, segments, type, render perfect. Ensure you're happy with the sphere setup before moving on to this step.

Clicking the Make Editable button
Clicking the Make Editable button

Step 2

Ensuring the sphere is still selected, click on the Polygons button. This changes the appearance of the sphere temporarily in order to make the modelling process easier. Then click the Live Selection Tool.

Selecting the Live Selection Tool
Selecting the Live Selection Tool

Step 3

With the Live Selection Tool selected, right click and select Brush. In the options, set Falloff > Constant and set the Mode > Surface. 

You can also adjust the Strength and Radius settings as well to suit your preference. For the purpose of this tutorial I will set the Strength > -25% and the Radius > 75cm. 

Editing brush options
Editing brush options

Step 4

Use the cursor to brush over the sphere object to manipulate it into the shape that you want the island to be.

Using the brush
Using the brush

Step 5

Deselect your sphere to check out how the low poly island looks.

Checking the island
Checking the island

3. How to Cut the Floor of the Island

Step 1 

Create a Cube by clicking on the cube object button and resize it so that it is large enough to cover the top half of the island. Make sure that the part of the sphere you cover is that section you wish to cut.

Using the new cube
Using the new cube

Step 2 

Go to the top menu and select Array > Boole. Once you have selected Boole, click and drag both the Sphere and the Cube into it. Ensure the Sphere is placed above the Cube.

Selecting Boole from the menu
Selecting Boole from the menu

Step 3

Where the cube overlaps the sphere is where you will cut the floor. You can now select the cube object and move it up and down to find a spot that you like best. 

Cutting the top of the island
Cutting the top of the island

4. How to Create the Mountains

Step 1

Now it is time to create the mountains. Go to the top menu again and select Cube > Landscape. This will spawn a landscape plane. 

Selecting Landscape from menu
Selecting Landscape from menu

Step 2

In the options menu, experiment with the Size settings—particularly the middle option—until you create the size of the mountain that you like.

Editing the size parameters
Editing the size parameters

Step 3

You can also use the Scale Tool (T) to resize the mountain to the desired size.

Scaling the Landscape
Scaling the Landscape

Step 4

Delete the Phong Tag which is located on the right side of the landscape object. This will help give the mountain the Low Poly look.

Deleting the Phong Tag from the Landscape
Deleting the Phong Tag from the Landscape

Step 5

Making sure that the Landscape is still selected, make the Width Segments > 15 and the Depth Segments > 15.

Editing width and height segments from the landscape
Editing width and height segments from the landscape

Step 6

Use the Move Tool (E) to move the mountain into place. Put the base of the mountain inside the floor.

Placement of the landscape on the island
Placement of the landscape on the island

Step 7

Go to the top menu bar, select Bend > Polygon Reduction and drag it into the mountain. Edit the look of the mountain further by editing the Reduction Strength.

Selecting Polygon Reduction from the menu
Selecting Polygon Reduction from the menu

Step 8

Repeat the same steps to create a few more mountains and arrange them to your liking. Change the Seed in the options menu to change the look of the mountain.

Editing the landscape
Editing the landscape

Step 9

Ensure you have the mountain Landscape selected. By clicking up or down on the Seed option you can scroll through different randomised mountain shapes. Select a number that you like. 

Remember you can always go back through all the different options that you used—Polygon Reduction, Displacer and Random—to further tweak the island and landscapes to the shapes that you like.

Choosing the Seed for the Landscape
Choosing the Seed for the Landscape

5. How to Create Mini Trees

Step 1

To create the trees for our floating island, go back to the blue Add Cube Object button again. Primary-Click-Hold and then select the Pyramid tool from the menu.

Selecting Pyramid from the menu
Selecting Pyramid from the menu

Step 2

With the Pyramid selected, click on the Make Editable button and use the Scale Tool to resize it and reshape it to the appropriate size.

Scaling the Pyramid
Scaling the Pyramid

Step 3

Select the Points Tool on the left side of the screen and then use the Move Tool (E) to move the top of the Pyramid down a little. This squashes the object a little bit so that I can fit a second Pyramid underneath. 

If you prefer the look of a taller tree, however, you can leave it as it is or even move the point further up.

Squashing the Pyramid
Squashing the Pyramid

Step 4

Next, you will want to duplicate the pyramid. Control-Click-Drag on your object on the right of the screen. Then using the Move Tool (E) place one pyramid on top of the other.

Duplicating the Pyramid
Duplicating the Pyramid

Step 5

For the tree trunk, we'll need to create a cube. Click on the Cube button and following the same steps as before scale it down and position it below the two pyramids to create a tree. 

Group all the tree objects together by selecting them all and pressing Alt-G. Before duplicating the group and adding it to the island, I'll move on to the next step where we will learn how to add colour.

Adding the Cube
Adding the Cube

6. How to Add Colour to 3D Objects

Step 1

To add some colour to our 3D objects, click on the Create button at the bottom left of the screen. Then select New Material.

Select New Material from menu
Select New Material from menu

Step 2

Double click on the small sphere icon that appears. In the material editor, you have access to a variety of options that will change the appearance and properties of the shapes that you create. 

Untick Reflectance.

Untick Reflectance from Material
Untick Reflectance from Material

Step 3

Click on Color. Choose the colour you want—you can see the colour I have used for the tree below. Once you've chosen the colour, close the material editor. 

Choosing a new colour
Choosing a new colour 

Step 4

Click-Drag the material onto your tree to apply the material colour.

Adding the colour to the tree
Adding the colour to the tree

Step 5

Repeat the steps for the tree trunk and rest of the floating island.

Adding the colours to the rest of the model
Adding the colours to the rest of the model

7. How to Group and Duplicate you Objects

Step 1

I'll begin to populate out floating island with the trees that I created earlier. I must first select all the objects associated with the tree (cube, pyramid x2) and then press Alt-G on the keyboard to create a group. 

Rename the group from Null to Tree and duplicate the group to create more trees.

Grouping objects in the scene
Grouping objects in the scene

Step 2

Hold the Control key on the keyboard while you Click and Drag the tree group to the section below. This duplicates the whole group.

Do this several times until you have the desired number of trees for the island.

New tree groups in the scene
New tree groups in the scene

Step 3

Use the Move Tool (E) to move the trees around the island.

Placing the trees on the island
Placing the trees on the island

8. How to Create the Moon

Step 1

To create the moon for the floating island, return to the blue Add Cube Object button again. Left Click-Hold and then select the Sphere tool from the menu.

Creating a new Sphere from the menu
Creating a new Sphere from the menu

Step 2

Delete the Phong Tag. I'll add a Polygon Reduction and a Displacer to the Sphere. Edit the settings to your liking as before.

Editing the new Sphere
Editing the new Sphere

Step 3

Add a colour to the moon and use the Move Tool (E) to the location that you like.

Choosing a colour for the Sphere
Choosing a colour for the Sphere

9. How to add Lighting and Render the Scene

Step 1

Choose a suitable angle in the viewport by navigating around the scene. Click on the Camera button at the top to create a camera.

Select Camera from the menu
Select Camera from the menu

Step 2

To set up the basic lighting, you’ll want to go to the Floor button located in the top menu bar. Left Click-Hold and then select Physical Sky from the menu.

Select Physical Sky from the menu
Select Physical Sky from the menu

Step 3

Ensuring that Physical Sky is selected in the menu on the right, a new menu will appear on the bottom right of the screen. Select the Time and Location tab and choose a time using the left and right arrow keys. This changes the lighting.

Choose lighting using Time and Location tab
Choose lighting using Time and Location tab

Step 4

Click on the Render Settings button on the top menu bar.

Click the Render Settings button
Click the Render Settings button

Step 5

Choose the resolution, height and width of your image. For this tutorial I have chosen 1920x1200 72dpi.

Choosing Output settings
Choosing Output settings

Step 6

Choose where you'd like to save your file and the file name. You may wish to tick Alpha Channel on, if you want to continue editing the image in another program like Adobe Photoshop.

Choosing Save settings
Choosing Save settings

Step 7

Go to the Effect button at the bottom left and select both Ambient Occlusion and Global Illumination from the drop down menu. This will add these options to the render.

Adding Ambient Occlusion and Global Illumination
Adding Ambient Occlusion and Global Illumination

Step 8

Click the Render button and wait for your render to finish!

Conclusion

And with that, the 3D Floating Island is complete. Feel free to share your own creations below. 

You can also export the image into Adobe Photoshop to enhance it further or to use it as part of a larger illustration. 

Final rendered image of the Floating Island
Final rendered image of the Floating Island

Balancing a Closed Economy in Multiplayer Games

$
0
0

For players, one of the most scrutinized aspects of a video game is its immersion factor. For designers, it’s creating the illusion with seamless finesse. From the first apprehensive steps of level 1 to the final bold strut of level 70, players are deeply woven into an economic system. 

How much they notice, however, is the measure of its designers’ success. Especially evident in Massively Multiplayer Online Role Playing Games (MMORPGs), closed-economy structures are magnificent to behold. These games are composed of potentially thousands of tightly controlled interlocking inputs and outputs, and ostensibly appear to be purely about their chosen theme.

Behind the scenes exists a network of intricate maths and economic principles continuing to maintain that immersion. To illustrate, players fresh out of character creation will inevitably begin by doing the following: exploring the environment, conquering enemies, and then purchasing items. This progression will also often occur in that same order. It’s predictable for a reason, and this article will explore why. The concepts explored below will explain how closed economies operate and sustain themselves and the challenges throughout.

Basics of Stability

When conceptualizing an economy, game designers must begin by choosing a currency. Depending on thematic overtures, the name of the currency will vary. For example, many games use the prototypical “gold” moniker. Whether the setting takes place in a fantastical realm or a futuristic timescape will heavily influence the type of currency depicted. 

In the case of a closed economy, currency carries a set value. Some designers utilize open economies, however, which operate similarly to real-world money. There are exchange rates, and differential values, which are each relative to one another’s values. Using this model significantly increases the difficulty of creating and maintaining the currency within the game’s world but allows a realistic perspective and some compelling implications. For the purpose of this article, the focus will be on the former.

For example, if an iron sword costs 100 gold, it is expected that it will continue to cost 100 gold. This basic stability allows for the remaining structure to be upheld throughout each play through. While in-game currency, gold, is what your players will be trading, the actual currency that an MMO employs is time. Operating as the game’s independent variable, player progression serves as a substitution for time passing. This commonality between games allows balance for the economy since items can easily have pre-determined time values.

A few basic principles can govern this process nicely. For example, the less progress a player experiences (often expressed as “XP”), the less expensive the product remains. The inverse is also true. So product price and player progression have a directly corresponding relationship. 

At level 1, the local tavern sells an iron sword at 100 gold. The difficulty of an event and the reward given share a directly corresponding relationship as well. So a player defeats a worm at level one and receives 5 gold. A player can purchase this sword at any time, but will most likely buy it very early in the game because there is less money available and the item is weaker. It is best suited for the level 1 warrior and will predictably be purchased by the level 1 warrior. Mechanisms like these control the hidden economic fabric of the traditional MMO.

Keeping these principles inextricably connected will continue to provide economic stability to any MMO. Introducing unbalanced items, like downloadable content weaponry that is significantly stronger than currently available weapons, will always disrupt the network. To counterbalance, these items are often not worth much in-game currency or cannot be used until the player reaches a certain level. When these measures are not taken, however, players may feel less engrossed in the game. 

Taking this out of theory and into brass tacks, let’s continue.

System Inputs

Developing the specific input modality for item creation and currency allotment is less complicated than it sounds. To begin, there are three interchangeable models for how to complete this feat: utilizing generators, creating event-based inputs, and compiling individually matched inputs.

Generators can be used for anything that regularly adds to the economy without necessary interaction, the only stipulation being some resource-dependency. For example, if you have a player strike oil during renovations, the amount of oil can be determined by the generator, but whether the player uses the pickaxe is his or her prerogative. So when mining for resources, if an unusually specific amount of coal appears on the player’s screen, this is the culprit. After completing the unrelated task the player was engaged in prior to the generator’s activation, he or she may check the inventory and voila! That resource will have manifested itself.

Event-based inputs can be used when given conditions are met. This is most often used in recurring collection quests—quests that require extracting certain herbs from plants to concoct a potion, for example. The formula behind the quest is: “x plant harvested = y herb extracted”. This modality is often tapped for crafting quests and side-missions.

Single inputs are used for circumstantially driven resource acquisition. When certain conditions are met, but they are also not repeatable, these items are offered—for example, when a player conquers a specific opponent and it drops a unique helmet. These are usually reserved for boss battles and story-driven events since they do not require repetition.

System Outputs

Functioning in the opposite way, system outputs remove items and currency from your economy. Similarly to system inputs, there are three major categories: degenerators, event-based outputs, and single outputs.

Degenerators regularly take away resources that do not necessitate interaction. While more sparingly used than their input counterpart, these appear as ongoing costs throughout game play—for example, tax collection that briefly pops up on the Heads Up Display at regular intervals. This oddly specific number will turn up on its own accord without player interference. When checking the inventory, the player will suddenly be missing exactly that amount of currency.

Event-based outputs are used when players complete specific actions that remove resources from their inventories. For instance, a player sells that iron sword to the shopkeep. In doing so, the event-based output activates to remove the sword from the player’s inventory. Depleting resources while crafting, submitting items for quests, and dropping unwanted items all constitute event-based outputs.

Single outputs are utilized when a resource is removed from the economy altogether and cannot be altered again. Many designers use this mechanism when items must be delivered or destroyed based upon story elements—for example, when obtaining a quest item that players cannot use. These items are usually distinguishable from the others by being held in a separate section of the player’s inventory—like “key items”—and can only be removed when certain events unfold.

Artificial Stability in an Unstable World

Utilizing all three techniques enables game designers to create seamless worlds for their players—if they are in harmony. Ideally, the planned economy would be a perpetually operative and well-oiled machine. It would have a set of inputs that exactly equals the number of outputs, which together produce a purely immersive experience. 

However, the ideal rarely becomes real. Being human hosts a number of spectacular pros, but one con is that we are not perfect. We are not machines, and thus our creations will usually come to fruition with flaws. To keep these flaws at a minimum, and relatively minuscule, this article will leave you with some machine-ly wisdom from experience.

  • Flag Impactful Items: to most efficiently contain simple mistakes in an intricate economy, assign priorities to each resource based on its orb of influence. For example, implementing tighter controls on an epic-level sniper rifle should become a higher priority since it can easily upset the economy. Having an overabundance of iron ore, however, is less likely to have such a significant effect. This way, when entering miles of code in the vast matrix that is the economy, little red flags will tip off any developer that this particular item is a heavy-hitter.
  • Don’t Underestimate Bug Checkers: having players test an alpha version of any game is the first line of defense against potentially disastrous economies. Though some issues may not become evident until more time has passed, these players are ready and willing to try. If an enemy is just too powerful or a weapon is just too rare, they will be upfront with their critique. If this prospect seems a little too gut-wrenching, having friends and loved ones look it over is always a gentler option.
  • Matrix Double-Glance: daunting, yet unfailingly practical, this technique involves compiling all the game’s items included in the economy and listing them in spreadsheets. Check it against itself forwards, and backwards, and then code it manually. To add another level of security, implementing an automated system and letting it convert the items will drastically improve both accuracy and speed.
  • Abandoned Accounts: multiplayer economies have several unique challenges to keep in mind. Suspended, dormant, and otherwise abandoned accounts can create unaccounted-for outputs across a wide variety of resources. This situation can be combated by building slightly different expected-resources-per-player ratios. Do away with generators and de-generators that operate at a fixed rate. Instead, control the flow of resources based on the current amount operating in the economy. This should eliminate any wealth hoarded by abandoned accounts.

Conclusion

Creating a multiplayer economy is an ambitious but rewarding journey. Being able to observe the careful cogs of code manifest themselves as a bustling marketplace is truly spectacular. Even when players gripe about how expensive the rare daggers are, designers know that it is all working according to plan. 

This article has only scratched the surface of what makes MMORPG economies thrive. But the first step is always the hardest! Being able to successfully track resources is a fundamental building block that will launch any game developer ahead in his or her project and field. Examples of how the next steps in this journey may look include exploring ideal resource ratios, establishing player-to-player commodity trading, virtual banks for storing currency, and many more.

To continue the discussion, feel free to drop a comment in the box below!


Grab 16 Free Stock Photos and Design Assets From Envato Elements

$
0
0

Last month, we made a big announcement: unlimited stock photos on Envato Elements. Now, to celebrate the launch, we're giving away 16 free images and design assets, to give a small taste of what Elements has to offer. They all come with a simple license allowing you to use them in any single project you want.

The Freebies You Can Download

So what exactly can you download? You'll find a selection of beautiful photos, such as this stunning underwater shot:

Turtle swimming underwater

You'll also find striking portraits, creative close-up shots, landscape images, and work photos suitable for illustrating a report or proposal:

Colleagues working

And it's not just images you can download. There's also an amazing Photoshop action that allows you simply to brush onto areas of a photo and play the action to turn those areas into a powerful sandstorm effect.

Sandstorm Photoshop action

And on top of all this, you can download an elegant script font, a flyer template, and a PowerPoint presentation template. 

How to Unlock Your Free Photos

To access the free photos and design assets, all you have to do is go to the launch page and enter your email address. Then you can download as many of the free files as you want. 

If you like what you see, you can also explore the full range of more than 200,000 stock photos now available on Envato Elements, or browse the thousands of web templates, 3D renders, graphics and more that come with a monthly subscription. But if it's not right for you, no worries—you can just enjoy your freebies, with no obligation to buy anything. 

Introduction to Vuforia on Unity for Creating Augmented Reality Applications

$
0
0
What You'll Be Creating

This tutorial is going to cover how to implement a basic augmented reality application with Vuforia SDK on Unity. Throughout the tutorial, you are going to learn how to generate a scene compatible with Vuforia and how to implement various scripts, including ray-tracing, in order to be able to interact with the object within the scene.

Creating a Developer Account

Before starting off, you need to register for a Vuforia developer account. Go to the Vuforia Developer Portal to create an account.

Once you create your account, it is time to download the Unity package of Vuforia. Go to the download page and download the specific package for Unity.

Creating an Image Target

An image target is required in order for a device's camera to recognize a reference and track it. The orientation and actual size of the target image directly affect the same attributes of the superimposed images.

Any image can be assigned as a target. However, the features of the target image effectively determine how well the target is tracked. In this tutorial, we are going to use an online tool to generate feature-rich target images. Generate an image target by using the Augmented Reality Marker Generator online tool, and save the image on your computer.

Preparing the Unity Scene

Vuforia Package

Create a new 3D unity project and then double-click the Unity package you downloaded for Vuforia. This will prompt the following window. Click All to select all the content of the package, and then hit Import. This is going to import all the necessary tools for the AR application.

Importing Vuforia Package

Image Target

The next step is to import the image target files. In order to obtain the image target files, we need to use the Vuforia developer page.

Go to the Vuforia Developer Portal and then log in to your account. Under the Develop tab, you will see the Target Manager. First you need to add a database. Use the designated button and add a database. 

Name your database as you wish, and select Device as the type.

Creating Database for targets

Now we are ready to add a target in this database. Click on the Add Target button, and the following window will appear. The type should be selected as Single Image in our case. Select the image target that we generated by using the online tool. If you have any trouble uploading the file, try converting it to .jpg file format and uploading again.

Width is a crucial parameter. This should match the real size of the target image that you will be eventually printing on paper. I set the width to 40. There is no unit since it matches the unit of your scene.

Adding target image

Once you add the target into your database, Vuforia rates your target. With the target image generator we used, features are high and therefore it gets 5 stars, which means it's easy for Vuforia to recognize and track this target.

Now you need to download this database. To do so, hit the Download Database button and select Unity Editor as the development platform.

Downloading database

Once you've downloaded the database, double click on it and import all the content to the Unity scene we are working on.

ARCamera Object

We start by adding the ARCamera object of Vuforia to our scene. To do so, simply follow the Assets > Vuforia > Prefabs directory and add the ARCamera object by dragging and dropping to the scene.

ARCamera directory

Select the ARCamera object and under the Inspector tab, you will see the App License Key section. This license key will be obtained from the Vuforia developer portal.

Log in to your Vuforia account on the Developer Portal and under the Develop tab, you will find the License Manager section. Click the Add License Key button. On the following page, select Development as the project type and define an application name for your project. This name is not crucial, and you can alter it later on if you wish.

Generating the License Key

Hit Next, and then confirm your license key on the next page.

Select the license you've just created. It will reveal the license key that we need to copy and paste to the ARCamera object. Copy this license and then paste it into the App License Key section under the ARCamera settings.

Revealing License Key
Copy and Paste License Key

Under Database Load Behaviour, check the Load ARdemo Database option. Once you check it, another option called Activate will appear right under it. Check this option as well.

The ARdemo part of the Load ARdemo Database option depends on how you named your database.

Loading Database

Image Target Object

The second object we need in our scene is the Image Target object.

Under the Assets > Vuforia > Prefabs directory, you will also find the "ImageTarget" object. Add this object to your scene and select it to reveal the options.

Under the Image Target Behaviour section, you will see the Database option. Select your database from the dropdown menu and select the specific image target you want to assign to the image target object from the "Image Target" option's dropdown menu. If you have multiple image targets for one database, they will all be listed here.

The width and height parameters will be automatically set depending on the value you assigned when creating the image targets in Vuforia's developer portal.

Image target behaviour settings

Augmenting Graphics

The next step is to create the graphics and tie them to the image target. You can either create a GameObject or you can import your own 3D model into Unity and use it. In this tutorial we are going to use a simple 3D cube object for the sake of simplicity.

Add a cube object to the scene as shown in the following figure.

Adding a cube object

Set its x, y and z parameters for the Scale option under Transform to 40, so that it matches the size of the image target we generated.

If you set another width value for your image target when generating it in the developer portal, use the value you selected in order to match the full size of the image target.

Scaling the cube

The last step to get our AR app working is to set the cube object as the child of the image target. To do so, simply drag the cube object and drop it on the imageTarget object under the hierarchy menu.

The final state of the scene should be as follows:

Final state of the scene

Now hit the Play button to run your application. It will use your webcam. Either get the target image printed or open it from your phone so that Vuforia can detect it through your webcam. I did the latter and opened the target image from my phone. 

Here is the actual screenshot of the view of the webcam. You can see that the cube object covers the whole target image, since we matched the scaling factor values both for the 3D object and the target image.

Initial test of augmentation

Interaction Scripts

So far, we've developed a basic AR application that recognizes and tracks our target image and displays the designated 3D graphics. However, for a complete AR application, we also need to be able to interact with the objects, augmenting the reality.

For this purpose, we need to be able to detect where we clicked—or touched, in the case of a mobile device. We'll do this by implementing a ray-tracer.

First, create a folder named "scripts" under Assets to keep everything organized. We are going to store our script files in this folder. Then create a C# Script file in this folder. Name it "rayTracer". Naming is important due to the fact that the following code should match this specific file name. If you prefer to use a different name for your script file, you should also change the provided code accordingly.

Creating a script file

Ray-Tracer Script

Copy and paste the following code into the C# Script file you have just created and named "rayTracer".

This script detects both mouse clicks if you are working on the Unity editor and touch inputs if you have deployed your application on a mobile device with a touch screen.

Once you've created your rayTracer script, you need to activate it by assigning it to one of the objects in the scene. I selected the ARCamera object and added the rayTracer scripts as a component by using the Add Component button under the Inspector tab.

Assigning rayTracer script

Object Material

Now we are going to assign a material to our Cube object and change the color of the material upon interaction with the cube.

Under Assets, create a material and name it as you wish.

Creating material

Now assign this material by dragging and dropping over the cube object.

Interaction Script

Create a new C# Script under the scripts folder and name it "interaction".

Copy the following C# code into your "interaction" script file and then add this script file to the cube object as a component, just as we did with the "rayTracer" script file. However, this time it should be a component of the cube object—this is important in order to be able to only interact with the cube object.

In this "interaction" script, we are referring to the material of the cube object as "mat".

We created two different material objects named defaultColor and selectedColor. defaultColor is selected to be white, as the RGBA parameters indicate, which are (255, 255, 255, 255).

We initialize the cube object's material color as defaultColor by the following line:

mat.color = defaultColor;

We have four different functions for four different states:

  • touchBegan() is called at the instant you touched on the object.
  • touchEnded() is called when you release your finger.
  • touchStay() is called right after you touched on the object—this function follows touchBegan(). So, if you assign different colors to your material in these functions, you are unlikely to see the color assigned in the touchStay() function, since it is the very first instant the touch is recognized.
  • touchExit() is called when you drag your finger out of the cube object's surface, instead of releasing your finger, which calls the touchEnded() function as explained above.

In our code, when we touch on the cube object, we assign the selectedColor object to mat.color, which is the color of our cube object's material.

By assigning the selectedColor within the touchStay() function, we make sure that the color of the cube object will be equal to selectedColor as long as we keep our finger on the cube object. If we release our finger or drag it out of the cube object, we assign  defaultColor to the material's color parameter by calling the touchEnded() or touchExit() functions in accordance with the action we took.

Now run the project and click on the cube object once the target image is recognized and the cube object has appeared. It should turn red and white again when you release your click or move it out of the cube object's surface.

Final result

You can experiment with different colors for the four different actions to comprehend them thoroughly.

Conclusion

In this tutorial, we've gone through an introduction to the Vuforia SDK for Unity along with its developer portal, and we've seen how to generate a target image and an appropriate license key. 

On top of that, we generated custom script files in order to be able to interact with the augmented graphics. This tutorial is just an introduction to enable you to start using Vuforia with Unity and creating your own AR applications.

SpriteKit Basics: Putting It All Together

$
0
0
Final product image
What You'll Be Creating

In this post we'll build a simple game from scratch. Along the way, we'll touch on some of the most important aspects of the SpriteKit library.

This post builds on what we've learned earlier in the SpriteKit Basics series. If you want to refresh your SpriteKit knowledge, take a look at some of my other posts.

New Project

Open Xcode and start a new project from the menu File> New Project. Make sure iOS is selected and choose Game as your template.

new project

Give your project a name, and make sure that Language is set to Swift,Game Technology is set to SpriteKit, and Devices is set to iPad.

project options

Planning the Game Scenes

One of the first things I like to do when creating a project is to determine how many scenes I will need for the project. I will usually have at least three scenes: an intro scene, a main game scene, and a scene to show high scores, etc.

For this example, we just need an intro and main gameplay scene since we won't be keeping track of lives, scores, etc. SpriteKit already comes with one scene when you create a new project, so we just need an intro scene.

From Xcode's menu, choose File> New> File. Make sure iOS is selected, and choose Cocoa Touch Class.

new cocoa touch class

Name the class StartGameScene, and make sure that Subclass of is set to SKScene and Language is set to Swift.

startgamescene class

Setting Up GameViewController

Open GameViewController.swift. Delete everything in that file and replace it with the following.

When you create a new project, GameViewController.swift is set up to load GameScene.sks from disk. GameScene.sks is used along with SpriteKit's built-in scene editor, which allows you to visually lay out your projects. We will not be using GameScene.sks, and will instead create everything from code, so here we initiate a new instance of StartGameScene and present it.

Create the Intro Scene

Add the following to the newly created StartGameScene.swift.

This scene is pretty simple. In the didMove method, we add a logo and a button. Then, in touchesBegan, we detect touches on the new game button and respond by loading the main scene GameScene.

Planning Game Classes

The next thing I like to do when creating a new game is decide which classes I will need. I can tell right away that I will need a Player class and an Enemy class. Both of these classes will extend SKSpriteNode. I think for this project we will just create the player and enemy bullets right from within their respective classes. You could make separate player bullet and enemy bullet classes if you prefer, and I suggest you try to do that as an exercise on your own. 

Lastly, there are the islands. These do not have any specific functionality but to move down the screen. In this case, since they're just decorations, I think it's also okay not to create a class, and instead just create them in the main GameScene.

Creating the Player Class

From Xcode's menu, choose File> New> File.  Make sure iOS is selected and choose Cocoa Touch Class.

new cocoa touch class

Make sure that Class is set to Player, Subclass of: is set to SKSpriteNode, and Language is set to Swift.

player class

Now add the following to Player.swift.

Within the init() method, we set up the physicsBody and invoke generateBullets(). The generateBullets method repeatedly calls fireBullet(), which creates a bullet, sets its physicsBody, and moves it down the screen.

When the player loses a life, the respawn() method is invoked. Within the respawn method, we fade the plane in and out five times, during which time the player will be invincible. One the player has exhausted all the lives, the kill() method is invoked. The kill method simply loads the StartGameScene.

Creating the Enemy Class

Choose File> New> File from Xcode's menu. Make sure iOS is selected and choose Cocoa Touch Class.

new cocoa touch class

Make sure that Class is set to EnemySubclass of: is set to SKSpriteNode, and Language is set to Swift.

Add the following to Enemy.swift.

This class is pretty similar to the Player class. We set its physicsBody and invoke generateBullets(). The move() simply moves the enemy down the screen.

Creating the Main Game Scene

Delete everything within GameScene.swift and add the following.

We create an instance of Player and an instance of CMMotionManager. We are using the accelerometer to move the player in this game.

Within the didMove(to:) method we turn off the gravity, set up the contactDelegate, add an edge loop, and set the player's position before adding it to the scene. We then invoke setupAccelerometer(), which sets up the accelerometer, and invoke the addEnemies() and generateIslands() methods.

The addEnemies() method repeatedly calls the generateEnemy() method, which will create an instance of Enemy and add it to the scene.

The generateIslands() method works similarly to the addEnemies() method in that it repeatedly calls createIsland() which creates an SKSpriteNode and adds it to the scene. Within createIsland(), we also create an SKAction that moves the island down the scene.

Within the didBegin(_:) method, we check to see which nodes are making contact and respond by removing the appropriate node from the scene and invoking player.die() if necessary. The createExplosion() method creates an explosion animation and adds it to the scene. Once the explosion is finished, it is removed from the scene.

Conclusion

During this series, we learned some of the most important concepts used in almost all SpriteKit games. We ended the series by showing how simple it is to get a basic game up and running. There are still some improvements that could be made, like a HUB, high scores, and sounds (I included a couple of MP3s you can use for this in the repo). I hope you learned something useful throughout this series, and thanks for reading!

If you want to learn more about game programming with SpriteKit, check out one of our comprehensive video courses! You'll learn how to build a SpriteKit game from A to Z.

Adobe Alternatives: Pixel Art Applications

$
0
0

Pixel art is often viewed as just a retro style of graphics made for the purpose of nostalgia; a throwback to the early days of video games. However to me, and many other lovers of pixel art, it’s the precision, intricacy and aesthetic born of meticulously placing each pixel onto a miniature stage that truly makes it a wonderful and fascinating art form–one that belongs just as much today as it did yesteryear. Outstanding pixel artists often remind me of artisans who create tiny ships in tiny bottles; achieving a lot with a little is always impressive.

Beautiful pixel art from the upcoming game No Place for Bravery

Just as pixel art is an exacting art form, so too can it be helped along by equally exacting applications. Adobe Photoshop has been a common application of choice for pixel artists for a long time, but there exist today some fantastic alternatives, and those designed expressly for pixel art arguably offer the most.

In this article we’ll be looking at five alternative applications for pixel art, and the tools they include that can help pixel artists along. Some of the key types of tools we’ll be looking for are: selecting and resizing tools that don’t add anti-aliasing, access to pixel art color palettes, pixel friendly shortcut tools for things like gradient creation and dithering, help with tilemap creation and animation, easily accessible color selectors for quick changes while drawing, pixel friendly shape drawing tools, real size preview pane, among others.

As far as deciding which software and feature set is “best” for pixel art, it goes a little further than just confirming the inclusion of the most commonly sought after tools, because there are roughly three subsets of pixel art creation to consider: 

  • Seamless tiles for games
  • Sprites & animation
  • Complete artworks

Whether an application is suitable to you can depend on which of the above types of pixel art you do. As we go through these alternatives to Photoshop for pixel art I’ll try to fill you in on which applications have features well suited to each area.

The beauty of dedicated pixel art applications is they tend to be very inexpensive, so you don’t even really have to choose a single application you want to use. You could get every application on this list and still have only spent $23.99, coming in well under our series per application price cap of $100.

Let’s start taking a look at what we have to play with!

1. Pyxel Edit

First cab off the rank is Pyxel Edit. I’m talking about this program at the top of our list, despite its current beta status, because it has strong tools for all three of the pixel art areas we described in the introduction to this article–something quite rare.

Pyxel Edit’s interface. Art by ansimuz

It includes absolutely fantastic tile tools, (not only for seamless tile creation but also full tilesets and even exportable tilemaps), it has animation tools that give you all the essentials, and it allows you to create complete artworks as well. This is software built from the ground up with pixel artists, and in particular game artists, in front of mind.

Pyxel Edit has a lot of great features, but to me its tile creation tools are the real standout, so if you’re involved in game development this might be of particular interest to you. You can define tiles as you go along and place multiple instances of them anywhere in your document. Then if you paint on one instance of a tile all other instances are updated in real time. This is very helpful for creating seamless textures as you can place tile instances next to each other and paint right over the seams.

Instead of painting over the seams between tiles, you also have the option to lock your pencil to only draw within the constraints of the tile you started on. And with the offset tool you can click & drag to shift the contents of an entire tile, with the displaced pixels wrapping around to reappear on the opposite side of the tile.

A big benefit of Pyxel Edit’s excellent tile system is you can see how your tiles will actually look together in a real level, instead of working on your game art in a vacuum. You can watch this process in action in the video below.

Pyxel Edit’s tile functionality means you can also use it as your main level design tool if you choose. It has the ability to export your tilemap data in JSON, XML or TXT format so, depending on the game engine and toolset you use, you may be able to load this data directly into your game projects. For example, you can use this importer addon for Unity, Haxe has an importer, and I understand Phaser has Pyxel Edit importing baked in.

As well as the great tile editing tools, Pyxel Edit checks almost all the boxes for the most commonly required tools for pixel art. It provides a 100% scale preview in the sidebar, it has a “clean 1 pixel line” setting for drawing lines you don’t have to painstakingly tweak afterwards, it has rectangle and ellipse tools, easy color picker access with right-click or ALT+left-click, great color palette management with classic palettes preloaded, and very good selection tools. It also autosaves your work as you go along.

Duplication and movement of pixels is made very easy in Pyxel Edit with a handy set of shortcuts. Hit S to select an area, CTRL to move a selection of pixels, or CTRL+ALT to duplicate and move those pixels. When working with tiles you can also double-click any tile with the Select tool active to select the whole tile, making it easy to duplicate frames for adjustment.

Unfortunately, however, the software doesn’t seem to have live mirroring, (though you can flip selections horizontally or vertically), or any type of dithering tools at present. Hopefully we’ll see these features added as the project moves through its beta phase.

Another really standout set of features in Pyxel Edit is its color management tools, in particular its automated suggestions of different colors, which are generated by adjusting your current color’s shading, lightness, saturation and hue:

These color suggestion tools are so useful I wish they were in every graphics application. Just by selecting a good “seed” color right at the beginning of your project you can get a glimpse of how your entire color palette might look.

Another great tool in Pyxel Edit is its Color Replace tool, which allows you to easily change your mind about colors after you’ve put them on the canvas. It will replace any pixels of the current secondary color, (equivalent to Photoshop’s background color), with the current primary color, (equivalent to Photoshop’s foreground color). So you just sample the color you want to change into the secondary slot, choose your new color in the primary slot, and draw over the pixels whose color you want to alter.

You also get some help with the creation of gradients: choose two colors in your palette and Pyxel Edit can generate a selection of graduating colors in between them. With these colors you can then paint out your gradients.

I’ve focused primarily here on Pyxel Edit’s tile and drawing tools, but it also includes solid animation tools. The layout for animation is the same as for tile creation, whereby you work in a grid layout and place a frame of your animation into each one of the grid squares. You can create multiple animations within a single document, and you can control the time each frame in your animation is held. You can also turn on onion skinning, however it can only be used to show the frame before and after any particular frame.

And finally, if you don’t want to create either a tileset or animation, rather you want to create a single artwork, you just select the “Single image document” option when creating a new file.

Pyxel Edit is a great tool, especially for people involved in game dev, and it can be picked up for $9 while it’s still in beta. It runs on Adobe Air so natively it only works on Mac and Windows, however I’ve found it runs quite well on Linux via Wine also.

  • Website: http://pyxeledit.com/
  • Platforms: Mac, Windows, (also works via Wine on Linux)
  • Price: $9 (Currently in beta)

2. Aseprite

Aseprite is the favorite tool of a great many pixel artists, and with its outstanding range of pixel art specific tools, that’s for good reason. Everything about Aseprite is 100% focused on pixels–even the UI itself is done in pixel art style.

Where Aseprite shines is as a tool for sprite creation and animation. It has a powerful layer and frame based animation system with several features that are not present in many pixel art focused applications.

There are many animation features in Aseprite, too many to list here, but I’ll give you a quick rundown. You have the ability to move multiple frames in your sequence to a new spot in the timeline, copy and paste a number of frames at a time, set onion skinning to show as many of your previous and next frames as you choose, loop or reverse sections of your timeline, move and copy frames (all layers) or cells (selected layers within a frame), and control frame duration. You can read about the full list of animation functions in Aseprite’s animation docs.

As well as the animation features, all the most essential tools for pixel art are present in Aseprite. You have a 100% preview window that floats over your main window, a “pixel perfect” mode for drawing clean lines, great color palette management with the ability to drag & drop swatches to reorder them, easy color picking by holding ALT then left mouse clicking, filled and empty ellipse tools, filled and empty rectangle tools, and a series of really fantastic selection tools including rectangle and ellipse marquees, magic wand, lasso tool and polygonal lasso tool.

On top of that it has quite a long list of super useful drawing tools. For example, with the Contour Tool you can draw an arc or partial outline and it will automatically be closed and filled for you. With the Polygon Tool you can draw out shapes with as many straight sides as you want and it will be automatically filled. With the Spray Tool you can add randomized speckles.

With the Curve Tool you can draw pixel perfect curved lines with a method comparable to using bezier curves. With the Jumble Tool you can randomize the location of an area of pixels to rearrange them. And with the Blur Tool you can generate pixels around the edge of a shape that blur it with the background color.

While drawing you can activate either horizontal or vertical symmetry modes, great for things like character faces. However you’re not stuck with said symmetry being around the center of your document. With either mode activated a line appears on your canvas and you can shift it to any position and draw your symmetrical shape there.

Aseprite’s interface. Art by Charles Gabriel

One of Aseprite’s coolest features, in my view, is the “Shading” ink mode which allows you to select a series of colors and use them all to automatically layer shadows and highlights onto a shape. It also has an alpha compositing ink mode which allows you to blend colors together, and an alpha lock mode to enable painting only inside existing shapes on a layer.

Aseprite does focus on animation, but it’s not without tile creation tools. It has an excellent tiled mode, whereby you can have an image repeat itself horizontally, vertically, or in both directions, allowing you to draw directly over seams to create seamless tiles.

Aseprite also has very useful color mode settings that allow you to choose between RGB mode for full color images, grayscale for black and white, or indexed mode where your colors will be confined to those in the currently active palette.

If you draw in indexed mode any color you choose will automatically replace itself with the closest color in your active palette. If you draw in RGB mode then switch to indexed mode your image will be converted to use colors from that palette only. This can be a great way to allow yourself to draw with a little more freedom, then refine your color palette down to be more crisp at the end of the process.

Aseprite has a color replacement tool, but in contrast with Pyxel Edit’s color replace tool where you draw over the pixels you want to update, in Aseprite you just provide two colors and it will auto replace all pixels of the specified color at once. I personally feel both methods have advantages.

Aseprite was originally GPL so you can still get that open source version free of charge from GitHub, but it won’t have the latest features. The most recent version is available for $14.99, and works across all three desktop operating systems.

3. Piskel

Piskel is very straight forward and to the point sprite and animation creation software. If you want to get in and out fast this is a great solution. It’s so quick, in fact, that it only takes about two and a half minutes for the essentials to be explained in this video:

The focus of Piskel is definitely sprite creation and animation as opposed to tilesets or complete scene creation. It has a relatively limited set of tools, but it also has a direct approach that can be very efficient for sprite creation and animation. It’s made particularly convenient given it has a fully fledged online version, meaning you can access it anywhere.

After drawing your initial character sprite, animations are created easily by just hitting the Add new frame button to the left of the canvas and adjusting an FPS slider to control your speed. Onion skinning is included, which is always a valuable feature in animation.

One thing to bear in mind is Piskel’s pen tool can only be set to between 1px and 4px in size, meaning this software really is best for focusing on sprites and not large pieces like landscapes where you want to paint large areas such as skies quickly.

Of the common pixel art features you always like to have access to, Piskel includes a 100% preview in the right sidebar, it has rectangle, ellipse and stroke/lines tools, a vertical mirror pen for symmetrical drawing, and ellipse and shape selection tools. It also has a dithering tool, something very helpful yet surprisingly rare in pixel art applications.

Additionally it has a really great “shape selection” tool, which will identify any block of connected pixels of the same color. It’s comparable to a magic wand tool, but is a little simpler to use and also allows you to drag the selected shape around immediately after selection without needing to switch to another tool.

As well as a regular fill tool, Piskel also has a modified fill tool that will alter the color of all pixels that share the same color, whether they’re connected to one another or not. This is yet another approach to color replacement, the third we’ve seen in our article so far, and something incredibly helpful in those moments when you’re fine tuning to get just the right color.

Another fantastic tool is the lighten/darken tool which semi-automates the process of creating highlights and shadows. Draw directly over existing pixels with this tool to create highlights, or hold CTRL to instead create shadows. You can either progressively shift the color of a pixel as you draw back and forwards over it, or you can hold down SHIFT to ensure the color is only tinted or shaded one step at a time.

Piskel describes itself as an online app, which can be very convenient, but if you’d rather work offline you can also get desktop versions for Linux, Mac and Windows.

4. GIMP

GIMP is known primarily as an image manipulation program, so it’s perhaps ironic that I didn’t recommend it in our series entry on photo editing software but I am recommending it here. I personally find it to be fantastic for pixel art, with the right setup. I based my own setup on the video you see above, which is quite old now, but still an excellent starting point for pixel art in GIMP.

GIMP doesn’t have some of the pixel art specific tools that dedicated software like Pyxel Edit or Aseprite have, but it does have some general tools that I find very helpful when doing pixel art. For example, GIMP’s selection tool. Once you draw out a selection the marquee has transformation handles that make it easy to select the exact pixels you need. Its floating window mode is something many people turn off right away, but with it active you can  create a second view into your document at actual size and nestle it right into your layout.

GIMP’s color indexing mode can also be very useful for pixel art. If you’re under time pressure and need to produce fast, you can draw something with a more traditional painting technique in RGB mode then convert it to indexed mode to have it translated into a restricted color palette.

For example, I’ve taken the machete from this free game vector art pack.

I scaled it down, with no interpolation, to get it to a size where the pixels will be nice and chunky. Then in the main application menu I went to Image > Mode > Interpolated and allowed a 256 color palette to be generated for me, with no dithering. Then I scaled the image back up, again with no interpolation, to the original size. Here’s the before and after:

This could still use some cleaning up to give it the crispness expected from pixel art, but it’s certainly off to a running start. Strictly speaking this is not pixel art, but for large projects like games you might need to create such a large number of assets that some shortcuts here and there are helpful.

You can also do things like switching in between RGB mode and indexed mode while working in order to speed certain things along. For example, you can draw out a gradient while in RGB mode, which will transition smoothly between the colors. Then you can switch to Indexed mode and enforce a color palette to get a pixel art friendly gradient effect instead.

Another helpful feature for game pixel artists is GIMP’s new tiling symmetry mode. You’ll need version 2.9.5 (compiled from source via Github) to access this. What it does is allow you to repeat whatever you are drawing every certain number of pixels. So if you are drawing a 16x16 tile, set the symmetry offset to 16px on both axis then you can ensure you have seamless tiling as you work:

GIMP isn’t a dedicated pixel art application, but it has a lot to offer and even if you don’t use it as your primary design software, you still might find some of these features slot right into your workflow.

5. Krita

Krita might not seem like the obvious choice when it comes to pixel art but in my experience it can be fantastic. Out of the box it includes a selection of dedicated pixel art brushes, including a square brush, a round brush and a dithering brush.

A big help is the wrap around feature, making seamless tile creation a smooth experience. Just hit W on the keyboard and your canvas tiles in both directions, allowing you to paint over any seams. Another thing I find helpful in Krita is having a fully fledged set of high level color selection tools for fine tuning of color palettes.

Krita also has an excellent alpha locking system, allowing you to do things like drawing out a shape on one layer, then nesting other layers so their content is only visible through the previous layer’s shape–a sort of masking, essentially. This makes adding shadows, highlights and details a much easier process, and allows for a workflow uncommon in pixel art apps.

Part of why I find Krita enjoyable for pixel art is its excellent support for a drawing tablet, while on the other hand I’ve found some pixel art applications have lag when using a tablet, or just overall feel more mouse and keyboard oriented.

Index painting is also available in Krita as it is in GIMP, with the advantage it can be used along with non destructive filter layers. However the setup for this technique is somewhat complex, as detailed in this tutorial.

And another feature Krita has is some basic vector tools you can use to draw out irregular shapes then have them automatically stroked with your selected pixel brush, a technique you can see used in the YouTube video at the start of this section. This is functionality you won’t typically find in pixel art applications.

Krita does have basic frame by frame animation tools but they’re still very new, and probably not the number one choice for pixel animation just yet. But Krita development is always moving fast, so keep an eye out!

For the creation of complete artworks however, Krita is a real prospect.

Wrapping Up

In my personal experience, the two strongest applications on this list are Pyxel Edit and Aseprite, and I don’t feel you can really separate which of the two is “best”. This is because if you are involved in game development and the creation of tilesets you’ll find Pyxel Edit’s specialization very helpful. But if you’re a character and animation artist, you’ll find Aseprite’s specialization very helpful.

Both applications can do some of what the other specializes in, though I’d say Pyxel Edit is probably stronger in animation than Aseprite is strong in tileset creation. However Aseprite is probably stronger for self contained artwork creation than Pyxel Edit. Overall I’d suggest if you’re involved in multiple types of pixel art, using the two together might serve you well.

I would class Piskel as a great application for when you want to get something done fast, or for when you’re on the move and need to access a quality pixel art editor online.

As for GIMP and Krita, in reality they can’t offer the same set of pixel art specific features that the aforementioned applications can. However they do offer a whole gamut of other features, the kind that come with software meant for fully fledged image editing or digital art. Whether you want to use one of these programs for pixel art will likely depend on how much you enjoy each one’s overall toolset and UI.

For me I particularly enjoy that in each application I can use a pencil brush and my drawing tablet to sketch out a rough draft of what I want to create as though I were working on paper, then I can draw my pixel art over the top. And GIMP’s ability to process images into indexed mode is particularly useful. Neither Krita nor GIMP are really top tier options for tile creation or sprite animation, but they can be great for drawing self contained artworks.

That brings us to the end of our roundup of Adobe Photoshop alternatives for pixel art. With a bit of luck you’ve found an application in this list that you’re considering taking on as your new favorite pixel art editor!

Up Next: Animation

Adobe has two animation tools in its suite at the moment: Animate (formerly Flash) which allows for skeletal and keyframe based animation, and Photoshop which also allows for keyframe animation. However, just as with all the other software specialty fields we’ve looked at so far, there are several options for you to choose from when it comes to animation.

In the next article we’ll be checking out some of the best software available for skeletal, keyframe, and frame by frame animation. Some of these programs have fantastic specialist tools that will make your life a whole lot easier while creating animations.

I’ll see you in the next article!







Basic 2D Platformer Physics, Part 7: Slopes Groundwork

$
0
0
Final product image
What You'll Be Creating

Demo

The demo shows the end result of the slope implementation. Use WASD to move the character. Right mouse button creates a tile. You can use the scroll wheel or the arrow keys to select a tile you want to place. The sliders change the size of the player's character.

The demo has been published under Unity 5.5.2f1, and the source code is also compatible with this version of Unity.

Slopes

Slopes add a lot of versatility to a game, both in terms of possible interactions with the game's terrain and in visual variance, but their implementation can be very complex, especially if we'd like to support a vast number of slope types.

As was true for the previous parts in the series, we'll be continuing our work from the moment we left off the last part, even though we'll be reworking a big chunk of the code we've already written. What we'll need from the start is a working moving character and a tilemap. 

You can download the project files from the previous part and write the code along with this tutorial.

Changes in Movement Integration

Since making the slopes work is pretty difficult, it'd be nice if we could actually make things easier in some aspects. Some time ago I stumbled upon a blog post on how Matt Thorson handles the physics in his games. Basically, in this method the movement is always made in 1px intervals. If a movement for a particular frame is larger than one pixel, then the movement vector is split into many 1px movements, and after each one the conditions for collision with the terrain are checked. 

This saves us the headache of trying to find obstacles along the line of movement at once, and instead, we can do it iteratively. This makes the implementation simpler, but unfortunately it also increases the number of collision checks performed, so it might be inappropriate for games where there are many moving objects, especially high-resolution games where naturally the speed at which the objects are moving is higher. The plus side is that even though there will be more collision checks, each check will be much simpler since it knows that the character moves by a single pixel each time.

Slopes Data

Let's start defining the data that we'll need to represent the slopes. First of all, we'll need a height map of a slope, which will define its shape. Let's start with a classic 45-degree slope.

Slopes Data

Let's also define another slope shape; this one will serve as more of a bump on the ground than anything else.

Another slope shape

Of course we will want to use variants of these slopes, depending where we'd like to place them. For example, in the case of our defined 45-degree slope, it will fit nicely if there's a solid block to its right, but if the solid block is on its left then we'd like to use a flipped version of the tile we defined. We'll need to be able to flip the slopes on the X axis and Y axis as well as rotate them by 90 degrees to be able to access all the variants of a predefined slope.

Let's look at what the transformations of the 45-degree slope look like.

Transformations of the 45 degree slope

As you can see, in this case we can get all the variants using flips. We don't really need to rotate the slope by 90 degrees, but let's see how things look for the second slope we defined earlier.

Rotating slopes

In this case, the 90-degree rotation transform makes it possible to place the slope on the wall.

Calculate Offsets

Let's use our defined data to calculate the offsets which will need to be applied to the object that is overlapping with a tile. The offset will carry the information about:

  • how much an object needs to move up/down/left/right in order not to collide with a tile
  • how much an object needs to move to be right next to the top/bottom/left/right surface of a slope
Calculating Offsets

The green parts of the above image are the parts where the object overlaps with the empty parts of the tile, and the yellow squares indicate the area in which the object overlaps with the slope.

Now, let's start to see how we'd calculate the offset for case number 1. 

The object does not collide with any part of the slope. That means we don't really need to move it out of collision, so the first part of our offset will be set to 0.

For the second part of the offset, if we want the bottom of the object to be touching the slope, we would need to move it 3 pixels down. If we wanted the object's right side to touch the slope, we would need to move it 3 pixels to the right. For the object's left side to touch the right edge of the slope, we'd need to move it 16 pixels to the right. Similarly, if we wanted the top edge of the object to touch the slope, we'd need to move the object 16 pixels down.

Now, why would we need the information of how much distance there is between the object's edge and the slope? This data will be very useful to us when we want an object to stick to the slope. 

So, for example, let's say an object moves left on our 45-degree slope. If it moves fast enough it will end up in the air, and then eventually it will fall on the slope again, and so on. If we want it to remain on the slope, each time it moves left, we'll want to push it down so it remains in touch with the slope. The below animation shows the difference between having slope sticking enabled or disabled for a character.

Animation of moving down a slope

We'll be caching a lot of data here—basically, we want to calculate an offset for every possible overlap with a tile. This means that for every position and for every overlap size, we'll have a quick reference of how much to move an object. Note that we cannot cache the final offsets because we can't cache an offset for every possible AABB, but it's easy to adjust the offset knowing the AABB's overlap with the slope's tile.

Defining Tiles

We'll be defining all the slope data in a static Slopes class.

First of all, let's handle the heightmaps. Let's define a few of them to process later on.

Let's add the test tile types for the defined slopes.

Let's also create another enumeration for tile collision type. This will be useful for assigning the same collision type to different tiles, for example a grassy 45-degree slope or stone 45-degree slope.

Now let's create an array which will hold all the tiles' heightmaps. This array will be indexed by the TileCollisionType enumeration.

Processing the Slopes

Before we start calculating the offsets, we'll want to unfold our heightmaps into full collision bitmaps. This will make it easy to determine whether an AABB is colliding with a tile and also will enable more complex tile shapes if that's what we need. Let's create an array for those bitmaps.

Now let's create a function which will extend the heightmap into the bitmap.

Nothing complicated here—if a particular position on the tile is solid, we set it to 1; if it's not, it's set to 0.

Now let's create our Init function, which will eventually do all the caching work we need to have done on the slopes.

Let's create the container arrays here.

Now let's make every tile collision type point to the corresponding cached data.

Offset Structure

Now we can define our offset structure.

As explained before, the freeLeft, freeRight, freeDown, and freeUp variables correspond to the offset that needs to be applied so the object is no longer colliding with the slope, while the collidingLeft, collidingRight, collidingTop, and collidingBottom are the distance that the object needs to be shifted to touch the slope while not overlapping it.

It's time to create our heavy-duty caching function, but just before we do it, let's create a container which will hold all that data.

And create the array in the Init function.

Memory Issues

As you can see, this array has plenty of dimensions, and each new tile type will actually require quite a lot of memory. For every X position in the tile, for every Y position in the tile, for every possible Width in the tile and for every possible Height, there will be a separate offset value calculation. 

Since the tiles we are using are 16x16, this means that the amount of data needed for each tile type will be 16*16*16*16*8 bytes, which equals 512 kB. This is a lot of data, but still manageable, and of course if caching this amount of information is unfeasible, we'll need to either switch to calculating the offsets in real time, probably using a more efficient method than the one we're using for caching, or optimize our data. 

Right now, if the tile size in our game was bigger, say 32x32, each tile type would occupy 8 MB, and if we used 64x64, then it would be 128MB. These amounts seem way too big to be useful, especially if we want to have quite a few slope types in the game. A sensible solution to this seems to be splitting the big collision tiles into smaller ones. Note that it is just each newly defined slope that requires more space—the transformations use the same data.

Checking Collisions Within a Tile

Before we start calculating the offsets, we need to know if an object at a particular position will collide with the solid parts of the tile. Let's create this function first.

The function takes the collision bitmap, the position of the overlap, and the overlap size. The position is the bottom left pixel of the object, and the size is the 0-based width and height. By 0-based, I mean that width of 0 means that the object is actually 1 pixel wide, and width equal to 15 means that the object is 16 pixels wide. The function is very simple—if any of the object's pixels overlap with a slope, then we return true, otherwise we return false.

Calculate the Offsets

Now let's start calculating the offsets.

Again, to calculate the offset, we'll need the collision bitmap, position and size of the overlap. Let's start by declaring the offset values.

Now let's calculate how much we need to move the object to make it not collide with the slope. To do that, while the object is colliding with the slope we need to keep moving it up and checking for collision until there's no overlap with the solid parts of the tile.

No overlaps

Above is the illustration of how we calculate the offset. In the first case, since the object is touching the top bound of the tile, instead of just moving it up we also need to decrease its height. That's because if any part of the AABB moves outside the tile bounds, we are no longer interested in it. Similarly, offsets are calculated for all other directions, so for the above example the offsets would be:

  • 4 for the up offset
  • -4 for the left offset
  • -16 for the down offset—that's the maximum distance because basically if we move the object down, we need to move it all the way out of the bounds of the tile to stop colliding with the slope
  • 16 for the right offset

Let's start by declaring the temporary variable for the height of the object. As mentioned above, this will change depending on how high we'll be moving the object.

Now it's time for the main condition. As long as the object hasn't moved out of the tile bounds and it collides with the solid parts of the tile, we need to increase the offsetUp.

Finally, let's adjust the size of the object-tile overlapping area if the object moves outside the bounds of the tile.

Now let's do the same thing for the left offset. Note that when we're moving the object left and the object is being moved out of the tile bounds, we don't really need to alter the position; instead, we just change the width of the overlap. This is illustrated on the right side of the animation illustrating the offset calculation.

But here, since we weren't moving the freeLeft offset along the way as we were decreasing the width, we need to convert the reduced size into the offset.

Now let's do the same thing for the down and right offsets.

Alright, we've calculated the first part of the offset—that is how much we should move the object for it to stop colliding with the slope. Now it's time to figure out the offsets which are supposed to move the object right next to the solid parts of the tile. 

Notice that if we need to move the object out of collision, we're already doing that, because we stop right after the collision is no more.

Move the object out of collision

In the case on the right, the up offset is 4, but it is also the offset that we need to move the object for its bottom edge to sit on a solid pixel. The same goes for the other sides.

Now the case on the left is where we need to find the offsets ourselves. If we want to find the collidingBottom offset there, we need to move the object 3 pixels down. The calculations needed here are similar to previous ones, but instead this time we'll be looking for when the object will collide with the slope, and then moving while reducing the offset by one, so it barely touches the solid pixels instead of overlapping them.

If freeUp is equal the 0, free down must be equal to 0 as well, so we can throw in the calculations for collidingTop under the same brackets. Again, these calculations are analogous to what we've been doing so far.

Let's do the same for the left and right offsets.

Caching the Data

Now that all the offsets are calculated, we can return the offset for this particular data set.

Let's create a container for all our cached data.

Initialize the array.

And finally, create the caching function.

The function itself is very simple, so it's very easy to see how much data it caches to satisfy our requirements!

Now make sure to cache the offsets for each tile collision type.

And that's it, our main caching function is finished!

Calculating the World Space Offset

Now let's use the cached data to make a function which will return an offset for a character which exists in a world space.

The offset that we'll be returning is not the same struct we used for the cached data, since the world space offsets can end up being bigger than the limits of the single byte. The structure is basically the same thing, but using integers.

The parameters are as follows:

  • the world space center of the tile
  • the left, right, bottom and top edges of the AABB we want to receive the offset for
  • the type of tile we want to receive the offset for

First, we need to figure out how the AABB overlaps with a slope tile. We need to know where the overlap starts (the bottom left corner), and also how much the overlap extends over the tile. 

To calculate this, let's first declare the variables.

Now let's calculate the edges of the tile in the world space.

Now this should be quite easy. There are two main categories of cases we can find here. First is that the overlap is within the tile bounds.

The dark blue pixel is the position of the overlap, and the height and width are marked with the blue tiles. Here things are pretty straightforward, so calculating the position and the size of the overlap doesn't require any additional actions.

The second category of cases looks as follows, and in the game we'll mostly be dealing with those cases:

Let's look at an example situation pictured above. As you can see, the AABB extends well beyond the tile, but what we need to figure out is the position and size of the overlap within the tile itself, so we can retrieve our cached offset value. Right now we don't really care about anything that lies beyond the tile bounds. This will require us to clamp the overlap position and size to the tile's bounds.

Position x is equal to the offset between the left edge of the AABB and the left edge of the tile. If AABB is to the left of the tile's left edge, the position needs to be clamped to 0. To get the overlap width, we need to subtract the AABB's right edge from the overlap's x position, which we already calculated. 

The values for the Y axis are calculated in the same way.

Now we can retrieve the cached offsets for the overlap.

Adjust the Offset

Before we return the offset, we might need to adjust it. Consider the following situation.

Let's see how our cached offset for such an overlap would look. When caching, we were only concerned about the overlap within the tile bounds, so in this case, the up offset would be equal to 9. You can see that if we moved the overlap area within the tile bounds 9 pixels up, it would cease to collide with the slope, but if we move the whole AABB, then the area which is below the tile bounds will move into the collision.

Basically, what we need to do here is adjust the up offset by the number of pixels the AABB extends below the tile bounds.

The same thing needs to be done for all of the other offsets—left, right, and down—except that for now we'll skip handling the left and right offsets in this manner since it is not necessary to do so.

Once we're done, we can return the adjusted offset. The finished function should look like this.

Of course, it's not completely done yet. Later on we'll also be handling the tile transformations here, so the offset is returned appropriately depending on whether the tile has been flipped on the XY axes or rotated 90 degrees. For now, though, we'll be playing only with the non-transformed tiles.

Implementing One-Pixel Step Physics

Overview

Moving the objects by one pixel will make it quite easy to handle a lot of things, especially collisions against slopes for fast objects, but even though we're going to check for collision each pixel we move, we should move in a specific pattern to ensure accuracy. This pattern will be dependent on the object's speed.

Checking 1-pixel collisions

On the picture above, you can see that if we blindly move the object first all the pixels it needs to move horizontally, and after that vertically, the arrow would end up colliding with a solid block that's not really on its course. The order of movement should be based on the ratio of the vertical to horizontal speed; this way we'll know how many pixels we need to move vertically for each pixel moved horizontally.

Define the Data

Let's move to our moving object class and define a few new variables.

First of all, our main mPosition variable will be holding only the integer numbers, and we'll be keeping another variable called mRemainder to keep the value after the floating point.

Next, we'll add a few new position status variables to indicate whether the character is currently on the slope. At this point, it will be good if we pack all the position status into a single structure.

Now let's declare an instance of the struct for the object.

Another variable that we'll need is slope sticking.

Basic Implementation

Let's start by creating the basic collision checking functions; these will not handle the slopes yet.

Collision Checks

Let's start with the right side.

The parameters used here are the current position of the object, its top right and bottom left corners, and the position state. First of all, let's calculate the top right and top left tile for our object.

Now let's iterate through all the tiles along the object's right edge.

Now, depending on the collision tile, we react appropriately.

As you can see, for now we'll skip handling the slopes; we just want to get the basic setup done before we delve into that.

Overall, the function for now should look like this:

We'll do the same for all the other three directions: left, up, and down.

Moving Functions

Now that we have this covered, we can start creating two functions responsible for movement. One will handle the movement horizontally, and another will handle the vertical movement.

The arguments we'll use in this function are the current position, a boolean which indicates whether we find an obstacle along the way or not, an offset which defines how much we need to move, a step which is a value we move the object with each iteration, the AABB's lower left and upper right vertices, and finally the position state.

Basically, what we want to do here is move the object by a step so many times, so that the steps sum up to the offset. Of course, if we meet an obstacle, we need to stop moving as well.

With each iteration, we subtract the step from the offset, so the offset eventually becomes zero, and we know we moved as many pixels as we needed to.

With each step, we want to check whether we collide with a tile. If we're moving right, we want to check if we collide with a wall on the right; if we're moving left, we want to check for obstacles on the left.

If we didn't find an obstacle, we can move the object.

Finally, after we move, we check for collisions up and down, because we could slide right under or above a block. This is just to update the position state to be accurate.

The MoveY function works similarly.

Consolidate the Movement

Now that we have functions responsible for vertical and horizontal movement, we can create the main function responsible for movement. 

The function takes the value of how much to move the object, the object's current speed, its current position together with the floating point remainder, the object's AABB, and the position state.

The first thing we'll do here is add the offset to the remainder, so that in the remainder we have the full value of how much our character should move.

Since we'll be calling the MoveX and MoveY functions from this one, we'll need to pass the top right and bottom left corners of the AABB, so let's calculate them now.

We also need to get the step vector. It will be used as a direction in which we'll be moving our object.

Now let's see how many pixels we actually need to move. We need to round the remainder, because we are always going to move by an integer number, and then we need to subtract that value from the remainder.

Now let's split the movement into four cases, depending on our move vector values. If the move vector's x and y values are equal to 0, there is no movement to be made, so we can just return.

If only the y value is 0, we're going to move only horizontally.

If only the x value is 0, we're going to move only vertically.

If we need to move both on the x and y axes, we need to move in a pattern that was described earlier. First off, let's calculate the speed ratio.

Let's also declare the vertical accumulator which will hold how many pixels we need to move vertically with each loop.

The condition to stop moving will be that we either met an obstacle on any of the axes or the object was moved by the whole move vector.

Now let's calculate how many pixels vertically we should move the object.

For the movement, we first move one step horizontally.

And after this we can move vertically. Here we know that we need to move the object by the value contained in the vertAccum, but in case of any inaccuracies, if we moved all the way on the X axis, we also need to move all the way on the Y axis.

All in all, the function should look like this:

Now we can use the functions we've built to compose our main UpdatePhysics function.

Build the Physics Update Function

First of all, we want to update the position state, so all of the previous frame's data goes to the adequate variables, and the current frame's data is reset.

Now let's update the collision state of our object. We do this so that before we move our object, we have updated data on whether it's on the ground or is pushing any other tiles. Normally the previous frame's data would still be up to date if the terrain was unmodifiable and other objects wouldn't be able to move this one, but here we assume that any of this could happen.

CollidesWithTiles simply calls all the collision functions we've written.

Then update the speed.

And update the position. First off, let's save the old one.

Calculate the new one.

Calculate the offset between the two.

Now, in case the offset is non-zero, we can call our Move function.

Finally, update the object's AABB and the position state.

That's it! This system now replaces the older one, the results should be the same, although the way we do it is quite a bit different.

Summary

That's it for laying down the groundwork for the slopes, so what's left is to fill up those gaps in our collision checks! We've done most of our caching work here and eliminated a lot of geometrical complexities by implementing the one-pixel movement integration. 

This will make the slope implementation a breeze, compared to what we'd need to do otherwise. We'll be finishing the job in the next part of the series. 

Thanks for reading!

Viewing all 728 articles
Browse latest View live