Using MovieClips to spawn npcs over time

19 posts

Flag Post

I am fairly new to Flash, but have started learning the basics. Is there a way that I can use a MovieClip or Video to spawn npcs (that extend MovieClip) onto the stage over time? If so, is this a good way to do it? Or should do I have to just code a way to save the spawn positions / times of the npcs.

 
Flag Post

You need to brush up some more. MovieClips don’t “spawn” npcs, and Videos sure as hell don’t.

But yes, it’s possible to write code that does that.

 
Flag Post

Okay, I think I was being a little vague. I want to know if it’s possible to use the timeline feature of movie clips to create other movie clips on a base movie clip at specific times. If this is not possible, then how would I “write code that does that?”

 
Flag Post

I think that’s possible, but it’d be far better to code it. Is this AS2 or AS3?

 
Flag Post
Originally posted by Arloistale:

Okay, I think I was being a little vague. I want to know if it’s possible to use the timeline feature of movie clips to create other movie clips on a base movie clip at specific times. If this is not possible, then how would I “write code that does that?”

You can create a keyframe at the wanted time. In the “action” part of the new keyframe you then create the new movie clip and attach it to the current movieclip.

But as Draco and Amibtious are trying to tell you, this is not the way to write game code and your attempt at making a game will only fail, it’s designed for for fixed animations like an intro.

You should instead learn to write code in either AS2 or AS3 and then use timers or count frames for your purpose of introducing NPCs. :)

 
Flag Post

Okay then, what would be the optimal way to have a layout of the positions/spawntimes of each npc?

 
Flag Post

This is AS3, btw.

 
Flag Post

An external file (embedded and parsed into the game structure), an enter frame listener with frame counter, and a lot of testing if it works correctly. The file is to store position and time offset, and which npc to spawn, the listener to control if it’s time to spawn and to actually spawn.

 
Flag Post

Sorry for the nooby question, but what kind of external file would be best for this? And how would I implement this? (I’m assuming XML but I’m not sure)

 
Flag Post
Originally posted by Arloistale:

Sorry for the nooby question, but what kind of external file would be best for this? And how would I implement this? (I’m assuming XML but I’m not sure)

The only kind that works:
An ActionScript Class File.

 
Flag Post
Originally posted by Draco18s:
Originally posted by Arloistale:

Sorry for the nooby question, but what kind of external file would be best for this? And how would I implement this? (I’m assuming XML but I’m not sure)

The only kind that works:
An ActionScript Class File.

Not exactly. While ActionScript class file is required anyway, an external file with metadata can be either XML or JSON. Either works, but first you have to be able to control every operation you want your movieclips do. How to implement – there are libraries that allow you to parse an XML file into a complicated object, which you can access inside your code. JSON works similarly.

 
Flag Post

It sounds like the OP needs a tutorial that explains how to implement NPC spawning. I’m going to explain how one can write AS3 code to make it seem like an NPC is spawning other NPCs.

First, we need MovieClips for the spawner and the — uh — “spawnee,” for lack of a better word. Let’s make a MovieClip of the spawner and call her “Mom.” Say hi to Mom. Notice that I’ve associated the MovieClip to an AS3 class that is also named Mom.

Next, we need a MovieClip for the NPC to be spawned. Let’s call it “Baby.” Like Mom, Baby has an associated AS3 class of the same name.

Now for some code. What we want to do is add Mom to the stage and have her spawn babies at a regular rate. These babies will then start moving. First, we need a way for Mom to announce to the game that she is about to deliver a baby. This means that the Mom Class has to tell the Document Class to spawn a new baby. Classes generally communicate with each other through events. Since there is no built-in event for announcing childbirth, we need to create one. Let us make a new class called “GameEvent,” which will contain all the relevant events that classes will use to communicate with each other. Right now, we only have one custom event to make, but as the game grows, we might want to add more. Here’s the code:

package  {
	import flash.events.Event;
	
	public class GameEvent extends Event {
		
		public static const CHILDBIRTH: String = "NewChild";

		public function GameEvent(gameEvent: String) {
			super(gameEvent);
		}  // public function GameEvent

	}  // public class GameEvent
	
}  // package

Next, we’ll add code to make Baby move immediately after he is born. Create a new class called Baby with this code:

package  {
	import flash.display.MovieClip;
	
	public class Baby extends MovieClip {
		private const MOVE_RATE: Number = 5;  // Movement speed in pixels per game tick

		public function Baby() {
			// constructor code
		}  // public function Baby()
		
		public function move(): void {
			x -= MOVE_RATE;
		}  // public function move()

	}  // public class Baby
	
}  // package

