Purpose of this tutorial is to get you familiar with basic concepts
AnimationCore extension. We will create simple bot that will just stand in
the environment and execute two animation planners in succession. One will
be a SimpleAnimationPlanner
instance, the other will
be a BMLAnimationPlanner
instance.
Put Anim-01-Static
into your
projects
(or workspace
)
directory.
Follow these steps:
Open Netbeans (
→ → → )Once Netbeans were loaded open example project:
→ → → → then clickIn New Project dialog enter name of the
folder where the example will be unpacked, for example
Anim-01-Static
, after you are finished click
button.
Now a project named "Anim-01-Static" will be opened in the Projects tab, open project's Source Packages sub folder and then the cz.cuni.amis.pogamut.ut2004.examples package contained in this folder
Finally double click Static.java
file
containing source code of our first animating bot.
Notice that the project's node in Projects tab is in bold, this means that the (F6) and (Ctrl + F5) buttons are linked to this project. Before we will start this first bot we have to launch the Unreal Tournament listen server.
Follow these steps:
Start Unreal Tournament 2004
Press
Choose
Choose
in the list of maps (left side of menu)Click on Mutators and add
and (by either double-clicking on them in the left list or clicking on them in the left list, then clicking on ). You should have both mutators listed on the right side of the menu now.Click
, to start the server.Wait until the map loads, then press Escape and click on .
Let's get our agent running now. Use Alt+Tab to get
back to NetBeans and hit F6, use Alt+Tab
again to get back to UT2004. Soon, you should be able to see a new bot
named "AnimationBot
" in the world. In a few
seconds, bot will pose itself into basic animation position and start
executing a sequence of simple animations.
Now, we are going to examine the source code in greater detail. We will skip any code that you should already know from previous tutorials and code that is not relevant to the use of AnimationCore.
Let's have a look on Static.java
.
AnimationCore propagates its functionality to its user through a class
called Animation
. Its constructor looks like
this:
public Animation( AbstractEmbodiedAgent<UT2004SyncLockableWorldView> agent, AgentInfo agentInfo, Items itemsModule, Players playersModule, UT2004SyncLockableWorldView worldView, ICommandSerializer commandSerializer, Logger log, String ipAddress, int port) throws IOException, PogamutException
We don't have these classes instantiated yet:
AgentInfo
Items
Players
UT2004SyncLockableWorldView
In order to instantiate them, we have this code:
// Instantiate modules. game = new Game(worldView, this.getLogger().platform()); info = new AgentInfo(worldView, game, this.getLogger().platform()); players = new Players(worldView, info, this.getLogger().platform()); items = new Items(worldView, info, this.getLogger().platform());
Now we are ready to instantiate the animation module. Since its constructor can throw two types of exceptions, it is enclosed in a try statement:
// Try to instantiate new animation module. animation = new Animation(this, info, items, players, worldView, commandSerializer, this.getLogger().getCategory("Animation"), "127.0.0.1", 3002);
Pay attention to the last two parameters, since they have to correspond with an IP address and port of GameBotsAnim. Port 3002 is the default port and "127.0.0.1" represents your present computer. We have experienced some issues with the way Java looks up and/or connects to server. In case the connection doesn't work, change "127.0.0.1" to "localhost".
After this, we have to supply a plan to our newly created
animation module. That can be done through a method called
setPlanner
of the animation module. But first
we have to create it.
The first planner we will make our bot to execute will be an
instance of SimpleAnimationPlanner
called
WristFlapAnimationSimplePlanner
. This planner
makes the bot do a simple wrist flapping animation (as the name
suggests). So let's instantiate it and assign it to the animation
module:
// Try to create and set a new planner, WristFlapAnimationSimplePlanner planner = new WristFlapAnimationSimplePlanner(); // then assign it. animation.setPlanner(planner);
Ok we are almost done in the bot's constructor. There are only two more things you should know about and you can do in the constructor.
The first one is that you can attach event listeners to
animation module, that listens for report that animation module
finished the planner. A listener has to implement an
AnimationListener
interface. We will get more
into detail about it a bit later in the tutorial. The second one is
that you can also listen for the message
ANIMSTOP
coming from GameBots2004 (through
standard means), that reports that bot has returned from animating
state, to normal state and you can do all the standard things that you
can do with an unarmed scenario bot. Listener for this event is a
standard Pogamut event listener and as such implements
IWorldEventListener
with a type parameter
AnimationStop
. More on that later as
well.
In order to take advantage of these feature, examine this code:
// Set a listener to PlannerFinished event. animation.addAnimationListener(moduleListener); // Set a listener to ANIMSTOP message coming from GameBots2004 // (GameBotsAnim communicates using a different binary connection) worldView.addEventListener(AnimationStop.class, serverListener);
As you already know, doLogic
is where
most of the bots actions originate from. This is also the place the
animation module gets ticked from, since animation module required
this kind of tick as well. In order to give you some time to
Alt+Tab back into the game, first few (25) iterations
are skipped using a simple counter. The pause between each iteration
is handled by Pogamut itself, since it calls doLogic in set
intervals.
After the first iterations pass, the "beef" of doLogic comes to hand. The beef consists of two parts:
Starting animation (once).
Ticking animation module (called till the end of bots execution).
Starting animation gets done by calling
startAnimation
method on animation module.
This is to be done after each assignment of a new plan and positioning
a bot to the target location of animation execution. Ticking the
animation module should be happen every time since bot's starting
animation up until it stops. In the next section we will cover how
that is reported to you.
Two kinds of events should be of particular interested for you. We have mentioned them in the section called “Finishing touches to the bot's constructor”.
When the animation module finishes the execution of the plan,
then every registered object that implements
AnimationListener
gets notified. In our
example the class that handles the event is
AnimListener
. Let's have a look upon its
code:
protected class AnimListener implements AnimationListener { boolean once = false; @Override public void plannerFinished(IAnimationPlanner planner) { // We want to restart the planner only once. if (!once) { once = true; try { // Change input file as you wish. IAnimationPlanner new_planner = new BMLAnimationPlanner("BMLExample2.xml"); animation.setPlanner(new_planner); animation.startAnimation(); } catch (PogamutException e) { getLogger().user().severe(e.getMessage()); } } } }
What we see here is that a method called
plannerFinished
is resposible for the
handling of the event. For the users' convenience also the recently
finished planner is passed. For the purpose of this tutorial we use
this method to append another planner. This time it is a
BMLAnimationPlanner using a BMLExample2.xml
plan. For the explanation of BML look into the reference directory
of the AnimationCore distribution.
As you can see setting a different planner works similary to what we seen already. It is practically same.
When bot reverts back to the standards state (not controlled
by the animation module), you will get notified through the world
view that recognizes the ANIMSTOP
message
using the AnimationStop
class. This is
handled by AnimationStopListener
class. Since
you should know by now how to handle such messages we leave this up
to you.