collinhover / impactplusplus

Impact++ is a collection of additions to ImpactJS with full featured physics, dynamic lighting, UI, abilities, and more.
http://collinhover.github.com/impactplusplus
MIT License
276 stars 59 forks source link

Basic examples on how to use impact++ #123

Open Pattentrick opened 10 years ago

Pattentrick commented 10 years ago

Hi @ everyone who is interested in ++,

@collinhover and I just had a small discussion about how ++ lacks some kind of basic examples for certain features. I just finished my first game with ++ a while ago, and although I felt in love with ++, I also had some problems figuring out how to exactly use it.

Yes there are the detailed docs, but they are more a reference to how the methods behind these features are working. And yes, there is the awesome SUPERCOLLIDER demo, but even @collinhover stated, that he realized that the demo is to big and that it is a confusing example for devs that have not used ++ before.

So the idea now is, to add examples on how to use some single features of ++ on the main page of the project, as well as in the GitHub readme. So ++ gets more accessible for new devs.

Here are some topics that we think, are worth explaining first:

But this is open to suggestions! So if anyone out there thinks, that something deserves some specific explanation for beginners, please post your suggestion here.

Also I pretty much volunteered myself on doing these examples, since I came up with this topic. But I would be more than happy, if another ++ dev is willing to add some examples on his favourite ++ feature as well.

@collinhover I am not sure how to exactly write an example in terms of length and style. So I thought I just go for it, and post it here, so we could discuss about that in public. Like this we could maybe develop some kind of “guideline”, in case some other devs want to participate in this.

Because I had some major trouble with pathfinding as beginner, I think I should start with that first!

Pattentrick commented 10 years ago

Pathfinding

So you want to do pathfinding, eh? Okay, but before we start we should cover some basics. First of, pathfinding works best if the entity is <= 3x the tilesize. Also, if you are using a pathfinding map, it must match the tilesize of your collision map. You don't have to require the pathfinding module manually. If you are using an entity that extends a character abstractity, like creatures or the player, pathfinding is already built in.

The moveTo method

To use pathfinding, just call the moveTo method on the entity, which should move it to another position or entity, like this:

javascript this.moveTo({ x: 200, y: 10 }, { avoidEntities: false });



The `moveTo` method expects two object literals as parameters. The first one tells the entity where to go, based on x and y coordinates. You could also use a reference to another entity as destination, instead of x and y coordinates, if you want to. The second one is optional and allows us to declare some settings for pathfinding. In the example above I decided to avoid other entities. 

##### Pathfinding maps

But what if your entity should avoid certain tiles, or prefer some others? For that case there are pathfinding maps. Open the Weltmeister level editor and add a new layer called 'pathfinding' to your level. As stated before, make sure that it has the same tilesize as the collision map.