The above code is simpler than it ought to be. Things get more complicated if you want Baby to do various animations such as walking, running, attacking, and whatnot. That is beyond the scope of this tutorial, however. A quick Google search will turn up AS3 animation tutorials if you need them.

Next, let’s write some code for Mom. What we want Mom to do is to tell the Document class when she is due to give birth to another Baby. We’ll do this through the use of an event and a timer.

package  {
	import flash.display.MovieClip;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	
	public class Mom extends MovieClip {
		private const SPAWN_RATE: int = 800;  // Number of milliseconds to spawn babies
		
		private var _spawnTimer: Timer;

		public function Mom() {
			_spawnTimer = new Timer(SPAWN_RATE);
			_spawnTimer.addEventListener(TimerEvent.TIMER, onGivingBirth);
			_spawnTimer.start();
		}  // public function Mom()
		
		private function onGivingBirth(timerEvent: TimerEvent): void {
			dispatchEvent(new GameEvent(GameEvent.CHILDBIRTH));
		}  // private function onGivingBirth

	}  // public class Mom
	
}  // package

Finally, we bring everything together in the Document Class. Let’s call this class Main. What we want it to do is to put Mom on the stage and initially create an empty pool of babies. We’ll also add a timer to monitor when things in the game world ought to change. In our case, we want all the babies that have been spawned to move left every time the game timer advances. Finally, we’ll write an event listener for when Mom is due to give birth. This will call a function that adds a new Baby to the stage and includes it in our pool of babies. Here’s the code for all that:

package  {
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	
	public class Main extends MovieClip {
		private var _gameTimer: Timer;

		private var _mom: Mom;
		private var _babyPool: Array;

		public function Main() {
			_mom = new Mom();
			addChild(_mom);
			_mom.x = 482;
			_mom.y = 360;
			_mom.addEventListener(GameEvent.CHILDBIRTH, onChildBirth);
			
			_babyPool = new Array();
			
			_gameTimer = new Timer(17);  // Set the game to run at 59 ticks per second.
			_gameTimer.addEventListener(TimerEvent.TIMER, onTick);
			_gameTimer.start();
		}  // public function Main()
		
		private function onTick(timerEvent: TimerEvent): void {
			for (var i: int = 0; i < _babyPool.length; i++) {
				_babyPool[i].move();
			}
		}  // private function onTick
		
		private function onChildBirth(gameEvent: GameEvent): void {
			var baby = new Baby();
			addChild(baby);
			baby.x= 393;
			baby.y = 360;
			_babyPool.push(baby);
		}  // private function onChildBirth

	}  // public class Main
	
}  // package

Here’s a screen shot of Mom and her babies, who are happily marching on their way to world domination.

The code that I presented here will do everything that you want it to do, which is to spawn NPCs over time. Experienced AS3 programmers will notice that it will also cause some serious trouble if this code is not modified somehow. As the babies are spawned, our array of babies will also grow inexorably until we run out of memory to store them all. What we should have done is to re-use babies that exit the frame instead of spawning new ones all the time. Since you didn’t ask how to do that, I’ll assume that you already know how. If you don’t, I’ll leave that as an exercise for you to work out. :)

 
Flag Post
Originally posted by vesperbot:

Not exactly. While ActionScript class file is required anyway, an external file with metadata can be either XML or JSON. Either works, but first you have to be able to control every operation you want your movieclips do. How to implement – there are libraries that allow you to parse an XML file into a complicated object, which you can access inside your code. JSON works similarly.

Right, sort of misread the question.

 
Flag Post

Wow, Elyzius. Thanks a lot for the really in-depth answer. I understand how to create code to spawn npcs onto the map with a timer. My game, however, needs npcs to spawn at a specific time, not periodically. I think I will go figure out how to read and write XML files in Flash. Thanks again!

 
Flag Post
Originally posted by Arloistale:

Wow, Elyzius. Thanks a lot for the really in-depth answer. I understand how to create code to spawn npcs onto the map with a timer. My game, however, needs npcs to spawn at a specific time, not periodically. I think I will go figure out how to read and write XML files in Flash. Thanks again!

Yep, XML files. It’s actually not that hard once you start messing around. XML will take anything you throw at it, provided you use the syntax properly (and even then the syntax is very light).

json handles even more data types, but IMO is harder to write by hand.

 
Flag Post

XML files are not what you need. Just because it is possible for Flash to read them doesn’t mean they do anything even resembling what you want.

