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

Creating a 3D City in Unity 5

$
0
0
What You'll Be Creating

Unity 3D is an open-source game engine used by indie developers and game studios. It is best known for its user-friendly platform, realistic graphics, and multi-platform publishing. This tutorial is great for beginners or anyone looking for a simple way to create a city in Unity.

Downloading Unity

Let's start by going to the Unity website. Unity 3D offers different packages. As an indie developer, their free package is exactly what you need to get started. Click Get Unity and download the package that is compatible with your system. Unity is both Mac and PC compatible, which makes it very popular. It is very important to check the system requirements. As of March 2016, they require a minimum of Windows 7 and Mac OS X 10.8 and above.

Download Unity

Next, you will want to register. By registering, you can keep track of your downloads and purchases from the Unity asset store. Once downloaded, Unity will start up. Depending on your system, it can take two to eight minutes. A dialogue box will open, asking you for your credentials. After you log in, it's time to start a new project. 

Start a New Project and call it "My City". For the time being, do not choose any packages. 

Pay close attention to the folder you add your projects, as all files need to remain in the same location. Keep the default location for this project. Once your project is open, go to File > New Scene, and name your scene "MyFirstCity".

Unity Interface

At first, it will be a little overwhelming, but don't worry—we will take it step by step in order for you to understand what does what. At this point, your window should look like the picture below:

Learning Unity Interface

Let's begin at the bottom. 

  • The Project tab is where your project files, images, textures, and prefabs will go. It is good practice to keep your files organized from the very start. Games require tons of project files so it's better to start off on the right foot. 
  • The Console tab is where you will see any code or file errors. 
  • The Hierarchy tab will be where your current on-screen objects will be. Every project begins with a Light and Main Camera
  • The Scene tab shows your current scene through yourmain camera's focus. 
  • The Game tab shows you what your game looks like when it's being played. 
  • The Animator tab is where you will add your animator controller commands for your character.
  • The Inspector tab is where you will see your current object details, for example, color, texture, scripts, etc. 
The toggle bar

The toggle bar contains the controls to move around in your world. Moving an object in the scene also moves it in real time on the game menu. Make sure you always save your scene to ensure your object stays in the position you want it. Let's go in order.

  • The Hand icon allows you to grab the screen and move in the world freely. 
  • The Crossed Arrow symbol is used to move objects. In a 3D world, you can move up, down, left, and right. 
  • The Rounded Arrows are used to rotate your objects. 
  • The Outward Arrows are used to resize your object.
  • The Box gives you an eye view. When you right-click your mouse, it allows you to see in a first-person view perspective.

Across the top bar, we have File, Edit, Assets, Game Objects, Component, Mobile Input, Window, and Help. The best way to learn about the menu is trial and error. We will go through the menu step by step later in this tutorial. 

Layout

Setting Up Your Unity Layout

When you first open Unity, you will see the above layout. Go to Window then Layouts, and you can view the different layouts available in the Unity editor. Click each one until you are comfortable with them. 

You can also create your own layout by left-clicking the tab and moving it anywhere you want. In my case, I use two monitors so I have my Game Scene on one monitor and my edit Scene in another. Play around with it until you're happy!

Downloading Assets

Now that we've created our scene and are happy with our layout, its time to download the assets we need for our project. Keep in mind any asset you bring into your scene can be used for multiple projects. 

Go to Window and click the Asset Store. The asset store will open; here you will see hundreds of objects, textures, characters, and unity tools. You can purchase any item you would like. Although for this tutorial I will show you how to create your own textures, we will also download free assets. When you open the asset store for the first time, it may ask you to log in. 

Let's start by typing Yughues Free Concrete Materials in the search box. Your window will look like the below sample.

Downloading Assets

Now click Download. After a few moments, a box will open. Click Import. Depending on your system it can take anywhere from two to ten minutes. Once it's imported, you will see your new asset in your Project tab.

Now let's go back to the asset store and import the City Props Pack. Repeat the above instructions. 

We will also be downloading a skybox. Go back to the asset store and import Wispy Skybox.

Now it's time for our Unity packages. Go to Assets > Import Package. We will need the Characters, Cameras and Environment packages. 

Finding Free Assets

We need a road and building textures, so in keeping my promise of free assets let's go to the web. Go to Bing and type "road", and once some images pop up, make sure that under the License section, Free Domain is chosen. 

Feel free to choose any road you like, but a road with no background or sides would be best. You can also feel free to open the image in your editor and remove what is not needed. I have attached the road I used for this tutorial. 

To keep things organized, save your images in your Unity folder. You may need to find where your files are being stored; usually, the default location is Public documents in My Computer. Now we need approximately five building textures. Click this Bing shortcut to be directed to the textures I used for this project. Right-click and save in the same Unity folder. 

Tip:Always remember when using your projects commercially, it is better to be safe than sorry. You can visit websites like Envato Market to purchase royalty-free images.

Now let's create a folder in our Project tab and name it "Artwork". Go to Asset > Import Asset and choose your image. Move your image into your Artwork folder. 

Tip: If you move your image once you have saved your project, there is a chance your image will not appear or appear pink (without a texture). Once all of your assets are downloaded, we are ready to begin setting up our world. Let's click File > Save Scene.

Let's Get Grounded

Let's add our terrain. Go to Game Object > 3D Object > Terrain. This will add a 3D Terrain into the scene. Now is a good time to play with the toggle menu to get used to moving around the world. 

Tip: If your mouse has a wheel, you can use it to move closer or farther away from an object by clicking the Hand icon.

Adding A Ground Texture

Once you add a terrain, your scene should look like the image above. There are a couple of reports of shader glitches when first opening Unity 5. If your project looks like the image below, don't worry—we will fix it! We will discuss lighting in another tutorial, but for now, click Terrain, and then under the Inspector tab choose the Cogwheel, scroll down to Material, and choose Built-In Legacy Diffuse. This should fix the issue.

Shader Glitch in Unity5

Camera Position

When you choose an object in the Hierarchy, the objects detail will show in the Inspector window (on the right). This is where you can make changes to the object, add textures, add colliders and add code. 

Let's get the camera in the correct position. Choose the Main Camera in the Hierarchy tab. Now look at the Inspector tab and on the right, under Transform, you will see Position. Type 265, 20, 20. Your camera should now be in the position where we want it.

Positioning Your Camera

Follow the Grey Brick Road

Now let's add a texture to the terrain. Choose Terrain from the Hierarchy tab and click the paint brush in the Inspector window. Under Textures you will see Edit Textures. Left-click and choose Add a Texture, and a small window will pop up asking you to choose a texture. Once you click that box, the textures you imported from the Asset Store will show. Double-click and add one you like. I chose Dark Concrete.  

Look Into the Sky

Unity comes with a default skybox which works great if you like it. I think it's a little boring, so I'm going to add the skybox we downloaded earlier. Let's click Main Camera and in the Inspector window click Add Component at the bottom. Type Skybox and click the circle on the right. A box will open where you can choose a skybox of your choice by double-clicking it. Now if you look in your Game Scene you will see the new skybox. Looking good so far!

If You Build It

Now that our environment is coming along, let's add some buildings. Go to Game Object > 3D Object > Cube. At first, you won't see the cube because it's at a far distance. Let's get it to where we can see it. Click on Cube from the Hierarchy. Let's position the cube by typing 300, 25, 100. Let's also scale it to 20, 50, 20. You can use the scale tool or just type the size into the boxes. Once you've added the first Cube, right-click it in the Hierarchy tab to rename it. Name it Building 1.

Adding A 3D Building

Awesome. Let's add some more buildings. Repeat the steps above. You will see the additional cube in your Hierarchy as Cube (1), so let's rename it Building 2 by right-clicking your mouse and typing it in.Now scale to 20, 70, 20 and position to 275, 25, 100. 

As you add buildings, change the scale and position for each one. Make sure you keep the middle positions at 25 to keep them lined up. You can also use the toggle bar to scale and move the buildings. Continue the steps until you have five buildings, and name them consecutively, for example Building 2, Building 3, and so on. I have my buildings positioned by skipping 25 numbers like so: 250, 0, 100, 225, 0, 100 etc. Don't forget to save your scene!  

Tip: You can also right-click a building in the Hierarchy tab, copy and paste it. 

Adding Building Textures

Now we get to turn our cubes until buildings. Click on your Artwork folder in the Project tab(this is where you added your building textures). Choose a texture and drag it to a box on your Scene tab. You will immediately see the texture change in your Scene and Game views. Feel free to adjust, move and rotate your buildings until you're satisfied. 

Tip: At times the texture can be backward. An easy fix is to rotate your box by changing the Z rotation to 180.

The Road Ahead

It's time to add the road. Go to Game Object > 3D Object > Plane. Position it at 250, 0.2, 80. Add a Y rotation of 90 and scale it to 1, 1, 15.  Now choose your road texture and add it to the plane. Rename the plane Road.

A Place for Everything

Final Unity projects can have thousands of objects, scripts, and prefabs. It is important to keep your items organized, and now is a good time to organize your Hierarchy. 

Any city is made up of numerous buildings, so let's keep ours itemized by the block. Go to Game Object > Create Empty, and you will now see a new item in your Hierarchy named GameObject. Rename it Block1(L). Click building 1, hold down Shift and highlight all of your other buildings. You can now move them all under Block1(L) which becomes the buildings' parent.

Organizing Your Buildings by Blocks

Copy Cat

We will now create the other side of the street. Right-click Block1(L) and copy and paste. Name it Block1(R). Position Block1(R) to 235, -90, 300. 

You can now change the textures around or download new ones if you wish. When changing a texture, you must click the individual box, otherwise you will change all the textures for the block. Let's reposition the Camera to 340, 10, 80 and rotate to -80. 

Tip: If you don't like the way an item is positioned, you can move it with your toggle menu. Click save. 

Adding City Props

From here on out we will need to use the toggle bar. Practice using the right and left mouse buttons to move around your world. It takes a little practice. 

Click the down arrow on the City Props Pack folder in the Project tab. Scroll down to the Prefabs folder and click the down arrow until you see the list of objects. Choose the Stop sign. When you choose it you will see it displayed in the Inspector window on the right. 

Let's move to the front of the first building. Choose the Stop sign and drag it to the Scene window; depending on your scene, you may need to scale it down. Scale to 0.2, 0.2, 0.2. Great! 

Let's get creative and add more props. Feel free to choose the ones you like and place them anywhere you like on the sidewalk. Remember you can copy and paste any object in your Hierarchy. In the spirit of keeping things organized, create an Empty parent under Game Object and call it City Props. Move items accordingly. Save your scene.

Tip: Remember, if your objects glow white, you will need to change the shader to Legacy Shaders/Bumped Diffuse.

Adding Trees

Now it's time to add some trees to our city. Unity comes with standard trees that work great. You can always download different types of trees from the asset store if you are going for a different look. 

Let's click Terrain in the Hierarchy tab. In the Inspector window, you will see a picture of what looks like a tree under Terrain—click it. Under the settings, change the Brush Size to 1. Now click Edit Trees > Add Tree. In the Tree Prefab box, click the circle at the end. 

Choose a tree (I chose Broadleaf). Double-click and add. You will now see the tree you chose under the Trees box in the Inspector tabWhen you move your mouse on the Scene,a blue circle will follow. Since we have the Brush size on 1, you will place one tree at a time. If you add a tree and it's too large, you can resize under settings by changing the Tree Height. If you make a mistake, click Edit Trees and remove the tree. You can then start over. 

Adding Trees

Adding a Third-Person Character

OK, so we finally have our environment where we want it, and now it's time for our friend Ethan to walk around in our world. Click the down arrow under Standard Assets from the Project tab, then Characters > ThirdPersonCharacter. Go into Prefabs and drag the ThirdPersonController into your Scene. Position the controller at 315, 0.1, 78 and resize to 3, 3, 3.  

You can also rotate him so he is facing the direction you want. Click Play, and you should be able to control Ethan. Click the arrow buttons on your keyboards and run around. 

At some point, you will notice he moves off the screen, so we need the camera to follow him. Under Hierarchy, highlight the Main Camera and drag under ThirdPersonController. Your MainCamera should now be a child of the ThirdPersonController. Now when you hit play, the camera will follow Ethan. 

Adding a First-Person Controller

We can also view our world in the first-person view. Go into your Project tab. Choose Standard Assets, Prefab, FPS Controller. Drag it to your scene, rotate and scale. Before you hit play, it is important to note that the FPS comes with its own camera, so you will need to delete the MainCamera. 

Tip: If your character falls through the ground, you probably have them positioned too low. Double-click your character on the Hierarchy tab and you will see a close-up on the Scene tab. Move the controller up with the arrow bar or position the Y at 1.

Congratulations! You have built your first 3D City in Unity 5! As you can see, it's easy and lots of fun. You can get as creative as you like and add houses, cars, stores, etc. Stay tuned for more Unity tutorials coming soon!


Making Difficult Fun: How to Challenge Your Players

$
0
0

We are game developers. Most of us love games (which is why we got into this business in the first place), so it's likely we've played hundreds of different games over our lives.

The thing is, though, that gaming is a skill. Much like playing an instrument, it is something that can be honed with practice over time. Therefore, it's not unreasonable to assume that most of us are pretty good at gaming.

But not everyone is great at playing games. When you develop a game, you need to bear your target audience's abilities in mind, and that our own preconceptions of “simple” and “hard” can be skewed. Let's have a look at what you need to think about, and how these ideas were put into practice for my game, Cosmic Logic.

A level from Cosmic Logic
A level from Cosmic Logic

What Do Players Want?

One of the most fundamental elements of gameplay design is challenge. Without challenge, a game isn't a game: at best, it's an interactive movie. And while there are "game-movies" out there which are successful, developing one is closer to a movie maker's skill set than a game designer's.

So when playing a game, players generally want a challenge. But, importantly, they want a challenge they can complete. If I play Street Fighter with a friend, then we'll most likely be evenly matched, having fun button bashing away an occasional victory. 

If I challenge a pro-player to a game, then I will just get repeatedly destroyed. It's not fun for me, and simply emphasises how bad I am at the game. As a rule, being reminded that you are bad at something is not a positive experience.

On the flip side, however, players also want to feel as if they've earned a victory. When I play games, I don't sit down and play children's games. Sure, I can probably set a record time for "work out which hole the square block goes into", but it doesn't provide me with any real stimulation. The purpose of challenge within a game is to test the player, and once a player has mastered that challenge, it no longer serves a purpose.

So, when we design our game, we need to decide how difficult it's going to be. All players want to play a game that provides a challenge, but that challenge is relative to the skill of the player. Someone who only plays games for a few hours a month might enjoy solitaire, whereas a serious gamer might only play a game like Starcraft. 

Neither of these games is necessarily better than the other, as their audiences are vastly different. Regardless, the basic rules of game design apply to them both, and we have to appreciate that difficulty means different things to different people.

Making Difficult Fun

So what is the difference between an easy and a hard game? Games are complex, and it's not possible to simply say, "Oh, if you change this one variable, then the game becomes difficult." 

In fact, taking the simplistic approach of changing variables is a very good way to make a game "unfun hard": you can double the hitpoints of the enemy boss, but you're not changing the actual difficulty—you're simply making it take more effort. The term "bullet sponge" is often used to describe these fights, as it often feels as if the boss just constantly soaks up damage with no regard.

As I mentioned earlier, the purpose of a challenge is to test the player until they have mastered that challenge. Bullet sponge enemies don't really modify the challenge—they simply make the player repeat the challenge an additional number of times. Worse, if the player dies, then they have to repeat said challenge from the start: and then you find yourself in the position of playing something which is no longer fun.

We can think of every gameplay element as a mini-challenge. When you're playing Mario, you move to the right. First challenge, jump over a pit. Jump over a goomba. Jump on a koopa. All of these things are challenges that must be overcome. 

If the game was simply "jump over a goomba" ten thousand times, it'd be tedious. But because the challenges differ slightly each time (oh, this one is on a platform, and this one is protected by a Hammer Brother, etc.) it provides enough variation for the player to keep interest.

The first-level of Super Mario Bros
Mini-challenges: cross the pit, avoid the goombas, hit the ? block and navigate the platforms.

So a basic rule to keep things interesting is to slightly modify the challenges. In fact, you can get away with quite a simple gameplay premise if the "mini-challenges" are constantly changing or evolving. In a game like Mario, you can keep reusing the same basic challenge (jump over a pit) if you make slight modifications to it (this one is guarded by an enemy, this one has a moving platform). 

Patrick Holleman has talked about this idea of designing challenges within Mario previously, but the base principles are applicable across almost any game.

Forcing a player to repeat content is where "difficult" becomes "tedious". For example, if a player dies, then you don't necessarily have to force them back to the start of the game. Recent Mario games contain infinite continues, or even mid-level checkpoints to ensure that if the player dies, they don't have to replay the same content over and over.

A difficult game should be one which pushes a player into mastering their skills, rather than forcing them to repeat something over and over until they make a mistake.

A Game Everyone Can Enjoy

Ideally, we want to develop a game that appeals to both serious and hardcore gamers. One popular solution is to include a choice of difficulties (easy/hard) at the start of your game. However, there is no guarantee the player will choose the correct difficulty to maximise enjoyment. There exists the possibility to design your game for all skill levels: where a crossover of players can enjoy the game without being forced into a particular path.

Grand Theft Auto is arguably the most popular of the "crossover" games. It's an incredibly successful title series, and for good reason—for the most part, it has something for everyone to enjoy.

Part of the reason for this is because the game is so expansive, you can choose what you want to do. In fact, there's a rather cute story about a four-year-old playing GTA (under parental supervision, obviously). If a four-year-old can have fun playing a game that 30-year-old veteran gamers can enjoy as well, then you're probably doing something right.

But your game doesn't necessarily have to be GTA big to have mass appeal. A game like Jetpack Joyride is very much aimed at the casual market, but is still playable for more seasoned gamers. The game is an endless runner, which means levels have no "win-state"—you play until you die. The aim of the game is simply to see how far you can get. In this sense, the player is playing against themselves—can you beat your own score?

It should be noted, however, that designing for casual and experienced players can provide difficulties. Team Fortress 2, which is a fairly popular game across the spectrum, has "the sentry", a unique weapon which uses a very rudimentary AI. The sentry is powerful enough to instantly destroy almost anyone that walks in front of it, and clever positioning and teamwork are required to take one down.

For unskilled players, however, sentries can act as a sort of impassable barrier. They may not have the tactical positioning or teamwork skills to effectively destroy turrets, which means turrets provide "binary gameplay", something the designers themselves were aware of. This sort of "casual player wall" is not unique to complex games: when we test our own games, we designed the puzzles, so the solutions are obvious. 

Casual players may not be able to see these solutions in the same way, so no matter how obvious we consider it, we need to make sure they don't end up hitting an impassable wall.

SpaceChem one of the best puzzle games around today And also one of the most brutal
SpaceChem, one of the best puzzle games around today. And also one of the most brutal.

In Practice

So how do we actually go about developing our game? Well, first off, decide what sort of game you want to make. When we started developing Cosmic Logic, we had a fairly solid idea of what we wanted: a simple puzzle game, essentially snooker/pool with a twist, which challenges the player to solve puzzles within a limited number of shots. We wanted to attract as many players as possible, so we needed to make it relatively casual, but with enough content to keep more serious gamers engaged.

Here are some basic points to consider.

How Difficult Is It to Understand the Game?

Generally speaking, serious gamers are more tolerant of tutorials than casual gamers. Serious gamers don't necessarily enjoy tutorials, but because of their "advanced gaming skill", they tend to enjoy games which are more complex. This complexity means additional rules, which must be explained.

When you look at a game like Bejewelled (or any match 3), the game is designed to be immediately accessible. You start a game, and you are given one objective: line up three objects of the same colour. Compare this to a game like Crusader Kings 2, where the objective can very loosely be described as "control Europe", and one of the best tutorials is a six-hour YouTube series.

For Cosmic Logic, we took the simple approach. As soon as the player hits the play button, they are given a simple goal: hit two balls together. In fact, the first level is designed to be very difficult to fail. The first level is not designed to be a challenge, but to let the player recognise the most basic game concept: hitting balls together is good. As the game progresses, additional concepts are added (some balls are bad), and each time the player solves a level, they learn a new way to manipulate the playing field to their advantage.

Where Is the Challenge?

What makes your game hard? Is it devious puzzles and tests of skill, or is it lengthy boss battles and pixel-perfect jumps?

It can be hard to make the distinction between "fun hard" and "unfair hard"—all players are different, and some players may find gameplay elements frustrating that others find trivial. In fact, you can look at a game like "Super Mario Frustration", which is little more than a series of unfair challenges. It's obvious someone out there liked this, and although the market for this style of difficulty may be tiny, it does exist.

The key to testing hard vs. unfair is feedback. Watch people play your game, see which parts provide difficulty, and try to figure out where people are getting annoyed and where people are having fun. Test with everyone: children, grandparents, serious gamers, people who barely touch games. Take notes, see where they get stuck and where they get annoyed, and ask yourself if the challenge is providing a positive gameplay experience or is just obtuse.

This is exactly what we did with Cosmic Logic. I did the bulk of the initial testing myself: I've run through the game so many times I'm thoroughly sick of playing it. The advantage of this was that I could see which levels are tricky: if I'm unable to complete a level first time, then it'll likely be frustrating for a casual gamer. 

Can a Challenge Be Easy and Hard at the Same Time?

This might seem like a stupid question, but easy-hard challenges have been used in gaming for some time. 

The principle revolves around what the player perceives as the challenge. Winning a boss fight is hard; winning a boss fight without getting hit is harder. Some players will happily self-impose these sorts of additional rules upon themselves, but a better way to approach it is a rudimentary reward system—giving the player additional points for completing challenges with restrictions.

When you complete a level of Angry Birds, you get one to three stars to indicate how well you did. Hitman players get graded A+ to F. In Lego Marvel, collecting a certain number of studs awards the player with "True Believer" status. Getting a high score doesn't really mean anything, but it gives players an additional goal to aim for.

Miss a note Doesnt matter keep playing
Miss a note? Doesn't matter, keep playing.

For Cosmic Logic, the level difficulty was designed backwards. Each level was created to have a very specific solution in mind. Once these solutions had been established (i.e. complete a level in three shots), we would then make it easier (but you have five shots to do it). 

Players who could complete each level with the “true” solution would earn a gold star, and completing each level with a gold star unlocks a “bonus” ending. The gold stars and bonus ending don't really change the way the game is played, but they ensure that players have something to aim for beyond simply crashing through levels.

What Happens If I Fail a Challenge?

With any challenge comes the possibility of failure. It's important that we make the separation between failing the player and punishing the player, however. As we said earlier, challenges are only fun while a player hasn't "solved" them. If we make a player go back to the very start of the game every time they die, then it's very likely they'll get bored of seeing the first level very quickly.

In a skill-based game (such as a platformer or first-person shooter), there is some leeway in making the player repeat content, as the longer they play the game, the better they get at it (hopefully). With a puzzle game, this leeway doesn't exist, meaning puzzles are often very binary: either a player can solve it, or they can't. If they can solve it, then great—unless they die and have to solve it again. If they are unable to solve it, then the player becomes stuck. 

There are several ways to avoid this problem. The first option, used by games like flow free, is simply to make all levels open to the player at the start of the game. In flow free, every level is unlocked. Players can choose which puzzles to solve at their leisure, and can entirely skip the first half of the game if they so desire. Flow free has so many levels that skipping a few doesn't really affect the game, but for a more "story-driven" game (such as Mario), allowing a player to skip right to the last level might not be an option.

Flow free puzzles are entirely independent and self-contained so each can be solved at leisure
Flow free puzzles are entirely independent and self-contained, so each can be solved at leisure.

Another possibility is allowing a player to skip levels. Some puzzle games allow a player to skip a certain amount of levels: a player might have three free passes at the start of the game, which means that particularly hard levels can be avoided. This can be partially replicated in other games, by giving the player branching paths, optional fights, or even warp pipes to allow them to skip content.

In Cosmic Logic, we took a third approach: making each level incredibly easy. As we mentioned above, we had an idea of how each level was to be completed, and we simply allowed the player additional shots for them to complete it. We wanted to avoid a level skip mechanic, for there is a gradual learning curve—something you used on level 11 might be necessary to complete level 25. We wanted players to grasp the fundamental concepts of how to play the game, so we simply gave them the leeway to be really bad at it. 

Does the Game Get Harder as the Skill of the Player Increases?

This is a problem that simple games can face. If you're playing something like Space Invaders, then once a player has cleared a few waves, they have essentially "mastered" the game, and it will no longer provide a challenge. 

Most games use a difficulty curve system, which is what we did with Cosmic Logic. As the game progresses, the player learns more ways to clear tables, and new challenges are provided to ensure they are constantly challenged. Nearly all games with a level system use this mechanic.

However, not all games use level systems. For "endless" games, having the difficulty increase as the player continues is one option: but if the player has to play through "easy" content to get to the fun part, then the game might just be boring. 