![pathfindinglayer](https://f.cloud.github.com/assets/1792087/2080026/4d27c072-8dd1-11e3-8eb9-044b05cbfc86.png)

There are some tilesets in the media folder that came with impact++ called something like “pathfindingtiles_plusplus_8”. The number at the end of the file name represents the tilesize. So if the tilesize of your collison map is 8, select “pathfindingtiles_plusplus_8” for example.  Once you selected the pathfinding tileset and you clicked on the “Apply Changes” button, hitting space will now bring up your new pathfinding tiles. You are now ready to paint some awesome pathfinding tiles!

![tiles](https://f.cloud.github.com/assets/1792087/2080035/7afb4b72-8dd1-11e3-8435-aef0b97464bf.png)

The idea behind those tiles is rather simple. The colours represent how likely your entity will use a tile, where light green ones are the most preferred and the red one will be avoided.

That's it! As complicated as pathfinding sounds, it's just about calling the `moveTo` method and painting some pathfinding tiles to your pathfinding map. Impact ++ will take care of the rest.

##### Learn more!

The moveTo method and its pathfinding settings:
http://collinhover.github.io/impactplusplus/ig.Character.html#moveTo

@collinhover I am not sure if this is too long, so I skipped explaining the pathfinding settings in detail. Should I explain this too, or can we expect that a beginner will look at the ++ source code at that point?
collinhover commented 10 years ago

You're awesome @Pattentrick =)

Pathfinding tutorial looks great, and I don't think it is necessary to talk about all the settings as you can find that in the docs for the moveTo method. We probably want to end each post with a section called "Learn More" and link to things in the docs such as: http://collinhover.github.io/impactplusplus/ig.Character.html#moveTo.

When we have time I'd like to add images as well, but for now explanation + code is perfect.

collinhover commented 10 years ago

Getting Started

Welcome to Impact++! Our goal in this tutorial is to get you up and running as fast as possible, without wasting your time whether you're new to ImpactJS or a long time user. Let's break this down into a step-by-step:

1. The HTML file

We'll assume you're starting simple, so make sure you have an index.html file in your game's root directory. In this file, you'll need the basic HTML code for any page (head, title, css, body), as well as two additional pieces: the canvas and the core javascript files for ImpactJS and your game:

<!doctype html><html>
<head>
    <title>My Impact++ Game</title>
    <style type="text/css">
        html,body { background-color: #111111; color: #fff; font-family: helvetica, arial, sans-serif; margin: 0; padding: 0; font-size: 12pt; }
        #canvas { position: absolute; left: 0; right: 0; top: 0; bottom: 0; margin: auto; }
    </style>
</head>
<body>
    // all rendering goes into this canvas
    <canvas id="canvas"></canvas>
    // you should already have the impact.js file
    <script type="text/javascript" src="lib/impact/impact.js"></script>
    // you may need to create the main.js file
    <script type="text/javascript" src="lib/game/main.js"></script>
</body>
<html>
2. The main.js file and the main module

Open your main.js file, and setup the basics of a module (this assumes your main.js is blank):

ig.module('game.main').requires('plusplus.core.plusplus').defines(function () {});

The above is calling ig.module to create a new module in the "game" folder with a name of "main", then telling that module to require another module in the "plusplus/core" folder with a name of "plusplus", and finally defining a function to be executed when all requirements are loaded.

3. Create a custom game class

Inside the defined function for our main module we'll add the code to make a custom game class:

ig.module('game.main').requires('plusplus.core.plusplus').defines(function () {
     var myGameClass = ig.GameExtended.extend({ /* game settings go here */ });
});

This creates a new game class for your game and assigns it to the myGameClass variable. ig.GameExtended is a layer Impact++ adds on top of ImpactJS's ig.Game, and it will coordinate all of your main game logic such as updates and rendering. Remember, you can always get a reference to the currently running game using ig.game (note the lowercase).

4. Starting a blank game
ig.module('game.main').requires('plusplus.core.plusplus').defines(function () {
    var myGameClass = ig.GameExtended.extend({ /* game settings go here */ });
    ig.main( '#canvas', myGameClass, 60, 320, 240, 1, ig.LoaderExtended );
});

The new line above tells ImpactJS to start a new game that will draw into the HTML element with an id of "canvas", using myGameClass to control the game, to run at 60 fps, to have a size of 320 x 240 and a scale of 1, and to use the Impact++ customizable loader. Remember, Impact++ can scale dynamically based on the screen size and can be resolution independent (see step 8 on config).

5. Structure

Before you can add anything to your game, you'll need media such as images, sprite sheets, and sound files. ImpactJS has a strong opinion on the organization of your project, and Impact++ has been built with the same opinions in mind. Your game directory should look something like this:

index.html
lib/
    game/
        main.js
        entities/
            (your game entities)
        levels/
            (your game levels)
    impact/ 
        (ImpactJS engine files)
    plusplus/ 
        (Impact++ files)
    weltmeister/ 
        (ImpactJS and Impact++ editor files)
media/ 
    (images, sprite sheets, sounds)
6. Loading a level

Making levels with Impact++ is no different than with ImpactJS, so go ahead and make a level using the Weltmeister editor, called "test". While you're working with the editor, don't forget to copy the lib/weltmeister/ from your Impact++ download into your project's lib/weltmeister directory. Now, let's add your test level to the game:

ig.module('game.main')
.requires(
    'plusplus.core.plusplus',
    'game.levels.test'
)
.defines(function () {
    var myGameClass = ig.GameExtended.extend({
        init: function () {
            this.parent();
            this.loadLevel(ig.global.LevelTest);
        }
    });
    ig.main( '#canvas', myGameClass, 60, 320, 240, 1, ig.LoaderExtended );
});
7. Creating a player character

We'll need a player character so we can explore our test level. In the game's entities folder, located at lib/game/entities/, create a new file called player.js. To create the most basic of player characters, place the following code into the new file:

ig.module( 'game.entities.player' )
.requires(
    'plusplus.abstractities.player'
)
.defines(function () {
    ig.EntityPlayer = ig.global.EntityPlayer = ig.Player.extend({
        animSheet: new ig.AnimationSheet( "media/player.png", 32, 32),
        animInit: "idleX",
        animSettings: {
            idleX: { sequence: [0], frameTime: 0.1 }
        }
    });
});

The idea here is to create a new entity, ig.EntityPlayer, that extends Impact++'s player abstract which has all sorts of built in functionality. Next, open up / refresh the level editor, Weltmeister, and add the player entity to your test level's entities layer. Once your restart your game, Impact++ will hook the player entity automatically and you should be able to move, jump, and climb all around the level. You can add animations to an entity the ImpactJS way, or you can add them through the animSettings object by following the format of the "idle" animation example above. If you need a test player sprite sheet, check out the Run N' Jump or SUPERCOLLIDER example media folders.

Remember, Impact++ expects animations in a "name" + "direction" format, and entities that extend the ig.Character abstract, such as the player abstract above, expect specific animation names for various action. For example, when moving the player entity will automatically try to play "moveX" and "moveY" if we can flip/mirror on the x-axis and y-axis, otherwise it will try to play "moveLeft" or "moveRight" and "moveUp" or "moveDown", if we cannot flip on the x-axis and y-axis. The full list of automatic animation can be found in the docs for ig.Character

8. The configuration files

One last optional thing we can do is fiddle with settings. In the lib/plusplus/core folder, you'll find a config.js file, and in the lib/plusplus/ folder, you'll find a config-user.js file. The config file has a huge list of settings for almost every option in Impact++, and any of those settings can be overwritten by the user config file. For example, let's have Impact++ to do some heavy lifting for us when it comes to resizing the screen. Place the following into your config-user.js file, inside the module definition:

ig.CONFIG_USER = {
    // make the game fullscreen!
    GAME_WIDTH_PCT: 1,
    GAME_HEIGHT_PCT: 1,
    // dynamic scaling based on dimensions in view (resolution independence)
    GAME_WIDTH_VIEW: 320,
    GAME_HEIGHT_VIEW: 240
};
10. Learn More!

Player Manager: http://collinhover.github.io/impactplusplus/ig.PlayerManager.html Player Abstract: http://collinhover.github.io/impactplusplus/ig.Player.html Character Abstract: http://collinhover.github.io/impactplusplus/ig.Character.html

Pattentrick commented 10 years ago

Thank you @collinhover :D

I agree with you on adding a "Learn More" section to the tutorials. Good idea! I will edit the text above to include that. Also i may do a picture for selecting the pathfinding tiles/creating a pathfinding map later on.

You did a great start with your 10 step tutorial on how to setup a proper ++ project. Nice one, looks awesome so far! By the way, there is a little typo at step 4. In the code it says 320 x 250 and in the text 320 x 240.

Pattentrick commented 10 years ago

Your tutorial is like gold for beginners. Excellent!

collinhover commented 10 years ago

Images look good in the pathfinding tutorial. I'll add these to the docs site as soon as I can, and probably merge the current dev into master as r7 while I'm at it.

Pattentrick commented 10 years ago

Glad that you liked the images. I am hoping forward to seeing the new docs online, but don't stress yourself ;-)

The next tutorial i will do is about conversations.

Pattentrick commented 10 years ago

Conversations

Wouldn't it be neat, if all your entitys could have conversations with each other? Or if your hero could start an inspiring monologue before confronting the final boss? Or having something like a narration similar in style to a comic book? That sure would be awesome, but it sounds like lots of extra programming work, right?

Good news, everyone! Impact++ has this feature already built in!

conversation1

Doing it with Weltmeister

Hit space while you are on the entities layer and select the conversation entity. Drag it to your level and change the height and width of it if needed. The conversation entity extends the trigger entity. So by default it will get triggered once it collides with the player. But you can modify it to check against characters and other certain types as well.

Conversations are build around the idea of steps. Each step is a text bubble that will appear above the speaker. To start with a basic conversation, add the following key value pairs to your conversation entity via Weltmeister:

javascript steps.1.name: player steps.1.text: Hi there!


If you collide now with the conversation entity, your player should say “Hi there!”. To include another entity in this conversation, just add another step to your conversation entity and mention the name of the entity you want include there:

``` javascript```
steps.1.name: player
steps.1.text: Hi there!
steps.2.name: rock
steps.2.text: Sorry mate, rocks can't speak.

By default conversation will auto advance to the next step after a given time. This time can be edited on the conversation entity like this:

durationPerLetter: 0.1

con2

If you define an advancing action to continue the conversation, you could also pause the game during a step. So conversations will just advance, if the player does hit the x key for example.

The conversation entity will also trigger talking and listening animations, on your participating entities, if you have defined them. The default name for those animations are listen and talk. Make sure you have specified them on your entity animSettings, if you want to use this feature.

javascript animSettings: { idle: { frameTime: 1, sequence: [0] }, listen: { frameTime: 1, sequence: [3,4,5] }, talk: { frameTime: 1, sequence: [6,7,8] } }


You could also apply a certain animation just for one step, which could be rather useful.

`steps.2.animNameTalk: lookAngry`

However, this is totally optional. You don't have to define extra animations to use the conversation entity.

Also the text bubble itself is, as everything in Impact++, highly customizable and has some more options to offer. You can edit the padding, change the font file or choose a different background colour to just name a few. 

Don't want a conversation and rather need a comic book narration? Just use the narrative entity that came with Impact++. They narrative entity extends the conversation entity, because of that the usage is almost the same. But you don't have to define a speaker.

Confused? Take a look at this example:

``` javascript```
steps.1.text: It was dangerous to go alone.
steps.2.text: So our hero stole a wooden sword from an old man.
Doing it programmatically

But what if you want to spawn a conversation independent from a collision. For example, when your player added an item to his inventory. In that case you could do it like this:

javascript // Kill existing conversation entities before // spawning new ones to avoid memory leaks

if( ig.game.getEntitiesByClass(ig.EntityConversation)[0] ){ ig.game.getEntitiesByClass(ig.EntityConversation)[0].kill(); }

var textbubble = ig.game.spawnEntity(ig.EntityConversation, 0, 0);

textbubble.addStep( 'Hi there!', 'player', 1); textbubble.addStep( 'Sorry mate, rocks can't speak.', 'rock', 2);

textbubble.activate();



Make sure to remove all other running conversations, before spawning a new one, to avoid memory leaks.

##### Learn More!

Conversation entity: http://collinhover.github.io/impactplusplus/ig.EntityConversation.html
Narrative entity: http://collinhover.github.io/impactplusplus/ig.EntityNarrative.html
Trigger entity: http://collinhover.github.io/impactplusplus/ig.EntityTrigger.html
Config file: http://collinhover.github.io/impactplusplus/ig.CONFIG.html
Pattentrick commented 10 years ago

@collinhover I made the conversation tutorial. Feel free to correct me for using some kind of awkward english, or for explaining something wrong. I did not go to deep into details, because i assumed that a dev will look at the docs for further information. I hope that is ok.

aroth commented 10 years ago

Just wanted to chime in and say that you guys rock. This effort is much needed and will help out so many people. Once my life gets back on track I'd love to help out. Impact++ caused me to bang my head on the desk for a couple of weeks until I finally got it. Collin was incredibly patient and helpful through the entire process -- an absolute stand-up guy. Thank you both.

On Wed, Feb 5, 2014 at 10:20 PM, Pattentrick notifications@github.comwrote:

@collinhover https://github.com/collinhover I made the conversation tutorial. Feel free to correct me for using some kind of awkward english, or for explaining something wrong. I did not go to deep into details, because i assumed that a dev will look at the docs for further information. I hope that is ok.

Reply to this email directly or view it on GitHubhttps://github.com/collinhover/impactplusplus/issues/123#issuecomment-34288582 .

collinhover commented 10 years ago

@Pattentrick looks great. Only one suggestion: wrap the code you're using in all the examples, such as myConversationEntity.durationPerLetter = 0.1

@aroth you're not alone in letting your head meet the desk thanks to impact++ :-)

Pattentrick commented 10 years ago

@collinhover I wrapped all examples in code blocks. I also added another example on how to use specific animations for talking/listening and a sentence here and there. I also appended a link to the trigger entity at the learn more section. Correct me if i have explained something wrong. I still consider myself a beginner in terms of ++ ;-)

Making another tutorial on particles and dynamic light would be cool. Especially because i did not use those features before and could learn about them this way. However i think more on characters, the player and creatures is more important now. Because that are the modules that a new user will encounter first when making a game. What do you think?

@aroth Glad to hear that you appreciate this effort. It would be more than awesome if you want to contribute to this! But don't stress yourself. I do know what an unrewarding bitch life is sometimes, and fixing that has of course a higher priority :D

Let us know, if you feel that there is a certain feature which deserves more explanation.

collinhover commented 10 years ago

@Pattentrick setting up a player with a custom ability and input is high on my list, as are the basics of creatures and characters. Lighting is a great one also, and Spawners should probably replace particles.

collinhover commented 10 years ago

Player

In this tutorial, we're going to setup a simple side-scrolling player character, make a laser gun ability, and attach some input handlers so we can shoot some bad guys. You can extend this setup into a top-down game by flipping the TOP_DOWN config switch. Boom, headshot!

Prerequisites

We're assuming you've read at least the Getting Started tutorial and have a game with at least one level for testing purposes. You'll also need to grab the following media if you want to work through this with us:

  1. The player sprite sheet at examples/jumpnrun/media/player.png.
  2. The projectile sprite sheet at examples/jumpnrun/media/projectile.png. (these can both be found in the Impact++ repo).
The Player Character

Lets start with a player character. In your game's entities folder, located at lib/game/entities/, create a new file called player.js. To create the most basic of player characters, place the following code into the new file:

ig.module( 'game.entities.player' )
.requires(
    'plusplus.abstractities.player'
)
.defines(function () {
    ig.EntityPlayer = ig.global.EntityPlayer = ig.Player.extend({
        size: {x: 8, y: 14},
        offset: {x: 4, y: 2},
        animSheet: new ig.AnimationSheet( "media/player.png", 16, 16),
        animInit: "idleX",
        animSettings: {
            idleX: { sequence: [0], frameTime: 0.1 }
        }
    });
});

The idea here is to create a new entity, ig.EntityPlayer, that extends Impact++'s player abstract which has all sorts of built in functionality. We've set the sprite frame size to 16x16, set the player bounding box or collision box to 8x14, and offset the sprite frame slightly to account for the collision box's size.

Lets also add a few animations preemptively, which the player character will use automatically based on what they are doing at any given moment. Inside the animSettings property of your player character, add:

moveX: { sequence: [0, 1, 2, 3, 4, 5], frameTime: 0.07 },
jumpX: { sequence: [8, 9], frameTime: 0.1 },
fallX: { sequence: [6, 7], frameTime: 0.4 }
The Laser Beam

Before we can shoot anything, we need something to shoot out of something that does the shooting. Lets start with the thing we'll shoot, a laser beam. In your game's entities folder, located at lib/game/entities/, create a new file called laser.js and place the following code into the new file:

ig.module( 'game.entities.laser' )
.requires(
    'plusplus.abstractities.projectile'
)
.defines(function () {
    ig.EntityLaser = ig.global.EntityLaser = ig.Projectile.extend({
        collides: ig.EntityExtended.COLLIDES.LITE,
        size: {x: 4, y: 4},
        offset: {x: 2, y: 2},
        animSheet: new ig.AnimationSheet( "media/projectile.png', 8, 8),
        animInit: "idleX",
        animSettings: {
            moveX: { sequence: [0], frameTime: 1 },
            deathX: { sequence: [1,2,3,4,5], frameTime: 0.05 }
        }
    });
});

The idea here is to create a new entity, ig.EntityLaser, that extends Impact++'s projectile abstract which has all sorts of built in functionality. Similar to the player and character abstracts, the projectile can automatically play certain animations based on its state. Lets add a few more properties in the class definition to make use of these automatically handled states:

damage: 2, // lasers hurt
lifeDuration: 2, // lasers eventually fade (like a particle)
gravityFactor: 0, // lasers ignore gravity
friction: {x:0, y:0}, // lasers have no friction
bounciness: 0, // lasers don't bounce
collisionKills: true, // lasers stop if they hit a wall
The Laser Gun

To be fair, we won't actually make a laser gun. What we're going to do now is tap into the Impact++ abilities and use the shoot ability to create a character usable ability for our player character. In your game folder, located at lib/game/, add a new folder named abilities and inside it create a new file called laser-gun.js. Place the following code into the new file:

ig.module( 'game.abilities.laser-gun' )
.requires(
    'plusplus.abilities.ability-shoot',
    'game.entities.laser'
)
.defines(function () {
    ig.LaserGun = ig.AbilityShoot.extend({
        spawningEntity: ig.EntityLaser,
        offsetVelX: 200
    });
});

All we're doing here is extending the shoot ability to make a specific shooting ability that shoots lasers with a specific velocity in the direction our character is facing. Note that we're requiring the laser beam projectile and setting it as the spawningEntity (or thing we want to shoot out) of our laser gun ability.

Bringing it Together

Back to the player entity, we need to add a few things to hook the laser gun into place. Require the ability: 'game.abilities.laser-gun', and add the shooting animation to the animSettings: shootX: { sequence: [2], frameTime: 0.25 }. Next, create the ability and store it with the player:

initProperties: function() {
    this.parent();
    this.shoot = new ig.LaserGun(this);
    this.abilities.addDescendants([this.shoot]);
}

The initProperties method is part of the Impact++ entity init pattern. It is recommended to use initType or initProperties for any properties that will only be created once in an entity's existence, and resetCore or resetExtras for any properties that need to be reset each time an entity to added to the game.

Fourth, handle input to activate the ability:

handleInput: function() {
    this.parent();
    if (ig.input.pressed('shoot')) {
        this.shoot.activate({
            x: this.flip.x ? this.pos.x : this.pos.x + this.size.x,
            y: this.pos.y + this.size.y * 0.5
        });
    }
}

And finally, add the input to the game by opening your game's main file, located at lib/game/main.js. Here, we'll set it so that our game binds the "F" key to the "shoot" input, which our player is already waiting for:

inputStart: function () {
    this.parent();
    ig.input.bind(ig.KEY.F, 'shoot');
},
inputEnd: function () {
    this.parent();
    ig.input.unbind(ig.KEY.F, 'shoot');
}

Now you're all set to run n' jump n' blast!

Learn More!

Player: http://collinhover.github.io/impactplusplus/ig.Player.html Player Manager: http://collinhover.github.io/impactplusplus/ig.PlayerManager.html Ability Shoot: http://collinhover.github.io/impactplusplus/ig.AbilityShoot.html

Pattentrick commented 10 years ago

@collinhover great tutorial! I really liked the "boom headshoot style" ;-)

The information that are present in this tutorial are very useful. You did a great job on that. Learning about the shoot ability and projectiles is especially important for my upcoming shoot em up. You just avoided at least 2-3 issues being posted by me regarding that topic ;-)

I would like to do the lighting tutorial next! But i have to mention that i probably don't have time for that until sunday.

collinhover commented 10 years ago

@Pattentrick no rush, I'm having trouble keeping up with you :-)

Pattentrick commented 10 years ago

Dynamic Lights

One of the many awesome things that Impact++ has to offer, are dynamic lights that can be used right out of the box. You can cast static shadows which are based upon your collision map and dynamic ones for moving entities. You can change the colour of your light to a specific value, modify it's opacity, and use a pixel perfect rendering for your cone of light. You could even cast shadows that are specific to certain entity animations!

You don't know how to use all the cool stuff I just mentioned? Then this tutorial is for you. Let me enlighten you and shed some light on how this awesome feature of Impact++ works.

The Basics

Open a level with the Weltmeister level editor. Make sure that you are on the entities layer and hit space. A drop down should now be visible with your own entities and some that came with Impact++.

If you just see your own entities in that list, assure yourself that you copied the Impact++ config.js in your weltmeister folder. That file can be found in the Impact++ project folder under `lib\weltmeister\config.js``.

Select an entity called “Light” and drag it to your level. Looks a bit to small? You can easily scale it up in Weltmeister! Your light should now look like this:

lights1

You can change the colour of your light via it's RGB values. For example, like this you could make your light red:

r: 1
g: 0
b: 0

RGB values in Impact ++ are ranging from 0 to 1. In case you are wondering how you could express something like R: 198 with that notation, just divide your original value by 255. So R: 198 becomes 0,77 (198 / 255).

It is also possible to change the colour of your light dynamically, if you add the following property to your light entity:

dynamicColor: true

As with every entity you can change the alpha property of it, to fit the atmosphere of your game better.

alpha: 0.6

Did you notice the gradient of the light? Don't like it? You can easily disable it like this:

gradient: false

Also you can render your light in a retro pixel perfect style. Just add this to your light entity:

pixelperfect: true

But remember, pixel perfect scaling has a very high performance cost, so use it wisely. As well make sure to disable the gradient, or else pixel perfect scaling won't work

Static Shadows

That light we made is looking very neat, but as you all know, where there is light, there must be shadow. So let's add some! First, add the following to your light entity:

castsShadows: true

Your light is now almost ready to do some cool shadow casting. But to cast shadows, based upon your collision map, you have to modify the shapesPasses property of your game. Append this code to your game class in your main.js:

javascript // convert the collision map shapes // either or both can be removed shapesPasses: [ // for climbing // we ignore solids and one ways // to only retrieve climbable areas { ignoreSolids: true, ignoreOneWays: true }, // for lighting and shadows // we ignore climbables and the edge boundary { ignoreClimbable: true, // throw away the inner loop of the edge of the map discardBoundaryInner: true, // throw away the outer loop of the edge of the map retainBoundaryOuter: false } ]


Add some collision tiles and fancy graphics around your light. You should now see something like this:

![lights2](https://f.cloud.github.com/assets/1792087/2119863/7517a594-9190-11e3-8be2-1cedb5bdc4d5.png)

Pretty cool, eh? Static shadows based upon our collision map! But maybe you have already noticed that something is wrong with the picture above. Where is the shadow of the pretty young girl? 

##### Entities and Shadows

By default entities don't cast any shadows. But we can simply change this, by setting the opaque property of the entity which should cast shadows to true:

`opaque: true`

It is important to note that you should define opaque when you create that entity and not after. As Impact++ keeps a list of all opaque entities for performance reasons and this list changes only if an entity is removed or added to the game. 

But shadows are calculated once per level, so even if you have an opaque entity nothing will happen unless you define the following on your light:

`castsShadowsMovable: true`

`performance: movable`

Also make sure that the entity which should cast shadows is dynamic:

`performance: dynamic`

Your entity should now cast some awesome looking shadow!

![lights3](https://f.cloud.github.com/assets/1792087/2119870/da946448-9190-11e3-9459-79c0e4853066.png)

You can specify how much light will be blocked by opaque entities. Set the `diffuse` property to any value you like from 0 to 1:

`diffuse: 0.4`

Keep in mind that pixel perfect light has a very high performance cost, so you should avoid casting shadows on moving entities with your pixel perfect light. You will not get more than 2 – 5 FPS at best.

##### Animation Specific Shadows

On top of that you can enable animation specific shadow casting. This can be easily achieved by modifying the `animSettings` of your entity class:

``` javascript```
jumpX: {
    sequence: [16, 18, 19],
    frameTime: 0.05,
    // animation specific shadow casting!
    // i.e. when playing this animation
    // shadows will be cast using the base size
    // with these offsets
    // (also used in other animations)
    opaqueOffset: {
        left: 6,
        right: -6,
        top: 0,
        bottom: -5
    }
}

On your entity class you can also add a, non animation specific, general shadow casting setting:

javascript // general shadow casting // i.e. when playing any animation // shadows will be cast using the base size // with these offsets

opaqueOffset: { left: 6, right: -6, top: -1, bottom: 3 }



##### Learn More!

Light Entity: http://collinhover.github.io/impactplusplus/ig.EntityLight.html
shapesPasses property: http://collinhover.github.io/impactplusplus/ig.GameExtended.html#shapesPasses
Pattentrick commented 10 years ago

Hi @collinhover,

I just made the lighting tutorial. This was the first tutorial I did on a ++ feature that I did not use before. But everything I explained should work that way, since I did every step for myself to provide some pictures.

As always feel free to correct me if I explained something wrong or used some engrish.

I tend to use sometimes german sayings that don't make much sense in english. But I think I avoided that completely on this tutorial. For some funny examples on that see:

http://www.ithinkispider.com/

I would like to do a tutorial about the camera next in the upcoming week, because it is one of the bigger things featured on the project page and it can do some cool stuff (shakes, atmosphere, follow).

collinhover commented 10 years ago

@Pattentrick awesome job! I have no suggestions for this one, really well done. I actually had forgotten about the camera, good idea. Those German English sayings are bizarre, what is the story behind that?

Pattentrick commented 10 years ago

Glad you liked the tutorial :D

Because the german and the english syntax is quite similar, and some words sound a like, some germans tend to speak english like they would german, and just swap some words. That works most of the time, as you can see with my posts, but sometimes that approach fails hard. Especially with sayings.

For example the meaning of "unter aller Sau" is "very awful". So the correct sentence would be: "My english is very awful". But when i just swap the words and translate it literally it becomes: "My english is under all pig".

German politicans are famous for doing something like that. Angela Merkel said once: "Let the butter by the fishes". "Butter bei die Fische" is an saying that means something like "get to the point".

That webpage is a collection of those funny mistakes. But i think to really get the joke you need to understand both languages. So it must appear really bizarre indeed for a non german speaking person xD

My favorite is "you walk me animally on the cookie", which means something like "You really get on my nerves."

collinhover commented 10 years ago

That's actually pretty cool. I didn't realize German was similar in those ways.

Pattentrick commented 10 years ago

Camera

Impact++ has a built in camera with lots of awesome options for controlling the screen. In this tutorial we will learn how to use it for cool shake effects, following entities and for adding some atmosphere to your game. Lights, Camera, Action!

The Basics

You don't need to include or instance the camera for yourself. The camera gets automatically created for you after your game gets initialized. You can use the camera via the camera property of your game. For instance, like this in your game class:

this.camera

And like this from outside your game class:

ig.game.camera

That's all, no extra code needed!

Following Entities

The camera has a method called follow which, as you might have guessed, enables the camera to follow an entity. The follow method takes three parameters.

The first one is the entity that will be followed by the camera. If your are new to Impact++, please keep in mind that all entities have to extend the ig.EntityExtended class, or else the camera and many other features won't work. The second one determines if the camera should snap to an entity, instead of transitioning. And the last one defines if the camera should center on the entity or not.

Here is a short example:

javascript var bee = this.namedEntities["bee"];

// first parameter is the entity to follow // second parameter is snap (instead of transition) // third parameter is to center on entity

ig.game.camera.follow(bee, false, false);


By default the game will auto follow the player, if you don't set `AUTO_FOLLOW_PLAYER` to `false` at your `config-user.js` file located under `lib\plusplus\ config-user.js`. On auto follow the camera will center the player and snap to it. 

To prevent black borders, the camera will always try to stay inside the level. You don't like that? You can disable this if you set `KEEP_INSIDE_LEVEL` to false at your `config-user.js`.

You can also change the duration of the transition when switching entities that the camera is following. Take a look at `TRANSITION_DURATION` in your `config-user.js` if you want to change that.

##### It's a Trap!

The camera will center the entity in the middle of the screen every time it will move by default. You can add a lerp to this behaviour. This enables the camera to move slowly behind the following entity as long as the entity is moving. Setting the `LERP` to `0.025` in your `config-user.js` looks very smooth for example. Setting the lerp to `1` will disable it.

But in many games you don't want this kind of camera behaviour. Especially in games where there is lots of running and jumping, it can feel very annoying if the player is centred all the time. In this case  you should rather use a trap.

Imagine a trap as an invisible rectangle around your player. As long as the player moves inside that trap, the camera won't move. But as soon as the player steps outside that trap the camera will move again in the correspondent direction.

To set up a trap you should disable the centering behaviour of your camera first. Add this to your `config-user.js` file:

``` javascript```
CAMERA: {
    KEEP_CENTERED: false
}

You can define the dimensions of your trap via an absolute value, or as a percentage of the screen size. We will use percentages in this example:

javascript CAMERA: { KEEP_CENTERED: false, BOUNDS_TRAP_AS_PCT: true, BOUNDS_TRAP_PCT_MINX: -0.2, BOUNDS_TRAP_PCT_MINY: -0.3, BOUNDS_TRAP_PCT_MAXX: 0.2, BOUNDS_TRAP_PCT_MAXY: 0.3 }


##### Shake the Camera!

A really cool effect provides the camera with the `shake` method. It does exactly what you think it does. It shakes the camera! This is very useful for simulating explosions and earthquakes. And the usage is quite simple:

``` javascript```
ig.game.camera.shake(2,5);

The first Parameter defines how long the shake should take, and the second how strong the shake should be. For some extra action, you can define your own shake function as third parameter.

Adding some Atmosphere

You can easily create and overlays atmosphere on top of game world. This works very well with dynamic lighting.

Just call:

javascript ig.game.camera.addAtmosphere();


For example, you can define the fade duration, the color and the opacity of your atmosphere like this:

``` javascript```
// An atmosphere without a "fade in" which
// is slightly red and barely visible

ig.game.camera.addAtmosphere(0,{
    r: 0.1,
    g: 0,
    b: 0,
    alpha: 0.4
});

See the lightAmplification, the lightBaseOnly and the lightsCutout properties for more useful options regarding to atmosphere.

Trigger Entities

Impact++ has also three camera trigger entities built in, that you you can use together with the Weltmeister level editor. EntityCameraAtmosphere is a trigger that changes camera atmosphere. EntityCameraFollow causes the camera to follow each target defined in the targetSequence array of the trigger. And EntityCameraShake is a trigger that causes the camera to shake and simulate an earthquake or explosion.

Learn More!

Camera Class: http://collinhover.github.io/impactplusplus/ig.Camera.html Config File: http://collinhover.github.io/impactplusplus/ig.CONFIG.html Atmosphere Trigger: http://collinhover.github.io/impactplusplus/ig.EntityCameraAtmosphere.html Follow Trigger: http://collinhover.github.io/impactplusplus/ig.EntityCameraFollow.html Shake Trigger: http://collinhover.github.io/impactplusplus/ig.EntityCameraShake.html

Pattentrick commented 10 years ago

@collinhover Finished the camera tutorial. As always feel free to correct me if i used some engrish, or when i have explained something wrong. Getting some sleep now.

collinhover commented 10 years ago

@Pattentrick slow down man :-) so far so good!

Pattentrick commented 10 years ago

Suggestions for upcoming tutorials: creature abstract, UI elements, spawner abstract. And what about tweens? I just read about them and i have no idea how to use them.

@collinhover I want to do the tutorial on the creature abstract next, if that is ok for you. I should find some time for that in the upcoming week.

collinhover commented 10 years ago

@Pattentrick sounds good. The creature abstract is also quite close to the character abstract, due to pathfinding. It will be hard to cover it all, so I'd say just stick to the simple things. I'll see if I can do an overview of the character abstract to go along with your creature tutorial.

Pattentrick commented 10 years ago

@collinhover Ok, i'll try to keep it simple ;-)

Pattentrick commented 10 years ago

@collinhover I noticed that i wrote nothing about the Impact++ camera trigger entities in my camera tutorial. Because of that I appended a short section about that in the tutorial just a moment ago.

collinhover commented 10 years ago

Good catch!

Pattentrick commented 10 years ago

Creature

Oh you heard about the creature abstract, which provides some basic AI that you can use for your character entities, but you don't know how you should use it? Don't look any further, you have come to the right place! In this tutorial we well explain the basics of the creature abstract like attacking, wandering and fleeing, so you can make your very own creatures in no time!

Attack!

One of the core concepts behind the creature abstract is the idea to have prey and predators. A creature can automatically find, move to, and attack prey. You just need to supply it with one of the 4 prey finding options.

A creature can find prey by name:

javascript creaturePrey.name = "nameOfPrey"; creaturePredator.preyName = "nameOfPrey";


By class (this can also be the name of the class as string):

``` javascript```
creaturePrey = ig.game.spawnEntity(ig.EntityPreyClass);
creaturePredator.preyClass = ig.EntityPreyClass;

By a specific type:

javascript ig.utils.addType(ig.EntityExtended, creaturePrey, 'type', "TYPE_OF_PREY"); creaturePredator.preyType = ig.utils.getType(ig.EntityExtended, "TYPE_OF_PREY");


Or even by a group:

``` javascript```
ig.utils.addType(ig.EntityExtended, creaturePrey, 'group', "GROUP_OF_PREY", "GROUP");
creaturePredator.preyGroup = ig.utils.getType(ig.EntityExtended, "GROUP_OF_PREY", "GROUP");

These same 4 finding options also apply to finding a predator. But keep in mind that a creature will only try to flee, or run away, from a predator. Not from another prey. Normally a creature won't react to prey or predator until they are within a certain range. But you can easily modify that range:

creaturePredator.reactionDistance = 100;

On top of that you can also force the creature to have a line of sight to the prey or predator:

javascipt creaturePredator.needsLineOfSightPrey = true; creaturePrey.needsLineOfSightPredator = true;


Once a prey or predator is found, the creature will use pathfinding via the `moveTo` method of the character abstract to move around your level. You can  define your own settings for that pathfinding like this:

``` javascript```
creaturePredator.moveToPreySettings = {...};
creaturePrey.moveToPredatorSettings = {...};

One notable setting is the pathfinding search distance which, for best results, should match the reaction distance:

javascript creaturePredator.moveToPreySettings = { searchDistance: creaturePredator.reactionDistance };


For more pathfinding options see the `moveTo` method of the character abstract:

http://collinhover.github.io/impactplusplus/ig.Character.html#moveTo

While a predator is approaching its prey, it will call its `attack` method. By default this method will just do a distance check and returns `true` if it's near enough and stops the creature movement. Feel free to overwrite that method with your own attack game mechanics. 

##### Fly, you fools!

A creature will automatically flee if it notices a predator in its reaction range. For fleeing the creature will also use pathfinding as mentioned above. You can use the `moveToPredatorSettings` if you want to change the pathfinding behaviour on fleeing.

Don't like cowardly prey creatures? You can disable fleeing:

`canFlee: false;`

And don't forget that your prey needs to know about its predator for proper fleeing:

`predatorClass: "EntityWolf";`

##### Let's take a Walk

Creatures can wander around your level. Just set the wander properties to true:

``` javascript```
// wandering on the x axis
canWanderX: true;
// wandering on the y axis (in top down mode)
canWanderY: true;

Wandering also uses pathfinding. You can change the default settings for that via the moveToWanderSettings. Also you can define in percentage how often the creature should switch directions while wandering:

wanderSwitchChance: 0.004;
wanderSwitchChanceStopped: 0.010;

A creature can also wander around its tether. A spawned creature will use its spawner as tether, unless you set the name of another entity as its tether:

tetherName: "carpet";

When tether distance is <= 0, a creature can go as far as it wants:

tetherDistance = 0;

When tether distance is > 0, a creature will only go up to that distance:

tetherDistance = 100;

Unless it can break its tether to follow prey or flee from a predator:

canBreakTether = true;

Learn More!

Creature Class: http://collinhover.github.io/impactplusplus/ig.Creature.html Character Class: http://collinhover.github.io/impactplusplus/ig.Character.html

Pattentrick commented 10 years ago

@collinhover I made the creature tutorial. It's rather short and not as much detailed as my other tutorials, because we agreed to keep it simple this time. That is also the reason why most of the content is based upon your code comments.

Feel free to correct me if I used some engrish or I explained something wrong.

danielmahon commented 10 years ago

An input tutorial would be helpful as I am digging through how to handle mouse/click interactions and such now.

Pattentrick commented 10 years ago

@danielmahon Sounds good to me. I would limit the tutorial to ++ specific input topics, like the handleInput method from the character/player class, or multi touch and gestures. In addition to that a short note about the playerManager would be also cool. As far as i am concerned this one is on the list for upcoming tutorials.

collinhover commented 10 years ago

I could be wrong, but mouse input should be identical to in impactJS. All that ++ adds is some basic touch and multi touch stuff. As far as interaction through clicking, that is something impactJS does not have and ++ adds.

collinhover commented 10 years ago

Character

Characters are Impact++'s way of separating "living" things from all other entities. Our definition of living is pretty loose, but the basic idea is that if an entity needs to either pathfind, jump, climb, use abilities, automatically animate, or regenerate, then you may want that entity to extend the ig.Character abstract.

Movement and Performance

Do you want your characters to move? Of course you do! When we're talking about very basic movement, with no extra features and no pathfinding to another entity/point, you'll need to do two things: set the performance level and use the move methods.

First, a couple words on performance. An entity's performance property controls how it behaves with regard to movement and physics in the update phase of your game. Think of it like a cascade, where the three levels are static, movable, and dynamic. Static entities skip all movement code in the update loop and only update their animations. Movable entities can move in addition to everything static entities do, but they ignore physics forces such as gravity and don't collide with the collision map. Dynamic entities have full collisions and physics forces in addition to everything movable entities do. The default performance for ig.EntityExtended is static, while the default for ig.Character is movable, and the default for ig.Player is dynamic.

So, if we need a character that can move itself, the character's performance property should be ig.EntityExtended.PERFORMANCE.DYNAMIC. Then, to get the character moving, just call its moveLeft, moveRight, moveUp, and moveDown functions. Note that if you want your character to fly, you should set its gravityFactor to 0, otherwise moveUp and moveDown won't do much of anything.

Pathfinding

Quite often, basic movement is fine, but there are many instances where it just won't cut it. For that, we can bring in pathfinding. We won't cover it here, because @Pattentrick has written an awesome tutorial on it already, but know two things: first, all characters have pathfinding built in, and second, if you need characters with AI such as attacking and fleeing, then you should take a look at the Creature abstract (which also has a great tutorial of its by @Pattentrick).

Colliding

Collisions? Sign me up! Collisions work the same as in ImpactJS, just set the collides property of the entity to one of the options other than ig.EntityExtended.COLLIDES.NEVER. Your options are:

(note it is possible to get fixed entities to collide, but it is disabled by default by ig.CONFIG.COLLISION.ALLOW_FIXED)

Jumping

If you want your character to jump like mario, make sure you've set its canJump property to true, and then call its jump method to get hopping. Check out the jumpSteps, jumpForce, and jumpControl for ways to change the jump itself.

Climbing

Climbing is another integral part of platformers, and it works exactly like jumping. Make sure you've set your character's canClimb property to true, and then call its climbUp or climbDown method. Check out the climbingControl for one way to change the speed of climbing.

States and Animation

Characters looks for a set of animations to use as the current animation based on various properties. You can think of this as automatic animation handling. The set itself is controlled by the animsExpected property, and is set to [ "idle", "move", "stairs", "climb", "jump", "fall" ] by default. You can see how it covers all of the basic states the character may encounter, and then you can expand from there. If you don't like automatic animation handling, you can turn it off by setting the animAutomatic property to false.

Now, before you go and add a bunch of extra expected animations, you'll also need to override the animation switching method. The actual animation switching is done in the updateCurrentAnim method. As an example, when the character is moving, this method will set the animation to move, something like this:

if ( character.moving ) {
     character.currentAnim = character.anims[ character.getDirectionalAnimName( "move" ) ];
}

Note here the directional animation name, found by getDirectionalAnimName. Animations in Impact++ are directional and based on flip and facing. So, for example, if a character has both canFlipX and canFlipY set to true, your character should have "moveX" and "moveY" animations. On the other hand, if an entity cannot flip X and Y, then the character should have animations for up, down, left, and right, i.e. "moveUp", "moveDown", "moveLeft", "moveRight".

Regeneration

Characters have both health and energy stats, and also have options to regenerate them over time. By default, the regen property is set to false, so you'll need to enable it if you want any regeneration to happen. From there, you can set the regenRateHealth to control how much the character regenerates per tick, set the regenDelay to control how much time passes between each tick, and set the regenAsPctHealth if you want the character to regenerate a percentage of their health instead of a fixed value. The energy regeneration options are all the same, except the word "Energy" replaces the word "Health" in the above properties.

Good luck with characters!

Learn More!

Character class: http://collinhover.github.io/impactplusplus/ig.Character.html Player class: http://collinhover.github.io/impactplusplus/ig.Player.html

collinhover commented 10 years ago

Okay, the character tutorial still needs images but the text is in place. Thanks so much for all the tutorials so far @Pattentrick, you're a beast.

Pattentrick commented 10 years ago

You're welcome @collinhover :D

The character tutorial looks great! This will be so extreme useful for beginners. Also for intermediate users like me, who just want to look up something quickly. I am really happy about the quality of the tutorials we made so far. Great job!

I will do the next tutorial about UI elements. That is kind of a big topic (13 classes), so I need some extra time for that. I don't think that i have enough time to do the UI tutorial this week, but i should be able to do it in the upcoming week.

aroth commented 10 years ago

I'm very inspired by both of you. I hope I can find a way to help.

I've had to learn the hard way across all of these elements of Impact++. @Pattentrick, if I can find a moment, I may send you some of my notes on working with the UI. Your tutorials have been have been superb so far, so I hope I can give back in some way.

Adam

On Wed, Feb 19, 2014 at 8:05 AM, Pattentrick notifications@github.comwrote:

You're welcome @collinhover https://github.com/collinhover :D

The character tutorial looks great! This will be so extreme useful for beginners. Also for intermediate users like me, who just want to look up something quickly. I am really happy about the quality of the tutorials we made so far. Great job!

I will do the next tutorial about UI elements. That is kind of a big topic (13 classes), so I need some extra time for that. I don't think that i have enough time to do the UI tutorial this week, but i should be able to do it in the upcoming week.

Reply to this email directly or view it on GitHubhttps://github.com/collinhover/impactplusplus/issues/123#issuecomment-35496787 .

Pattentrick commented 10 years ago

@aroth Thank you for your feedback. Glad that you like the tutorials we made so far. Your notes would be highly useful!

Pattentrick commented 10 years ago

User Interfaces

ui

Welcome to the exciting and wonderful world of UI elements! Impact++ offers a variety of simple UI elements right out of the box. There are ready to use elements for buttons, displaying text, meters, overlays and much more. In this guide we will take a closer look at the idea behind UI elements in Impact++ and how you can use them for your game.

The Basics

First of all, please keep in mind that the UI elements of Impact++ should be used for simple user interfaces. If you need something big and complicated, you should consider to use the good old DOM instead. Using the DOM is a lot cheaper regarding to performance. And complex user interfaces are also easier to implement with classic DOM elements.

But for simple user interfaces Impact++ provides us with very cool UI elements. All UI elements inherit from the UIElement base class, which is located by default under plusplus/ui/ui-element.js inside the project folder. You will also find every other UI element under plusplus/ui/.

The UIElement class itself again is an entity which extends the EntityExtended class. Because of that, UI elements behave very similar to your ordinary Impact++ entities. For example, you can define an animation sheet, or a size, like you would for every other normal entity. However, there are a few things that are specific to UI elements.

UI elements are frozen: true by default. An entity with frozen: true will skip updating, which is good for performance, and UI elements usually don't need to be updated. Also, all UI elements are on an own layer called ui, so they won't interfere with your other entities. And they are fixed to the screen too, so you don't have to worry about reposition them manually, if you move your camera around. But you can disable this behaviour if you set fixed: false on your UI element if you like.

Additionally UI elements won't be destroyed if you change levels and they ignore game pauses. If you want to change this behaviour, take a look at the CLEAR_ON_LOAD_UI_LAYER and IGNORE_PAUSE_UI_LAYER property in the Impact++ config file located under plusplus/core/config.js. But make sure that your overwrite these properties in your own config-user.js and not in the config.js.

Also keep in mind that like all other EntityExtended entities, UI elements are static by default. If you change the performance to dynamic the UI element will be automatically removed from the UI layer and will be added to the entities layer.

Positioning

If you spawn a new UI element, it will appear in the top left corner of your game. This is the default behaviour, but you can reposition it or even set a margin if needed. Let's take at look at some examples.

You can spawn a new UI element like this:

javascript var ui = ig.game.spawnEntity(ig.UIElement, 0, 0);


Let's add a margin of 2% for a little more space:

``` javascript```
var ui = ig.game.spawnEntity(ig.UIElement, 0, 0, {
    margin: {
        x: 0.02,
        y: 0.02
    }
});

Note that margins on UI elements are actually pseudo margins. That means that they don't really keep other entities away, they are used to offset the element based on the pivot.

Of course you could also set a new position based on percentages in values from 0 to 1, but make sure that posAsPct is set to true if you use the posPct property:

javascript var ui = ig.game.spawnEntity(ig.UIElement, 0, 0, { posPct: { x: 0.5, y: 0.5 } });


Additionally you can set `posAsPct` to `false` and set the `pos` as normal:

``` javascript```
var ui = ig.game.spawnEntity(ig.UIElement, 0, 0, {
    posAsPct: false,
    pos: {
        x: 30,
        y: 10
    }
});

There is also the moveTo method which moves an UI element to another entity or position, which might come in handy in some situations of your game.

By the way, you don't have to define all of the properties of your UI element in the spawnEntity method, as seen in the examples above. For a better code organization you can also make a new class, which extends the UIElement class, and just spawn an entity with it.

Interactive UI Elements

Now that we understand the basics about UI elements, and how we can move them around, we should examine interactive UI elements. Impact++ has a base class for interactive UI elements called UIInteractive which offers some cool stuff for your game.

When a UIInteractive entity is touched or clicked it, will automatically call its activateComplete or its deactivateComplete method. Look at the code of this custom UIInteractive entity for example:

javascript ig.UICustomElement = ig.global.UICustomElement = ig.UIInteractive.extend({

// size, animation sheet and other stuff goes here ...

// override the activate method to do something special when button interacted with
activateComplete: function ( entity ) {

   // call parent activate
   this.parent();

   // do some activation behavior

},

// and since interactive elements are toggled by default // you can also do something when deactivated deactivateComplete: function ( entity ) {

   this.parent();

   // do some deactivation behavior

}

});


As you can see, you could easily add your own game mechanics to the `activateComplete` or `deactivateComplete` method after `this.parent()` is called. By default an `UIInteractive` element will toggle between the `activateComplete` and `deactivateComplete` methods.

In some cases you don't want this behaviour. You may just want that the `activateComplete` method gets called every time your element is interacted with, without any toggle at all. In  that case you can set the `alwaysToggleActivate` property of your UI element to `true`. 

Setting `alwaysToggleActivate: true` will result in always calling the `activateComplete` method if you click or touch the element, no matter how often you click or touch it.

Another useful feature is, that you can also hook into the activated or deactivated signals of the  `UIInteractive` element, as you can see in the example below:

``` javascript```
var ui = ig.game.spawnEntity(ig.UIInteractive, 0, 0);

ui.onActivated.add( player.pickUpItem, player );
ui.onDeactivated.add( player.dropItem, player );

The first parameter of the add method is the callback method you want to call, and the second one is the context of the callback. So in the example above the player will pick up, or drop, an item when the corresponding UI element is clicked or touched.

Like that you can even use abilities:

javascript var ui = ig.game.spawnEntity(ig.UIInteractive, 0, 0);

ui.onActivated.add( myPlayer.specialAbility.activate, myPlayer.specialAbility );


As you may have guessed, the `UIInteractive` element is highly useful for buttons. Impact++ provides us with a ready to use button class called `UIButton`, which is based on the `UIInteractive` element. 

The `UIButton` class disables toggling between the `activateComplete` and `deactivateComplete` methods by default, so that only the activate method gets called. On top of that the `UIButton` class helps with some basic animation handling.

##### Text for User Interfaces

Impact++ provides us with a class called `UIText`, which is highly useful for displaying text in your game world. A good example of use for the `UIText` class, would be displaying the player score in your game, or the amount of collected coins. 

Let's take a closer look at this code example :

``` javascript```
var _c = ig.CONFIG;

var score = ig.game.spawnEntity(ig.UIText, 0, 0, {

    font: new ig.Font( _c.PATH_TO_MEDIA + 'font_04b03_white_16.png' ),

    text: 'Score: 9000'

});

Please note that you need to define a font for your UIText entity. If you don't it will use the font mentioned in ig.CONFIG.FONT.MAIN_NAME of your config file. The value of the text property gets displayed in the game. You can of course easily change the value of the text property later on to update it:

javascript score.text = 'Score: 9001';



With the `maxWidth` and `maxHeight` properties you can define the maximum width or height of the text area. If you have multiple lines, you can set the text alignment via the `textAlign` property. Possible values for `textAlign` are `ig.Font.ALIGN.CENTER`, `ig.Font.ALIGN.LEFT` and `ig.Font.ALIGN.RIGHT`.  

##### More UI Elements

We looked at the basics of UI elements, at interactive UI elements and at UI elements for text. But you know what? There are a lot more in Impact++! Taken as a whole, Impact++ offers 13 UI related classes that are really awesome and can help you with your current game!

There are toggle classes like `UITogglePause` or `UIToggleVolume`, which are useful for toggling the game pause or the volume of the game music. The `UIMeter` class displays horizontally or vertically meters that are perfect for health bars. `UITracker` is an UI element for tracking the closest entity of a type or name in a level. And with the `UIOverlay` you can add all sorts of overlays to your game. 

Have a closer look at the `plusplus/ui/` folder of your Impact++ project, or take a look at the docs under http://collinhover.github.io/impactplusplus/ig.html, to get an overview of all the UI classes.

##### Learn More!

UI Element: http://collinhover.github.io/impactplusplus/ig.UIElement.html
UI Interactive: http://collinhover.github.io/impactplusplus/ig.UIInteractive.html
UI Button: http://collinhover.github.io/impactplusplus/ig.UIButton.html
UI Text: http://collinhover.github.io/impactplusplus/ig.UIText.html
Pattentrick commented 10 years ago

@collinhover I made a beginner tutorial/guide for UI elements. Feel free to correct me if I explained something wrong, something important is missing, or if I used some awful English.

I think we have enough tutorials right now to start with ;-)

collinhover commented 10 years ago

@pattentrick With this last one, it looks like we have over 9000 :-) I'm working on updating the docs site with the tutorials, thanks again for the great guides you've written.

Pattentrick commented 10 years ago

We have indeed over 9000 :D

You're welcome @collinhover! I am glad that i could contribute to the project. And I learned a lot in the process of making those tutorials with you. There may be some topics left, that needs some explanation. But for now I think we covered all of the important stuff.

agadzik commented 10 years ago

Awesome tutorials so far, keep up the great work! Could I request a tutorial on the Tutorial / Demo entities? Sort of confused on how they work at the moment.

collinhover commented 10 years ago

All examples posted above this comment are live at: http://collinhover.github.io/impactplusplus/

Pattentrick commented 10 years ago

@collinhover Hot stuff! The new project page looks so damn neat! Awesome job! I am actually very proud about our tutorials. And it's a great honor for me to be mentioned at the project page. Thank you very much! I am very busy at the moment, but i will continue to do some tutorials in the future ;-)

@agadzik As i mentioned above, i am very busy at the moment. So i can't provide a tutorial about the demo entity right now. But it's definitely on my list for upcoming tutorials. In the meantime you could take a look at the SUPERCOLLIDER demo. At the first level (title.js) there is a demo / tutorial entity that may answer your questions. If not, post an issue and we will try to help.

Falconerd commented 10 years ago

Just want to say thanks to @collinhover, this project is awesome. I'm very glad you used JSDoc. Also, @Pattentrick, thank you muchly for writing tutorials as they are immensely helpful in getting started.

Pattentrick commented 10 years ago

You're welcome @Archadian! Don't hesitate to post an issue here at github, if you have any trouble with ++.

Falconerd commented 10 years ago

Hey guys, I actually do have a question and it would be great if at some point it's covered in your tutorials. I'll just ask here before I go and make something from scratch as you may know a way to do it with plusplus or even impact that I haven't thought of yet.

What i'd like to happen is when the player picks up a new ability, the animation set changes to reflect this. EG: You pick up a shield, your character is now using the animations that show it holding a shield. You then pick up an axe, the shield disappears and you are now holding an axe.

I may have overlooked something simple, but it's really doing my head in as I've been staring at the code for a long time now.

Pattentrick commented 10 years ago

Good question @Archadian! At first I thought this was a simple one. If your player won't change his size, I thought it was as easy as defining a new sheet at the animSheet property of your player like this:

javascript // At your “equipped axe code”

this.animSheet = new ig.AnimationSheet( _c.PATH_TO_MEDIA + 'player-with-axe.png', 16, 16 );

// Add new animSettings …



However, I tested that a few minutes ago and that won't do anything. Although I get the new animation sheet if I print my logs to the console, the old animation sheet is still present in the game. So either my approach to this is totally wrong and I made some awkward errors while testing, or ++ won't check for animation sheet changes after the initialization of the entity.

I'll take a closer look at the `entity.js` and some other files to examine this. I am sure @collinhover could clear this up quickly for us, but he's rather busy at the moment as far as I know.

Another workaround would be to make more player classes (player-axe, player-sword), kill the current player and spawn a new one at the same position with the corresponding ability. But that solution feels rather unnatural. 

If the player also changes his size you could find some tipps on that here:

https://github.com/collinhover/impactplusplus/issues/148

However, that wont help you with your original question.