Elyzius’ answer is close to what you asked for. You just need to adjust the timing. Keep a running total of how much time has passed, and spawn the unit(s) when that total reaches the time value you have in mind.

(It’s possible you were going to use XML files to store the time value(s) you have in mind. That would work, but so would an array, so you might as well just use the array.)

 
Flag Post
Originally posted by player_03:

XML files are not what you need. Just because it is possible for Flash to read them doesn’t mean they do anything even resembling what you want.

Agreed. XML and JSON give you flexible ways to store structured data, but data by themselves will not spawn DisplayObjects. The only way to do that is with code.

Elyzius’ answer is close to what you asked for. You just need to adjust the timing. Keep a running total of how much time has passed, and spawn the unit(s) when that total reaches the time value you have in mind.

Yep, that’s how to do it. Here’s a detailed explanation of the process:

For this particular example, I set up my stage with two buttons on the upper left and a summoning circle on the lower left. When pressed, the buttons will start summoning the creature pictured on them. It will take a shorter period of time to summon the baby creature than the mom creature. You can queue your summon orders by repeatedly pressing either or both buttons. The instance name of the first button is “buttonBaby,” and that of the second button, “buttonMom.” The instance name of the summoning circle is “summoningCircle.”

You may have heard that you should keep your stage empty. Well, that advice is absolutely right. For this example, I deliberately put DisplayObjects on my stage because I was too lazy to do everything in code, although I obviously was not too lazy to write a mini-tutorial. :D

I associated the Mom and Baby MovieClips with AS3 classes of the same name. I did not actually write code for those classes, however, because I didn’t need to. Instead, I wrote code for a superclass called Creature. Notice in the following image that the base class of Mom is the Creature class. The same is true for the Baby.

The code for the Creature class is really very simple. Its main purpose is to make the creature move. If you wanted to have the creature do other things, you would have to add more code to the class.

package  {
	import flash.display.MovieClip;
	
	public class Creature extends MovieClip {
		private var _moveRate: Number;  // Movement speed in pixels per game tick

		public function Creature() {
			// constructor code
		}  // public function Creature
		
		public function get moveRate(): Number {
			return _moveRate;
		}  // public function get moveRate
		
		public function set moveRate(movementRate: Number): void {
			_moveRate = movementRate;
		}  // public function set moveRate
		
		public function moveRight(): void {
			x += _moveRate;
		}  // public function moveRight()

	}  // public class Creature
	
}  // package

As for the Document class, its name is Main as in my previous post. What it does is to add a schedule for creatures to be summoned to a queue called _buildOrder whenever the player clicks any of the summoning buttons. Whenever the game timer advances, all creatures that have already been summoned are made to move. The Document class also checks if the schedule in the _buildOrder queue indicates that it is time to summon a new creature. If so, the new creature is summoned and added to the pool of creatures.