This was one of the major flaws of Starbyte, another game I worked on some time ago. In retrospect, allowing the player to select a difficulty level would have been smart, but at the time we decided that simply increasing the game's difficulty as the player progressed would be enough. In practice, it meant that the game got too hard too quickly for novice players, and was too easy for too long for advanced players.

Starbye image
Starbyte gameplay. The player has to wade through four or five levels to get to the "real" challenge.

A game doesn't necessarily have to be harder to be fun, though: allowing the player to skip through easy levels, or even offering a "turbo" button, allowing the player to play at double speed and thereby cruising through the simple challenges, are simple but effective ways of keeping your more skilled players engaged.

Bringing It Together

Not all of these techniques are applicable for all games, but they're worth thinking about. A good general rule of thumb for providing a challenge is: "Is this something the player can be realistically expected to do, or are they going to fail?" 

There's nothing wrong with failure, but players don't want to feel cheated out of victory. If a player says, "Well, I should have jumped earlier, that was my fault," then you've provided a good challenge. If a player says, "There was literally no way for me to avoid that," then you're punishing the player for no reason. Most of these design techniques are applicable to all games, as no player likes unfair gameplay.

And remember: although we like to talk about a casual/hardcore divide in gaming, this divide is somewhat arbitrary. With careful planning, there's no reason a good game can't be enjoyed by everyone—and if a four-year-old child can enjoy Grand Theft Auto, what else can we achieve?

Getting Started in WebGL, Part 1: Introduction to Shaders

$
0
0

Shaders are at the heart of most graphics applications and APIs. Typically around half of your WebGL code will be about creating and interfacing with shaders. A good understanding of shaders is therefore necessary. In this tutorial, I'm going to show you around the graphics pipeline (the series of sequential operations performed on the inputs to produce the results) and explain what shaders are, and while we're at it we'll write our first shader.

Note: you don't have to remember everything mentioned in this article. Only by extensive practice will it ever settle in. So, don't take it too seriously. Enjoy reading it now, and you can always return to it for more details later.

What Are Shaders?

In graphics APIs, a shader is a computer program that is used to do shading: the production of appropriate levels of color within an image. It's the right answer, but I bet you are not satisfied! For better understanding, we'll quickly review the history of shaders to know what they are and what led to them.

A Brief History of Shaders

At the beginning, there was software rendering. You'd typically have a set of functions that draw primitives, like lines, rectangles and polygons. By calling one of these functions, the CPU would start rasterizing the primitive (filling the pixels that belong to it on the screen). How these primitives should look was either specified in function arguments or set in state variables. 

Later, it became clear that CPUs were not particularly efficient at doing graphics. They are general purpose by design, so they don't make assumptions about the nature of the programs they are going to run. They provide large and diverse instruction sets to handle all kinds of things, like interfacing memory and I/O, interrupt handling, access protection, memory paging, context switching and a plethora of other stuff. Drawing graphics is just one of many things CPUs can do. And to make things worse, they have to do all these things virtually simultaneously. A solution had to be found to support the ambitions of graphics developers (and game developers).

It was clear that better performance required more specialized hardware. Beginning in 1975, hardware implementations of some of the computationally expensive graphics operations came into existence. Graphics workstations, arcades and game consoles were the first to adopt the new technologies. Personal computers were quite late to join the party.

This gave a good boost in performance, but was just not enough. So, hardware manufacturers responded by implementing drawing primitives in hardware, relieving the CPU from this burden altogether. Professional solutions existed from the 1980s onwards, but only in 1995 did 3DLabs release the first accelerated 3D graphics card aimed at the consumer market.

Software rendering was still very popular back then, and games were among the most important reasons for users to upgrade their CPUs. CPU manufacturers had to maximize on this selling point. They had to come up with something to reinforce their gaming abilities.

One of the core areas that were addressed was vector arithmetic. Graphics applications make heavy use of floating point vectors and matrices. From 1997, hardware manufacturers started including multi-media targeted specialized instruction sets in their CPUs, like MMX, SSE and 3DNow! These instructions were different to regular arithmetic instructions by being SIMD (Single Instruction Multiple Data). You could do vector operations in one go, like adding four values to another four values in one instruction instead of four.

As awesome as they were, game developers demanded more! Games became more CPU demanding than ever. They needed better physics, better AI, better sound effects, etc. Even the multi-core processors that came later couldn't compete with separate hardware whose sole purpose was accelerating graphics. Advanced versions of the SIMD instruction sets still exist in modern CPUs, but are more commonly used in software rendering suites, video encoders/decoders, and hardware emulation software.

The Fixed Pipeline

Graphics APIs filled the gap between the applications and the graphics hardware. They acted like an abstraction layer that hid the details of the hardware implementation, and provided a software implementation if hardware acceleration was not present. This made developers worry less about hardware compatibility. 

It was the responsibility of the hardware manufacturers to provide drivers that implemented the popular APIs. It was up to the manufacturer to decide the API level the hardware was going to support, how much of it was going to be implemented in hardware, how much would be emulated in software (the driver) and how much wouldn't be supported at all. OpenGL and Glide were among the APIs with early support for consumer-level hardware acceleration.

Graphics APIs were not limited to drawing primitives only. They also did transformations, lighting, shadows, and lots of other stuff. So, let's say you wanted to add a light source to your scene. The API gave you the means to detect the maximum number of lights supported by the hardware. You would then enable one of these lights and set its source type (point, spot, parallel), color, power, attenuation, etc. Finally the light was usable. Shadows? You'd have to set its bla bla bla. Anything else? Bla bla bla.

It was inevitable that a certain way of doing things had to be forced to enable maximum compatibility. This was called the fixed pipeline. Although it was customizable, it was still fixed. Developers were limited by the API capabilities, which had to grow larger with every release.

Something to Be Desired

While it worked for games, an entirely fixed pipeline is not very useful for scientific and cinematic graphics. These have to be more innovative and to break the mold quite often. From 1984 onwards, some pioneers worked on "shaders". Instead of performing a fixed function, the renderer would execute some arbitrary code to achieve the desired results. This was made possible in Pixar's RenderMan around 1989, but only as a software implementation.

Like almost every other technology, stuff that belongs to the labs takes time to become democratized. By the end of the 1990s, it was obvious that programmable graphics hardware was the right next step. For around a decade, hardware manufacturers were shying away from this, but they finally had to do it. Games were pushing the limits, and graphics APIs were becoming huge. It was time to stop telling developers what they could and couldn't do and give them control over their hardware.

Thus, pieces of the graphics pipeline were made programmable. Fragment processing (assume a fragment is a pixel for now) was the first to become programmable, followed by vertex processing. The first consumer graphics cards supporting both types of shaders hit the market in 2001. Later, the graphics pipeline became more flexible and allowed for more types of shaders to fit in. Now it's up to the developers to decide how they want to process their data to produce their desired results. This opened the door for limitless innovation.

So, What Are Shaders?

Having said all the above, it's time to sum things up. Shaders are programs that run on the graphics hardware. In modern graphics APIs, they are obligatory parts of the graphics pipeline (the fixed pipeline is no longer supported). Every pixel drawn to the screen must be processed by shaders, no matter how lame or cool it is. Some shader types are optional and can be skipped, but not all of them.

How much processing is done in shaders and how much is done on the CPU is up to the developer to decide. One can have very simple shaders and do everything on the CPU. Another option is to split the load between the two. Or maybe do everything in shaders. While it's up to the developer to decide, what the developer chooses will significantly affect the performance of the application. 

It might feel obvious that moving everything to shaders is the way to go, but it's not always the case. In the end, it's the CPU that knows what should be rendered, how and when, and it has to continuously communicate these to the GPU. They have to collaborate to produce the end results, and they heavily affect each other. It's quite common to see performance bottlenecks caused by nothing but the communication overhead, while the CPU and the GPU are idle or not actually doing any constructive work.

With the background covered, it's time to dive into more details.

The Graphics Pipeline

OpenGL 44 pipeline

This is a simplified (parts were intentionally omitted) version of the OpenGL 4.4 pipeline. There are several other shaders besides the vertex and fragment shaders. Don't worry, we won't have to deal with them now! OpenGL is mainly for desktop operating systems. What we are interested in is OpenGL ES (for embedded systems). Here is a simplified version of the OpenGL ES pipeline:

OpenGL ESWebGL pipeline

Much easier! When it was first introduced, mobile devices weren't a match for desktop OpenGL, so another standard had to be written for limited configuration devices. OpenGL ES is for most a stripped-down version of OpenGL. However, it does deviate from OpenGL in various places.

Since WebGL is meant to be run in browsers, it has to be universal enough to work on both computers and mobile devices. Therefore, WebGL and OpenGL ES share a lot. WebGL 1.0 is based on and equivalent to OpenGL ES 2.0, and WebGL 2.0 is based on and equivalent to OpenGL ES 3.0. The shading language used in WebGL is the same as the one used in OpenGL ES. It's called GLSL ES (OpenGL Shading Language). Hence, this is also the WebGL pipeline.

As of the time of writing this article:

  • Mobile devices have grown much more capable. Now both desktop and mobile devices are converging towards using the same API, namely Vulkan.
  • Experimental Vulkan drivers have been shipped by nVidia, AMD and Intel for Windows and Linux desktop operating systems.
  • Mac OS is still stuck at OpenGL 4.1 (OpenGL 4.5 was released in 2014), and Apple shows no signs of implementing Vulkan on any of its devices. Instead, it's focusing on its proprietary Metal API.
  • The mobile market is dominated by OpenGL ES 2.0/3.0 devices (not even 3.1).
  • WebGL 2.0 has just been released, and its support is still experimental in Chrome and Firefox. It's not supported at all in Safari, Edge and Internet Explorer 11. Whether Vulkan will ever come to browsers is still unknown.

It's quite reasonable to say that WebGL 1.0 (or even 2.0 if we are looking a little bit ahead) is still our best choice for maximum compatibility for years to come. WebGL is basically the only API that works on all major platforms.

Let's get back to our WebGL pipeline.

Vertex Shader

To draw anything, it has to be made up from primitives. Primitives are made from vertices (points in 3D space) and faces joining these vertices (depending on the primitive in question). You can draw points, lines and triangles in WebGL. The most commonly used primitive is the triangle, so we'll stick to it. However, the other primitives may become very handy depending on your application.

The vertices enter the pipeline at the vertex shader. How the vertices are represented is totally up to you. For example, you may decide that each vertex needs to have an xy pair for position. If you are doing 3D then maybe xyz is more appropriate. You may decide that each vertex has a color—why not? Maybe a pair of texture coordinates, a normal vector and an id that represents what object it belongs to. You decide what works for your application. This is known as the Flexible Vertex Format (in DirectX terminology), or just vertex format (in OpenGL). Each one of these vertex parameters is referred to as an "Attribute".

Each and every vertex is then processed by the vertex shader you provide. What does the vertex shader do? How could I know! Again, it's up to you to decide what it actually does. Typically it's used to transform the vertices to their final locations on the screen. This includes accounting for their location with respect to the camera and any scaling or rotation needed, and then projecting them onto the viewing plane (typically the screen) using your desired projection (orthogonal, perspective, fish-eye, or whatever). It can also be used to apply vertex animations—for example, waves on a water surface, or a flesh-like organic movement.

Don't be overwhelmed. Things will gradually clear up as you work your way through this series. All you have to know for now is that the vertex shader accepts arbitrary vertex data (Vertex Attributes) and some data that are constant with respect to all the vertices being processed (Uniforms). It then performs some arbitrary computations on them to decide the final vertex position and produce new arbitrary data for the fragment shader to consume (known as Varyings).

Our First Shader

We'll be filling the viewport with a nice colorful gradient that fades in and out with time. For this we need four vertices (one for each corner of the viewport) and two faces (triangles) to join them. We'll be using this simple vertex shader:

Yes, it looks as if it's written in C. For the most part, GLSL has C-like syntax, but is not C. GLSL is OpenGL's way of making sure shaders are portable enough to work on all OpenGL-compatible hardware. The GLSL code is actually shipped with the applications, and is compiled at run-time to the target hardware instruction set. This way you don't have to rewrite your shaders to support every type of hardware in the market. However, you can still do that!

GLSL compilers face a great challenge, which is to generate optimized programs very quickly from the source code at run-time. They often fail miserably! A scene with moderately complex shaders can take several seconds to compile the shaders only. This degrades the user experience considerably. For this reason, OpenGL allows you to query the binary formats supported by the hardware to load pre-compiled, pre-optimized shader programs. Large game engines do this.

There's no reason to favor one way over the other. We can take the best out of both worlds. We can include the GLSL source code together with some compiled binaries in our applications. If none of our pre-compiled binary formats is supported, we just fall back to compiling at run-time.

Now let's take a closer look at our vertex shader:

This is a declaration of a variable named vertexPosition. It's:

  • global, since it is declared in the global scope. It can be used outside the main function.
  • an attribute, which means that its value is a part of the vertex data associated with each vertex.
  • read-only. Attributes are inputs to the vertex shader. They cannot be modified.
  • vec3. A vector with three floating point components.

Another variable declaration, vertexColor, is:

  • global, just like vertexPosition.
  • a varying. It's an output from the vertex shader, so its value should be computed and set by it.
  • vec4. A vector with four floating point components.

The shader entry point. This function is called once for every vertex to be processed. Before the main is called, all the attributes are initialized to the corresponding data of the current vertex. It takes no arguments, and has no return values. The outcomes of the shader are passed to the next stages of the pipeline in "varyings" or special variables.

Here's one such special variable. gl_Position is where the vertex shader should write the final vertex position. It's:

  • a vector with four floating point components.
  • a built-in variable. We don't need to declare it.
  • in homogeneous coordinates. Not only does it have x, y and z components, but it also has a w component. This component is particularly useful in perspective correct texture mapping. This is out of the scope of this article. Meanwhile, we set w to 1.0.
  • normalized. WebGL uses the coordinates (-1, -1) to represent the lower left corner of your viewport, and (1, 1) to represent the upper right corner. It's the responsibility of the vertex shader to make sure all vertices are transformed from their local coordinate systems to the correct viewport coordinates. Anything outside the viewport dimensions is skipped and is not drawn altogether.

