Rainy Day

In this tutorial we'll learn how to use particle effects and the T2DTrigger object to make a game in which rain will make plants grow.

### 1. Getting started

Start Torque Game Builder and create a new project -- Call it RainyDayTutorial.

### 2. A little background information

Drag this image from your browser onto TGB:

background.png

From the Create pane in TGB, drag the backgroundMaterial you just added into the Scene View area, to create a static sprite that we can use as the background of our scene. Go to the Edit pane, and enter 0 for both Position X and Position Y -- this will center the sprite in the scene. For Width enter 100, and for Height enter 75. This will make the sprite exactly match the viewable area of the default camera, so the image will completely fill up the background of the scene.

For Layer, enter 31. Higher layers are further "back" in the scene, so we want our background to be very far back.

When we dragged the image onto TGB that updated the project file to include the image. Since we updated the project file and the scene, we need to save it. From the menu, choose File -> Save and replace Untitlted.t2d with Rainy Day Level.t2d and hit ok.

Let's see our background in action by choosing Project -> Run Game from the menu! Okay, so it's a static background and as a result there's not a lot of action to see. Let's fix that.

###

### 3. Flower power

Drag this image onto TGB:

plant.png

This image is actually multiple frames of an animation. Let's tell TGB about how the image should be broken up into frames. Go to the Create pane, and the Materials rollout. Double-click the Plant, to bring up the Image Builder window. From the Image Mode pulldown menu select "Cell". Then in Cell Count X enter 6, and in Cell Count Y enter 3. Now you should see the image broken up into the individual frames. Click the Save button to save these changes.

Now that we have the image broken up into frames, let's string those frames together into an animation. Click the "Create a new Animation" button. Choose plantMaterial, and click the Select button. This brings up the Animation Builder window. Click the little green "Add all frames from the image" button -- this will add the frames in order to the animation sequence. The default speed is pretty fast for these particular frames, so for Frames Per Second enter 5. Also, this animation doesn't make sense when it cycles from the last frame to the first, so clear the checkmark out of the Cycle Animation checkbox. Click the Save button to save this animation. Now you have a new Animation in the Animations rollout.

Let's put a flower into the scene. From the Create pane, from the Animations rollout, drag the plantAnimation into the scene somewhere onto the grassy hill. Go to the Edit pane. In the Scene Object rollout, set the Width and Height 16, to shrink it down to a more reasonable size. Then go to the Collision rollout and make sure the Send Collision and Receive Collision boxes are checked and the Send and Receive Physics boxes are unchecked.

Use the menu to do File -> Save. Then use the menu to do Project -> Run Game. Now we've got some action -- flower dying action! Kind of a downer, huh? Maybe we'll find a silver lining if we add a cloud.

### 4. Into every life a little rain must fall

Drag this image onto TGB:

cloud.png

Drag the Cloud from the Create pane into the middle of the scene. Click the "Edit this objects linkpoints" quick-edit button. Create a linkpoint in the middle of the main mass of the cloud by left-clicking, hit the Esc key to exit out of linkpoint editing mode when you're done creating the linkpoint. Creating a linkpoint will let us mount things onto the cloud. What would we want to mount to the cloud? How about a particle effect that creates raindrops! Drag this image onto TGB:

raindrop.png

Now, from the Create pane, from the Particle Effects rollout, drag a New Particle Effect into the scene. Go to the Edit pane. Expand out the "Emitter - Untitled Emitter" rollout. This will let us control aspects of what particles are emitted by the particle effect. Set Image to raindropImageMap so we can start emitting some raindrops. Finally uncheck the Use Effect Emission checkbox. Now let's start changing some parameters of the particles themselves. Click the Edit Emitter Graph button.

In the select box, choose Emission Arc Base. This controls how the particles spread out. By default its set to 360, so particles spread out in every direction. Drag the dot down to 0.000 0.000. This will cause the particles to be issued in only a single direction.

Now choose Emission Angle Base. Drag the dot to about 0.000 180.000, so the drops are created heading down instead of up.

Select Particle Life Base, and drag the dot to the top of the graph to set it to 0.000 10.000. This will keep the particles "alive" for 10 seconds from when they are created.

Select Size X Base. Drag the dot to about 0.000 11.013 -- this will make the drops look more like actual rain.

Select Speed Base, and drag the dot to about 0.000 12.658. This will speed the drops up a bit.

Click the Close button.

Finally set Type to LINEX so that the particles are created along a horizontal line instead of at a single point. Now that we have the particle effect creating drops, let's attach it to the cloud so the drops look like they're falling from the cloud. Click the "Mount this object to another object" quick-edit button, and then click on the yellow cross on the cloud that represents the linkpoint we created there earlier. Now the particle effect is connected to the cloud, but the drops are being created in front of it, which looks a little funky. Go to the Edit pane, and the Scene Object rollout, and set the Layer to 5. This will put the drops behind the cloud, so they'll look like they're falling out of the bottom.