package  {
	import flash.display.SimpleButton;
	import flash.events.MouseEvent;
	import flash.utils.Timer;
	import flash.events.TimerEvent;
	import flash.display.MovieClip;
	
	public class Main extends MovieClip {
		private const CREATURE_ID_BABY: int = 1;
		private const CREATURE_ID_MOM: int = 2;
		
		private const MOVE_RATE_BABY: Number = 4.2;
		private const MOVE_RATE_MOM: Number = 3.1;
		
		private const SUMMONING_TIME_BABY: int = 40;  // Number of game ticks to summon Baby
		private const SUMMONING_TIME_MOM: int = 100;  // Number of game ticks to summon Mom
		
		private var _gameTimer: Timer;

		private var _buildOrder: Array;    // Queue of creatures to be summoned
		private var _creaturePool: Array;  // Pool of summoned creatures

		public function Main() {
			_buildOrder = new Array();
			_creaturePool = new Array();
			
			buttonBaby.addEventListener(MouseEvent.CLICK, onClickBaby);
			buttonMom.addEventListener(MouseEvent.CLICK, onClickMom);
			
			_gameTimer = new Timer(25);  // Set the game to run at 40 ticks per second.
			_gameTimer.addEventListener(TimerEvent.TIMER, onTick);
			_gameTimer.start();
		}  // public function Main
		
		public function onClickBaby(event: MouseEvent): void {
			// Indicate that the next creature to be summoned is a Baby.
			var newSummoning = new Object();
			newSummoning.creature = CREATURE_ID_BABY; 
			
			// Determine when the summoning process will end.
			if (_buildOrder.length > 0) {
				// Start the summoning process only after the previous creature has been summoned.
				newSummoning.when = _buildOrder[_buildOrder.length - 1].when + SUMMONING_TIME_BABY;
			}
			else {
				// The queue of creatures to summon is empty. Start the summoning process now.
				newSummoning.when = _gameTimer.currentCount + SUMMONING_TIME_BABY;
			}
			
			// Add the creature to be summoned to the queue.
			_buildOrder.push(newSummoning);
		}  // public function onClickBaby
		
		public function onClickMom(event: MouseEvent): void {
			// Indicate that the next creature to be summoned is a Mom.
			var newSummoning = new Object();
			newSummoning.creature = CREATURE_ID_MOM; 
			
			// Determine when the summoning process will end.
			if (_buildOrder.length > 0) {
				// Start the summoning process only after the previous creature has been summoned.
				newSummoning.when = _buildOrder[_buildOrder.length - 1].when + SUMMONING_TIME_MOM;
			}
			else {
				// The queue of creatures to summon is empty. Start the summoning process now.
				newSummoning.when = _gameTimer.currentCount + SUMMONING_TIME_MOM;
			}
			
			// Add the creature to be summoned to the queue.
			_buildOrder.push(newSummoning);
		}  // public function onClickMom
		
		private function onTick(timerEvent: TimerEvent): void {
			// Move all the creatures that have already been summoned.
			for (var i: int = 0; i < _creaturePool.length; i++) {
				_creaturePool[i].moveRight();
			}
			
			// Check if there are creatures to be summoned.
			if (_buildOrder.length > 0) {
				// Check if it is time to summon a new creature.
				if (_gameTimer.currentCount >= _buildOrder[0].when) {
					if (_buildOrder[0].creature == CREATURE_ID_BABY) {
						// Summon a Baby.
						var baby = new Baby();
						addChild(baby);
						baby.x = summoningCircle.x;
						baby.y = summoningCircle.y;
						baby.moveRate = MOVE_RATE_BABY;
						_creaturePool.push(baby);  // Add Baby to the creature pool.
						_buildOrder.shift();  // Remove this build order from the queue.
					}
					else if (_buildOrder[0].creature == CREATURE_ID_MOM) {
						// Summon a Mom.
						var mom = new Mom();
						addChild(mom);
						mom.x = summoningCircle.x;
						mom.y = summoningCircle.y;
						mom.moveRate = MOVE_RATE_MOM;
						_creaturePool.push(mom);  // Add Mom to the creature pool.
						_buildOrder.shift();  // Remove this build order from the queue.
					}
				}
			}
		}  // private function onTick

	}  // public class Main
	
}  // package

And here’s the game in action:

At this point, I’d like to mention a few caveats regarding the above code. As in my previous example, creatures that have moved off the frame will still be in the creature pool. Additional code will have to be written to either remove them from the pool or to save them for possible re-use. Secondly, you can write shorter and more efficient code if you store creature data in arrays instead of storing them in constants. Whether you store your data in JSON, XML, or some other format is up to you. Do note that JSON is quicker to parse than XML. Finally, using the shift method of an Array to remove its first element is an inefficient way of going about it. If you write a separate class to implement a Queue data structure, you may be able to remove the first element more efficiently depending on how you implement the Queue class.

 
Flag Post
Originally posted by player_03:

XML files are not what you need. Just because it is possible for Flash to read them doesn’t mean they do anything even resembling what you want.

Elyzius’ answer is close to what you asked for. You just need to adjust the timing. Keep a running total of how much time has passed, and spawn the unit(s) when that total reaches the time value you have in mind.

(It’s possible you were going to use XML files to store the time value(s) you have in mind. That would work, but so would an array, so you might as well just use the array.)

Cough:

My game, however, needs npcs to spawn at a specific time, not periodically.

Data structure anyone?

The advantage of an XML file over an array structure is three fold:

1) holding information other than a single value (i.e. “enemy x at position y at time t with health h…”1
2) easily modifiable in order to tweak values (i.e. six enemies at that time is too much, I’ll make it four instead, and have the other two come in later…").
3) modifiable without requiring a recompile of the program (I have a game that I can no longer recompile, because the last known source files were corrupted, but good news: all the level data was XML based! If I felt like it I could still add levels to the game without the source code!)

1 notably, they don’t even need to be absolute times, you can use time offsets. Great for making chains of enemies that all show up one after another with a slight delay. Example (<at> denotes a specific time, <offset> indicates as a delay from the previous xml entry)

 
Flag Post

Thanks a lot guys; I think an XML is the solution to my problem. I’m learning how to use it in Flash right now!