It is also used by the later stages of the pipeline to do:

  • Primitive assembly (like creating faces from vertices).
  • Clipping (breaking faces that extend outside the clipping volume into smaller ones, and skipping the ones outside altogether).
  • Culling (skipping faces that won't be drawn because they are hidden by other primitives, or just facing backwards if we are drawing single-sided polygons).
  • Any other fixed function operations needed by the pipeline.

Back to our important line,

vec4 is called a vector constructor. It constructs a vector with four floating point components from the given parameters. In this particular case, it uses the three values of vertexPosition (which is a vec3) as xyz, and uses 1.0 for the w component. We could also have written:

which has the same effect. We can also do this:

Useless in this particular situation, but possible. Now check this one out:

Interesting, huh? Yes, we can do that. We can even shuffle the order of the components:

This is called swizzling. It comes at no cost, so use it! We can also replicate components:

That's not all! Since vectors are not always used as positions, you get to use different names to refer to your components:

where rgba is usually used when referring to colors, xyzw for positions and stpq for texture coordinates.

I'm not done yet! There's more:

GLSL ES is type-safe. It doesn't allow implicit conversions between types. Thus, a vec3 can't be assigned to a vec2. But applying the vec2() constructor to vertexPosition stripped it from its z component, turning it into a vec2. Therefore, the above lines work perfectly.

Note: while GLSL ES doesn't normally allow implicit conversions, there's an extension to support it. So if it works on your hardware, don't be too happy. It could break on other hardware. Welcome to the wildest nightmares of graphics developers! It often pays off to stick to the standard and make no assumptions.

One last trick:

Using vector constructors on a single scalar value replicates the value over all the components of the vector. vec4(1.0) is identical to vec4(1.0, 1.0, 1.0, 1.0).

All the above forms do essentially the same thing, but some are more efficient than the others in this particular situation. You don't have to maintain the lifetime of the resulting vectors. Consider them temporary, or registers. You don't have to delete these when you are done using them.

Moving on to the next line:

Let's assume it wasn't written like this. Instead:

Remember when we said that gl_Position should be normalized, and that the viewport coordinates in OpenGL range from (-1, -1) to (1, 1)? In this line, we give the vertex a color based on its final location in the viewport. But color values are clamped to the range from 0 (darkest) to 1 (brightest). This means that values less than 0 are treated like a 0, while values above 1 are treated like 1. Since our viewport position ranges from -1 to 1, it means that any vertices in the negative area will be zeroed. What we want is to stretch the colored area over the entire viewport. Let's do this then:

Instead of ranging from -1 to 1, the new range is from 0 to 2. We fixed the negative range problem, but we introduced another range in which all values are 1s. We want a smooth change everywhere on the viewport, so let's give the line its final look:

Thus it ranges from 0 to 1. Exactly what we want! But this is not how we wrote it in the original program. What we wrote was:

We just applied the division to the parentheses, nothing more. So what's special about it? In this form, the line became a MAD instruction (Multiply then Add). Most types of hardware have MAD instructions, so executing this line takes one cycle instead of two. It gives twice the performance, and the code is not any less readable. Sure, the compilers should be smart enough to do this on their own, but you can't guarantee that. Lots of low-quality drivers get shipped every now and then!

Note that we are multiplying a vec4 by 0.5, then adding 0.5 to it. We are mixing scalers and vectors! GLSL ES is type-safe and doesn't allow implicit conversions during assignments, but operations among scalars and vectors are allowed. This is equivalent to:

While this has the desired effect on our red and green components, it leaves the blue component in a different state. The red and green components are based on the vertex xy coordinates, which range from -1 to 1, while the blue is based on the z coordinate, which is a flat zero over the entire viewport. Thus, multiplying by half and adding half results in blue being half over all the viewport. We'll consider this a feature rather than a bug and leave it the way it is! We could have fixed it easily though (do it in your mind as an exercise).

Phew! This concludes our first vertex shader! It just:

  • appends a 1.0 to the vertex position attribute and passes it without modification to the next steps.
  • assigns a color to every vertex by defining and using the varying vertexColor.

Let's move further down the pipeline and see what happens next.

The Rasterizer

We've mentioned that there are several fixed functions performed using gl_Position after the vertex shader, like primitive assembly, clipping and culling. The rasterizer comes after all such fixed functions. Its purpose is to rasterize the primitives created in the primitive assembly step. That is, turn them into fragments, which in turn become pixels.

A fragment is a set of data contributing to the computation of a pixel's final value. Setting a pixel's final value needs one or more fragments, depending on your scene, your shaders and your settings.

Fragment Shader

Just as a vertex shader processes vertices one by one, fragment shaders process fragments one by one.

Your powers of observation continue to serve you well! Yes, fragment shaders use GLSL as well, but they:

  • don't accept attributes, since they don't process vertices.
  • have a different set of input and output built-in variables. For example, they have no access for gl_Position (again, because they don't process vertices), but they have access to another variable called gl_FragCoords, representing the pixel's 2D position in the viewport, in pixels.

Moving on,

We finally meet uniform variables! Uniforms are:

  • accessible from both the vertex and fragment shaders, as long as they are explicitly declared in each.
  • constant with respect to all vertices and fragments within a single draw-call (we get to know what a draw call is in the following article. For now, their values are set by the CPU and are not per-vertex or per-fragment).
  • just like regular constants, using them for branching (conditionals and loops), texture look-ups (reading from textures) or dereferencing arrays can speed up things a lot. It's because the hardware knows that their values won't change throughout the pipeline, so it can perform look-aheads, prefetches and predict branching.

It's also the first time we meet precision qualifiers. GLSL ES support three types of precision qualifiers that apply to integers and floats:

  • lowp. Low Precision. That's somewhere between 9 and 32 bits worth of precision. Floats of this type can hold values in the range [-2, 2], and are accurate to steps of 1/256.
  • mediump. Medium Precision. Somewhere between 14 and 32 bits worth of precision, but at least as precise as lowp if lowp is within this range. Floats of this type can hold values in the range [-214 , 214].
  • highp. High Precision. 32 bits worth of precision (1 sign, 8 exponent and 23 fraction). Floats of this type can hold values in the range [-2126, 2127]. However, implementing this precision is not mandatory. If the hardware doesn't support it, it is reduced to a mediump.

GLSL hardware is allowed to ignore all precision qualifiers and treat everything as highp if it wants. It is also allowed to choose any precisions within the supported ranges. WebGL allows you to query your device to get the exact specification of the implemented precision types.

Giving your variables appropriate precision qualifiers affects performance and compatibility significantly. Always use the lowest precision level acceptable. For example, for representing colors, lowp is the way to go. Since only 8 bits are used to represent every color component in "true color" configurations, lowp is more than enough, unless of course you are doing some fancy stuff, like HDR (High Dynamic Range) and Bloom effects.

Back to our line,

This line declares time to be a float uniform of mediump precision. In GLSL ES fragment shaders, specifying precision when declaring variables is mandatory, unless we declare a global default:

The above line instructs the compiler to treat all floats without a precision qualifier as mediumps. If so, we can write:

We said that uniforms are accessible from both the vertex and fragment shaders, as long as they are explicitly declared in each of them. If that's the case, they are required to have the same precision. They are required to appear the same to the shaders, and graphics hardware may even use the same storage for them in both the vertex and fragment shaders.

Technicalities aside, we are going to update this uniform every frame, adding to it the time elapsed since the last frame in seconds. This will allow us to change pixel colors with time to achieve a nice fading in/out effect.

To the next line,

We have seen vertexColor declaration before in the vertex shader. But unlike uniforms, these are not the same! This vertexColor:

  • is an input to the fragment shader, so it's read-only.
  • represents vertex color as seen by this particular fragment. Since this fragment belongs to the body of a primitive, it lies in the distance between a number of vertices forming this primitive (unless it coincides with a vertex, or the primitive is a point).
  • gets its value by distance-based smooth interpolation of the values of vertexColor set by the vertex shader at the vertices forming the primitive. The rasterizer is responsible for such interpolation.
  • is not that same as the vertex shader vertexColor, so it doesn't have to have the same precision qualifier.

That's the use of varyings. They are arbitrary data produced by the vertex shader to be interpolated and consumed in the fragments. Let's carry on with our shader,

Just like in the vertex shader, it's the shader entry point. It's called once for every fragment to be processed. Before the main is called, all the varyings are initialized to the corresponding data of the current fragment. It takes no arguments, and has no return values. The outcomes of the shader are passed to the next stages of the pipeline in special variables.

gl_FragColor is one such special variable. It's where the shader writes the final value of the fragment, if there's only one color buffer attached. The fragment shader can write to multiple buffers at the same time, but this is beyond the scope of this article.

There's something interesting about fragment shaders, in which they differ from vertex shaders. Fragment shaders are optional. Not having a fragment shader doesn't make the pipeline useless. There are reasons why you might want to disable fragment shaders altogether. One such reason is if the only purpose of drawing is to obtain the depth buffer of the scene, which can be used in drawing later to compute shadows.

Also, fragment shaders can be used to do more than just set colors. They can alter a fragment's depth, or maybe discard it altogether (although not recommended as this prevents hidden surface removal optimizations). They can also be one of several steps before reaching the final results. 

So what's written to gl_FragColor may not be a color at all. Finally, writing a value to gl_FragColor doesn't mean that it will find its way to the color buffer directly. There are still more stages in the pipeline that follow fragment shading—stuff like blending (like when primitives are partially transparent), scissoring (discarding all fragments outside a certain rectangular boundary) or anti-aliasing (removing stair-like artifacts at the primitive edges).

For example, when MSAA (Multi-Sampling Anti-Aliasing) is enabled, fragments don't correspond to pixels directly. MSAA basically means that every pixel is sampled at slightly different locations and the result is the weighted sum of all the samples. In such a case, a fragment only represents one sample among others contributing to the final looks of the pixel.

Just as you can enable or disable anti-aliasing altogether, you can do the same with respect to scissoring and blending. There's an extension that allows you to read from the target buffer before writing to it in the fragment shader (which is called framebuffer fetching). It allows you to apply your own blend functions or post-processing effects (like making everything in grey-scale) without having to render to an intermediate framebuffer. This is more powerful than the fixed blend modes, and makes the following blending step useless.

In reality, sometimes the fixed functions are not physically present at all. Instead of implementing them in hardware, the driver appends their equivalent of shader code to your shaders without ever telling you.

Returning to the line in question,

Don't be intimidated. It's very easy. We want the gradient to fade out and in slightly, as if it's breathing deeply. Let's do this step by step:

Introducing our first built-in function, sin. It's what you expect, the sine of an angle (trigonometry and stuff). It's an oscillating function, as its value oscillates from 1 to -1 as the angle increases. This is what we need for our smooth fade in/out effect. 

However, the sine function goes all the way down, and then spends half its time as a negative value before becoming positive again. All we want is a slight change in the color value, fading out about half the value and then restoring it again. Let's do this:

That's more like it. The base value around which the color oscillates is 75% of the original vertexColor. The color then goes down 25%, returns, and then rises up 25% as the sine oscillates from -1 to 1. Perfect!

No, not really perfect. While it works, there's something important that we need to consider. Not all hardware supports vector operations (this comes as a shock, but unfortunately is true). Instead of performing vector operations in one clock cycle, they have to perform the operations one component at a time. Now take a look at the line we've just written,

It performs vertexColor*0.25 first, and then multiplies the result by sin(time). This means that all the components of vertexColor will be multiplied by 0.25 first, just to be multiplied by sin(time) again. That's a total of eight multiplications. Now consider reordering the parentheses:

Now the 0.25 is multiplied by sin(time) before being applied to vertexColor. That's a scaler by scaler multiplication (one cycle). This reduces the number of multiplications from eight to five, creating a significant boost, especially for hardware that doesn't support vector operations. 

So as a rule of thumb, mind the order of your operations. Also, mask any components you are not using (like the blue component in our vertex shader). It can't harm a good GPU, but can very well increase the performance of weak ones. 

One last rule. Use the built-in functions whenever possible. They are likely to be implemented in hardware and would be much faster than your software counterparts.

This concludes our vertex and fragment shaders pair. Since the vertex shader is tightly tied to the type vertex data provided, we'll delay messing around with our vertex shader till later, when we'll address how to specify these data. For now, test and play around with the fragment shader as you please.


Finally, now that we have our working vertex and fragment shaders, let's do some analysis.

This scene has exactly four vertices. This means that the vertex shader is called four times only on every frame. 

At the same time, our fragment shader is being called once for every pixel on the viewport. Depending on its size, it could be thousands or even millions of times. This means that our fading in/out calculations are being performed too often, even though they don't do anything pixel-specific. 

We could move this calculation from the fragment shader to the vertex shader (just apply it to vertexColor there). As simple as this act is, it saves tons of computations and has the same result. So always double check if your computations really belong to the fragment shader or if they can just be moved to the vertex shader.

Looking further, we can see the parallel nature of shaders clearly. The same code is being executed over and over again on different inputs. There's no reason why we should wait for the first batch of vertices or fragments to be processed before starting on the next one. That's why graphics hardware is known to have massive numbers of cores. It's because of the parallel nature of the pipeline steps that such numbers of cores can work together to finish the workload more efficiently.

Another thing to notice is the pipeline nature. Every step can be performed immediately after the previous step finishes a simple task. For example, fragment shaders can start working right after the first primitives are assembled. The entire pipeline should always be in a state of motion, taking inputs and producing outputs, without having any stages idling. 

There was a time when vertex and fragment shaders had different capabilities, thus the number of vertex and pixel shader cores were fixed and stated in the hardware specs. In a scene like ours, it would be a total waste to have some vertex shader cores process four vertices and then idle forever, while the fragment shaders are entrusted to a load thousands of times larger.

Luckily, this is no longer the case. Vertex and fragment shaders evolved to become the same thing. This is known as the Unified Shader Model. The same cores are capable of acting as vertex or fragment shaders on demand. A scheduler is entrusted to monitor the workload and to balance the resources assigned to every stage to achieve maximum performance. 

Such flexibility unlocks new horizons for computing on graphics hardware. Shader cores are now used to perform not only graphics, but other parallel natured compute-intensive applications. 

But don't jump to the wrong conclusion. While the cores could be the same, the resources available to different stages of the pipeline still differ. So not everything you can write in a vertex shader can be done in a fragment shader, and vice versa.

Conclusion

There is a lot more that could have gone into this article, but that's enough to get you started. Next in this series, we cover how to initialize and use shaders in your WebGL applications using JavaScript. I hope this was helpful. Thanks a lot for reading!

References and More Reading

Get Started With Mobile Game Development

$
0
0

At this week's E3 expo, the latest mobile games are sure to create a buzz. But what if you want to get started in this growing field yourself? How do you learn how to develop games for Android or iOS?

iOS Game Development

For iOS, a great way to get started is by taking our Game Development With Swift and SpriteKit course. In it, Derek Jensen walks you through the basics of building a simple game for the iPhone from scratch using SpriteKit. You'll learn to create scenes, introduce gravity, detect collisions, and much more.

If you want to learn more about Apple's Swift 2 programming language, check out Derek's comprehensive course, Up and Running With Swift 2. The course consists of 30 lessons and almost five hours of video instruction, covering everything from controlling flow to working with collections. It really is a solid foundation for creating iOS apps.

Android Game Development

For Android, a similar foundational course would be Getting Started With Android. In the course, Paul Trebilcox-Ruiz takes you step by step through the process of native Android development, from setup to creating a finished app.

Once you've got that under your belt, you can try Gaming With the Corona SDK. Corona is a high-performance SDK that exports as a native application for both Android and iOS from a single codebase. Rather than spending time looking at various APIs of Corona, this course instead takes a game-centric approach. You'll learn the fun parts of Corona, specifically for making your own game.

Start Learning With a Free Trial

You can take our full range of game development courses with a free 10-day trial of our monthly subscription. And over on Envato Market, you can find hundreds of mobile game app templates to give you a starting point for creating your own games.

Still looking for more resources? Have a look at these free game development tutorials:


5 Courses to Get You Started With Game Design

$
0
0

If all the coverage of this week's E3 expo has inspired you to improve your game design skills, read on. In this article, I'll introduce you to five of our best game design courses. Whether you want to design characters, environments or landscapes, these comprehensive video courses will teach you everything you need to know.

1.Environment Concept Art for Games

In this course, concept artist and game designer Jonathan Lam will teach you how to paint environment concept art for video games. The course will take you through a step-by-step process of learning how to paint and design in Adobe Photoshop. Topics covered will include composition, value, painting with colour, lighting effects, and shape language.

2. Character Design & Animation for Games

This time, Jonathan Lam will take you through a step-by-step process from learning how to design your character to managing your assets in animation programs such as Spine. Topics covered will include sketching, asset creation, posing and basic movement.

3. Landscape Concept Art for Film and Games

In this short course, Brian Lee will walk you through his process of developing several designs as he would in a real production environment. This is an advanced course and moves very quickly from one concept to the next, covering concepts such as color, atmosphere, and composition.

4. Creating Compelling Environments for Concept Art

Join Kalen Chock to learn how to develop a compelling environment for games or film. You'll learn the core principles of sketching, lighting, composition, color and design. At the end of this course, you will have learned the foundation of how to create your own compelling environments for concept art.

5. Design Isometric Environments for Games

In this course, Jonathan Lam will teach you how to create isometric props for your video game levels and scenery. This course will take you through a step-by-step process of learning how to sketch out and design your in-game assets using both Adobe Illustrator and Adobe Photoshop.

Start Learning With a Free Trial

You can take all of these and more game design courses with a free 10-day trial of our monthly subscription. So get started today, and who knows, maybe you'll see one of your own games taking the limelight at a future E3.

And if you want some extra resources to help you with your projects, check out the range of beautifully designed sprites, backgrounds, and other game assets on Envato Market.

We also have some great free tutorials on game design, so check these out if you'd like to learn that way:


How to Build a Prince-Of-Persia-Style Time-Rewind System, Part 1

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

In this tutorial, we'll build a simple game where the player can rewind progress in Unity (it can also be adapted to work in other systems). This first part will go into the basics of the system, and the next part will flesh it out and make it much more versatile.

First, though we'll take a look at what games use this. Then we'll look at the other uses for this technical setup, before ultimately creating a small game that we can rewind, which should give you a basis for your own.

A demonstation of the basic functionality
A demonstation of the basic functionality

You will need the newest version of Unity for this, and should have some experience with it. The source code is also available for download if you want to check your own progress against it.

Ready? Let's go!

How Has This Been Used Before?

Prince of Persia: The Sands of Time is one of the first games to truly integrate a time-rewinding mechanic into its gameplay. When you die you do not just have to reload, but can rather rewind the game for a few seconds to where you were alive again, and immediately try again.

Prince of Persia The Forgotten Sands The Sands Of Time Trilogy integrates time-rewinding beautifully into its gameplay and avoids immersion-breaking quick-reloading
Prince of Persia: The Forgotten Sands. The Sands Of Time Trilogy integrates time-rewinding beautifully into its gameplay and avoids immersion-breaking quick-reloading.

This mechanic is not only integrated into the gameplay, but the narrative and universe as well, and is mentioned throughout the story.

Other games that employ these systems are Braid, for example, which is also centered around the winding of time. The hero Tracer in Overwatch has a power that resets her to a position a few seconds ago, essentially rewinding her time, even in a multiplayer game. The GRID-series of racing games also has a snapshot-mechanic, where you have a small pool of rewinds during a race, which you can access when you have a critical crash. This prevents frustration caused by crashes near the end of race, which can be especially infuriating.

When you have a fatal crash in GRID you get the chance to rewind the game to a point before the crash
When you have a fatal crash in GRID you get the chance to rewind the game to a point before the crash.

Other Uses

But this system can not only be used to replace quick-saving. Another way this is employed is ghosting in racing games and asynchronous multiplayer.

Replays

Replays are another fun way to employ this feature. This can be seen in games like SUPERHOT, the Worms series, and pretty much the majority of sports games.

Sports-replays work the same way they are presented on TV, where an action is showed again, possibly from a different angle. For this not a video is recorded but rather the actions of the user, allowing the replay to employ different camera angles and shots. The Worms games use this in a humorous way, where very comical or effective kills are shown in an Instant Replay.

SUPERHOT also records your movement. When you are done playing around your entire progress is then replayed, showing the few seconds of actual movement that happened.

Super Meat Boy uses this in a fun way. When you finish a level you see a replay of all your previous attempts laid on top of each other, culminating with your finishing run being the last left standing.

The end-of-level replay in Super Meat Boy Every one of your previous attempts is recorded and then played back at the same time
The end-of-level replay in Super Meat Boy. Every one of your previous attempts is recorded and then played back at the same time.

Time-Trial Ghosts

Race-Ghosting is a technique where you race for the best time on an empty track. But at the same time, you race against a ghost, which is a ghostly, transparent car, which drives the exact way you raced before on your best attempt. You cannot collide with it, which means you can still concentrate on getting the best time.

Instead of driving alone you get to compete against yourself, which makes time-trials much more fun. This feature shows up in the majority of racing games, from the Need for Speed series to Diddy Kong Racing.

Racing a ghost in Trackmania Nations This one has the silver difficulty meaning I will get the silver medal if I beat them Note the overlap in car-models showing the ghost isnt corporeal and can be driven through
Racing a ghost in Trackmania Nations. This one has the silver difficulty, meaning I will get the silver medal if I beat them. Note the overlap in car-models, showing the ghost isn't corporeal and can be driven through.

Multiplayer-Ghosts

Asynchronous Multiplayer-Ghosting is another way to use this setup. In this rarely-used feature, multiplayer matches are accomplished by recording the data of one player, who then sends their run to another player, who can subsequently battle against the first player. The data is applied the same way a time-trial-ghost would be, only that you are racing against another player.

A form of this shows up in the Trackmania-games, where it is possible to race against certain difficulties. These recorded racers will give you an opponent to beat for a certain reward.

Movie-Editing

Few games offer this from the get-go but used right it can be a fun tool.Team Fortress 2 offers a built-in replay-editor, with which you can create your own clips.

The replay-editor from Team Fortress 2 Once recorded a match can be seen from any perspective not just the players
The replay editor from Team Fortress 2. Once recorded a match can be seen from any perspective, not just the player's.

Once the feature has been activated you can record and watch previous matches. The vital element is that everything is recorded, not only your view. This means you can move around the recorded game-world, see where everyone is, and have control over time.

How to Build It

In order to test this system, we need a simple game where we can test it. Let's create one!

The Player

Create a cube in your scene, this will be our player-character. Then create a new C#-script calls Player.cs and adapt the Update()-function to look like this:

This will handle simple movement via the arrow keys. Attach this script to the player cube. When you now hit play you should already be able to move around.

Then angle the camera so that it views the cube from above, with room on its side where we can move it. Lastly, create a plane to act as floor and assign some different materials to each object, so that we're not moving it inside of a void. It should look like this:

Angle the camera so it views the cube from above

Try it out, and you should be able to move your cube using the WSAD and arrow-keys.

The TimeController

Now create a new C#-script called TimeController.cs and add it to a new empty GameObject. This will handle the actual recording and subsequent rewinding of the game.

In order to make this work, we will record the movement of the player character. When we then press the rewind button we will adapt the player coordinates. To do so start by creating a variable to hold the player, like this:

And assign the player-object to the resulting slot on the TimeController, so that it can access the player and its data.

Assign the player-object to the resulting slot on the TimeController

Then we need to create an array to hold the player data:

What we will do next is continuously record the position of the player. We will have the position stored of where the player was in the last frame, the position where the player was 6 frames ago, and the position where the player was 8 seconds ago (or however long you will set it to record). When we later hit a button we'll go backward through our array of positions and assign it frame by frame, resulting in a time-rewinding feature.

First, let's save the data:

In the FixedUpdate()-function we record the data. FixedUpdate() is used as it runs at a constant 50 cycles per second (or whatever you set it to), which allows for a fixed interval to record and set the data. The Update()-function meanwhile runs depending on how many frames the CPU manages, which would make things more difficult.

This code will store the player-position of each frame in the array. Now we need to apply it!

We'll add a check to see if the rewind button was pressed. For this, we need a boolean variable:

And a check in the Update()-function to set it according to whether we want to rewind the gameplay:

To make the game run backward, we will apply the data instead of recordingThe new code for recording and applying of the player position should look like this:

And the entire TimeController-script like this:

Also, don't forget to add a check to the player-class to see if the TimeController is currently rewinding or not, and only move when it is not reversing. Otherwise, it might create buggy behavior:

These new lines will automatically find the TimeController-object in the scene on startup and check it during runtime to see if we are currently playing the game or rewinding it. We can only control the character when we are currently not reversing time.

Now you should be able to move around the world, and rewind your movement by pressing space. If you download the build package attached to this article and open TimeRewindingFunctionality01 you can try it out!

But wait, why does our simple player-cube keep looking in the last direction we left them in? Because we didn't get around to also record its rotation!

For that you need another array to keep its rotation-values, to instantiate it at the beginning, and to save and apply the data the same way we handled position-data.

Try it out! TimeRewindingFunctionality02 is the improved version. Now our player-cube can move backward in time, and will look the same way it did when it was at that moment.

Conclusion

We have built a simple prototype game with an already usable time-rewinding system, but it is far from done yet. In the next part of this series we'll make it much more stable and versatile, and add some neat effects. 

Here is what we still need to do:

  • Only record every ~12th frame and interpolate between the recorded ones to save on the huge data load
  • Only record the last ~75 player positions and rotations to make sure the array doesn't become too unwieldy and the game doesn't crash

We'll also take a look at how to extend this system past just the player-character:

  • Record more than just the player
  • Add an effect to signify rewinding is happening (like VHS-blurring)
  • Use a custom class to hold player position and rotation instead of arrays

Amazon Lumberyard: Introduction, Installation, First Hours

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

Introduction

Lumberyard is the latest 3D game engine to hit the market. It is a free, multi-deploy platform engine that offers deep integration with both the Amazon Web Services (AWS) infrastructure and Twitch to improve general online gameplay.

The Lumberyard engine technology is based on CryEngine. Amazon licensed one version of CryEngine and got complete access to its technology. That does not mean that CryEngine will leave the market, since Lumberyard only represents a branch of CryEngine technology. Both will be present and will struggle for market share.

Lumberyard is a powerful and full-feature AAA game engine that enables you to create games for the latest console generation (Xbox One and PlayStation 4). Mobile support is also a goal (the engine already has rendering options for iOS and Android).

Lumberyard's wide range of features include the following:

  1. State-of-the-art rendering techniques such as: physically based rendering, dynamic global illumination, real-time dynamic water caustics, HDR lens flares, motion blur, depth of field, among many others.
  2. Real-time gameplay editor that enables you to iterate on gameplay elements and immediately see the results.
  3. Robust Networking through the use of a flexible networking subsystem called GridMate. GridMate integrates with major online networking services and lets you handle peer to peer client server typologies with host migration.
  4. Modular Gems offers you a library of several pre-built features (camera, controls, and environment, among others) that can be used to start new projects quickly. Gems give you increased control over which technologies you want to include in your project.
  5. C++ development, and completely free access to its native C++ source code. The engine (and its full source code) is completely free to download and use. However, Amazon expects to generate money through the use of its AWS cloud computing service.

Note that Lumberyard is still in beta version.

Who Should Read This Tutorial Series?

This tutorial series is primarily aimed at two groups of game developers:

  1. those who are completely unfamiliar with game engines at all
  2. those who are familiar with other game engines (such as Unity, Unreal Engine, or Cry Engine), but not with Lumberyard

I assume that you have some knowledge of computer graphics notations, so I won't exhaustively cover all notations.

Prerequisites

In order to install and have a smooth experience while using Lumberyard, your computer must achieve certain minimum requisites:

  • Windows 7 or higher (64 bit versions only)
  • Intel Quad-Core (i 2300), AMD Octo-Core (FX810), or better
  • 8GB of RAM (at least)
  • NVIDIA GeForce 6600Ti. Radeon HD790, or better
  • 40 GB of disk space
  • Visual Studio 2013 (Community, Pro, or Ultimate) with update version 4

Note that if you are at the threshold of the minimum requirements, you may have an inferior quality of experience. In that case, remember that you can lower the overall graphics quality at: File > Global Preferences > Configure.

Installation

The first step in this tutorial is to download Lumberyard. The current version (v1.1) is about 5.3GB file size. While the download is progressing, you should register with Amazon.com (if you don't already have an account).

To install Lumberyard, you can download a complete bundled file (.zip) or use an installer (.exe). The end result is the same, though; this tutorial uses the bundled version.

Step 1: Extraction

After the download is complete, extract it to a path that does not have spaces in the name. For example, do not extract the files to C:\Program Files\Lumberyard because the path has a space in it. An example of an acceptable location is C:\Lumberyard.

You now have Lumberyard installed on your computer, but before you can run it, you need to configure your environment and eventually install additional software.

Step 2: Configuration

The next step is to configure the environment to ensure that you have the necessary software to run the engine. For that purpose, you will use the Lumberyard Launcher (LumberyardLauncher.exe), which can be found inside the folder where you previously installed Lumberyard. Run the LumberyardLauncher.exe file and a similar interface should appear:

The Lumberyard Installer

The Launcher will assist you in ensuring that you always have the necessary software for the execution of tasks. It shows you where the default installation path is located and what actions can be performed based on the software that is currently installed.

Your next step is to select three options:

  • Run your game project
  • Run the Lumberyard Editor and Tools
  • Compile the game code
Options for what you want to do with Lumberyard

Note that as soon as you select one of the aforementioned options, the left part of the Launcher is modified and several menus appear (Install softwareInstall SDKs, Install Plugins). A green check mark means that everything is OK, while a red cross means that something is wrong (some software is missing).

If you see at least one red cross, you should investigate what is happening. Click Next (bottom right corner) or click on the Install software option. A list of available and missing software is presented.

You need to install all the Missing software. Go ahead and click Install it for every single software that is missing. When you have a green check mark at Install software, click Next.

Viewing the available plugins to install

The Install Plugins interface, as the name suggests, "allows you to use certain features and functionality between third party software and Lumberyard". At this point you don't need to add any additional plugins, but make a mental note of them. They are primarily useful when you want to import assets from Photoshop, Autodesk Max, or Autodesk Maya. Click Next.

Step 3: Lumberyard Launcher

The Summary interface shows an activity log (based on previously actions) and three major options:

  • Configure project
  • Launch Lumberyard editor
  • A list of optional software you may want to install

This interface is from now on called Lumberyard Launcher (or simply Launcher). Click on Configure project.

A summary of the software thats been installed

The Project configurator displays several projects with specific configurations, packages, and assets. Here you can create your projects and select the specific assets or configurations that the project will be using. 

Initially you will only have two available projects (MultiplayerProject and SamplesProject). As the names suggest, the former is a multiplayer project, while the second is a more generic project (initially you will be using it). 

Furthermore, if you notice, the SamplesProject is highlighted with a white check mark. It means that this project is the default project loaded by Lumberyard. Click on Enable packages.

The project configurator

Here you access the available Gems of Lumberyard. A Gem is a collection of assets, resources, and others to extend or modify functionality in Lumberyard applications. Several Gems are available, as you can see.

Extensions available to Lumberyard

Close this window and return to Lumberyard Launcher.

Returning to the Lumberyard Launcher after installing required software

Recall that you can always access the Launcher using the LumberyardLauncher.exe executable available in the folder dev\Bin64 under your Lumberyard installation path. It is now time to click on Launch Lumberyard editor.

Step 4: Lumberyard Editor

A new interface (Asset Processor) should appear. The Asset Processor is responsible for loading Lumberyard default project assets (the one highlighted in the Project Configurator). The estimated time is about 10+ minutes.

The Lumberyard Asset Processor

Soon the Lumberyard Editor should load.

The Lumberyard Editor

Wait for the Asset Processor to finish its work. Later, I’ll present a scenario where you load a project that does not have all the resources available.

Recall that, similar to Launcher, you can always access the Editor using the Editor.exe executable available in the folder dev\Bin64 under your Lumberyard installation path.

Editor Layout

Before using Lumberyard Editor, you will need to learn its layout configuration and how to navigate within the Perspective Viewport.

The Lumberyard Editor interface is divided into the following areas (each numerically represented in the following image):

  1. Main menu: Access to all game engine functions and settings.
  2. Editor toolbar: Most commonly used tools (Select, Move, Rotate, Scale, Lock on, Ruler, Snapping, among others). It is composed of three bars: EditMode, Object, Editors.
  3. Viewport header: Search bar and several display options for Perspective Viewport (display resolution, ratio, helpers, among others).
  4. Perspective Viewport: A preview of your 3D environment. It is where the action occurs.
  5. Viewport controls: Several controls for selected objects, mouse location, navigation speed, camera collision detection, AI/Physics, and others.
  6. Console: Display of input and output between the user and the Editor.
  7. Rollup Bar: Access to objects and tools for building and managing content in the Perspective Viewport.
A guide through the interface of Lumberyard

The Rollup Bar is more complex than it initially appears, since it handles all properties, definitions and characteristics of all objects within the Perspective Viewport. Therefore, it's important to enumerate its tabs:

  1. Objects: Contains options for Artificial Intelligence, Entities (Actor, Archetype, Component, Geometry, Particles), Audio, Brushes, and Prefabs, among others.
  2. Terrain: Contains options to apply, modify, and remove terrains, vegetation, holes, Fog, Wind, Clouds, Skyboxes, and others.
  3. Modeling: Contains options for geometry handling, such as selection of geometry types and display types (wire-frame, flat shading, full geometry).
  4. Display: Contains options regarding the rendering settings, i.e., clouds, roads, Fog, Terrain, and Sky box, among others.
  5. Layers: As the name suggests, it contains options to organize your assets by layers.
The Lumberyard RollupBar

Open the First Level

It is now time to open your first level and play with it. Inside the Welcome to Lumberyard Editor window, click on Open level.

The Lumberyard Editor

Then, expand the GettingStartedFiles, choose the getting-started-completed-level, and click Open.

Note that the list of files and samples presented here belongs to the project that is set by default.

Getting Started with Completing a Level

Soon a small 3D village is presented:

A Small 3D Village

3D Level Navigation

Navigating inside the Perspective Viewport is easy, since it uses traditional First Person Shooter (FPS) controls.

ActionKeyboard Key
Strafe forwardW
Strafe backwardD
Strafe leftcell
Strafe rightcell

For the record, note that you can modify these keys if you want (more on that later).

Since 3D scenes are composed of objects or entities, you can interact with them using the mouse.

Action
Mouse Button
Select objectsLeft mouse button
Turn left/right, look up/downRight mouse button
Pan left, right, up, or down Middle mouse button
Zoom in, outMouse wheel or (Right mouse + middle mouse button)

Before continuing to read the tutorial, you can invest some time playing with these controls within the village demo (or load any other demo from the available ones). To load another demo you only need to select File > Open and choose another sample.

Assets Installation

Lumberyard currently offers three additional ready-to-use art assets and code that you can use as examples:

  1. Woodland: A collection of wilderness (forest, vegetation, and other natural features) assets.
  2. Beach City: A dark and stormy night containing several assets (cars, houses, vegetation).
  3. Legacy Game Sample: A ready-to-go FPS game, including complex animated characters, vehicles and game IA. This sample uses the woodland sample assets.

The first step is to download them all.

Step 1: Woodland

The Woodland asset is the easiest to install since it comes packaged as a Gem. Unzip the Woodland zip file to the dev\Gems folder inside your default Lumberyard installation.

To verify that everything is fine, open the Project configurator >Enable packages; at the bottom you should now see the Woodland Asset Collection.

The Woodland Asset Collection

To add the Woodland asset to the SamplesProject (your current default project), you only need to check the box and wait for the Asset Processor to load all resources.

Step 2: Beach City

To install the Beach City, you must follow the following steps:

  1. Unpack the Beach City zip file into your Lumberyard \dev directory.
  2. Navigate to dev\_WAF_ (inside the installation folder).
  3. Edit the file *projects.json and add the following to the end of the file before the last closing brace:

Now open the Project configurator, click Configure project, select BeachCity and click Set as default.

Beach City

Open the Editor and open the level (Open level > BeachCity_NightTime). If everything is working, you should be able to navigate within the Beach City environment. Note that by default this asset doesn’t have a Camera Framework, so you can only (for now) navigate in the Editor mode.

Setting the Beach City to Night Time

Step 3: Legacy Game Sample

The Legacy Game Sample installation is similar to Beach City.

  1. Unpack the Legacy Game Sample zip file into your engine directory.
  2. Navigate to dev\_WAF_ (inside the installation folder).
  3. Edit the file projects.json and add the following to the end of the file before the last closing brace:

The complete projects.json is now:

Before you test the Legacy Game Sample you need to perform an additional step. Open a Command Prompt in your Lumberyard dev folder and run the following command:

If you get any error, it should be solved by the following steps:

  1. Open the Launcher.
  2. Select Compile the engine and asset pipeline.
  3. Install the required software.

Run the lmbr_waf configure command again.

To test these assets you just need to open the Project configurator, click Configure project, select GameSDK and click Set as default. Wait until the Asset Processor loads all the assets. Now you can play a complete FPS within Lumberyard.

A complete FPS within Lumberyard

To enter game mode, you must select from the Main menu the option Game > Switch to Game.

Conclusion

This concludes this introductory tutorial to Lumberyard. You learned where and how to download, install, and configure it. Then you learned the basic notations of the interface and navigation. Finally, you found out how to import, configure and use the available external assets.

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

The Must-Have Game Assets for Designers and Digital Artists

$
0
0

There are so many assets needed when creating a game. Speed up your process with pre-made asset sets, sprite kits, user interfaces, and more from Envato Market! Whether you're in need of graphics to complete  your game or are looking to stock up on supplies for learning different aspects of game design, this list is jam-packed with everything you need.

Sprite Sheets

First up on this list are sprite sheets. Whether you need a character and movement set, icons, or a set of sprites to dot around a game level, the list below should do fantastically.

Game Character Sprite 08

This set of character sprites gives you a full sprite sheet including walking, running, and jumping cycles. Add an action-packed character easily into your 2D runner game design.

Game Character Sprite 08

Pixel Characters

If you're after pixel sprites, this set includes over 40 characters with 10 poses each. It's a perfect addition to a retro styled game, allowing you to focus on a player's experience rather than designing background characters or non-playable characters.

Pixel Characters

Zombies Sprite Sheets

Add animated living dead to your game easily with this fantastic zombie sprite sheet. Five zombie designs, each with walk and death cycles, are included in this set. Perfect for runner or platform games.

Zombies Sprite Sheets

Vegas Slot Icons Collection : 30 Vectorial Icons

Make a fun Vegas-styled slot machine with this set of 30 icons, ready for all of your icon-matching needs.

Vegas Slot Icons Collection  30 vectorial icons

Explosions and Impacts Spritepack

Pack a punch with beautifully designed pixel explosion sprites. Perfect for action games, RPGs, and more!

Explosions And Impacts Spritepack

Physics Game Block Set 3

Have fun with these colorful block sets, great for games that play with physics or feature emotional animals that fling themselves at poorly built structures. A variety of shapes, faces, and block conditions are included in this set.

Physics Game Block Set 3

Game Character Sprite 07

Give your running girl sprite from earlier in this list a friend with this "nimble boy" sprite sheet. Fantastic for runner or platformer games where you need multiple movement and actions.

Game Character Sprite 07

Virtual Coins for Your Games

Whether you need coin animations to feature heavily in your game, within your game level, or as a part of the user interface, this set of coin sprites has you covered!

Virtual coins for your games

Shark Game Assets

Create an action-packed shark game with this sprite sheet and bonus assets! This set is great for simple and fun sidescrollers.

Shark Game Assets

Flying Turtle Game Art

Why should birds have all the fun? Check out this flying turtle sprite sheet and asset set and create a fun and silly sidescroller today!

Flying Turtle Game Art

Sky Birds Game Assets

Take to the skies, fly high, and have fun with this set of character and action sprite sheets. Perfect for sidescroller games with a shooter or action twist.

Sky Birds Game Assets

Game Asset Ornaments

Fill in your game's environment with this set of graphic ornaments and sprites. Give your runner or shooter something fun to interact with and keep players guessing from level to level!

Game Asset Ornaments

Game Animals Sprite Sheet | Volume 1

Add some pixel animals to your runner or sidescrolling game with this set of 14 different animals. Each animal character has a full sprite sheet of seven different actions like walking, running, sliding, and teleporting.

Game Animals Sprite Sheet  Volume 1

Game Sprites 1

This set of sprites is fantastic for a top-down RPG or adventure game. It comes complete with four character sprite sheets, so you'll be creating fun fantasy-inspired games in no time!

Game Sprites 1

Space Shooter Creation Kit 3

Construct space shooters with these wonderfully detailed sprite sheets. Fantastic for top-down shooters filled with complex spaceships.

Space Shooter Creation Kit 3

Backgrounds

Give your sprites something to run, jump, and fly in with fantastic background sets. From sci-fi to jungle themes, you'll find everything you need to create fantastic environments and moods for your game design.

6 Game Backgrounds

This set of tileable vector backgrounds is the perfect addition to sidescrolling adventure games. Each background is easily editable in Adobe Illustrator, and the background files are parallax ready if you want to create a game with more dimension.

6 Game Backgrounds

5 in 1 Game Background

Give your game's characters a variety of level themed from space to forests to a candy kingdom! This set of five backgrounds is colorful and fun, ready for all of your scrolling background needs.

5 in 1 Game Background

Jungle Run Game Background

Keep your game's setting in the jungle with this set of vector backgrounds. Scroll your character through vines, trees, and lush, large leaves!

jungle run game background

Retro City Building Pack

Build a busy city for your game with this background building set. Easily editable assets in vector form so you can create the retro city of your dreams! 

Retro City Building Pack

Nature Game Background

Keep things simple with this nature-inspired game background, fantastic for flying or running sprites to explore!

Nature Game Background

Game Backgrounds #1

This set of strong and simply designed backgrounds features 10 different location styles that are easy to repeat and are parallax ready.

Game Backgrounds 1

Game Backgrounds in One Set

Get more bang for your buck with this set of 15 backgrounds ready for shooter, runner, and other side scrolling games. 

Game Backgrounds in one Set

Game Background

I love the feel of these backgrounds, showcasing dreamy mountain scenes or spooky cemeteries. Give your characters 10 fantastic levels with this set of backgrounds.

Game Background

9 Cartoon Game Backgrounds

The color palettes in this set of nine cartoon-styled backgrounds are absolutely fantastic. Any game with such style and colors would be something I could not put down. 

9 Cartoon Game Backgrounds

8 Chinese Game Background

Give your game a more concrete setting with this fantasy-themed set of backgrounds featuring Chinese architecture and design styles.

8 Chinese Game Background

Tile Sets

Build your game world, tile by tile, creating a full and fantastic setting for a variety of game styles from adventure to platformer and more!

Scifi Shooter Sprite Sheet

This sci-fi set of sprites and tiles allows you to build a fantastic top-down world for your characters to fight alien invaders and save the day!

Scifi Shooter Sprite Sheet

Platformer Game Tile Set 4

Create a spooky platformer with this tile set perfect for a horror-themed adventure game. This bundle includes two tile set styles, backgrounds, and an assortment of props to complete your game levels.

Platformer Game Tile Set 4

Pixel City Creation Kit

Build a city tile by tile with this pixel city creation kit. Fantastic for simulation games and more!

Pixel City Creation Kit

Platformer Game Tile Set 5

Feel the chill in the air! It's your winter-themed platformer, outfitted with snowmen, icicles, and icy game tiles.

Platformer Game Tile Set 5

Platformer Game Tile Set 6

What I love about themed platformer tile sets like these is you can easily create multiple levels for one game from multiple sets, giving players a chance to run around through a variety of settings. In this case, we have a fantastic adventure-themed tile set complete with ladders to climb, spikes to avoid, and cherries to gather.

Platformer Game Tile Set 6

Platformer Game Tile Set 9

This dungeon-themed tile set is fantastic for all of your castle platformer creation needs. Sets like these can also serve as a point of inspiration for a game's style, allowing you to create additional elements in the style of the tile set.

Platformer Game Tile Set 9

2D Tileset Platform Game

Keep things fun, brightly colored, and simple with this 2D platformer tile set. This bundle includes two tile set styles, backgrounds, and items to fill in your game level.

2D Tileset Platform Game

2D Tileset Platform Game 3

Create a lush, jungle-themed platformer with this tile set. The detail in each item, tile, and background is enough to make this tile set a must-have.

2D Tileset Platform Game 3

Platform Game Tileset 4: Abandoned Castle

For a more realistically styled tile set, look no further than this gorgeous abandoned castle set. Featuring beautifully painted tiles, items, and backgrounds, this set is a great starting point for your platformer game.

Platform Game Tileset 4 Abandoned Castle

Top-Down Roguelike Dungeon Crawl RPG Tileset

I love a good top-down dungeon set for an RPG or adventure style game. The vector assets in this bundle are easily editable, so your dungeon creating possibilities have just begun with this tile set.

Top-Down Roguelike Dungeon Crawl RPG Tileset

User Interfaces

Whether you need something to complete your game or to give your game a graphic interface to pull your assets together, these user interface bundles are the perfect addition to your game developer toolbox.

RPG User Interface

This RPG-styled UI set is clean and elegant, perfect for a hack and slash or MMORPG design. Just seeing it makes me want to play whatever game would use this asset, no questions asked.

RPG User Interface

Cartoon Games GUI Pack 3

Consider GUI packs like this to be a perfect addition to some of the tile sets, sprite packs, and background sets from earlier in this list. This set is clean, fun, and perfect for so many mobile game genres!

Cartoon Games GUI Pack 3

Match-3 Candy Game GUI

I adore the detail and vibrancy of this candy matching UI. Whether you're creating a beautiful gem matching game for the first time or simply wish to use something gorgeous for your UI, this set is utter perfection.  

Match-3 Candy Game GUI

Cartoon Games GUI Pack 9

With such fun backgrounds and tile sets above, you'll need a bright user interface to match. This set is perfectly styled for vibrant, shiny, games for mobile devices or tablets.

Cartoon Games GUI Pack 9

Cartoon Games GUI Pack 11

Looking for a UI fit for a fun forest adventure game? Look no further than this UI set!

Cartoon Games GUI Pack 11

Mobile Game GUI Pack 02

For a lovely 2D mobile game, you'll need a lovely UI set. This pack contains fantastic vector items, each with just enough dimension to stand out from the other sets out there.

Mobile Game GUI Pack 02

Mobile Game GUI Pack 04

Focused on the mobile format more than any others? Check out this fantastic UI set! Perfect for puzzle games that track a user's progress, this set is a great start to your latest game design.

Mobile Game GUI Pack 04

Cartoon Games GUI Pack 14

This UI set's button style is what won me over when compiling this list. With a great color palette that would fit well with so many assets, this pack is a must-have.

Cartoon Games GUI Pack 14

DingDong: Game GUI Pack

If bells and whistles are what you need for your interface, check out this GUI set. With badges, banners, tile sets, icons, buttons, sliders, and more, this set is a great start to a beautifully designed mobile game!

DingDong Game GUI Pack

Space Game GUI Pack

For a version of space, check out this UI design. With six formats for each file, you'll find over 350 assets included so you can spend more time working on the game itself rather than just asset building.

Space Game GUI Pack

Game Kits

When you need a bit of everything or the entire package, these game kits are there for your game development needs.

Wirawiri: Game Level Map Builder

Get creative with this gorgeous map builder set. Featuring a variety of terrain, path, and surface styles, as well as icons and buttons, this set allows for a nearly unlimited amount of game level results.

Wirawiri Game Level Map Builder

Top Down Racing Game Creation Kit

Get your motor running with this top-down racing game kit. Featuring cars, buildings, terrain, and more, this set is sure to give you a head start with your racing game design.

Top Down Racing Game Creation Kit

2d Pixel Art Game Assets

Go old school with your game design style with this 2D pixel game asset set. Over 150 assets included, giving you a great start to creating a nostalgia-heavy platformer.

2d Pixel Art Game Assets

Casino Card Game GUI

No need to take a gamble with your game design when you have this casino card game set. Featuring a full deck of cards, chips, tables, glorious golden text style, and more, this set is the perfect addition to your game development arsenal. 

Casino Card Game GUI

Cannon Ball Shooter Game Assets

Yar, matey! Build a bubble shooter game with style with this cannon ball game asset set! Spritesheets, elements, animations and more included in 3 file types!

Cannon Ball Shooter Game Assets

Flying Adventure Dark Style Game Kit

For a unique take on the flying adventure genre, this game set features a brilliantly designed atmosphere and assets. It includes character sprites, backgrounds, element sets, and more!

Flying Adventure Dark Style Game Kit

Spooky Places Game Assets

Get spooky with this cartoon horror-themed game set. From sprite sheets to buttons to the UI, this set is everything you need to create a fun adventure game.

Spooky Places Game Assets

Game Assets for Tank Wars

Create a game that players can enjoy together for hours with this cartoony tank warfare game set. The set features sprites, tile sets, GUI and more, so you'll be building your game in no time!

Game Assets for Tank Wars

Golden Slots Game Kit

With over 500 elements included, there's really no better set for creating a luxurious slots game. Each asset included is editable in six different file formats.

Golden Slots Game Kit

Space Game GUI Set

Shoot for the stars with this space-themed game set. Featuring wonderfully designed menus, buttons, sprites, backgrounds and more, it will have your players blasting off in no time!

Miscellaneous Things

Bits and bobs and all the rest. This category of assets is filled with additional game icons and assets that top off your final game design in a wonderful way! Take a look at what I've gathered below.

Common Game Icon Asset

With 100 icons in four sizes, this set should be everything you need for a variety of game types!

Common Game Icon Asset

RPG Item Bundle 1

What's an RPG without a plethora of items? This bundle of 296 items has you covered with multiple sizes of hand-painted items.

RPG Item Bundle 1

Magic Bottles Icons

Add a beautifully painted set of bottles to your game with this set of 18 bottle designs. Whether you're showing items, attributes, or spells, these icons suit a variety of game design needs.

Magic bottles icons

Game Icons

I love this icon set for its soft, colorful style, and intricate designs. Add a spark of something beautiful to your UI or item menus with this set of icons.

Game Icons

2D Cartoon Forest Trees & Plants

Create backgrounds, environments, and more with this set of fun trees and plants. Over 230 customizable assets included!

2D Cartoon Forest Trees  Plants

Donut Game Icons Set

Top off your puzzle or gem matching game in style with this set of donut icons! Or use this set as a point of inspiration for a delicious game design featuring colorful foods.

Donut Game Icons Set

85 RPG Fantasy Spells Icons

In need of fantasy icons for all the spells your game characters need to cast? Then this icon set is for you!

85 RPG Fantasy Spells Icons

Asteroids Game Pack

An asset set like this is perfect for a fun cartoony space game or adding additional cartoon-styled elements to your mobile game design. Consider purchasing little packs like these for creating alternate levels, skins, or versions of your game designs.

Asteroids Game Pack

Isometric Map Icons Vol.01

If you're working on an isometric game, an asset set like this is a great boon to your design kit. Create an assortment of cities or towns from scratch or add them to a map generator.

Isometric Map Icons Vol01

Common Game Icon Pack HD

Need a small set of icon additions to your game? Maybe as an update or a new set of items characters can use in your RPG, this set of beautifully designed icons can be the perfect addition to an established game design.

Common Game Icon Pack HD

Conclusion

This list of fantastic resources aims to highlight useful and must-have content for game designers and artists. Chances are we've missed some Envato Market items that you think would be an excellent asset to any designer's toolbox. Share those links in the comment section below, and let this list be a jumping-off point for building your ultimate digital asset kit!


Making Levels With the Super Mario World Method: Skill Themes, Part 2

$
0
0

This is the fourth in a series of articles that explain how to use the design methods that Nintendo created in the making of Super Mario World, and how you can use them in your own level designs. If you haven't read the earlier articles, you should, or else this article won't make sense.  

In the previous article, I wrote about how most of Super Mario World's levels fit into one of four skill themes, and I gave examples of the moving targets and periodic enemies skill themes. In this article, I'm going to look at the final two skill themes: the preservation of momentum theme and the intercepts theme.  

Although I found these skill themes in Super Mario World, they actually appear in other games too, so the examples I'm about to give are still useful in contemporary game design. Plus, there's Mario Maker, which I use to build my examples, and that's more than enough reason to understand skill themes. Isn't it?

The Preservation of Momentum Theme

The first skill theme I want to explore is the preservation of momentum theme. If you recall from the last article, all the skill themes in Super Mario World take place in either the action or platforming genre, and in either the timing or speed skill style.

The diagram of skills in Super Mario-style games

The preservation of momentum theme lies at the intersection of platforming and speed. The basic idea of this theme is that it forces the player to keep Mario's momentum up for long stretches of time and space. This can be done in several ways, and we'll see a few of those ways in the level I've made. The intercepts theme, on the other hand, is the complement of the preservation of momentum theme, and leans more toward the action genre.  

As I explained in the first article in this series, an intercept is any object or enemy which interferes with a jump that Mario is already making. That is, intercepts do not cause jumps—they only modify jumps. The intercepts theme is all about throwing a variety of different obstacles into the path of jumps that Mario has to take. We'll see several examples of that in my level too.

The original design idea which gave rise to the preservation of momentum theme was the falling platform. Because Mario can only spend a second or two on the platform before it descends into an abyss, he has to keep moving across the platform the entire time. If he stops, he can lose the momentum he needs to get to the next platform.  

A shot of momentum in Super Mario World

Challenges in the preservation of momentum theme tend to be wider than in other themes because Mario has to run through them at a high speed. This doesn't make these challenges harder, necessarily; they're just more spaced out.  

Preservation of momentum challenges start as simply as the challenge you see above, which is the standard challenge for my level. Let's take a look at some evolutions of this.

Evolutions of Momentum

What I've done here is to add some Wing Koopas to patrol the space between the platforms. This is a very simple evolution that borrows from the complementary theme by adding intercepts. The Wing Koopas aren't the cause of Mario's jump—the falling platform is the cause—but they do modify the jump he is already taking.

The second evolution modifies the previous challenge by replacing the Wing Koopas with Boos. Like the Wing Koopas, the Boos aren’t the cause of the jumps. The real challenge for Mario is jumping through the platforms that fall away. Failing a jump results in death, while touching a Boo results in non-fatal damage. Unlike the Wing Koopas, however, the Boos will follow Mario around, making the jumps even more difficult. 

Being chased by enemies making jumping more difficult

To mitigate this chasing behavior a little bit, I have changed the middle platform so that it does not fall. It’s very common in Super Mario World for the evolution of one part of a challenge to involve the de-evolution of another part. The goal of an evolution is higher difficulty through qualitative change, but the emphasis is on qualitative change (at least in Mario games) rather than absolute difficulty. So I've softened part of the second evolution to emphasize the change rather than the difficulty.

The next section of the level presents a different way of forcing the player to keep moving. The Super Star power-up gives Mario invincibility, but only for a limited time. Several levels in Super Mario World use the star as a means for getting through otherwise very difficult gauntlets of enemies at a high speed. This is what I aimed to do in this section of my level. The star is placed in an obvious block so that the player won’t miss it.

Proceeding through a difficult area with a Super Star

The first section makes it obvious that the star is in play to allow the player to cross the otherwise damaging floor. This section is also relatively open, meaning the player can just plow through the spikes without any other difficulties, if Mario is under the effects of the star. The evolution to this challenge will make the next section less passable as the timer on the star runs down.

The challenge in the next section of the level

There's no danger in this evolution of Mario taking damage as long as he has the star; the purpose of this section is merely to slow him down. If Mario reaches the end of the challenge here without the star, he's essentially guaranteed to take damage from the enemies that occupy his landing spot. If the player can get him through there quickly, Mario will be fine, and will actually gain several 1-ups. 

The third challenge actually reverses the need for the star. If the player manages to make it to this spot with the star, they may face a problem. 

Facing Winged Koopas with no Super Star

Because the pit is so wide, the player once again needs to bounce off the head of a Wing Koopa in order to make it across. If Mario still has the star powerup, he actually can't bounce off the Koopa because the star powerup changes the way that collisions with enemies work. 

There are two interesting things about this challenge. This is an inversion—instead of needing the star to preserve Mario's momentum, the player needs the star to go away before attempting the jump, so that Mario can bounce and keep going when he hits the Koopa’s head. Inversions (total reversals of a standard challenge) are a common tool in the designer's toolkit and appear often in Super Mario World—and many other games too. But also, this challenge is clearly about preserving momentum, by bouncing off the heads of the Koopas.

The Intercepts Theme

For the next section, this level switches to the intercepts theme. There have been many intercepts present in the level so far, but always in the context of the preservation of momentum—Mario always had to keep moving forward. Speed is still essential in the intercepts theme, but that speed is often in quickness of the player’s reflexes rather than Mario’s forward run.  

The intercepts theme often requires Mario to run or air-dodge backwards to avoid some oncoming object. The most idiosyncratic aspect of the intercepts theme, however, is the layering of various kinds of intercepts. The first challenge is fairly easy, starting at the level of a standard challenge.

The first challenge in the intercepts theme

The cannon in the middle fires Bullet Bills at a regular rate. Although regularity is the hallmark of a periodic enemy, the bullet bills aren’t localized to a single jump, as a periodic enemy would be. Instead, they intercept every jump on this tier of the section. The first evolution of this idea, meanwhile, is simple: I just add Wing Koopas.

Adding Winged Koopas for difficulty

Now we have two intercepts modifying Mario’s jump path. Likewise, the final evolution is similar in structure, but different in content.

Three enemies in total for the evolution of difficulty

The evolution here is in exchanging the Wing Koopas for Boos again, and there is also an expansion in the number of cannons on the middle platform. 

You could call this a repetitive move, but one of the important aesthetics of Mario-style game design is not putting too many elements in a level. I could have thrown in 12 different enemies, but the CCST structure depends upon the same design ideas appearing throughout a level to maintain consistency. Small iterations preserve the newness and challenge of a level while at the same making sure that all the basic ideas are familiar to the player.

Back to the Preservation of Momentum

The final section of the level returns to the preservation of momentum theme using the last important method for the preservation of momentum in Super Mario World: the inability to stop. 

In Super Mario World, this was achieved through icy floors. Super Mario Maker doesn’t have as robust a set of tools for doing this, but it makes up for that by accomplishing something similar in conveyor belts. The essential idea is preserved. Mario is going to keep moving whether the player wants him to or not.

Perpetual Motion

Across the course of several layers of conveyor belts, I simply added new kinds of intercepts and other dangers like the Grinder. The final challenge has both cannons and a winged Dry Bones who throws bones.

A saw bullets and Dry Bones

What I've done here is to combine the preservation of momentum elements with the intercepts elements to create a climactic peak in the level's complexity and difficulty. The conveyor belt provides the momentum challenge, while the different kinds of intercepts make that momentum dangerous.

And then for the last section of the level I created a simple gauntlet where Mario has to run across some more conveyor belts beneath some Boos. The danger here is pretty minimal, but with the enhanced momentum the action can still feel exciting and fun. 

Enemies along with forced momentrum
Jumping across Winged Koopas after having forced momentum

I didn’t really turn this last section into a proper part of a cadence. Instead what I wanted to do was set up a “reward by fun” section. The idea behind this is to break the tension in a level by giving the player an easy, flashy task. 

My level wasn’t that tense, because I’m only trying to teach game design techniques, but this section replicates the structure of the reward by fun. Fleeing the ghosts is actually quite easy, even with the occasional backwards motion of some of the belts. The last jump is also quite easy, as the final belt is reversed and the “platform” of Koopas is quite wide.

Conclusion

That covers all the skill themes in Super Mario World, but it's not the end of the story. Although most of the levels in Super Mario World fit into one of the four skill themes, there are quite a few levels in the game which do not fit into any of them. 

If you want to know more, you should check out the book I wrote about the game. There are many other skill themes in other games, and many other cadence structures too. In the next article, we're going to take a look at some of those games and how they interpret the CCST structure.

Until then, good luck making your levels!

Amazon Lumberyard: Editor Analysis

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

Lumberyard is the latest 3D game engine to hit the market. It is a free, multi-deploy platform engine that offers deep integration with both the Amazon Web Services (AWS) infrastructure and Twitch to improve general online gameplay.

The Lumberyard engine technology is based on CryEngine. Amazon licensed one version of CryEngine and got complete access to its technology. That does not mean that CryEngine will leave the market since Lumberyard only represents a branch of CryEngine technology. Both will be present and will struggle for market share.

Lumberyard is a powerful and full-featured AAA game engine that enables you to create games for the latest console generation (Xbox One and PlayStation 4). Mobile support is also a goal (the engine already has rendering options for iOS and Android).

In this tutorial, I'll do an analysis of the Lumberyard editor, namely the editor layout, objects, essential tools, navigation, and layers.

Who Should Read This Tutorial Series?

This tutorial series is primarily aimed at two groups of game developers: those who are completely unfamiliar with game engines at all, and those who are familiar with other game engines (such as Unity, Unreal Engine, or Cry Engine) but aren't familiar with Lumberyard. I assume that you have some knowledge of computer graphics notation, so I won't exhaustively cover all notations.

Prerequisites

Despite the fact that you don't really need to read the first tutorial part, you are advised to do so since it covers the initial installation and configuration steps. 

If you just want to start using Lumberyard, you're right on track.

Editor Layout

The Lumberyard Editor provides several tools for creating and modifying your game environment, including levels, objects, textures, terrain, lighting, physics, animation, layers, and a lot more.

As you can already guess, the Editor will be your best companion during the creation of games. Before you can start using and learning the Editor, you must create a new level.

Create a New Level 

A level is a 3D environment (or a map) that represents the available virtual space or area for you to create your game (or single level). Launch Lumberyard Editor (Editor.exe) and a similar interface should appear.

Welcome

In the Welcome to Lumberyard Editor interface, you can create a new level, open a recent level, or open a level from within the Lumberyard directory. Click New Level.

New level

Name your level First_Level and click OK. For this tutorial, you will use the default values under Heightmap Resolution and Meters Per Texel

The first, as the name suggests, represents a 2D greyscale map of your height information. 

The latter represents the size of each Texel (represented as a square on the perspective floor). If you play with those values, you can see that the Terrain Size changes accordingly. 

Terrain texture

In the Generate Terrain Texture interface, you can control the appearance of your level's terrain. Texture Dimensions represents the overall texture quality (more quality implies more computational resources). Terrain Color Multiplier represents the number of colors that will be used to compensate for the texture compression. 

Normally, you should start with a lower value (ranges from 1 to 16) and increase it if the terrain colors are distorted or have artifacts. Checking the High-Quality check-box increases textures; this setting takes longer but results in fewer compression artifacts and does not affect memory or CPU usage in game mode.

You don't need to change the defaults values for now. Click OK. The Lumberyard Editor will appear.

Objects

Lumberyard only has three object types (Entities, Brushes, and Designed objects) that encompass every object that can be placed in a level. Even external imported objects will be automatically cataloged as one of these three object types.

Objects
  • Entities are objects with behavior properties. A behavior property uses a game script or programming code to enable objects to respond to game objects (for example, a moving car). Entities are subdivided into the following types:
  1. Entities represent general objects that are normally used to create gameplay conditions, such as actors, animations, lights, and cameras, among others.
  2. Geometry Entities represent the aforementioned objects but attached with geometry mesh information.
  3. Particle Entities represent physical particles.
  4. Archetype Entities represent a custom set of objects that are created based on the available entity properties.
  • Brushes are objects with 3D mesh data only; they do not contain behavior properties.
  • Designer objects are objects created with the Lumberyard Designer modeling tool. 

Later in this tutorial, you will learn how to create and modify each available object.

Essential Tools

Lumberyard Editor features several tools, settings, and options to help you create high-quality games. The essential tools for manipulating objects are Select, Move, Rotate, Scale, and Terrain Area.

You can select these tools either with the keyboard shortcut or from the Lumberyard Editor toolbar.

Editor toolbar

If you don't see the EditMode Toolbar, you can right-click an empty area of the menu or toolbar area and select EditMode Toolbar.

Editmode toolbar

Each tool provides its own unique 3D visual representation, called a gizmo, on the selected object. The gizmo helps you identify the tool that is currently selected.

To select each tool, you can use your mouse to select it or use the following keyboard shortcuts:

  • 1: Select
  • 2: Move
  • 3: Rotate
  • 4: Scale
  • 5: Terrain Area

Let us now experiment with each tool using 3D objects.

Place an Object

To place an object in the level you should use the Rollup Bar (right side).

  1. Click Brush to display your current loaded assets.
  2. Under the Browser section, in the directory tree, expand Objects > gettingstartedassets and select gs_block.
  3. Drag the gs_block object into the Perspective viewport.
gs_block

When you place the gs_block you will notice that you are not completely free to place it where you want. That behavior is related to the snapping options (Follow Terrain and Snap to Objects, Snap to Grid, and Snap Angle).

Snap
  • Snap to Objects is used when you want to attract one object to another.
  • Snap to Grid is used when you want to attract one object to points along a customizable grid.
  • Snap Angle is used when you want to attract one object using a specific angle.
  • Follow Terrain is used when you want to move an object along a terrain rather than along a specific X, Y, or Z axis or plane. This feature is particularly useful when you want to place objects sitting directly on the terrain.

Both Snap to Grid and Snap Angle are on by default.

Select

Selecting an object (or multiple objects) is the core of all game development stages. The Select gizmo is represented by a set of three lines (one for each X, Y, Z direction). You will notice that when Lumberyard detects the mouse over any object, that object is highlighted and therefore can be selected.

Select

Move

The Move tool selects and moves an object within the 3D world of the Perspective viewport. The Move gizmo is a set of three lines with arrowheads on the X, Y, and Z axis.

Move

The Move gizmo also features three small right-angle squares along the XY, ZY, and XZ planes. To move your object along a given plane, click on the selected one of the small squares.

Note that you can also restrain the object movement by using the Lock options (Lock on XAxisLock-on Y-AxisLock on Z-Axis.

Rotate

The Rotate tool selects and rotates an object. The Rotate gizmo is represented by a set of circles around the object along the X, Y and Z axis. To rotate an object, select one of the small circles and then rotate the object around that rotational plane.

Rotate

The white circle surrounding the entire gizmo represents a rotation of the object related to the screen display.

Scale

The Scale tool can select an object and change its size. The Scale gizmo has cubes on the three axes (X, Y, and Z). To scale the object, select the X, Y, or Z line and then drag to modify its scale property.

Scale

Terrain Area

The Terrain Area tool can select a terrain area. In the following figure the game is composed of two terrains: pool and townblock (available at: Brush objects > Objects > styletown > natural > terrain)

Terrain

Accurately Move, Rotate, and Scale

Lumberyard provides you a way to accurately move, rotate, and scale any object. That option is available in the Viewport Controls section of Lumberyard (bottom).

Accurately Move Rotate and Scale

These controls are exactly the same as the aforementioned Move, Rotate, and Scale; however, using them provides you a way to accurately move, rotate, or scale any object.

Editors

The Lumberyard Editor holds a collection of editor tools for building specific categories of content (such as Assets, Flow Graph, Material editors, scripts, and terrain editors, among many others). You can see a big picture of the editors by clicking on View > Open View Pane.

Lumberyard Editor

Another way to open the most commonly used editors is by using the editors toolbar. Note that this bar can be configured to add or remove editors.

editors toolbar

You can change several Perspective viewport options using the Viewport Header and Viewport Controls.

Viewport Header enables you to:

  • filter objects in the perspective viewport
  • change the default field of view (FOV), Ratio, and resolution
  • toggle amount of debug/display information, using the i icon
  • toggle each individual entity icon and their visual guidelines, using the H icon

To change the FOV, Ratio, and resolution, you only need to right-click on that option and change the default value:

Viewport Header

The Viewport Header has some additional "hidden" features that can be seen if you right click in an empty Viewport Header part.

Hidden header

You can play with those options and see the result in real time within the perspective viewport.

The Viewport Controls has two main properties: navigation speed and AI/Physics. The Speed setting displays the current movement speed setting. The AI/Physics button toggles the movement events for physics, AI (artificial intelligence), and particles in edit mode.

Viewport Controls

The major advantage of these modes is that you can test and view these events without entering game mode.

Layers

The Layers tab in the Rollup Bar helps you hierarchically organize your level content. You can use the toolbar on the Layers tab to interact with layers.

Layers

Each icon represents a specific action (in order): new, delete, rename, export, importsave external layers, and freeze.

Layers Button

Additionally, each layer has its own eye and arrow icons that help you manage objects. The eye icon toggles the layer visibility while the arrow icon toggles the ability to select objects in that layer.

Note that you can reorder your layers or event group them hierarchically by holding the Control key and dragging each layer to its next location.

Working With Layers and Their Files

When you create a new layer, that layer is stored as a file in the level\layers directory (inside your Lumberyard installation) with the extension .lyr.

To add content to a specific layer, you only need to select that specific layer. With that layer selected, you can create or add content, all of which are automatically created as a part of that layer.

Note that when you are working on a specific layer, you don't need to save the level file, but you do need to save the layer file. To save the layer file, click Save External Layers.

This feature is quite useful when you work with a team within the same level. Thus, each person can work on a specific layer and in the end one imports all layers to the final level.

Moving Assets Between Layers

Each Entity, Brush, or Designer object you place in the level is assigned to the currently selected layer. By default, and if you haven't created additional layers, all objects are placed in the default main layer. To assign an object to a different layer, you must:

  1. select the object in the Perspective viewport
  2. in the Rollup Bar, click the Objects tab
  3. click the Layers icon to display a list of all created layers
  4. select the destination layer from the list
Change Layer

Tips

Lumberyard provides you an Auto Backup feature. As the name suggests, it saves your level file incrementally, thus preventing any massive loss of your work. If you want, you can customize your Auto Backup settings by selecting File > Global Preferences > Editor Settings. Now select Files (under General Settings).

Three properties can be customized to your choice:

  1. the maximum number of backup saves (Maximum Save Backups)
  2. the default save directory (Standard Temporary Directory)
  3. save camera tag points (Auto Save Camera Tag Points)
Backup

Conclusion

This concludes this tutorial about the Lumberyard Editor. You learned how to create a new level and its properties. Then you learned the Lumberyard Objects and its essential tools. Finally, you discovered how to create, configure, and modify Layers. 

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

Amazon Lumberyard: Creating the First 3D Scene

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

In this tutorial part, I'll show you how to create a complete 3D level composed of both Lumberyard internal assets and imported new ones.

Then, you'll learn how to place both the player and the camera, and how to use several entities, creating prefabs and textures. Finally, you'll be introduced to Lumberyard lighting.

Note that you are advised to read the previous two parts (Part 1, Part 2) in order to fully understand the notations from this part.

Who Should Read This Tutorial Series? 

This tutorial series is primarily aimed at two groups of game developers:

  • those who are completely unfamiliar with game engines at all
  • those who are familiar with other game engines (such as Unity, Unreal Engine, or Cry Engine), but not with Lumberyard

I assume that you have some knowledge of computer graphics notation, so I won't exhaustively cover all notations.

Create a New 3D Level

Launch Lumberyard and click on New Level. Use the following data in the New Level interface.

  • Name: CompleteFirstLevel
  • Folder: Levels/ (default value)
  • Useterrain: checked!
  • Heightmap Resolution: 1024x1024
  • Meters Per Texel: 1

Click OK.

Note that all levels are saved by default at: YourLumbaryardInstallationpath\dev\SamplesProject\Levels.

For the terrain texture, use:

  • Resolution: 4096x4096
  • Terrain Color Multiplier: 3
  • High Quality: checked!

Click OK.

Camera Positioning

In order to game play your level, you must create and place a game camera. Then you need to modify it to enable character control and specify a starting point. Fortunately, Lumberyard provides a prefab object that has a gameplay camera with supporting input controls.

The camera can be found in the Database Editor, under View > Open View Pane.

Database Editor

You can also find the Database Editor in the EditMode Toolbar.

Database Editor in the EditMode Toolbar

The database view tabs (red rectangle) provides access and configuration for several database types. The editor toolbar (green rectangle) gives you access to tools such as Open, Save, Add, or Remove items from the database. Finally, the FileTree View (blue rectangle) gives you access to the database items available.

The FileTree View

In the Database View, open the Prefabs Library and click Load Library.

Database View in the Prefabs Library

From the prefabs directory listing, select character_controllers.xml and click OK.

The Character Controllers

From the Prefab Library file tree view, drag Sphere_Controller into the Perspective Viewport

Now you should have one robot lying on your level waiting for testing. Note that the location where you place it also determines the start point of the level. Save your level file (File > Save).

Robot

If you click on the Gizmo, you can see the complete prefab properties. If you can't see the Gizmo, then you need to click on the H icon in the Perspective Toolbar.

Gizmo

You should note that, by default, you cannot modify any prefab entity property. However, if you select the Gizmo, and then click on Open All under the Rollup Bar >Prefab Parameters, you will now have access to each prefab entity and its properties.

Prefab Parameters

Click on the Camera Controller Rig entity to inspect its Camera Params.

Camera Paramaters

It is now time to test your new game camera. Click on Game > Switch to Game or press Control-G.

Add a Camera

There are several scenarios where you intend to have custom cameras or even static cameras. For that, Lumberyard provides you access to the camera entity. There are two major ways to add a custom camera:

  1. using the RollupBar
  2. using the current Perspective viewport configuration

The former uses the entity Camera available at Objects > Misc > Object Type > Camera. You just need to select the Camera entity and then place it in within your Perspective viewport.

The latter uses your current view position so that the new camera will also use that same configuration. Place Perspective viewport in the desired positioning (for example looking at the robot). Right-click in the upper left corner of the Perspective toolbar, and click Create Camera from Current View. The current view from your Perspective viewport is now a fixed camera from that position. 

Camera From View

Now, navigate away and notice the new camera entity looking for your last Perspective Viewport configuration.

Navigate Camera From View

Objects

One way to place objects is by using brushes (RollUp Bar > Objects > Brush). Brushes are normally static objects placed within the 3D scene. They are cheap to render since they don't contain extra properties of an entity or physics properties.

In the Rollup Bar on the right, select Brush in the Objects tab. Under the Browser heading, open Objects > StyleTown > Natural > Terrain and select the object townbloc. Drag it into the Perspective viewport.

Perspective Viewport

From the Brush list, open StyleTown > Architecture > Buildings. Drag the b13_h02 building into the Perspective viewport and place it near one corner of the townbloc.

Another Perspective Viewport

Now you know how to place brushes in your level.

Importing External Objects

To import external objects, Lumberyard advises you to use the FBX file format. The current importer is still in preview release and some features like materials are missing.

The Lumberyard FBX Importer tool incorporates a scene graph, which is a tree-based layer of data between your .fbx model and Lumberyard. Every time you process a .fbx a new .scenesettings file with the same name is created; this new file stores the asset metadata.

If you change the mesh properties of the model, you don't need to re-import the .fbx file. Lumberyard Asset Processor listens and detects any changes to the .scenesettings file and uses the Resource Compiler to reprocess the .fbx file.

Let us proceed and download one external FBX file. Extract the compressed file you just downloaded and move the Wooden_House.fbx into YourLumbaryardInstallationpath\dev\SamplesProject\.

In Lumberyard Editors, select View > Open View Pane > FBX Importer.

 FBX Importer

Click the folder icon at the upper right of the tool window.

Open

 Select the Wooden_House.fbx file, and click Open.

Import

Change the Name property to Imported_Wooden_House and click Import.

Import

After a few seconds, you should see the success message window.

success

One last step must be performed before you can use your new asset. Under the RollupBar > Geom Entity, click Reload. Then a new folder should appear. Open it and you should have the imported_wooden_house model available. 

Finally, drag the model into the Perspective viewport.

First Challenge 

You should now add some brushes by yourself. Your next task is to create a 3D level similar to the following one:

Image 1
Image 2

When you finish the level creation, move to the next section. Note that you don't need to create a 3D world exactly like the previous one. The main idea is to add several brushes and interact with them (rotating, translating, and scaling). 

Prefabs

Prefabs enable you to create content more quickly using a combination of pre-defined assets. To use previously created Prefabs, open the Database View (View > Open View Pane).

Under the Prefabs Library tab, click on Open. Select the styletown.xml and click OK.

The Database

Now open the RollupBar and under Prefab you should now see the imported NeighborhoodBlock Prefab.

The NeighborhoodBlock Prefab

Select and drag the three assets (StreetSet_ABlock_A, and StreetLight_A) into the Perspective Viewport. You should have something like the following image.

A Rendered 3D Scene

Terrains

Lumberyard enables you to generate, edit, and texture a terrain in your level. For that, you must always have in mind three menus:

  1. Terrain Texture Layers
  2. Material Editor
  3. Terrain editor (in RollupBar)

To open the Terrain Texture Layers, you can use the main menu View > Open View Pane > Terrain Texture Layers or the shortcut available in the Editor Toolbar

Terrain Texture Layers

Open the Terrain Texture Layers.

Terrain Texture Layers

The Terrain Texture Layers interface is used to define the materials that will be used to paint your level terrain. There are four main sections within the interface:

  1. Layer Tasks is used to add, delete, move, and assign the selected material to the selected layer.
  2. Layer Info contains information regarding the selected layer, such as the size and surface type.
  3. Layer Texture displays a low-resolution texture containing its color information.
  4. Layer list contains a list of created layers for terrain painting.

Under the Layer Tasks, add two layers. Name the first one grass and the second dirt.

Layer Tasks

Open the Material Editor using View > Open View Pane > Material Editor or the shortcut available in the Editor Toolbar.

Material Editor

You will notice that you will have two windows (Terrain Texture Layers and Material Editor) or a single window with a tab separator in the bottom left side.

Material Editor

The Material Editor is composed using the following areas:

  1. Editor toolbar for applying, deleting, creating, and saving materials
  2. Material Preview that displays the selected material
  3. Material folder directory displaying a hierarchical folder structure containing materials which can be chosen
  4. Properties containing parameters that define the overall material appearance

It is now time to assign two materials to the aforementioned created layers. For the first one, select the material gr_grass_01 located in the directory path: materials > gettingstartedmaterials.

Material Editor

Now change the interface to the Terrain Texture Layers and select the grass layer. Click Assign Material. That action will apply the selected material to the selected layer. Note that the Material path has changed accordingly to material > gettingstartedmaterials->gr_grass_01.

Grass Layer

Now, let's add the ground material (gs_ground_01) into the dirt layer. This material is also located within the same folder.

  1. Select the gr_ground_01 material.
  2. Change the interface to the Terrain Texture Layers.
  3. Select the dirt layer.
  4. Click Assign Materials.

You are now ready to paint the grass and dirt textures onto the terrain.

In the RollUp Bar, select the Terrain tab, and then select the Layer Painter button.

Layer Painter

There are several aspects that you should consider when you apply your terrain texture: the Radius and Hardness properties; the Color and Brightness of the texture; the texture itself; and the type of fill (mouse-based or Flood-based). The former will apply the texture using your mouse position, while the latter will apply the texture to the whole ground.

Select the grass texture and modify the Color to a more green tint. Click OK.

tint Color

With the grass layer selected, click on the Flood button. The terrain is now covered in the grass texture and looks similar to the following one:  

Flood

You can now paint some dirt into the scene around the perimeter of the street. Select the dirt texture and modify the Color to a brown one. Click OK. Now, using the Perspective viewport, zoom in on your 3D scene and with your left mouse button, click to add the dirt texture.

Modify the Radius and Hardness to reduce the time of applying the texture. When you are finished, you will have a 3D level similar to the following:

Dirt

Terrain Height

You can also modify your terrain height using the Modify terrain tools.

Modify

The Modify terrain tool-set features the following options:

  • Flatten: Flatten the terrain to the designated height setting
  • Smooth: Soften the terrain down to a smoother surface
  • Rise/Lower: Raise or lower the terrain based on brush size settings
  • Pick Height: Find and set heights based on existing terrain geometry
  • Outside Radius: Set how big your brush is when painting
  • Inside Radius: Set how round or flat the brush is in relation to the outside radius setting
  • Hardness: Soften or harden the outer brush settings 
  • Height: Set the brush height 
  • Scale: Strength of the noise effect; higher values produce more noise
  • Frequency: How often the effect is applied 

Let's use the aforementioned options to create some mountains inside your 3D level. Select the Rise/Lower button. Note that your mouse cursor inside the Perspective Viewport has changed.

In the Perspective Viewport, navigate towards the outer perimeter of the terrain map and left click to paint on the terrain. Build some hills of different sizes and shapes. In the end, your scene should now look something like this: 

Mountains

If you want, you can play with the terrain properties, namely the Flatten, Smooth, and Pick Height options. When you are satisfied with the terrain generator, save your level (Control-S).

Lighting

Now that you've almost concluded the 3D scene, it's time to add some illumination to it. In Lumberyard, you can add three types of lighting:

  • Environment Probes
  • Time of Day
  • Basic Lights

Before placing single light objects into the scene, it's always good to start with the default global environment probe. Environment probes are great to achieve global ambient lighting because they contribute to reflections, diffuse materials, particles materials, and shadow colors.

When building a level, you are advised to place multiple environment probe groups to achieve high quality and realistic scenes.

Environment Probes

To create the environment probe, select the EnvironmentProbe in the RollUpBar under the Misc option. Move the mouse cursor into the viewport and place the environment probe wherever you want.

EnvironmentProbe

You normally want to put your probe in the center of the level and then configure its BoxSize to fill the desired area.

Under the EnvironmentProbe Properties section, you want to change the BoxSizeX, BoxSizeY, and BoxSizeZ to 512, 512, and 250 accordingly. If you zoom out of the scene, you should have a yellow box covering the scene.

Note that these values may not produce the same result in your scene. Thus, you should adjust them to recreate the desired effect.

Environment Probe Zoom

At this point, the scene has not really changed in terms of lighting because the lighting probe is turned off by default.

Activate the Lighting Probe

To activate the probe, check the box in the Active options under the EnvironmentProbe Properties and thenclick on the Generate Cubemap button under the Probe Functions.

You should notice that the shadows will be softer.

You can further customize the environment probe by changing the Diffuse and DiffuseMultiplier value. The former represents the probe color, while the latter represents the intensity multiplier between that color and the scene materials properties.

DifuseMultipler

Time of Day

You can control the time of day (TOD), and you can even animate your scene, taking into consideration the real time of day variation values. In order to set the TOD, you must open the TOD editor. Again, you can open it using View > Open View Pane > Time of Day or the shortcut available in the Editors toolbar.

TOD

The TOD editor has seven main areas:

TOD
  1. Editor toolbar has icons for importing, saving, and setting specific hours of the day.
  2. HDR Settings to adjust the HDR lighting.
  3. Tasks to configure basic functionalities of the editor.
  4. Time defines the current time for the level. This also includes the start and end time if you want to animate the lighting. 
  5. Update Tasks allows you to play or stop the animations.
  6. Time line editor gives you control over the light settings during a 24-hour period.
  7. Parameters give you more options to configure the lighting properties.

Let's import a predefined TOD .xml file. Click Import file and navigate to SamplesProject\Levels\GettingStartedFiles, choose the TimeOfDay file, and click Open. The lighting settings will be changed automatically. 

Time Of Day

You can further customize the TOD properties as you want. Play with the Sun color, Sun color multiplier, and Sun intensity to see the differences.

Time of Day

Change the TOD to 9:00 PM before continuing. Close the TOD editor.

 900 PM

Basic Lights

Your scene is now darker. It is now time to add basic lights. In the RollupBar, on the Objects tab, select the Entity button. Under the heading Browser, expand the folder Lights and select the Light object. Drag it into your scene and place it near one of the streetlamp objects.

Placing a Street Lamp

Note that, if you encounter any problem precisely aligning the light, you are advised to turn on the Snap to Grid option.

Because the light source is a streetlamp, it should be a spot light (rather than a fill light). To change the light from fill to spot: Beneath the header Entity Properties, find the title Projector. Select Texture, and then click the folder icon.

Texture

Now open the directory \SamplesProject\textures\lights\generic and open the spot_075.dds file. 

Loading a generic texture file

The light changes to a spotlight, but it is oriented sideways. Use the rotate tool to select and rotate the light so that it points down.

Placing the Point Light

Beneath the header Entity Properties, you can modify a variety of settings to customize the light.

  • AttenuationBulbSize is the light bulb size; this is the starting point for where light begins to fall off exponentially. A value of 1 sets the light at full intensity for one meter before it begins to fall off. Adjust this size in relation to the diffuse multiplier to manage the brightness of the light source without entering unmanageable numbers.
  • Radius is the distance from the source at which the light affects the surrounding area.
  • Diffuse represents the RGB color value of the light.
  • DiffuseMultiplier is the intensity of the diffuse color; balance this value with the AttenuationBulbSize to define the balance of natural light levels.
  • ProjectorFov represents the field of view for the projection light.
  • CastShadows makes the light cast a shadow based on the minimum selected configuration specifications. To ensure shadows are always cast, set this to 'Low Spec'. Note that the CastShadows setting is not a 'quality' setting but rather a performance specification setting for the type of machine running the level.

For this tutorial, use the following settings:

  • AttenuationBulbSize = 6
  • Radius = 20
  • Diffuse Color = 228, 224,102
  • DiffuseMultiplier = 20
  • ProjectorFov = 80
  • CastShadows = Low Spec 

Experiment with these settings to get a feel for how the differences between bulb size, radius, and diffuse multiplier change based on the input values you use.

Experimenting with

Run the game (Control-G) and see how your character behaves when in contact with the new light source. For each streetlamp, add a new light. You can do it by duplicating the current light or adding ones.

Challenge

In order to test the knowledge acquired so far, you are now challenged to recreate the getting-started-completed-level.

For that, you will need to play with the brushes, lighting, materials, textures, and terrains. In short, re-apply everything that you've learned so far. Your final level should look like the following:

Conclusion

This concludes this tutorial on Lumberyard. You learned how to configure the camera and player positioning, and you learned how to import external assets and place several entities, creating prefabs and textures. Finally, you were introduced to lighting properties.

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

Get Early Access to Envato Elements—and Lock in a Lifetime Discount

$
0
0

Do you often find yourself needing access to high-quality digital graphics for your creative projects? Would you like access to a library of ready-to-use icons, fonts, illustrations, brushes and more, all for a low monthly subscription?

If so, the new Envato Elements design asset subscription is for you. It's launching publicly later this month, but right now it's in beta, and we're offering a special reduced price if you sign up now.

Envato Elements beta access

How Is Envato Elements Different?

There are lots of design resource platforms out there already—including our own site, Envato Market. So what's different about Elements?

Well, Elements is for anyone who has a regular need for high-quality, ready-to-use design assets. Instead of paying for each item, your single monthly payment gives you unlimited downloads from the large and growing content library of more than 5,000 icons, fonts, graphic templates, and more. 

Envato Elements Watercolor designers kit

We've curated the library carefully, hand-picking the best designers from across the industry to ensure that you have an impressive selection to choose from. 

And you get a simple licence allowing you broad commercial usage rights for the items you download. So you can feel confident using them in projects for clients, knowing that you're fully covered with the right permissions.

Envato Elements design item

If you ever decide Elements is not for you any more, you can cancel whenever you want. But we'll be adding so many fantastic new items every week that we're betting you'll want to stick around.

How Much Does It Cost?

The regular price will be $49 a month, but while the site is still in beta, you can lock in a special price of $19 a month. When the regular pricing kicks in later this year, you'll keep that special $19 price as long as you keep your subscription continuously active

There are no pricing tiers or credits to keep track of—it's just a simple monthly price that gives you unlimited access.

Envato Elements Mobile UI Kit

The items in the library would be worth thousands of dollars if sold individually, so we think $19 a month is a sweet deal. No matter what else we add to the library—and we have lots of plans to add new types of content—you'll keep that low price for life.

Find Out More

You can browse the Envato Elements site to get an idea of what's on offer. If you have specific questions about how it works, check out the details in the help center—or leave a comment below.

Just be aware that this $19 monthly price is going away soon, and it won't be coming back. So if you want to get in on the ground floor with a design library that we think will become a prime go-to resource for designers and creative professionals around the world, sign up and lock in that discount!

Getting Started in WebGL, Part 2: The Canvas Element for Our First Shader

$
0
0

In the previous article, we wrote our first vertex and fragment shaders. Having written the GPU-side code, it's time to learn how to write the CPU-side one. In this tutorial and the next one, I'll show you how to incorporate shaders into your WebGL application. We'll start from scratch, using JavaScript only and no third-party libraries. In this part, we'll cover the canvas-specific code. In the next one, we'll cover the WebGL-specific one.

Note that these articles:

  • assume you are familiar with GLSL shaders. If not, please read the first article.
  • are not intended to teach you HTML, CSS, or JavaScript. I'll try to explain the tricky concepts as we encounter them, but you'll have to look for more information about them on the web. The MDN (Mozilla Developer Network) is an excellent place to do so.

Let's start already!

What Is WebGL?

WebGL 1.0 is a low-level 3D graphics API for the web, exposed through the HTML5 Canvas element. It's a shader-based API that is very similar to the OpenGL ES 2.0 API. WebGL 2.0 is the same, but is based on OpenGL ES 3.0 instead. WebGL 2.0 is not entirely backward compatible with WebGL 1.0, but most error-free WebGL 1.0 applications that don't use extensions should work on WebGL 2.0 without problems.

At the time of writing this article, WebGL 2.0 implementations are still experimental in the few browsers that do implement it. They are also not enabled by default. Therefore, the code we'll write in this series is targeted at WebGL 1.0.

Take a look at the following example (remember to switch tabs and take a few glances at the code as well):

This is the code we are going to write. Yeah, it actually takes a little more than a hundred lines of JavaScript to implement something this simple. But don't worry, we'll take our time explaining them so that they all make sense at the end. We'll cover the canvas-related code in this tutorial and continue to the WebGL-specific code in the next one.

The Canvas

First, we need to create a canvas where we'll show our rendered stuff. 

This cute little square is our canvas! Switch to the HTML view and let's see how we made it.

This is to tell the browser that we don't want our page to be zoomable on mobile devices.

And this is our canvas element. If we didn't assign dimensions to our canvas, it would have defaulted to 300*150px (CSS pixels). Now switch to the CSS view to check how we styled it.

This is a CSS selector. This particular one means that the following rules are going to be applied to all the canvas elements in our document. 

Finally, the rule to be applied to the canvas elements. The background is set to bright green (#0f0).

Note: in the above editor, the CSS text is attached to the document automatically. When making your own files, you'll have to link to the CSS file in your HTML file like this:

Preferably, put it in the head tag.

Now that the canvas is ready, it's time to draw some stuff! Unfortunately, while the canvas up there looks nice and all, we still have a long way to go before we can draw anything using WebGL. So scrap WebGL! For this tutorial, we'll do a simple 2D drawing to explain some concepts before switching to WebGL. Let our drawing be a diagonal line.

Rendering Context

The HTML is the same as the last example, except for this line:   

in which we've given an id to the canvas element so we can easily retrieve it in JavaScript. The CSS is exactly the same and a new JavaScript tab was added to perform the drawing.

Switch to the JS tab,

In the above example, the JavaScript code we've written is to be attached to the document head, meaning that it runs before the page finishes loading. But if so, we won't be able to draw to the canvas, which has yet to be created. That's why we defer running our code till after the page loads. To do this, we use window.addEventListener, specifying load as the event we want to listen to and our code as a function that runs when the event is triggered.

Moving on:

Remember the id we assigned to the canvas earlier in the HTML? Here is where it becomes useful. In the above line we retrieve the canvas element from the document using its id as a reference. From now on, things get more interesting,

In order to be able to do any drawing on the canvas, we first have to acquire a drawing context. A context in this sense is a helper object that exposes the required drawing API and ties it to the canvas element. This means that any subsequent usage of the API using this context will be performed on the canvas object in question.

In this particular case, we requested a 2d drawing context (CanvasRenderingContext2D) which allows us to use arbitrary 2D drawing functions. We could have requested a webgl, a webgl2 or a bitmaprenderer contexts instead, each of which would have exposed a different set of functions.

A canvas always has its context mode set to none initially. Then, by calling getContext, its mode changes permanently. No matter how many times you call getContext on a canvas, it won't change its mode after it has been initially set. Calling getContext again for the same API will return the same context object returned upon first usage. Calling getContext for a different API will return null.

Unfortunately, things can go wrong. In some particular cases, getContext may be unable to create a context and would fire an exception instead. While this is pretty rare nowadays, it's possible with 2d contexts. So instead of crashing if this happens, we encapsulated our code into a try-catch block:

This way, if an exception is thrown, we can catch it and display an error message, and then proceed gracefully to hit our heads against the wall. Or maybe display a static image of a diagonal line. While we could do that, it defies the goal of this tutorial!

Assuming we've successfully acquired a context, all there is left to do is draw the line:

The 2d context remembers the last path you constructed. Drawing a path doesn't automatically discard it from the context's memory. beginPath tells the context to forget any previous paths and start fresh. So yeah, in this case, we could have omitted this line altogether and it would have worked flawlessly, since there were no previous paths to begin with.

A path may consist of multiple sub-paths. moveTo starts a new sub-path at the required coordinates.

Creates a line segment from the last point on the sub-path to (30, 30). This means a diagonal line from the upper-left corner of the canvas (0, 0) to its bottom-right corner (30, 30).

Creating a path is one thing; drawing it is another. stroke tells the context to draw all the sub-paths in its memory.

beginPath, moveTo, lineTo, and stroke are available only because we requested a 2d context. If, for example, we requested a webgl context, these functions wouldn't have been available.

Note: in the above editor, the JavaScript code is attached to the document automatically. When making your own files, you'll have to link to the JavaScript file in your HTML file like this:

You should put it in the head tag.

This concludes our line drawing tutorial! But somehow, I'm not satisfied with this tiny canvas. We can do bigger than this!

Canvas Sizing

We shall add a few rules to our CSS to make the canvas fill the entire page. The new CSS code is going to look like this:

Let's take it apart:

The html and body elements are treated like block elements; they consume the entire available width. However, they expand vertically just enough to wrap their contents. In other words, their heights depend on their children's heights. Setting one of their children's heights to a percentage of their height will cause a dependency loop. So, unless we explicitly assign values to their heights, we wouldn't be able to set the children heights relative to them.

Since we want the canvas to fill the entire page (set its height to 100% of its parent), we set their heights to 100% (of the page height).

Browsers have basic style sheets that give a default style to any document they render. It's called the user-agent stylesheets. The styles in these sheets depend on the browser in question. Sometimes they can even be adjusted by the user.

The body element usually has a default margin in the user-agent stylesheets. We want the canvas to fill the entire page, so we set its margins to 0.

Unlike block elements, inline elements are elements that can be treated like text on a regular line. They can have elements before or after them on the same line, and they have an empty space below them whose size depends on the font and font size in use. We don't want any empty space below our canvas, so we just set its display mode to block.

As planned, we set the canvas dimensions to 100% of the page width and height.

We already explained that before, didn't we?!

Behold the result of our changes...

...

...

No, we didn't do anything wrong! This is totally normal behavior. Remember the dimensions we gave to the canvas in the HTML tag?

Now we've gone and given the canvas other dimensions in the CSS:

Turns out that the dimensions we set in the HTML tag control the intrinsic dimensions of the canvas. The canvas is more or less a bitmap container. The bitmap dimensions are independent on how the canvas is going to be displayed in its final position and dimensions in the page. What defines these are the extrinsic dimensions, those we set in the CSS.

As we can see, our tiny 30*30 bitmap has been stretched to fill the entire canvas. This is controlled by the CSS object-fit property, which defaults to fill. There are other modes that, for example, clip instead of scale, but since fill won't get into our way (actually it can be useful), we'll just leave it be. If you are planning to support Internet Explorer or Edge, then you can't do anything about it anyway. At the time of writing this article, they don't support object-fit at all.

However, be aware that how the browser scales the content is still a matter of debate. The CSS property image-rendering was proposed to handle this, but it's still experimental (if supported at all), and it doesn't dictate certain scaling algorithms. Not just that, the browser can choose to neglect it entirely since it's just a hint. What this means is that, for the time being, different browsers will use different scaling algorithms to scale your bitmap. Some of these have really terrible artifacts, so don't scale too much.

Whether we are drawing using a 2d context or other types of contexts (like webgl), the canvas behaves almost the same. If we want our small bitmap to fill the entire canvas and we don't like stretching, then we should watch for the canvas size changes and adjust the bitmap dimensions accordingly. Let's do that now,

Looking at the changes we made, we've added these two lines to the JavaScript:

Yeah, when using 2d contexts, setting the internal bitmap dimensions to the canvas dimensions is that easy! The canvas width and height are monitored, and when any of them is written to (even if it's the same value):

  • The current bitmap is destroyed.
  • A new one with the new dimensions is created.
  • The new bitmap is initialized with the default value (transparent black).
  • Any associated context is cleared back to its initial state and is reinitialized with the newly specified coordinate space dimensions.

Notice that, to set both the width and height, the above steps are carried out twice! Once when changing width and the other when changing height. No, there is no other way to do it, not that I know of.

We've also extended our short line to become the new diagonal,

instead of: 

Since we no longer use the original 30*30 dimensions, they are no longer needed in the HTML:

We could have left them initialized to very small values (like 1*1) to save the overhead of creating a bitmap using the relatively large default dimensions (300*150), initializing it, deleting it, and then creating a new one with the correct size we set in JavaScript.

...

on second thought, let's just do that!

Nobody should ever notice the difference, but I can't bear the guilt!

CSS Pixel vs. Physical Pixel

I would have loved to say that's it, but it's not! offsetWidth and offsetHeight are specified in CSS pixels. 

Here's the catch. CSS pixels are not physical pixels. They are density-independent pixels. Depending on your device's physical pixels density (and your browser), one CSS pixel may correspond to one or more physical pixels.

Putting it blatantly, if you have a Full-HD 5-inch smartphone, then offsetWidth*offsetHeight would be 640*360 instead of 1920*1080. Sure, it fills the screen, but since the internal dimensions are set to 640*360, the result is a stretched bitmap that doesn't make full use of the device's high resolution. To fix this, we take into account the devicePixelRatio:

devicePixelRatio is the ratio of the CSS pixel to the physical pixel. In other words, how many physical pixels a single CSS pixel represents.

window.devicePixelRatio is well supported in most modern browsers, but just in case it is undefined, we fall back to the default value of 1.0.

By multiplying the CSS dimensions with the pixel ratio, we are back to the physical dimensions. Now our internal bitmap is exactly the same size as the canvas and no stretching will occur.

If your devicePixelRatio is 1 then there won't be any difference. However, for any other value, the difference is significant.

Responding to Size Changes

That's not all there is to handling canvas sizing. Since we've specified our CSS dimensions relative to the page size, changes in the page size do affect us. If we are running on a desktop browser, the user may resize the window manually. If we are running on a mobile device, we are subject to orientation changes. Not mentioning that we may be running inside an iframe that changes its size arbitrarily. To keep our internal bitmap sized correctly at all times, we have to watch for changes in the page (window) size,

We've moved our bitmap resizing code:

To a separate function, adjustCanvasBitmapSize:

with a little modification. Since we know how expensive assigning values to width or height is, it would be irresponsible to do so needlessly. Now we only set width and height when they actually change.

Since our function accesses our canvas, we'll declare it where it can see it. Initially, it was declared in this line:

This makes it local to our anonymous function. We could have just removed the var part and it would have become global (or more specifically, a property of the global object, which can be accessed through window):

However, I strongly advise against implicit declaration. If you always declare your variables, you'll avoid lots of confusion. So instead, I'm going to declare it outside all functions:

This also makes it a property of the global object (with a little difference that doesn't really bother us). There are other ways of making a global variable—check them out in this StackOverflow thread

Oh, and I have sneaked context up there as well! This will prove useful later.

Now, let's hook our function to the window resize event:

From now on, whenever the window size is changed, adjustCanvasBitmapSize is called. But since the window size event is not thrown upon initial loading, our bitmap will still be 1*1. Therefore, we have to call adjustCanvasBitmapSize once by ourselves.

This pretty much takes care of it... except that when you resize the window, the line disappears! Try it in this demo.

Luckily, this is to be expected. Remember the steps carried on when the bitmap is resized? One of them was to initialize it to transparent black. This is what happened here. The bitmap was overwritten with transparent black, and now the canvas green background shines through. This happens because we only draw our line once at the beginning. When the resize event takes place, the contents are cleared and not redrawn. Fixing this should be easy. Let's move drawing our line to a separate function:

and call this function from within adjustCanvasBitmapSize:

However, this way our scene will be redrawn whenever adjustCanvasBitmapSize is called, even if no change in dimensions took place. To handle this, we'll add a simple check:

Check out the final result:

Try resizing it here.

Throttling Resize Events

So far we are doing great! Yet, resizing and redrawing everything can easily become very expensive when your canvas is fairly large and/or when the scene is complicated. Moreover, resizing the window with the mouse can trigger resizing events at a high rate. That's why we'll throttle it. Instead of:

we'll use:

First,

instead of directly calling adjustCanvasBitmapSize when the resize event is fired, we used a function expression to define the desired behavior. Unlike the function we used earlier for the load event, this function is a named function. Giving a name to the function allows to easily refer to it from within the function itself.

Just like other objects, properties can be added to function objects. Initially, timeoutId is undefined, thus, this statement is not executed. Be careful though when using undefined and null in logical expressions, because they can be tricky. Read more about them in the ECMAScript Language Specification.

Later, timeoutId will hold the timeoutID of an adjustCanvasBitmapSize timeout:

This delays calling adjustCanvasBitmapSize for 600 milliseconds after the event is fired. But it doesn't prevent the event from firing. If it isn't fired again within these 600 milliseconds, then adjustCanvasBitmapSize is executed and the bitmap is resized. Otherwise, clearTimeout cancels the scheduled adjustCanvasBitmapSize and setTimeout schedules another one 600 milliseconds in the future. The result is, as long as the user is still resizing the window, adjustCanvasBitmapSize is not called. When the user stops or pauses for a while, it is called. Go ahead, try it:

Err... I mean, here.

Why 600 milliseconds? I think it's not too fast and not too slow, but more than anything else, it works well with entering/leaving fullscreen animations, which is out of the scope of this tutorial.

This concludes our tutorial for today! We've covered all the canvas-specific code we need to set up our canvas. Next time—if Allah wills—we'll cover the WebGL-specific code and actually run the shader. Till then, thanks for reading!

References

Envato Turns 10 Today!

$
0
0
Envato 10th birthday celebrations

Today marks the ten-year anniversary of the launch of our parent company, Envato, and we've got lots of celebrations planned—many of which involve giving away special discounts and other bonuses, so keep reading for details of those.

Where It All Began

Ten years ago today, Envato was launched with a simple goal: to build a space for creators to come together around a shared passion for creativity, learning, and design.

That small site has grown into a community of over seven million members to date. Find out more in this birthday message from Envato's co-founders, Collis and Cyan Ta'eed.

Special Offers

To celebrate our tenth anniversary, we've got some great limited-time offers:

More details on all those offers, plus more events like a special web-based tour of the Envato HQ, over on the Envato blog.

Learn More

There's lots more happening on the Envato blog today, so head over there to stay up to date. For example, you can:

Using a Texture Atlas to Optimize Your Game

$
0
0

Time. Months. Maybe years. You have spent your time (a lot of time) in order to create your game. Small or big, it doesn't matter. It's your game, and now you want to share it with the whole world—and maybe become famous and rich*. It's perfect: the art is good, and you are very proud of your idea inside the game. Your game.

But there is one last issue that you must resolve before the release. No, not a simple issue. The issue: the frame rate of your game is low. Very low. And that means only one thing: you need to find a way to fix it. You must. And you have no idea how.

Don't panic: there is a simple trick that can help you. It's called a "Texture Atlas".

* If you become rich thanks to this article, please remember me. Thank you so much!

What's a Texture Atlas?

If you are approaching the development of a 3D video game for the first time, you’ll begin to discover that 3D graphics are composed of several parts: 3D meshes, textures, particle systems, and many other elements that are usually drawn on the screen 30 times per second (in slang: 30 fps) during the rendering process, making the game’s world varied and lively.

Believe it or not, the first 3D video games I saw in my life had none of these elements. They were composed only of lines that formed objects or elements in 3D wireframe.

Elite - Masterpiece by David Braben and Ian Bell

Writing this is definitely making me feel old.

Back to us (indeed, to you) and to the important things, today we'll talk about the textures of the user interface (UI hereinafter) and, by extension, about all textures in the game.

In a 3D game, the UI is usually made of 3D elements (such as planes or boxes) with textures.

We mentioned before the rendering process: it’s the operation by which the elements in memory are physically drawn on the screen. It’s among the most complex and expensive processes that occur in a real-time 3D game. Then, any expedient to reduce the time taken by this process is welcome; less time spent in the rendering phase means a higher frame rate (i.e. if you reach the 60 fps you can render the image twice and then think of developing your game also for VR), or more screen elements (and then a richer game, more animated, more beautiful).

One of the means used to reduce the duration of the rendering process is a Texture Atlas: it’s nothing more than an image that contains many textures.

A Texture Atlas with some UI elements

How a Texture Atlas Works

Note: As mentioned in the previous paragraph, this article will discuss the Texture Atlas applied to the UI. However, many of the concepts explained here can also be applied to 3D models and their textures.

A Texture Atlas, we said, is a collection of textures inside a single image.

An Atlas is usually associated with a file descriptor, which indicates to the game where a texture is (in certain x and y coordinates), in order to retrieve it.

Depending on the system that you will use to generate and manage the Atlas, you will have more or less options, such as the distance between the images that compose it (reducing the risk of artifacts on the edges of the texture, caused by an overlap of two elements), or the ability to rotate the elements to optimize the space inside the Atlas (more optimized space means more images inside the same Atlas).

Different Ways to Create a Texture Atlas

There are different ways to create an Atlas. A complete development environment usually allows the internal management of the Atlas; there are also many external tools that provide a lot of additional options.

The choice of which system to use obviously depends on your personal preferences. Here we explain two of them: Sprite Packer, internal to Unity, and TexturePacker (a standalone tool, for a fee).

Sprite Packer

To open Sprite Packer, choose from the menu Window > Sprite Packer.

The management is really easy: the button Pack is used to create one or more Atlases (it depends on the number of your images and on the Atlas dimension that you want to use).

Now you can select an image to see where it is in the Atlas. If you add or remove images from your project, you must use the button Repack, to update the Atlas.

In order to configure the Sprite Packer, you can choose from the menu Edit > Project Settings > Editor; here you can disable the Atlas, activate it only for the game built, or always turn it on.

For more information about Sprite Packer, you can check the official guide.

Sprite Packer - Unity

Texture Packer

Texture Packer is a standalone tool used to manage Atlas.

You can add one or more folders from your project and Texture Packer will create the Atlas.

After that, you can choose the data format for the export. As you can see, there is also the option "JSON for Unity". This means that you can export your Atlas for your Unity project. But, in order to use them together, you must install a free editor extension from the asset store.

For more information about Texture Packer, you can check the official guide.

Texture Packer - Mac version

Why Is It Important to Use a Texture Atlas?

But why is it so important to collect multiple images into a single larger one?

Let's go back for a moment to the rendering process: if every element of the UI has a separate texture, it is drawn with a separated "draw call." This means that if in our interface we have the icon of hearts (representing the player’s energy) and the icon of the coins collected, we will have two draw calls.

Each draw call takes some time to complete, making the rendering process longer and longer. If there are five UI elements, instead of two as in the example above, there are five draw calls.

Do you begin to see the point?

More draw calls -> more time during the rendering phase -> less fps - > game with a low frame rate (with some frame drops) or fewer elements on the screen (then visually poor).

Wasting draw calls this way, unless there are special reasons, doesn’t really make sense, especially for the UI.

In fact, all the textures in an Atlas will be rendered together, in a single pass.

In Unity you can check your draw calls by the Stats button in Play Mode

Conclusion

In conclusion, especially if you're developing a game on a platform where performance is really important (such as a mobile platform):

  • You must pay attention to the number of draw calls: more draw calls means a higher rendering time (and a higher rendering time means the risk of having a low frame rate).
  • Generally, every object with a different texture can generate a single draw call (it's a generic statement: there are some exceptions, especially in the case of 3D objects).
  • One way to lower the number of draw calls is to use a Texture Atlas.
  • A Texture Atlas is basically a big texture with a group of different textures.
  • All objects that use the same Texture Atlas generate a single draw call.
  • Especially for the UI textures, the use of a Texture Atlas is a must-have to improve the performance of your project.

And... may the force be with you. And your code. Always.


Making Levels With the Super Mario World Method: Skill Themes, Part 2

$
0
0

This is the fourth in a series of articles that explain how to use the design methods that Nintendo created in the making of Super Mario World, and how you can use them in your own level designs. If you haven't read the earlier articles, you should, or else this article won't make sense.  

In the previous article, I wrote about how most of Super Mario World's levels fit into one of four skill themes, and I gave examples of the moving targets and periodic enemies skill themes. In this article, I'm going to look at the final two skill themes: the preservation of momentum theme and the intercepts theme.  

Although I found these skill themes in Super Mario World, they actually appear in other games too, so the examples I'm about to give are still useful in contemporary game design. Plus, there's Mario Maker, which I use to build my examples, and that's more than enough reason to understand skill themes. Isn't it?

The Preservation of Momentum Theme

The first skill theme I want to explore is the preservation of momentum theme. If you recall from the last article, all the skill themes in Super Mario World take place in either the action or platforming genre, and in either the timing or speed skill style.

The diagram of skills in Super Mario-style games

The preservation of momentum theme lies at the intersection of platforming and speed. The basic idea of this theme is that it forces the player to keep Mario's momentum up for long stretches of time and space. This can be done in several ways, and we'll see a few of those ways in the level I've made. The intercepts theme, on the other hand, is the complement of the preservation of momentum theme, and leans more toward the action genre.  

As I explained in the first article in this series, an intercept is any object or enemy which interferes with a jump that Mario is already making. That is, intercepts do not cause jumps—they only modify jumps. The intercepts theme is all about throwing a variety of different obstacles into the path of jumps that Mario has to take. We'll see several examples of that in my level too.

The original design idea which gave rise to the preservation of momentum theme was the falling platform. Because Mario can only spend a second or two on the platform before it descends into an abyss, he has to keep moving across the platform the entire time. If he stops, he can lose the momentum he needs to get to the next platform.  

A shot of momentum in Super Mario World

Challenges in the preservation of momentum theme tend to be wider than in other themes because Mario has to run through them at a high speed. This doesn't make these challenges harder, necessarily; they're just more spaced out.  

Preservation of momentum challenges start as simply as the challenge you see above, which is the standard challenge for my level. Let's take a look at some evolutions of this.

Evolutions of Momentum

What I've done here is to add some Wing Koopas to patrol the space between the platforms. This is a very simple evolution that borrows from the complementary theme by adding intercepts. The Wing Koopas aren't the cause of Mario's jump—the falling platform is the cause—but they do modify the jump he is already taking.

The second evolution modifies the previous challenge by replacing the Wing Koopas with Boos. Like the Wing Koopas, the Boos aren’t the cause of the jumps. The real challenge for Mario is jumping through the platforms that fall away. Failing a jump results in death, while touching a Boo results in non-fatal damage. Unlike the Wing Koopas, however, the Boos will follow Mario around, making the jumps even more difficult. 

Being chased by enemies making jumping more difficult

To mitigate this chasing behavior a little bit, I have changed the middle platform so that it does not fall. It’s very common in Super Mario World for the evolution of one part of a challenge to involve the de-evolution of another part. The goal of an evolution is higher difficulty through qualitative change, but the emphasis is on qualitative change (at least in Mario games) rather than absolute difficulty. So I've softened part of the second evolution to emphasize the change rather than the difficulty.

The next section of the level presents a different way of forcing the player to keep moving. The Super Star power-up gives Mario invincibility, but only for a limited time. Several levels in Super Mario World use the star as a means for getting through otherwise very difficult gauntlets of enemies at a high speed. This is what I aimed to do in this section of my level. The star is placed in an obvious block so that the player won’t miss it.

Proceeding through a difficult area with a Super Star

The first section makes it obvious that the star is in play to allow the player to cross the otherwise damaging floor. This section is also relatively open, meaning the player can just plow through the spikes without any other difficulties, if Mario is under the effects of the star. The evolution to this challenge will make the next section less passable as the timer on the star runs down.

The challenge in the next section of the level

There's no danger in this evolution of Mario taking damage as long as he has the star; the purpose of this section is merely to slow him down. If Mario reaches the end of the challenge here without the star, he's essentially guaranteed to take damage from the enemies that occupy his landing spot. If the player can get him through there quickly, Mario will be fine, and will actually gain several 1-ups. 

The third challenge actually reverses the need for the star. If the player manages to make it to this spot with the star, they may face a problem. 

Facing Winged Koopas with no Super Star

Because the pit is so wide, the player once again needs to bounce off the head of a Wing Koopa in order to make it across. If Mario still has the star powerup, he actually can't bounce off the Koopa because the star powerup changes the way that collisions with enemies work. 

There are two interesting things about this challenge. This is an inversion—instead of needing the star to preserve Mario's momentum, the player needs the star to go away before attempting the jump, so that Mario can bounce and keep going when he hits the Koopa’s head. Inversions (total reversals of a standard challenge) are a common tool in the designer's toolkit and appear often in Super Mario World—and many other games too. But also, this challenge is clearly about preserving momentum, by bouncing off the heads of the Koopas.

The Intercepts Theme

For the next section, this level switches to the intercepts theme. There have been many intercepts present in the level so far, but always in the context of the preservation of momentum—Mario always had to keep moving forward. Speed is still essential in the intercepts theme, but that speed is often in quickness of the player’s reflexes rather than Mario’s forward run.  

The intercepts theme often requires Mario to run or air-dodge backwards to avoid some oncoming object. The most idiosyncratic aspect of the intercepts theme, however, is the layering of various kinds of intercepts. The first challenge is fairly easy, starting at the level of a standard challenge.

The first challenge in the intercepts theme

The cannon in the middle fires Bullet Bills at a regular rate. Although regularity is the hallmark of a periodic enemy, the bullet bills aren’t localized to a single jump, as a periodic enemy would be. Instead, they intercept every jump on this tier of the section. The first evolution of this idea, meanwhile, is simple: I just add Wing Koopas.

Adding Winged Koopas for difficulty

Now we have two intercepts modifying Mario’s jump path. Likewise, the final evolution is similar in structure, but different in content.

Three enemies in total for the evolution of difficulty

The evolution here is in exchanging the Wing Koopas for Boos again, and there is also an expansion in the number of cannons on the middle platform. 

You could call this a repetitive move, but one of the important aesthetics of Mario-style game design is not putting too many elements in a level. I could have thrown in 12 different enemies, but the CCST structure depends upon the same design ideas appearing throughout a level to maintain consistency. Small iterations preserve the newness and challenge of a level while at the same making sure that all the basic ideas are familiar to the player.

Back to the Preservation of Momentum

The final section of the level returns to the preservation of momentum theme using the last important method for the preservation of momentum in Super Mario World: the inability to stop. 

In Super Mario World, this was achieved through icy floors. Super Mario Maker doesn’t have as robust a set of tools for doing this, but it makes up for that by accomplishing something similar in conveyor belts. The essential idea is preserved. Mario is going to keep moving whether the player wants him to or not.

Perpetual Motion

Across the course of several layers of conveyor belts, I simply added new kinds of intercepts and other dangers like the Grinder. The final challenge has both cannons and a winged Dry Bones who throws bones.

A saw bullets and Dry Bones

What I've done here is to combine the preservation of momentum elements with the intercepts elements to create a climactic peak in the level's complexity and difficulty. The conveyor belt provides the momentum challenge, while the different kinds of intercepts make that momentum dangerous.

And then for the last section of the level I created a simple gauntlet where Mario has to run across some more conveyor belts beneath some Boos. The danger here is pretty minimal, but with the enhanced momentum the action can still feel exciting and fun. 

Enemies along with forced momentrum
Jumping across Winged Koopas after having forced momentum

I didn’t really turn this last section into a proper part of a cadence. Instead what I wanted to do was set up a “reward by fun” section. The idea behind this is to break the tension in a level by giving the player an easy, flashy task. 

My level wasn’t that tense, because I’m only trying to teach game design techniques, but this section replicates the structure of the reward by fun. Fleeing the ghosts is actually quite easy, even with the occasional backwards motion of some of the belts. The last jump is also quite easy, as the final belt is reversed and the “platform” of Koopas is quite wide.

Conclusion

That covers all the skill themes in Super Mario World, but it's not the end of the story. Although most of the levels in Super Mario World fit into one of the four skill themes, there are quite a few levels in the game which do not fit into any of them. 

If you want to know more, you should check out the book I wrote about the game. There are many other skill themes in other games, and many other cadence structures too. In the next article, we're going to take a look at some of those games and how they interpret the CCST structure.

Until then, good luck making your levels!

Amazon Lumberyard: Editor Analysis

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

Lumberyard is the latest 3D game engine to hit the market. It is a free, multi-deploy platform engine that offers deep integration with both the Amazon Web Services (AWS) infrastructure and Twitch to improve general online gameplay.

The Lumberyard engine technology is based on CryEngine. Amazon licensed one version of CryEngine and got complete access to its technology. That does not mean that CryEngine will leave the market since Lumberyard only represents a branch of CryEngine technology. Both will be present and will struggle for market share.

Lumberyard is a powerful and full-featured AAA game engine that enables you to create games for the latest console generation (Xbox One and PlayStation 4). Mobile support is also a goal (the engine already has rendering options for iOS and Android).

In this tutorial, I'll do an analysis of the Lumberyard editor, namely the editor layout, objects, essential tools, navigation, and layers.

Who Should Read This Tutorial Series?

This tutorial series is primarily aimed at two groups of game developers: those who are completely unfamiliar with game engines at all, and those who are familiar with other game engines (such as Unity, Unreal Engine, or Cry Engine) but aren't familiar with Lumberyard. I assume that you have some knowledge of computer graphics notation, so I won't exhaustively cover all notations.

Prerequisites

Despite the fact that you don't really need to read the first tutorial part, you are advised to do so since it covers the initial installation and configuration steps. 

If you just want to start using Lumberyard, you're right on track.

Editor Layout

The Lumberyard Editor provides several tools for creating and modifying your game environment, including levels, objects, textures, terrain, lighting, physics, animation, layers, and a lot more.

As you can already guess, the Editor will be your best companion during the creation of games. Before you can start using and learning the Editor, you must create a new level.

Create a New Level 

A level is a 3D environment (or a map) that represents the available virtual space or area for you to create your game (or single level). Launch Lumberyard Editor (Editor.exe) and a similar interface should appear.

Welcome

In the Welcome to Lumberyard Editor interface, you can create a new level, open a recent level, or open a level from within the Lumberyard directory. Click New Level.

New level

Name your level First_Level and click OK. For this tutorial, you will use the default values under Heightmap Resolution and Meters Per Texel

The first, as the name suggests, represents a 2D greyscale map of your height information. 

The latter represents the size of each Texel (represented as a square on the perspective floor). If you play with those values, you can see that the Terrain Size changes accordingly. 

Terrain texture

In the Generate Terrain Texture interface, you can control the appearance of your level's terrain. Texture Dimensions represents the overall texture quality (more quality implies more computational resources). Terrain Color Multiplier represents the number of colors that will be used to compensate for the texture compression. 

Normally, you should start with a lower value (ranges from 1 to 16) and increase it if the terrain colors are distorted or have artifacts. Checking the High-Quality check-box increases textures; this setting takes longer but results in fewer compression artifacts and does not affect memory or CPU usage in game mode.

You don't need to change the defaults values for now. Click OK. The Lumberyard Editor will appear.

Objects

Lumberyard only has three object types (Entities, Brushes, and Designed objects) that encompass every object that can be placed in a level. Even external imported objects will be automatically cataloged as one of these three object types.

Objects
  • Entities are objects with behavior properties. A behavior property uses a game script or programming code to enable objects to respond to game objects (for example, a moving car). Entities are subdivided into the following types:
  1. Entities represent general objects that are normally used to create gameplay conditions, such as actors, animations, lights, and cameras, among others.
  2. Geometry Entities represent the aforementioned objects but attached with geometry mesh information.
  3. Particle Entities represent physical particles.
  4. Archetype Entities represent a custom set of objects that are created based on the available entity properties.
  • Brushes are objects with 3D mesh data only; they do not contain behavior properties.
  • Designer objects are objects created with the Lumberyard Designer modeling tool. 

Later in this tutorial, you will learn how to create and modify each available object.

Essential Tools

Lumberyard Editor features several tools, settings, and options to help you create high-quality games. The essential tools for manipulating objects are Select, Move, Rotate, Scale, and Terrain Area.

You can select these tools either with the keyboard shortcut or from the Lumberyard Editor toolbar.

Editor toolbar

If you don't see the EditMode Toolbar, you can right-click an empty area of the menu or toolbar area and select EditMode Toolbar.

Editmode toolbar

Each tool provides its own unique 3D visual representation, called a gizmo, on the selected object. The gizmo helps you identify the tool that is currently selected.

To select each tool, you can use your mouse to select it or use the following keyboard shortcuts:

  • 1: Select
  • 2: Move
  • 3: Rotate
  • 4: Scale
  • 5: Terrain Area

Let us now experiment with each tool using 3D objects.

Place an Object

To place an object in the level you should use the Rollup Bar (right side).

  1. Click Brush to display your current loaded assets.
  2. Under the Browser section, in the directory tree, expand Objects > gettingstartedassets and select gs_block.
  3. Drag the gs_block object into the Perspective viewport.
gs_block

When you place the gs_block you will notice that you are not completely free to place it where you want. That behavior is related to the snapping options (Follow Terrain and Snap to Objects, Snap to Grid, and Snap Angle).

Snap
  • Snap to Objects is used when you want to attract one object to another.
  • Snap to Grid is used when you want to attract one object to points along a customizable grid.
  • Snap Angle is used when you want to attract one object using a specific angle.
  • Follow Terrain is used when you want to move an object along a terrain rather than along a specific X, Y, or Z axis or plane. This feature is particularly useful when you want to place objects sitting directly on the terrain.

Both Snap to Grid and Snap Angle are on by default.

Select

Selecting an object (or multiple objects) is the core of all game development stages. The Select gizmo is represented by a set of three lines (one for each X, Y, Z direction). You will notice that when Lumberyard detects the mouse over any object, that object is highlighted and therefore can be selected.

Select

Move

The Move tool selects and moves an object within the 3D world of the Perspective viewport. The Move gizmo is a set of three lines with arrowheads on the X, Y, and Z axis.

Move

The Move gizmo also features three small right-angle squares along the XY, ZY, and XZ planes. To move your object along a given plane, click on the selected one of the small squares.

Note that you can also restrain the object movement by using the Lock options (Lock on XAxisLock-on Y-AxisLock on Z-Axis.

Rotate

The Rotate tool selects and rotates an object. The Rotate gizmo is represented by a set of circles around the object along the X, Y and Z axis. To rotate an object, select one of the small circles and then rotate the object around that rotational plane.

Rotate

The white circle surrounding the entire gizmo represents a rotation of the object related to the screen display.

Scale

The Scale tool can select an object and change its size. The Scale gizmo has cubes on the three axes (X, Y, and Z). To scale the object, select the X, Y, or Z line and then drag to modify its scale property.

Scale

Terrain Area

The Terrain Area tool can select a terrain area. In the following figure the game is composed of two terrains: pool and townblock (available at: Brush objects > Objects > styletown > natural > terrain)

Terrain

Accurately Move, Rotate, and Scale

Lumberyard provides you a way to accurately move, rotate, and scale any object. That option is available in the Viewport Controls section of Lumberyard (bottom).

Accurately Move Rotate and Scale

These controls are exactly the same as the aforementioned Move, Rotate, and Scale; however, using them provides you a way to accurately move, rotate, or scale any object.

Editors

The Lumberyard Editor holds a collection of editor tools for building specific categories of content (such as Assets, Flow Graph, Material editors, scripts, and terrain editors, among many others). You can see a big picture of the editors by clicking on View > Open View Pane.

Lumberyard Editor

Another way to open the most commonly used editors is by using the editors toolbar. Note that this bar can be configured to add or remove editors.

editors toolbar

You can change several Perspective viewport options using the Viewport Header and Viewport Controls.

Viewport Header enables you to:

  • filter objects in the perspective viewport
  • change the default field of view (FOV), Ratio, and resolution
  • toggle amount of debug/display information, using the i icon
  • toggle each individual entity icon and their visual guidelines, using the H icon

To change the FOV, Ratio, and resolution, you only need to right-click on that option and change the default value:

Viewport Header

The Viewport Header has some additional "hidden" features that can be seen if you right click in an empty Viewport Header part.

Hidden header

You can play with those options and see the result in real time within the perspective viewport.

The Viewport Controls has two main properties: navigation speed and AI/Physics. The Speed setting displays the current movement speed setting. The AI/Physics button toggles the movement events for physics, AI (artificial intelligence), and particles in edit mode.

Viewport Controls

The major advantage of these modes is that you can test and view these events without entering game mode.

Layers

The Layers tab in the Rollup Bar helps you hierarchically organize your level content. You can use the toolbar on the Layers tab to interact with layers.

Layers

Each icon represents a specific action (in order): new, delete, rename, export, importsave external layers, and freeze.

Layers Button

Additionally, each layer has its own eye and arrow icons that help you manage objects. The eye icon toggles the layer visibility while the arrow icon toggles the ability to select objects in that layer.

Note that you can reorder your layers or event group them hierarchically by holding the Control key and dragging each layer to its next location.

Working With Layers and Their Files

When you create a new layer, that layer is stored as a file in the level\layers directory (inside your Lumberyard installation) with the extension .lyr.

To add content to a specific layer, you only need to select that specific layer. With that layer selected, you can create or add content, all of which are automatically created as a part of that layer.

Note that when you are working on a specific layer, you don't need to save the level file, but you do need to save the layer file. To save the layer file, click Save External Layers.

This feature is quite useful when you work with a team within the same level. Thus, each person can work on a specific layer and in the end one imports all layers to the final level.

Moving Assets Between Layers

Each Entity, Brush, or Designer object you place in the level is assigned to the currently selected layer. By default, and if you haven't created additional layers, all objects are placed in the default main layer. To assign an object to a different layer, you must:

  1. select the object in the Perspective viewport
  2. in the Rollup Bar, click the Objects tab
  3. click the Layers icon to display a list of all created layers
  4. select the destination layer from the list
Change Layer

Tips

Lumberyard provides you an Auto Backup feature. As the name suggests, it saves your level file incrementally, thus preventing any massive loss of your work. If you want, you can customize your Auto Backup settings by selecting File > Global Preferences > Editor Settings. Now select Files (under General Settings).

Three properties can be customized to your choice:

  1. the maximum number of backup saves (Maximum Save Backups)
  2. the default save directory (Standard Temporary Directory)
  3. save camera tag points (Auto Save Camera Tag Points)
Backup

Conclusion

This concludes this tutorial about the Lumberyard Editor. You learned how to create a new level and its properties. Then you learned the Lumberyard Objects and its essential tools. Finally, you discovered how to create, configure, and modify Layers. 

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

Amazon Lumberyard: Creating the First 3D Scene

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

In this tutorial part, I'll show you how to create a complete 3D level composed of both Lumberyard internal assets and imported new ones.

Then, you'll learn how to place both the player and the camera, and how to use several entities, creating prefabs and textures. Finally, you'll be introduced to Lumberyard lighting.

Note that you are advised to read the previous two parts (Part 1, Part 2) in order to fully understand the notations from this part.

Who Should Read This Tutorial Series? 

This tutorial series is primarily aimed at two groups of game developers:

  • those who are completely unfamiliar with game engines at all
  • those who are familiar with other game engines (such as Unity, Unreal Engine, or Cry Engine), but not with Lumberyard

I assume that you have some knowledge of computer graphics notation, so I won't exhaustively cover all notations.

Create a New 3D Level

Launch Lumberyard and click on New Level. Use the following data in the New Level interface.

  • Name: CompleteFirstLevel
  • Folder: Levels/ (default value)
  • Useterrain: checked!
  • Heightmap Resolution: 1024x1024
  • Meters Per Texel: 1

Click OK.

Note that all levels are saved by default at: YourLumbaryardInstallationpath\dev\SamplesProject\Levels.

For the terrain texture, use:

  • Resolution: 4096x4096
  • Terrain Color Multiplier: 3
  • High Quality: checked!

Click OK.

Camera Positioning

In order to game play your level, you must create and place a game camera. Then you need to modify it to enable character control and specify a starting point. Fortunately, Lumberyard provides a prefab object that has a gameplay camera with supporting input controls.

The camera can be found in the Database Editor, under View > Open View Pane.

Database Editor

You can also find the Database Editor in the EditMode Toolbar.

Database Editor in the EditMode Toolbar

The database view tabs (red rectangle) provides access and configuration for several database types. The editor toolbar (green rectangle) gives you access to tools such as Open, Save, Add, or Remove items from the database. Finally, the FileTree View (blue rectangle) gives you access to the database items available.

The FileTree View

In the Database View, open the Prefabs Library and click Load Library.

Database View in the Prefabs Library

From the prefabs directory listing, select character_controllers.xml and click OK.

The Character Controllers

From the Prefab Library file tree view, drag Sphere_Controller into the Perspective Viewport

Now you should have one robot lying on your level waiting for testing. Note that the location where you place it also determines the start point of the level. Save your level file (File > Save).

Robot

If you click on the Gizmo, you can see the complete prefab properties. If you can't see the Gizmo, then you need to click on the H icon in the Perspective Toolbar.

Gizmo

You should note that, by default, you cannot modify any prefab entity property. However, if you select the Gizmo, and then click on Open All under the Rollup Bar >Prefab Parameters, you will now have access to each prefab entity and its properties.

Prefab Parameters

Click on the Camera Controller Rig entity to inspect its Camera Params.

Camera Paramaters

It is now time to test your new game camera. Click on Game > Switch to Game or press Control-G.

Add a Camera

There are several scenarios where you intend to have custom cameras or even static cameras. For that, Lumberyard provides you access to the camera entity. There are two major ways to add a custom camera:

  1. using the RollupBar
  2. using the current Perspective viewport configuration

The former uses the entity Camera available at Objects > Misc > Object Type > Camera. You just need to select the Camera entity and then place it in within your Perspective viewport.

The latter uses your current view position so that the new camera will also use that same configuration. Place Perspective viewport in the desired positioning (for example looking at the robot). Right-click in the upper left corner of the Perspective toolbar, and click Create Camera from Current View. The current view from your Perspective viewport is now a fixed camera from that position. 

Camera From View

Now, navigate away and notice the new camera entity looking for your last Perspective Viewport configuration.

Navigate Camera From View

Objects

One way to place objects is by using brushes (RollUp Bar > Objects > Brush). Brushes are normally static objects placed within the 3D scene. They are cheap to render since they don't contain extra properties of an entity or physics properties.

In the Rollup Bar on the right, select Brush in the Objects tab. Under the Browser heading, open Objects > StyleTown > Natural > Terrain and select the object townbloc. Drag it into the Perspective viewport.

Perspective Viewport

From the Brush list, open StyleTown > Architecture > Buildings. Drag the b13_h02 building into the Perspective viewport and place it near one corner of the townbloc.

Another Perspective Viewport

Now you know how to place brushes in your level.

Importing External Objects

To import external objects, Lumberyard advises you to use the FBX file format. The current importer is still in preview release and some features like materials are missing.

The Lumberyard FBX Importer tool incorporates a scene graph, which is a tree-based layer of data between your .fbx model and Lumberyard. Every time you process a .fbx a new .scenesettings file with the same name is created; this new file stores the asset metadata.

If you change the mesh properties of the model, you don't need to re-import the .fbx file. Lumberyard Asset Processor listens and detects any changes to the .scenesettings file and uses the Resource Compiler to reprocess the .fbx file.

Let us proceed and download one external FBX file. Extract the compressed file you just downloaded and move the Wooden_House.fbx into YourLumbaryardInstallationpath\dev\SamplesProject\.

In Lumberyard Editors, select View > Open View Pane > FBX Importer.

 FBX Importer

Click the folder icon at the upper right of the tool window.

Open

 Select the Wooden_House.fbx file, and click Open.

Import

Change the Name property to Imported_Wooden_House and click Import.

Import

After a few seconds, you should see the success message window.

success

One last step must be performed before you can use your new asset. Under the RollupBar > Geom Entity, click Reload. Then a new folder should appear. Open it and you should have the imported_wooden_house model available. 

Finally, drag the model into the Perspective viewport.

First Challenge 

You should now add some brushes by yourself. Your next task is to create a 3D level similar to the following one:

Image 1
Image 2

When you finish the level creation, move to the next section. Note that you don't need to create a 3D world exactly like the previous one. The main idea is to add several brushes and interact with them (rotating, translating, and scaling). 

Prefabs

Prefabs enable you to create content more quickly using a combination of pre-defined assets. To use previously created Prefabs, open the Database View (View > Open View Pane).

Under the Prefabs Library tab, click on Open. Select the styletown.xml and click OK.

The Database

Now open the RollupBar and under Prefab you should now see the imported NeighborhoodBlock Prefab.

The NeighborhoodBlock Prefab

Select and drag the three assets (StreetSet_ABlock_A, and StreetLight_A) into the Perspective Viewport. You should have something like the following image.

A Rendered 3D Scene

Terrains

Lumberyard enables you to generate, edit, and texture a terrain in your level. For that, you must always have in mind three menus:

  1. Terrain Texture Layers
  2. Material Editor
  3. Terrain editor (in RollupBar)

To open the Terrain Texture Layers, you can use the main menu View > Open View Pane > Terrain Texture Layers or the shortcut available in the Editor Toolbar

Terrain Texture Layers

Open the Terrain Texture Layers.

Terrain Texture Layers

The Terrain Texture Layers interface is used to define the materials that will be used to paint your level terrain. There are four main sections within the interface:

  1. Layer Tasks is used to add, delete, move, and assign the selected material to the selected layer.
  2. Layer Info contains information regarding the selected layer, such as the size and surface type.
  3. Layer Texture displays a low-resolution texture containing its color information.
  4. Layer list contains a list of created layers for terrain painting.

Under the Layer Tasks, add two layers. Name the first one grass and the second dirt.

Layer Tasks

Open the Material Editor using View > Open View Pane > Material Editor or the shortcut available in the Editor Toolbar.

Material Editor

You will notice that you will have two windows (Terrain Texture Layers and Material Editor) or a single window with a tab separator in the bottom left side.

Material Editor

The Material Editor is composed using the following areas:

  1. Editor toolbar for applying, deleting, creating, and saving materials
  2. Material Preview that displays the selected material
  3. Material folder directory displaying a hierarchical folder structure containing materials which can be chosen
  4. Properties containing parameters that define the overall material appearance

It is now time to assign two materials to the aforementioned created layers. For the first one, select the material gr_grass_01 located in the directory path: materials > gettingstartedmaterials.

Material Editor

Now change the interface to the Terrain Texture Layers and select the grass layer. Click Assign Material. That action will apply the selected material to the selected layer. Note that the Material path has changed accordingly to material > gettingstartedmaterials->gr_grass_01.

Grass Layer

Now, let's add the ground material (gs_ground_01) into the dirt layer. This material is also located within the same folder.

  1. Select the gr_ground_01 material.
  2. Change the interface to the Terrain Texture Layers.
  3. Select the dirt layer.
  4. Click Assign Materials.

You are now ready to paint the grass and dirt textures onto the terrain.

In the RollUp Bar, select the Terrain tab, and then select the Layer Painter button.

Layer Painter

There are several aspects that you should consider when you apply your terrain texture: the Radius and Hardness properties; the Color and Brightness of the texture; the texture itself; and the type of fill (mouse-based or Flood-based). The former will apply the texture using your mouse position, while the latter will apply the texture to the whole ground.

Select the grass texture and modify the Color to a more green tint. Click OK.

tint Color

With the grass layer selected, click on the Flood button. The terrain is now covered in the grass texture and looks similar to the following one:  

Flood

You can now paint some dirt into the scene around the perimeter of the street. Select the dirt texture and modify the Color to a brown one. Click OK. Now, using the Perspective viewport, zoom in on your 3D scene and with your left mouse button, click to add the dirt texture.

Modify the Radius and Hardness to reduce the time of applying the texture. When you are finished, you will have a 3D level similar to the following:

Dirt

Terrain Height

You can also modify your terrain height using the Modify terrain tools.

Modify

The Modify terrain tool-set features the following options:

  • Flatten: Flatten the terrain to the designated height setting
  • Smooth: Soften the terrain down to a smoother surface
  • Rise/Lower: Raise or lower the terrain based on brush size settings
  • Pick Height: Find and set heights based on existing terrain geometry
  • Outside Radius: Set how big your brush is when painting
  • Inside Radius: Set how round or flat the brush is in relation to the outside radius setting
  • Hardness: Soften or harden the outer brush settings 
  • Height: Set the brush height 
  • Scale: Strength of the noise effect; higher values produce more noise
  • Frequency: How often the effect is applied 

Let's use the aforementioned options to create some mountains inside your 3D level. Select the Rise/Lower button. Note that your mouse cursor inside the Perspective Viewport has changed.

In the Perspective Viewport, navigate towards the outer perimeter of the terrain map and left click to paint on the terrain. Build some hills of different sizes and shapes. In the end, your scene should now look something like this: 

Mountains

If you want, you can play with the terrain properties, namely the Flatten, Smooth, and Pick Height options. When you are satisfied with the terrain generator, save your level (Control-S).

Lighting

Now that you've almost concluded the 3D scene, it's time to add some illumination to it. In Lumberyard, you can add three types of lighting:

  • Environment Probes
  • Time of Day
  • Basic Lights

Before placing single light objects into the scene, it's always good to start with the default global environment probe. Environment probes are great to achieve global ambient lighting because they contribute to reflections, diffuse materials, particles materials, and shadow colors.

When building a level, you are advised to place multiple environment probe groups to achieve high quality and realistic scenes.

Environment Probes

To create the environment probe, select the EnvironmentProbe in the RollUpBar under the Misc option. Move the mouse cursor into the viewport and place the environment probe wherever you want.

EnvironmentProbe

You normally want to put your probe in the center of the level and then configure its BoxSize to fill the desired area.

Under the EnvironmentProbe Properties section, you want to change the BoxSizeX, BoxSizeY, and BoxSizeZ to 512, 512, and 250 accordingly. If you zoom out of the scene, you should have a yellow box covering the scene.

Note that these values may not produce the same result in your scene. Thus, you should adjust them to recreate the desired effect.

Environment Probe Zoom

At this point, the scene has not really changed in terms of lighting because the lighting probe is turned off by default.

Activate the Lighting Probe

To activate the probe, check the box in the Active options under the EnvironmentProbe Properties and thenclick on the Generate Cubemap button under the Probe Functions.

You should notice that the shadows will be softer.

You can further customize the environment probe by changing the Diffuse and DiffuseMultiplier value. The former represents the probe color, while the latter represents the intensity multiplier between that color and the scene materials properties.

DifuseMultipler

Time of Day

You can control the time of day (TOD), and you can even animate your scene, taking into consideration the real time of day variation values. In order to set the TOD, you must open the TOD editor. Again, you can open it using View > Open View Pane > Time of Day or the shortcut available in the Editors toolbar.

TOD

The TOD editor has seven main areas:

TOD
  1. Editor toolbar has icons for importing, saving, and setting specific hours of the day.
  2. HDR Settings to adjust the HDR lighting.
  3. Tasks to configure basic functionalities of the editor.
  4. Time defines the current time for the level. This also includes the start and end time if you want to animate the lighting. 
  5. Update Tasks allows you to play or stop the animations.
  6. Time line editor gives you control over the light settings during a 24-hour period.
  7. Parameters give you more options to configure the lighting properties.

Let's import a predefined TOD .xml file. Click Import file and navigate to SamplesProject\Levels\GettingStartedFiles, choose the TimeOfDay file, and click Open. The lighting settings will be changed automatically. 

Time Of Day

You can further customize the TOD properties as you want. Play with the Sun color, Sun color multiplier, and Sun intensity to see the differences.

Time of Day

Change the TOD to 9:00 PM before continuing. Close the TOD editor.

 900 PM

Basic Lights

Your scene is now darker. It is now time to add basic lights. In the RollupBar, on the Objects tab, select the Entity button. Under the heading Browser, expand the folder Lights and select the Light object. Drag it into your scene and place it near one of the streetlamp objects.

Placing a Street Lamp

Note that, if you encounter any problem precisely aligning the light, you are advised to turn on the Snap to Grid option.

Because the light source is a streetlamp, it should be a spot light (rather than a fill light). To change the light from fill to spot: Beneath the header Entity Properties, find the title Projector. Select Texture, and then click the folder icon.

Texture

Now open the directory \SamplesProject\textures\lights\generic and open the spot_075.dds file. 

Loading a generic texture file

The light changes to a spotlight, but it is oriented sideways. Use the rotate tool to select and rotate the light so that it points down.

Placing the Point Light

Beneath the header Entity Properties, you can modify a variety of settings to customize the light.

  • AttenuationBulbSize is the light bulb size; this is the starting point for where light begins to fall off exponentially. A value of 1 sets the light at full intensity for one meter before it begins to fall off. Adjust this size in relation to the diffuse multiplier to manage the brightness of the light source without entering unmanageable numbers.
  • Radius is the distance from the source at which the light affects the surrounding area.
  • Diffuse represents the RGB color value of the light.
  • DiffuseMultiplier is the intensity of the diffuse color; balance this value with the AttenuationBulbSize to define the balance of natural light levels.
  • ProjectorFov represents the field of view for the projection light.
  • CastShadows makes the light cast a shadow based on the minimum selected configuration specifications. To ensure shadows are always cast, set this to 'Low Spec'. Note that the CastShadows setting is not a 'quality' setting but rather a performance specification setting for the type of machine running the level.

For this tutorial, use the following settings:

  • AttenuationBulbSize = 6
  • Radius = 20
  • Diffuse Color = 228, 224,102
  • DiffuseMultiplier = 20
  • ProjectorFov = 80
  • CastShadows = Low Spec 

Experiment with these settings to get a feel for how the differences between bulb size, radius, and diffuse multiplier change based on the input values you use.

Experimenting with

Run the game (Control-G) and see how your character behaves when in contact with the new light source. For each streetlamp, add a new light. You can do it by duplicating the current light or adding ones.

Challenge

In order to test the knowledge acquired so far, you are now challenged to recreate the getting-started-completed-level.

For that, you will need to play with the brushes, lighting, materials, textures, and terrains. In short, re-apply everything that you've learned so far. Your final level should look like the following:

Conclusion

This concludes this tutorial on Lumberyard. You learned how to configure the camera and player positioning, and you learned how to import external assets and place several entities, creating prefabs and textures. Finally, you were introduced to lighting properties.

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

Get Early Access to Envato Elements—and Lock in a Lifetime Discount

$
0
0

Do you often find yourself needing access to high-quality digital graphics for your creative projects? Would you like access to a library of ready-to-use icons, fonts, illustrations, brushes and more, all for a low monthly subscription?

If so, the new Envato Elements design asset subscription is for you. It's launching publicly later this month, but right now it's in beta, and we're offering a special reduced price if you sign up now.

Envato Elements beta access

How Is Envato Elements Different?

There are lots of design resource platforms out there already—including our own site, Envato Market. So what's different about Elements?

Well, Elements is for anyone who has a regular need for high-quality, ready-to-use design assets. Instead of paying for each item, your single monthly payment gives you unlimited downloads from the large and growing content library of more than 5,000 icons, fonts, graphic templates, and more. 

Envato Elements Watercolor designers kit

We've curated the library carefully, hand-picking the best designers from across the industry to ensure that you have an impressive selection to choose from. 

And you get a simple licence allowing you broad commercial usage rights for the items you download. So you can feel confident using them in projects for clients, knowing that you're fully covered with the right permissions.

Envato Elements design item

If you ever decide Elements is not for you any more, you can cancel whenever you want. But we'll be adding so many fantastic new items every week that we're betting you'll want to stick around.

How Much Does It Cost?

The regular price will be $49 a month, but while the site is still in beta, you can lock in a special price of $19 a month. When the regular pricing kicks in later this year, you'll keep that special $19 price as long as you keep your subscription continuously active

There are no pricing tiers or credits to keep track of—it's just a simple monthly price that gives you unlimited access.

Envato Elements Mobile UI Kit

The items in the library would be worth thousands of dollars if sold individually, so we think $19 a month is a sweet deal. No matter what else we add to the library—and we have lots of plans to add new types of content—you'll keep that low price for life.

Find Out More

You can browse the Envato Elements site to get an idea of what's on offer. If you have specific questions about how it works, check out the details in the help center—or leave a comment below.

Just be aware that this $19 monthly price is going away soon, and it won't be coming back. So if you want to get in on the ground floor with a design library that we think will become a prime go-to resource for designers and creative professionals around the world, sign up and lock in that discount!

Getting Started in WebGL, Part 2: The Canvas Element for Our First Shader

$
0
0

In the previous article, we wrote our first vertex and fragment shaders. Having written the GPU-side code, it's time to learn how to write the CPU-side one. In this tutorial and the next one, I'll show you how to incorporate shaders into your WebGL application. We'll start from scratch, using JavaScript only and no third-party libraries. In this part, we'll cover the canvas-specific code. In the next one, we'll cover the WebGL-specific one.

Note that these articles:

  • assume you are familiar with GLSL shaders. If not, please read the first article.
  • are not intended to teach you HTML, CSS, or JavaScript. I'll try to explain the tricky concepts as we encounter them, but you'll have to look for more information about them on the web. The MDN (Mozilla Developer Network) is an excellent place to do so.

Let's start already!

What Is WebGL?

WebGL 1.0 is a low-level 3D graphics API for the web, exposed through the HTML5 Canvas element. It's a shader-based API that is very similar to the OpenGL ES 2.0 API. WebGL 2.0 is the same, but is based on OpenGL ES 3.0 instead. WebGL 2.0 is not entirely backward compatible with WebGL 1.0, but most error-free WebGL 1.0 applications that don't use extensions should work on WebGL 2.0 without problems.

At the time of writing this article, WebGL 2.0 implementations are still experimental in the few browsers that do implement it. They are also not enabled by default. Therefore, the code we'll write in this series is targeted at WebGL 1.0.

Take a look at the following example (remember to switch tabs and take a few glances at the code as well):

This is the code we are going to write. Yeah, it actually takes a little more than a hundred lines of JavaScript to implement something this simple. But don't worry, we'll take our time explaining them so that they all make sense at the end. We'll cover the canvas-related code in this tutorial and continue to the WebGL-specific code in the next one.

The Canvas

First, we need to create a canvas where we'll show our rendered stuff. 

This cute little square is our canvas! Switch to the HTML view and let's see how we made it.

This is to tell the browser that we don't want our page to be zoomable on mobile devices.

And this is our canvas element. If we didn't assign dimensions to our canvas, it would have defaulted to 300*150px (CSS pixels). Now switch to the CSS view to check how we styled it.

This is a CSS selector. This particular one means that the following rules are going to be applied to all the canvas elements in our document. 

Finally, the rule to be applied to the canvas elements. The background is set to bright green (#0f0).

Note: in the above editor, the CSS text is attached to the document automatically. When making your own files, you'll have to link to the CSS file in your HTML file like this:

Preferably, put it in the head tag.

Now that the canvas is ready, it's time to draw some stuff! Unfortunately, while the canvas up there looks nice and all, we still have a long way to go before we can draw anything using WebGL. So scrap WebGL! For this tutorial, we'll do a simple 2D drawing to explain some concepts before switching to WebGL. Let our drawing be a diagonal line.

Rendering Context

The HTML is the same as the last example, except for this line:   

in which we've given an id to the canvas element so we can easily retrieve it in JavaScript. The CSS is exactly the same and a new JavaScript tab was added to perform the drawing.

Switch to the JS tab,

In the above example, the JavaScript code we've written is to be attached to the document head, meaning that it runs before the page finishes loading. But if so, we won't be able to draw to the canvas, which has yet to be created. That's why we defer running our code till after the page loads. To do this, we use window.addEventListener, specifying load as the event we want to listen to and our code as a function that runs when the event is triggered.

Moving on:

Remember the id we assigned to the canvas earlier in the HTML? Here is where it becomes useful. In the above line we retrieve the canvas element from the document using its id as a reference. From now on, things get more interesting,

In order to be able to do any drawing on the canvas, we first have to acquire a drawing context. A context in this sense is a helper object that exposes the required drawing API and ties it to the canvas element. This means that any subsequent usage of the API using this context will be performed on the canvas object in question.

In this particular case, we requested a 2d drawing context (CanvasRenderingContext2D) which allows us to use arbitrary 2D drawing functions. We could have requested a webgl, a webgl2 or a bitmaprenderer contexts instead, each of which would have exposed a different set of functions.

A canvas always has its context mode set to none initially. Then, by calling getContext, its mode changes permanently. No matter how many times you call getContext on a canvas, it won't change its mode after it has been initially set. Calling getContext again for the same API will return the same context object returned upon first usage. Calling getContext for a different API will return null.

Unfortunately, things can go wrong. In some particular cases, getContext may be unable to create a context and would fire an exception instead. While this is pretty rare nowadays, it's possible with 2d contexts. So instead of crashing if this happens, we encapsulated our code into a try-catch block:

This way, if an exception is thrown, we can catch it and display an error message, and then proceed gracefully to hit our heads against the wall. Or maybe display a static image of a diagonal line. While we could do that, it defies the goal of this tutorial!

Assuming we've successfully acquired a context, all there is left to do is draw the line:

The 2d context remembers the last path you constructed. Drawing a path doesn't automatically discard it from the context's memory. beginPath tells the context to forget any previous paths and start fresh. So yeah, in this case, we could have omitted this line altogether and it would have worked flawlessly, since there were no previous paths to begin with.

A path may consist of multiple sub-paths. moveTo starts a new sub-path at the required coordinates.

Creates a line segment from the last point on the sub-path to (30, 30). This means a diagonal line from the upper-left corner of the canvas (0, 0) to its bottom-right corner (30, 30).

Creating a path is one thing; drawing it is another. stroke tells the context to draw all the sub-paths in its memory.

beginPath, moveTo, lineTo, and stroke are available only because we requested a 2d context. If, for example, we requested a webgl context, these functions wouldn't have been available.

Note: in the above editor, the JavaScript code is attached to the document automatically. When making your own files, you'll have to link to the JavaScript file in your HTML file like this:

You should put it in the head tag.

This concludes our line drawing tutorial! But somehow, I'm not satisfied with this tiny canvas. We can do bigger than this!

Canvas Sizing

We shall add a few rules to our CSS to make the canvas fill the entire page. The new CSS code is going to look like this:

Let's take it apart:

The html and body elements are treated like block elements; they consume the entire available width. However, they expand vertically just enough to wrap their contents. In other words, their heights depend on their children's heights. Setting one of their children's heights to a percentage of their height will cause a dependency loop. So, unless we explicitly assign values to their heights, we wouldn't be able to set the children heights relative to them.

Since we want the canvas to fill the entire page (set its height to 100% of its parent), we set their heights to 100% (of the page height).

Browsers have basic style sheets that give a default style to any document they render. It's called the user-agent stylesheets. The styles in these sheets depend on the browser in question. Sometimes they can even be adjusted by the user.

The body element usually has a default margin in the user-agent stylesheets. We want the canvas to fill the entire page, so we set its margins to 0.

Unlike block elements, inline elements are elements that can be treated like text on a regular line. They can have elements before or after them on the same line, and they have an empty space below them whose size depends on the font and font size in use. We don't want any empty space below our canvas, so we just set its display mode to block.

As planned, we set the canvas dimensions to 100% of the page width and height.

We already explained that before, didn't we?!

Behold the result of our changes...

...

...

No, we didn't do anything wrong! This is totally normal behavior. Remember the dimensions we gave to the canvas in the HTML tag?

Now we've gone and given the canvas other dimensions in the CSS:

Turns out that the dimensions we set in the HTML tag control the intrinsic dimensions of the canvas. The canvas is more or less a bitmap container. The bitmap dimensions are independent on how the canvas is going to be displayed in its final position and dimensions in the page. What defines these are the extrinsic dimensions, those we set in the CSS.

As we can see, our tiny 30*30 bitmap has been stretched to fill the entire canvas. This is controlled by the CSS object-fit property, which defaults to fill. There are other modes that, for example, clip instead of scale, but since fill won't get into our way (actually it can be useful), we'll just leave it be. If you are planning to support Internet Explorer or Edge, then you can't do anything about it anyway. At the time of writing this article, they don't support object-fit at all.

However, be aware that how the browser scales the content is still a matter of debate. The CSS property image-rendering was proposed to handle this, but it's still experimental (if supported at all), and it doesn't dictate certain scaling algorithms. Not just that, the browser can choose to neglect it entirely since it's just a hint. What this means is that, for the time being, different browsers will use different scaling algorithms to scale your bitmap. Some of these have really terrible artifacts, so don't scale too much.

Whether we are drawing using a 2d context or other types of contexts (like webgl), the canvas behaves almost the same. If we want our small bitmap to fill the entire canvas and we don't like stretching, then we should watch for the canvas size changes and adjust the bitmap dimensions accordingly. Let's do that now,

Looking at the changes we made, we've added these two lines to the JavaScript:

Yeah, when using 2d contexts, setting the internal bitmap dimensions to the canvas dimensions is that easy! The canvas width and height are monitored, and when any of them is written to (even if it's the same value):

  • The current bitmap is destroyed.
  • A new one with the new dimensions is created.
  • The new bitmap is initialized with the default value (transparent black).
  • Any associated context is cleared back to its initial state and is reinitialized with the newly specified coordinate space dimensions.

Notice that, to set both the width and height, the above steps are carried out twice! Once when changing width and the other when changing height. No, there is no other way to do it, not that I know of.

We've also extended our short line to become the new diagonal,

instead of: 

Since we no longer use the original 30*30 dimensions, they are no longer needed in the HTML:

We could have left them initialized to very small values (like 1*1) to save the overhead of creating a bitmap using the relatively large default dimensions (300*150), initializing it, deleting it, and then creating a new one with the correct size we set in JavaScript.

...

on second thought, let's just do that!

Nobody should ever notice the difference, but I can't bear the guilt!

CSS Pixel vs. Physical Pixel

I would have loved to say that's it, but it's not! offsetWidth and offsetHeight are specified in CSS pixels. 

Here's the catch. CSS pixels are not physical pixels. They are density-independent pixels. Depending on your device's physical pixels density (and your browser), one CSS pixel may correspond to one or more physical pixels.

Putting it blatantly, if you have a Full-HD 5-inch smartphone, then offsetWidth*offsetHeight would be 640*360 instead of 1920*1080. Sure, it fills the screen, but since the internal dimensions are set to 640*360, the result is a stretched bitmap that doesn't make full use of the device's high resolution. To fix this, we take into account the devicePixelRatio:

devicePixelRatio is the ratio of the CSS pixel to the physical pixel. In other words, how many physical pixels a single CSS pixel represents.

window.devicePixelRatio is well supported in most modern browsers, but just in case it is undefined, we fall back to the default value of 1.0.

By multiplying the CSS dimensions with the pixel ratio, we are back to the physical dimensions. Now our internal bitmap is exactly the same size as the canvas and no stretching will occur.

If your devicePixelRatio is 1 then there won't be any difference. However, for any other value, the difference is significant.

Responding to Size Changes

That's not all there is to handling canvas sizing. Since we've specified our CSS dimensions relative to the page size, changes in the page size do affect us. If we are running on a desktop browser, the user may resize the window manually. If we are running on a mobile device, we are subject to orientation changes. Not mentioning that we may be running inside an iframe that changes its size arbitrarily. To keep our internal bitmap sized correctly at all times, we have to watch for changes in the page (window) size,

We've moved our bitmap resizing code:

To a separate function, adjustCanvasBitmapSize:

with a little modification. Since we know how expensive assigning values to width or height is, it would be irresponsible to do so needlessly. Now we only set width and height when they actually change.

Since our function accesses our canvas, we'll declare it where it can see it. Initially, it was declared in this line:

This makes it local to our anonymous function. We could have just removed the var part and it would have become global (or more specifically, a property of the global object, which can be accessed through window):

However, I strongly advise against implicit declaration. If you always declare your variables, you'll avoid lots of confusion. So instead, I'm going to declare it outside all functions:

This also makes it a property of the global object (with a little difference that doesn't really bother us). There are other ways of making a global variable—check them out in this StackOverflow thread

Oh, and I have sneaked context up there as well! This will prove useful later.

Now, let's hook our function to the window resize event:

From now on, whenever the window size is changed, adjustCanvasBitmapSize is called. But since the window size event is not thrown upon initial loading, our bitmap will still be 1*1. Therefore, we have to call adjustCanvasBitmapSize once by ourselves.

This pretty much takes care of it... except that when you resize the window, the line disappears! Try it in this demo.

Luckily, this is to be expected. Remember the steps carried on when the bitmap is resized? One of them was to initialize it to transparent black. This is what happened here. The bitmap was overwritten with transparent black, and now the canvas green background shines through. This happens because we only draw our line once at the beginning. When the resize event takes place, the contents are cleared and not redrawn. Fixing this should be easy. Let's move drawing our line to a separate function:

and call this function from within adjustCanvasBitmapSize:

However, this way our scene will be redrawn whenever adjustCanvasBitmapSize is called, even if no change in dimensions took place. To handle this, we'll add a simple check:

Check out the final result:

Try resizing it here.

Throttling Resize Events

So far we are doing great! Yet, resizing and redrawing everything can easily become very expensive when your canvas is fairly large and/or when the scene is complicated. Moreover, resizing the window with the mouse can trigger resizing events at a high rate. That's why we'll throttle it. Instead of:

we'll use:

First,

instead of directly calling adjustCanvasBitmapSize when the resize event is fired, we used a function expression to define the desired behavior. Unlike the function we used earlier for the load event, this function is a named function. Giving a name to the function allows to easily refer to it from within the function itself.

Just like other objects, properties can be added to function objects. Initially, timeoutId is undefined, thus, this statement is not executed. Be careful though when using undefined and null in logical expressions, because they can be tricky. Read more about them in the ECMAScript Language Specification.

Later, timeoutId will hold the timeoutID of an adjustCanvasBitmapSize timeout:

This delays calling adjustCanvasBitmapSize for 600 milliseconds after the event is fired. But it doesn't prevent the event from firing. If it isn't fired again within these 600 milliseconds, then adjustCanvasBitmapSize is executed and the bitmap is resized. Otherwise, clearTimeout cancels the scheduled adjustCanvasBitmapSize and setTimeout schedules another one 600 milliseconds in the future. The result is, as long as the user is still resizing the window, adjustCanvasBitmapSize is not called. When the user stops or pauses for a while, it is called. Go ahead, try it:

Err... I mean, here.

Why 600 milliseconds? I think it's not too fast and not too slow, but more than anything else, it works well with entering/leaving fullscreen animations, which is out of the scope of this tutorial.

This concludes our tutorial for today! We've covered all the canvas-specific code we need to set up our canvas. Next time—if Allah wills—we'll cover the WebGL-specific code and actually run the shader. Till then, thanks for reading!

References

Viewing all 728 articles
Browse latest View live