Now let's let the player move the cloud, too. To do this we will need to write a behavior that we attach to our cloud. Open up your favorite text editor (Torsion works best, but Notepad works just fine) and enter the following code:

    	if (!isObject(MovementBehavior))
      	{
      		%template = new BehaviorTemplate(MovementBehavior);

      		%template.friendlyName = "Movement Behavior";
      		%template.behaviorType = "Movement Styles";
      		%template.description  = "Shooter style movement control";

    	  	%template.addBehaviorField(upKey, "Key to bind to upward movement", keybind, "keyboard up");
      		%template.addBehaviorField(downKey, "Key to bind to downward movement", keybind, "keyboard down");
    	  	%template.addBehaviorField(leftKey, "Key to bind to left movement", keybind, "keyboard left");
      		%template.addBehaviorField(rightKey, "Key to bind to right movement", keybind, "keyboard right");

    	  	%template.addBehaviorField(verticalSpeed, "Speed when moving vertically", float, 20.0);
      		%template.addBehaviorField(horizontalSpeed, "Speed when moving horizontally", float, 20.0);
      	}

The first part of the behavior checks to make sure a behavior doesn't already exist named "Movement Behavior". From there we give it a friendly name or the name that it is called in TGB, a behavior type which will allow us to categorize our behaviors inside TGB to find things easier, and a description. The Behavior Fields expose certain things to the editor so that we can edit our game from TGB instead of having to go back to code all the time. Go back to your script and add the following code:

    	function MovementBehavior::onBehaviorAdd(%this)
      	{
    	  	if (!isObject(moveMap))
      		return;

    	  	// bind our keys to the keyboard
      		moveMap.bindObj(getWord(%this.upKey, 0), getWord(%this.upKey, 1), "moveUp", %this);
    	  	moveMap.bindObj(getWord(%this.downKey, 0), getWord(%this.downKey, 1), "moveDown", %this);
      		moveMap.bindObj(getWord(%this.leftKey, 0), getWord(%this.leftKey, 1), "moveLeft", %this);
    	  	moveMap.bindObj(getWord(%this.rightKey, 0), getWord(%this.rightKey, 1), "moveRight", %this);

      		// set the default values to 0
    	  	%this.up = 0;
      		%this.down = 0;
    	  	%this.left = 0;
    	  	%this.right = 0;
      	}

     	function MovementBehavior::onBehaviorRemove(%this)
      	{
      		if (!isObject(moveMap))
      		return;
      		%this.owner.disableUpdateCallback();

      		// remove the keybinds
      		moveMap.unbindObj(getWord(%this.upKey, 0), getWord(%this.upKey, 1), %this);
    		moveMap.unbindObj(getWord(%this.downKey, 0), getWord(%this.downKey, 1), %this);
    		moveMap.unbindObj(getWord(%this.leftKey, 0), getWord(%this.leftKey, 1), %this);
      		moveMap.unbindObj(getWord(%this.rightKey, 0), getWord(%this.rightKey, 1), %this);

      		%this.up = 0;
      		%this.down = 0;
      		%this.left = 0;
      		%this.right = 0;
      	}

      	function MovementBehavior::updateMovement(%this)
      	{
    		// make the player move
      		%this.owner.setLinearVelocityX((%this.right - %this.left) * %this.horizontalSpeed);
      		%this.owner.setLinearVelocityY((%this.down - %this.up) * %this.verticalSpeed);
      	}

      	function MovementBehavior::moveUp(%this, %val)
      	{
      		%this.up = %val;
      		%this.updateMovement();
      	}

      	function MovementBehavior::moveDown(%this, %val)
      	{
      		%this.down = %val;
      		%this.updateMovement();
      	}

      	function MovementBehavior::moveLeft(%this, %val)
      	{

      		%this.left = %val;

      		%this.updateMovement();
      	}

      	function MovementBehavior::moveRight(%this, %val)
      	{
      		%this.right = %val;
      		%this.updateMovement();
      	}

From the menu use File -> Save. Save your file in the Behavior folder of your game project which can be found under My Documents/MyGames/Rainy Day Tutorial/Game/Behaviors and name the file MovementBehavior.cs (don't forget to add the extention .cs). Go back to TGB and from the menu use Project -> Reload Project, TGB should prompt you to save the project and the particle effect we created. Save both and name the particle effect Rain. Every time you create a new behavior you have to reload TGB so it can recognize the new behavior. Now let's add our newly created behavior to our cloud. Select the cloud sprite, and go to the Edit pane. In the Behaviors rollout, select Movement Behavior in the select box and click the green "+" button to add it. The Movement Behavior moves whatever object it is attached to based on the keys selected in the drop down menus in TGB (default is the arrow keys).

From the menu, use File -> Save. Next use the menu to do Project -> Run Game. Now you can move the cloud around, and watch the drops fall! But the rain isn't helping the flowers. That's because particle effects are just fancy graphical effects -- there's no game object interaction there. In order to make the rain have a game effect, we'll need to write some custom game code.

### 5. This plant is operating within acceptable parameters

We need to create another behavior so that the flowers can react to being watered. Go back to your script editor, use the menu to do File -> New to create a new script file.

Like before we are going to create the template of our behavior, add this code to declare some variables:

    	if (!isObject(PlantGrowthBehavior))
    	{
    		%template = new BehaviorTemplate(PlantGrowthBehavior);

       		%template.friendlyName = "Plant Growth Behavior";
    	    	%template.behaviorType = "Management";
       		%template.description  = "Controls the growth of the plants";

       		%template.addBehaviorField(Moisture, "", float, 10.0);
       		%template.addBehaviorField(minMoisture, "The lowest amount of moisture for the plant", float, 0.0);
       		%template.addBehaviorField(maxMoisture, "The largest amount of moisture for the plant", float, 10.0);
       		%template.addBehaviorField(LowMoistureThreshold, "The threshold that causes it to start growing or dying", float, 5.0);
       		%template.addBehaviorField(DryRate, "How fast it loses moisture", float, 0.05);
       		%template.addBehaviorField(WateringRate, "How fast it gains moisture", float, 0.05);
    	}

This creates a new behavior and several variables that we can access from inside TGB. Use the menu to do File -> Save save it to the same folder as the MovementBehavior and name it PlantGrowthBehavior.cs. Go back into TGB and from the menu do Project -> Reload Project and click yes to save the project. This updates TGB so we can access our newly created behavior. Select your flower and go to the Edit pane. In the Behaviors rollout, select Plant Growth Behavior in the select box and click the green "+" button to add it.

Scroll down and you'll see a rollout for the component you created. It has editable fields for all of the public properties you set up, and the default values you set are in there. Exposing tweak able values on your components to TGB like this can be very useful in the game design process, since it let's you do it in TGB, where you do other design related tasks like placing objects. Let's get some practice tweaking values in TGB by setting WateringRate to 0.1. Afterwards, save your changes by using the menu to do File -> Save Scene.

### 6. It's a matter of life and death

Well, we've got some variables and tunable parameters now, but we're not actually doing anything with them. Let's do something with them. Go back to your script editor and the PlantGrowthBehavior, and right after the section where we define our behavior, add this code:

    	function PlantGrowthBehavior::onAddtoScene(%this)
    	{
          	%this.dieAnim = %this.owner.getAnimation();

          	%j = 0;
          	for (%i = getWordCount(%this.dieAnim.animationFrames) - 1; %i >= 0; %i--)
          	{
            	%growAnim = setWord(%growAnim, %j, getWord(%this.dieAnim.animationFrames, %i));
             	%j++;
          	}
          	%this.growAnim = new t2dAnimationDatablock()
          	{
             	animationCycle = %this.dieAnim.animationCycle;
             	animationFrames = %growAnim;
             	animationTime = %this.dieAnim.animationTime;
             	imageMap = %this.dieAnim.imageMap;
             	randomStart = %this.dieAnim.randomStart;
             	startFrame = %this.dieAnim.startFrame;
          	};
       		%this.owner.enableUpdateCallback();
    	}

The first line, allows us to store the animation from the object onto the behavior as %this.dieAnim, the animation we'll play to make the plant die, since that's the animation we've got. We want to create another animation that makes the plant grow, basically just the same animation played in reverse. That's what the next few lines of code do -- they create a copy of the animation, and reverse it's frames. Lastly, we register with the engine to call the UpdateCallback method every tick of the engine (roughly 30 times per second).

Now that we have the two different animations, let's create a way to switch between them. Right below the "onAddtoScene" method, create the following method:

    	function PlantGrowthBehavior::runAnimation(%this, %direction)
    	{
          	if (%direction < 0.0)
       		{
          		if (%this.owner.getAnimation() != %this.growAnim)
          		{
             		%frame = (getWordCount(%this.growAnim.AnimationFrames) - 1) - %this.owner.getAnimationFrame();
             		%this.owner.PlayAnimation(%this.growAnim);
             		%this.owner.setAnimationFrame(%frame);
          		}
       		} else
       		{
          		if (%this.owner.getAnimation() != %this.dieAnim)
          		{
             		%frame = (getWordCount(%this.dieAnim.AnimationFrames) - 1) - %this.owner.getAnimationFrame();
             		%this.owner.PlayAnimation(%this.dieAnim);
             		%this.owner.setAnimationFrame(%frame);
          		}
       		}
    	}

This code decides which animation to run, and also accounts for the situation where the animation might be reversed while it's still running, and sets the current frame to be the corresponding frame in the opposite animation (e.g. one quarter dead is the same as three quarters alive), so there's a smooth transition between them.

Let's make use of that method. Right after the "runAnimation" region, add this code:

    	function PlantGrowthBehavior::onUpdate(%this)
    	{
       		if (%this.moisture < %this.lowMoistureThreshold)
       		{
          		// dying -- run animation forwards.
          		%this.RunAnimation(1.0);
       		} else
       		{
          		// growing -- run animation backwards.
          		%this.RunAnimation(-1.0);
       		}

       		// modify amount of moisture based on whether we're being watered or not
       		if (%this.watering)
          		%this.moisture += %this.wateringRate;
       		else
          		%this.moisture -= %this.dryRate;

       		// clamp moisture amounts.
       		if (%this.moisture < %this.minMoisture)
          		%this.moisture = %this.minMoisture;
       		if (%this.moisture > %this.maxMoisture)
          		%this.moisture = %this.maxMoisture;

    	}

This simply compares the current "moisture level" to the threshold, and makes the plant die if it doesn't have enough moisture, and grow if it does. It then uses the %this.watering variable to determine if we should increase the moisture, or dry out. Let's create some method that will let us set that %this.watering variable. Right after the "onUpdate" region, add these methods:

    	function PlantGrowthBehavior::startWatering(%this)
    	{
       		%this.watering = true;
    	}

    	function PlantGrowthBehavior::endWatering(%this)
    	{
       		%this.watering = false;
    	}

Why define these methods this way? Because defining them this way will let us use them with a T2DTriggerObject. But before we can set that up, we need to create a behavior to call on these methods when the "Trigger" events occur. Save your behavior then go to your script editor and use the menu to do File -> New and enter the following code:

    	if (!isObject(WateringBehavior))
    	{
       		%template = new BehaviorTemplate(WateringBehavior);

       		%template.friendlyName = "Watering Behavior";
       		%template.behaviorType = "Trigger";
       		%template.description  = "Defines when to begin watering";
    	}

    	function WateringBehavior::onEnter(%this, %object)
    	{
       		%object.startWatering();
    	}

    	function WateringBehavior::onLeave(%this, %object)
    	{
       		%object.endWatering();
    	}

This behavior will call the watering methods we created in the other behavior. Now use the menu to do File -> Save As and name it WateringBehavior.cs. As before, we need to update our project so that TGB knows about our new behavior. Go to TGB and use the menu to do Project -> Reload Project.

The particle effect was a graphical thing that had no effect on the game objects. Now let's do the opposite and create a game object that has an effect on other game objects, but isn't shown graphically. When we put the two together, we'll have a complete solution. From the Create pane, from the Other rollout, drag a new Trigger into the scene.

With the new trigger object selected, click the "Mount this object to another object" quick-edit button. Click on the yellow cross in the middle of the cloud. Once the object is mounted, resize it by grabbing the blue dot on the bottom-middle of the bounding box, and stretch the object so the height expands quite a way outside the visible camera area.

With the Trigger Object selected go to the Edit pane, and to the Behaviors rollout. Select Watering Behavior and click the green "+" button. The Watering Behavior lets us define methods for what happens when objects enter or leave the region of the object they're attached to. Scroll up to the Trigger rollout, and make sure the Enter and Leave Callback boxes are checked

Now, when plant enters the region of this object (because the cloud moves it over top of it) the plant starts growing, and when it leaves the region (because the cloud moves it away) they'll being to die. Use the menu to do File -> Save. Then use the menu to do Project -> Run Game. The flower should grow when you hover over it and die when you move away.

Having just one flower isn't very exciting so lets create a bunch more. Select the Plant in our scene and go the menu to do Edit -> Copy then go back to the menu and do Edit -> Paste. This will create a copy of our flower right on top of the old one so move it somewhere else on the grassy hill. Do this several times so that we have multiple flowers around the scene. Its best to do your copying when an object is at a final state so you don't have to adjust several different objects. Now use the menu to do File -> Save and then Project -> Run Game. Now the plants respond to the rain!

We want your feedback! Please follow this link to take a short survey about this tutorial. Telling us what you think about our tutorials (good and bad) helps us make our tutorials better. We need to know what we're doing right and what we're doing wrong, and we can't do that without your help!

Documents Involving the Same Genre | Documents Involving the Same Functionality