├── externals
└── Equationator.dll
├── ExampleApplication
├── App.config
├── FakeEmitter.cs
├── FakeBulletManager.cs
├── FakeBullet.cs
├── example.xml
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
└── ExampleApplication.csproj
├── .gitmodules
├── GameManager.cs
├── PositionDelegate.cs
├── Tasks
├── SetDirectionTask.cs
├── SetSpeedTask.cs
├── VanishTask.cs
├── RepeatTask.cs
├── WaitTask.cs
├── ChangeSpeedTask.cs
├── ActionTask.cs
├── AccelTask.cs
├── ChangeDirectionTask.cs
├── BulletMLTask.cs
└── FireTask.cs
├── Nodes
├── BulletNode.cs
├── DirectionNode.cs
├── ActionRefNode.cs
├── FireRefNode.cs
├── FireNode.cs
├── BulletRefNode.cs
├── NodeFactory.cs
├── ActionNode.cs
└── BulletMLNode.cs
├── README.md
├── IBulletManager.cs
├── Properties
└── AssemblyInfo.cs
├── LICENSE.txt
├── BulletMLEquation.cs
├── Enums.cs
├── BulletMLLib4Unity.sln
├── bulletml.dtd
├── .gitignore
├── Emitter.cs
├── BulletMLLib4Unity.csproj
├── BulletPattern.cs
└── Bullet.cs
/externals/Equationator.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eatfrog/bulletmllib4unity/HEAD/externals/Equationator.dll
--------------------------------------------------------------------------------
/ExampleApplication/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "BulletMLSample/Content/Samples"]
2 | path = BulletMLSample/Content/Samples
3 | url = https://github.com/dmanning23/BulletMLExamples.git
4 | [submodule "externals/Equationator"]
5 | path = externals/Equationator
6 | url = https://github.com/dmanning23/Equationator.git
7 |
--------------------------------------------------------------------------------
/GameManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 |
4 | namespace BulletMLLib
5 | {
6 | ///
7 | /// This thing manages a few gameplay variables that used by the bulletml lib
8 | ///
9 | public static class GameManager
10 | {
11 | ///
12 | /// callback method to get the game difficulty.
13 | /// You need to set this at the start of the game
14 | ///
15 | static public FloatDelegate GameDifficulty;
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/PositionDelegate.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | namespace BulletMLLib
3 | {
4 | ///
5 | /// This is a callback method for getting a position
6 | /// used to break out dependencies
7 | ///
8 | /// a method to get a position.
9 | public delegate Vector2 PositionDelegate();
10 |
11 | ///
12 | /// a method to get a float from somewhere
13 | /// separate from delgates
14 | ///
15 | /// get a float from somewhere
16 | public delegate float FloatDelegate();
17 | }
18 |
--------------------------------------------------------------------------------
/Tasks/SetDirectionTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 |
4 | namespace BulletMLLib
5 | {
6 | ///
7 | /// This task sets the direction of a bullet
8 | ///
9 | public class SetDirectionTask : BulletMLTask
10 | {
11 |
12 | ///
13 | /// Initializes a new instance of the class.
14 | ///
15 | /// Node.
16 | /// Owner.
17 | public SetDirectionTask(BulletMLNode node, BulletMLTask owner) : base(node, owner)
18 | {
19 |
20 | }
21 |
22 | }
23 | }
--------------------------------------------------------------------------------
/Nodes/BulletNode.cs:
--------------------------------------------------------------------------------
1 | namespace BulletMLLib
2 | {
3 | public class BulletNode : BulletMLNode
4 | {
5 | ///
6 | /// Initializes a new instance of the class.
7 | ///
8 | public BulletNode() : this(NodeName.Bullet)
9 | {
10 | }
11 |
12 | ///
13 | /// Initializes a new instance of the class.
14 | /// this is the constructor used by sub classes
15 | ///
16 | /// the node type.
17 | public BulletNode(NodeName nodeType) : base(nodeType)
18 | {
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Tasks/SetSpeedTask.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace BulletMLLib
4 | {
5 | ///
6 | /// This action sets the velocity of a bullet
7 | ///
8 | public class SetSpeedTask : BulletMLTask
9 | {
10 | #region Methods
11 |
12 | ///
13 | /// Initializes a new instance of the class.
14 | ///
15 | /// Node.
16 | /// Owner.
17 | public SetSpeedTask(BulletMLNode node, BulletMLTask owner)
18 | : base(node, owner)
19 | {
20 |
21 | }
22 |
23 | #endregion //Methods
24 | }
25 | }
--------------------------------------------------------------------------------
/ExampleApplication/FakeEmitter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using BulletMLLib;
7 |
8 | namespace ExampleApplication
9 | {
10 | public class FakeEmitter : Emitter
11 | {
12 | IBulletManager _bulletManager;
13 | Bullet rootBullet;
14 | public FakeEmitter(IBulletManager bulletManager, BulletPattern pattern, Bullet bl) : base(bulletManager, pattern, bl)
15 | {
16 | rootBullet = bl;
17 | _bulletManager = bulletManager;
18 | }
19 |
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## BulletMLLib4Unity
2 |
3 | A fork off of https://github.com/dmanning23/BulletMLLib/ with modifications for using it with Unity2d.
4 | This is a C# library used to read BulletML XML files, based on the implementation by Keiichi Kashihara of Bandle Games.
5 |
6 | https://sites.google.com/site/bandlegames/bulletml-c
7 |
8 | ## BulletML
9 |
10 | XML schema used to define bullets, patterns, and behaviors.
11 |
12 | Based on the spec at ABA Games:
13 |
14 | http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/index_e.html
15 |
16 |
17 | ## Getting started
18 |
19 | A proper guide is coming soon. Meanwhile, check out the example application.
--------------------------------------------------------------------------------
/ExampleApplication/FakeBulletManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using BulletMLLib;
6 | using UnityEngine;
7 |
8 | namespace ExampleApplication
9 | {
10 | public class FakeBulletManager : IBulletManager
11 | {
12 | public List Bullets = new List();
13 | public Vector2 PlayerPosition(Bullet targettedBullet)
14 | {
15 | return new Vector2(0, 0);
16 | }
17 |
18 | public void RemoveBullet(Bullet deadBullet)
19 | {
20 | Console.WriteLine("Bullet removed");
21 | var b = Bullets.Single(x => x == deadBullet);
22 | b.IsActive = false;
23 | }
24 |
25 | public Bullet CreateBullet(Emitter e)
26 | {
27 | Console.WriteLine("New bullet created");
28 | var bullet = new FakeBullet(this, e);
29 | Bullets.Add(bullet);
30 | return bullet;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/IBulletManager.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 |
3 | namespace BulletMLLib
4 | {
5 | ///
6 | /// This is the interface that outisde assemblies will use to manage bullets... mostly for creating/destroying them
7 | ///
8 | public interface IBulletManager
9 | {
10 | #region Methods
11 |
12 | ///
13 | /// a mathod to get current position of the player
14 | /// This is used to target bullets at that position
15 | ///
16 | /// The position to aim the bullet at
17 | /// the bullet we are getting a target for
18 | Vector2 PlayerPosition(Bullet targettedBullet);
19 |
20 | ///
21 | /// A bullet is done being used, do something to get rid of it.
22 | ///
23 | /// the Dead bullet.
24 | void RemoveBullet(Bullet deadBullet);
25 |
26 | ///
27 | /// Create a new bullet.
28 | ///
29 | /// A shiny new bullet
30 | Bullet CreateBullet(Emitter emitter);
31 |
32 | #endregion //Methods
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/ExampleApplication/FakeBullet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using BulletMLLib;
7 |
8 | namespace ExampleApplication
9 | {
10 | public class FakeBullet : Bullet
11 | {
12 |
13 | public FakeBullet(IBulletManager myBulletManager)
14 | : base(myBulletManager)
15 | {
16 | TimeSpeed = 1;
17 | Scale = 1;
18 | }
19 |
20 |
21 | public FakeBullet(IBulletManager myBulletManager, Emitter e) : base(myBulletManager)
22 | {
23 | Emitter = e;
24 | }
25 |
26 | public bool IsActive { get; set; }
27 |
28 | public override void BulletSpawned()
29 | {
30 |
31 | Console.WriteLine("New bullet spawned. PatterName: " + Node.GetPatternName());
32 |
33 | // instantiate prefab or something..
34 | }
35 |
36 | public override float X { get; set; }
37 | public override float Y { get; set; }
38 |
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("BulletMLLib")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("BulletMLLib")]
13 | [assembly: AssemblyCopyright("")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Dan Manning
4 | Copyright (c) 2014 Henri Toivonen
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
--------------------------------------------------------------------------------
/BulletMLEquation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 |
4 | namespace BulletMLLib
5 | {
6 | ///
7 | /// This is an equation used in BulletML nodes.
8 | /// This is an eays way to set up the grammar for all our equations.
9 | ///
10 | public class BulletMLEquation : Equationator.Equation
11 | {
12 | ///
13 | /// A randomizer for getting random values
14 | ///
15 | static private readonly Random GRandom = new Random(DateTime.Now.Millisecond);
16 |
17 | public BulletMLEquation()
18 | {
19 | //add the specific functions we will use for bulletml grammar
20 | AddFunction("rand", RandomValue);
21 | AddFunction("rank", GameDifficulty);
22 | }
23 |
24 | ///
25 | /// used as a callback function in bulletml euqations
26 | ///
27 | /// The value.
28 | public float RandomValue()
29 | {
30 | //this value is "$rand", return a random number
31 | return (float)GRandom.NextDouble();
32 | }
33 |
34 | public float GameDifficulty()
35 | {
36 | //This number is "$rank" which is the game difficulty.
37 | return GameManager.GameDifficulty();
38 | }
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/Tasks/VanishTask.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace BulletMLLib
4 | {
5 | ///
6 | /// This task removes a bullet from the game.
7 | ///
8 | public class VanishTask : BulletMLTask
9 | {
10 | #region Methods
11 |
12 | ///
13 | /// Initializes a new instance of the class.
14 | ///
15 | /// Node.
16 | /// Owner.
17 | public VanishTask(BulletMLNode node, BulletMLTask owner) : base(node, owner)
18 | {
19 |
20 | }
21 |
22 | ///
23 | /// Run this task and all subtasks against a bullet
24 | /// This is called once a frame during runtime.
25 | ///
26 | /// RunStatus: whether this task is done, paused, or still running
27 | /// The bullet to update this task against.
28 | public override RunStatus Run(Bullet bullet)
29 | {
30 | //remove the bullet via the bullet manager interface
31 | IBulletManager manager = bullet.MyBulletManager;
32 |
33 | manager.RemoveBullet(bullet);
34 | return RunStatus.End;
35 | }
36 |
37 | #endregion //Methods
38 | }
39 | }
--------------------------------------------------------------------------------
/Tasks/RepeatTask.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics;
3 | using System;
4 |
5 | namespace BulletMLLib
6 | {
7 | ///
8 | /// This is a task..each task is the action from a single xml node, for one bullet.
9 | /// basically each bullet makes a tree of these to match its pattern
10 | ///
11 | public class RepeatTask : BulletMLTask
12 | {
13 |
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | /// Node.
18 | /// Owner.
19 | public RepeatTask(BulletMLNode node, BulletMLTask owner) : base(node, owner)
20 | {
21 |
22 | }
23 |
24 | ///
25 | /// Init this task and all its sub tasks.
26 | /// This method should be called AFTER the nodes are parsed, but BEFORE run is called.
27 | ///
28 | /// the bullet this dude is controlling
29 | public override void InitTask(Bullet bullet)
30 | {
31 | //Init task is being called on a RepeatTask, which means all the sequence nodes underneath this one need to be reset
32 |
33 | //Call the HardReset method of the base class
34 | HardReset(bullet);
35 | }
36 |
37 | }
38 | }
--------------------------------------------------------------------------------
/ExampleApplication/example.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 |
10 |
11 | 100
12 |
13 |
14 | 0
15 | $rank + 0.13
16 |
17 |
18 |
19 | 5
20 | $rank + 0.13
21 |
22 |
23 | 0.7 + $rank
24 |
25 |
26 | 17
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | $1
38 | 0.2
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Enums.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace BulletMLLib
7 | {
8 | ///
9 | /// Different types of bullet patterns
10 | ///
11 | public enum PatternType
12 | {
13 | Vertical,
14 | Horizontal,
15 | None
16 | }
17 |
18 | public enum NodeType
19 | {
20 | None,
21 | Aim,
22 | Absolute,
23 | Relative,
24 | Sequence
25 | };
26 |
27 | public enum NodeName
28 | {
29 | Bullet,
30 | Action,
31 | Fire,
32 | ChangeDirection,
33 | ChangeSpeed,
34 | Accel,
35 | Wait,
36 | Repeat,
37 | BulletRef,
38 | ActionRef,
39 | FireRef,
40 | Vanish,
41 | Horizontal,
42 | Vertical,
43 | Term,
44 | Times,
45 | Direction,
46 | Speed,
47 | Param,
48 | Bulletml
49 | };
50 |
51 | ///
52 | /// Theese are used for tasks during runtime...
53 | ///
54 | public enum RunStatus
55 | {
56 | Continue, //keep parsing this task
57 | End, //this task is finished parsing
58 | Stop //this task is paused
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Nodes/DirectionNode.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace BulletMLLib
3 | {
4 | public class DirectionNode : BulletMLNode
5 | {
6 | ///
7 | /// Initializes a new instance of the class.
8 | ///
9 | public DirectionNode() : base(NodeName.Direction)
10 | {
11 | //set the default type to "aim"
12 | NodeType = NodeType.Aim;
13 | }
14 |
15 | ///
16 | /// Gets or sets the type of the node.
17 | /// This is virtual so sub-classes can override it and validate their own shit.
18 | ///
19 | /// The type of the node.
20 | public override NodeType NodeType
21 | {
22 | get
23 | {
24 | return base.NodeType;
25 | }
26 | protected set
27 | {
28 | switch (value)
29 | {
30 | case NodeType.Absolute:
31 | {
32 | base.NodeType = value;
33 | }
34 | break;
35 |
36 | case NodeType.Relative:
37 | {
38 | base.NodeType = value;
39 | }
40 | break;
41 |
42 | case NodeType.Sequence:
43 | {
44 | base.NodeType = value;
45 | }
46 | break;
47 |
48 | default:
49 | {
50 | //All other node types default to aim, because otherwise they are wrong!
51 | base.NodeType = NodeType.Aim;
52 | }
53 | break;
54 | }
55 | }
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/ExampleApplication/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using BulletMLLib;
8 |
9 | namespace ExampleApplication
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | var bm = new FakeBulletManager();
16 |
17 | GameManager.GameDifficulty = () => 1f;
18 |
19 | BulletPattern pattern = new BulletPattern("../../example.xml");
20 | var fakeBullet = new FakeBullet(bm);
21 | var emitter = new FakeEmitter(bm, pattern, fakeBullet);
22 |
23 | for (int i = 0; i < 500; i++)
24 | {
25 | emitter.Update(0, 0);
26 | for (int ii = 0; ii < bm.Bullets.Count; ii++)
27 | {
28 | bm.Bullets[ii].Update();
29 | }
30 | bm.Bullets.ForEach(bullet => Console.WriteLine("X: {0} Y: {1} Aim: {2} Direction: {3}", bullet.X, bullet.Y, bullet.GetAngleTowardsPlayer(), bullet.Direction));
31 | ConsoleKeyInfo key = Console.ReadKey();
32 | if (key.Key == ConsoleKey.Q) break;
33 | else Console.WriteLine("--- Press Q for break or any other key for next step ---");
34 | }
35 | Console.WriteLine("End");
36 | Console.ReadKey();
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Nodes/ActionRefNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Xml;
3 |
4 | namespace BulletMLLib
5 | {
6 | ///
7 | /// Action reference node.
8 | /// This node type references another Action node.
9 | ///
10 | public class ActionRefNode : ActionNode
11 | {
12 | #region Members
13 |
14 | public ActionNode ReferencedActionNode { get; private set; }
15 |
16 | #endregion //Members
17 |
18 | #region Methods
19 |
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | public ActionRefNode() : base(NodeName.ActionRef)
24 | {
25 | }
26 |
27 | ///
28 | /// Validates the node.
29 | /// Overloaded in child classes to validate that each type of node follows the correct business logic.
30 | /// This checks stuff that isn't validated by the XML validation
31 | ///
32 | public override void ValidateNode()
33 | {
34 | //do any base class validation
35 | base.ValidateNode();
36 |
37 | //Find the action node this dude references
38 | BulletMLNode refNode = GetRootNode().FindLabelNode(Label, NodeName.Action);
39 |
40 | //make sure we foud something
41 | if (null == refNode)
42 | {
43 | throw new NullReferenceException("Couldn't find the action node \"" + Label + "\"");
44 | }
45 |
46 | ReferencedActionNode = refNode as ActionNode;
47 | if (null == ReferencedActionNode)
48 | {
49 | throw new NullReferenceException("The BulletMLNode \"" + Label + "\" isn't an action node");
50 | }
51 | }
52 |
53 | #endregion //Methods
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/ExampleApplication/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("ExampleApplication")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("ExampleApplication")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("ea25f36e-e299-48bf-8320-113c4d05d19d")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Nodes/FireRefNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Xml;
3 |
4 | namespace BulletMLLib
5 | {
6 | public class FireRefNode : FireNode
7 | {
8 | #region Members
9 |
10 | ///
11 | /// Gets the referenced fire node.
12 | ///
13 | /// The referenced fire node.
14 | public FireNode ReferencedFireNode { get; private set; }
15 |
16 | #endregion //Members
17 |
18 | #region Methods
19 |
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | public FireRefNode() : base(NodeName.FireRef)
24 | {
25 | }
26 |
27 | ///
28 | /// Validates the node.
29 | /// Overloaded in child classes to validate that each type of node follows the correct business logic.
30 | /// This checks stuff that isn't validated by the XML validation
31 | ///
32 | public override void ValidateNode()
33 | {
34 | //Find the action node this dude
35 |
36 | BulletMLNode refNode = GetRootNode().FindLabelNode(Label, NodeName.Fire);
37 |
38 | //make sure we foud something
39 | if (null == refNode)
40 | {
41 | throw new NullReferenceException("Couldn't find the fire node \"" + Label + "\"");
42 | }
43 |
44 | ReferencedFireNode = refNode as FireNode;
45 | if (null == ReferencedFireNode)
46 | {
47 | throw new NullReferenceException("The BulletMLNode \"" + Label + "\" isn't a fire node");
48 | }
49 |
50 | //Do not validate the base class of this dude... it will crap out trying to find the bullet node!
51 | }
52 |
53 | #endregion //Methods
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/BulletMLLib4Unity.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.30110.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BulletMLLib4Unity", "BulletMLLib4Unity.csproj", "{09435B69-7AF7-452D-8B19-984FCFFED149}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleApplication", "ExampleApplication\ExampleApplication.csproj", "{D8719284-A3FC-461F-A39F-75177FEEE55D}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0AF76397-E91A-40BA-AD4A-C38CE7E339B3}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {09435B69-7AF7-452D-8B19-984FCFFED149}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {09435B69-7AF7-452D-8B19-984FCFFED149}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {09435B69-7AF7-452D-8B19-984FCFFED149}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {09435B69-7AF7-452D-8B19-984FCFFED149}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {D8719284-A3FC-461F-A39F-75177FEEE55D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {D8719284-A3FC-461F-A39F-75177FEEE55D}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {D8719284-A3FC-461F-A39F-75177FEEE55D}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {D8719284-A3FC-461F-A39F-75177FEEE55D}.Release|Any CPU.Build.0 = Release|Any CPU
26 | EndGlobalSection
27 | GlobalSection(SolutionProperties) = preSolution
28 | HideSolutionNode = FALSE
29 | EndGlobalSection
30 | EndGlobal
31 |
--------------------------------------------------------------------------------
/bulletml.dtd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/Nodes/FireNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 |
4 | namespace BulletMLLib
5 | {
6 | public class FireNode : BulletMLNode
7 | {
8 | #region Members
9 |
10 | ///
11 | /// A bullet node this task will use to set any bullets shot from this task
12 | ///
13 | /// The bullet node.
14 | public BulletNode BulletDescriptionNode { get; set; }
15 |
16 | #endregion //Members
17 |
18 | #region Methods
19 |
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | public FireNode() : this(NodeName.Fire)
24 | {
25 | }
26 |
27 | ///
28 | /// Initializes a new instance of the class.
29 | /// this is the constructor used by sub classes
30 | ///
31 | /// the node type.
32 | public FireNode(NodeName nodeType) : base(nodeType)
33 | {
34 | }
35 |
36 | ///
37 | /// Validates the node.
38 | /// Overloaded in child classes to validate that each type of node follows the correct business logic.
39 | /// This checks stuff that isn't validated by the XML validation
40 | ///
41 | public override void ValidateNode()
42 | {
43 | base.ValidateNode();
44 |
45 | //check for a bullet node
46 | BulletDescriptionNode = GetChild(NodeName.Bullet) as BulletNode;
47 |
48 | if (null != BulletDescriptionNode) return;
49 |
50 | //make sure that dude knows what he's doing
51 | BulletRefNode refNode = GetChild(NodeName.BulletRef) as BulletRefNode;
52 | if (refNode != null)
53 | {
54 | refNode.FindMyBulletNode();
55 | BulletDescriptionNode = refNode.ReferencedBulletNode;
56 | }
57 | }
58 |
59 | #endregion Methods
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Tasks/WaitTask.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace BulletMLLib
4 | {
5 | ///
6 | /// This task pauses for a specified amount of time before resuming
7 | ///
8 | public class WaitTask : BulletMLTask
9 | {
10 | #region Members
11 |
12 | ///
13 | /// How long to run this task... measured in frames
14 | /// This task will pause until the durection runs out, then resume running tasks
15 | ///
16 | private float Duration { get; set; }
17 |
18 | #endregion //Members
19 |
20 | #region Methods
21 |
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | /// Node.
26 | /// Owner.
27 | public WaitTask(BulletMLNode node, BulletMLTask owner) : base(node, owner)
28 | {
29 | Debug.Assert(null != Node);
30 | Debug.Assert(null != Owner);
31 | }
32 |
33 | ///
34 | /// this sets up the task to be run.
35 | ///
36 | /// Bullet.
37 | protected override void SetupTask(Bullet bullet)
38 | {
39 | Duration = Node.GetValue(this);
40 | }
41 |
42 | ///
43 | /// Run this task and all subtasks against a bullet
44 | /// This is called once a frame during runtime.
45 | ///
46 | /// RunStatus: whether this task is done, paused, or still running
47 | /// The bullet to update this task against.
48 | public override RunStatus Run(Bullet bullet)
49 | {
50 | Duration -= 1.0f * bullet.TimeSpeed;
51 | if (Duration >= 0.0f)
52 | {
53 | return RunStatus.Stop;
54 | }
55 |
56 | TaskFinished = true;
57 | return RunStatus.End;
58 | }
59 |
60 | #endregion //Methods
61 | }
62 | }
--------------------------------------------------------------------------------
/Nodes/BulletRefNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Xml;
3 |
4 | namespace BulletMLLib
5 | {
6 | public class BulletRefNode : BulletNode
7 | {
8 | #region Members
9 |
10 | ///
11 | /// Gets the referenced bullet node.
12 | ///
13 | /// The referenced bullet node.
14 | public BulletNode ReferencedBulletNode { get; private set; }
15 |
16 | #endregion //Members
17 |
18 | #region Methods
19 |
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | public BulletRefNode() : base(NodeName.BulletRef)
24 | {
25 | }
26 |
27 | ///
28 | /// Validates the node.
29 | /// Overloaded in child classes to validate that each type of node follows the correct business logic.
30 | /// This checks stuff that isn't validated by the XML validation
31 | ///
32 | public override void ValidateNode()
33 | {
34 | //do any base class validation
35 | base.ValidateNode();
36 |
37 | //make sure this dude knows where his bullet node is
38 | FindMyBulletNode();
39 | }
40 |
41 | ///
42 | /// Finds the referenced bullet node.
43 | ///
44 | public void FindMyBulletNode()
45 | {
46 | if (null == ReferencedBulletNode)
47 | {
48 | //Find the action node this dude references
49 | BulletMLNode refNode = GetRootNode().FindLabelNode(Label, NodeName.Bullet);
50 |
51 | //make sure we foud something
52 | if (null == refNode)
53 | {
54 | throw new NullReferenceException("Couldn't find the bullet node \"" + Label + "\"");
55 | }
56 |
57 | ReferencedBulletNode = refNode as BulletNode;
58 | if (null == ReferencedBulletNode)
59 | {
60 | throw new NullReferenceException("The BulletMLNode \"" + Label + "\" isn't a bullet node");
61 | }
62 | }
63 | }
64 |
65 | #endregion //Methods
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | [Bb]in/
3 | [Oo]bj/
4 |
5 | # mstest test results
6 | TestResults
7 |
8 | ## Ignore Visual Studio temporary files, build results, and
9 | ## files generated by popular Visual Studio add-ons.
10 |
11 | # User-specific files
12 | *.suo
13 | *.user
14 | *.sln.docstates
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Rr]elease/
19 | test-results/
20 | x64/
21 | *_i.c
22 | *_p.c
23 | *.ilk
24 | *.meta
25 | *.obj
26 | *.pch
27 | *.pdb
28 | *.pgc
29 | *.pgd
30 | *.rsp
31 | *.sbr
32 | *.tlb
33 | *.tli
34 | *.tlh
35 | *.tmp
36 | *.log
37 | *.vspscc
38 | *.vssscc
39 | .builds
40 | *.cachefile
41 | *.userprefs
42 |
43 | # Visual C++ cache files
44 | ipch/
45 | *.aps
46 | *.ncb
47 | *.opensdf
48 | *.sdf
49 |
50 | # Visual Studio profiler
51 | *.psess
52 | *.vsp
53 | *.vspx
54 |
55 | # Guidance Automation Toolkit
56 | *.gpState
57 |
58 | # ReSharper is a .NET coding add-in
59 | _ReSharper*
60 |
61 | # NCrunch
62 | *.ncrunch*
63 | .*crunch*.local.xml
64 |
65 | # Installshield output folder
66 | [Ee]xpress
67 |
68 | # DocProject is a documentation generator add-in
69 | DocProject/buildhelp/
70 | DocProject/Help/*.HxT
71 | DocProject/Help/*.HxC
72 | DocProject/Help/*.hhc
73 | DocProject/Help/*.hhk
74 | DocProject/Help/*.hhp
75 | DocProject/Help/Html2
76 | DocProject/Help/html
77 |
78 | # Click-Once directory
79 | publish
80 |
81 | # Publish Web Output
82 | *.Publish.xml
83 |
84 | # NuGet Packages Directory
85 | packages
86 |
87 | # Windows Azure Build Output
88 | csx
89 | *.build.csdef
90 |
91 | # Windows Store app package directory
92 | AppPackages/
93 |
94 | # Others
95 | [Bb]in
96 | [Oo]bj
97 | sql
98 | TestResults
99 | [Tt]est[Rr]esult*
100 | *.Cache
101 | ClientBin
102 | [Ss]tyle[Cc]op.*
103 | ~$*
104 | *.dbmdl
105 | Generated_Code #added for RIA/Silverlight projects
106 |
107 | # Backup & report files from converting an old project file to a newer
108 | # Visual Studio version. Backup files are not needed, because we have git ;-)
109 | _UpgradeReport_Files/
110 | Backup*/
111 | UpgradeLog*.XML
112 |
--------------------------------------------------------------------------------
/Nodes/NodeFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace BulletMLLib
4 | {
5 | ///
6 | /// This is a simple class used to create different types of nodes.
7 | ///
8 | public static class NodeFactory
9 | {
10 | ///
11 | /// Given a node type, create the correct node.
12 | ///
13 | /// An instance of the correct node type
14 | /// Node type that we want.
15 | public static BulletMLNode CreateNode(NodeName nodeType)
16 | {
17 | switch (nodeType)
18 | {
19 | case NodeName.Bullet:
20 | {
21 | return new BulletNode();
22 | }
23 | case NodeName.Action:
24 | {
25 | return new ActionNode();
26 | }
27 | case NodeName.Fire:
28 | {
29 | return new FireNode();
30 | }
31 | case NodeName.ChangeDirection:
32 | {
33 | return new BulletNode(NodeName.ChangeDirection);
34 | }
35 | case NodeName.ChangeSpeed:
36 | {
37 | return new BulletNode(NodeName.ChangeSpeed);
38 | }
39 | case NodeName.Accel:
40 | {
41 | return new BulletNode(NodeName.Accel);
42 | }
43 | case NodeName.Wait:
44 | {
45 | return new BulletNode(NodeName.Wait);
46 | }
47 | case NodeName.Repeat:
48 | {
49 | return new BulletNode(NodeName.Repeat);
50 | }
51 | case NodeName.BulletRef:
52 | {
53 | return new BulletRefNode();
54 | }
55 | case NodeName.ActionRef:
56 | {
57 | return new ActionRefNode();
58 | }
59 | case NodeName.FireRef:
60 | {
61 | return new FireRefNode();
62 | }
63 | case NodeName.Vanish:
64 | {
65 | return new BulletNode(NodeName.Vanish);
66 | }
67 | case NodeName.Horizontal:
68 | {
69 | return new BulletNode(NodeName.Horizontal);
70 | }
71 | case NodeName.Vertical:
72 | {
73 | return new BulletNode(NodeName.Vertical);
74 | }
75 | case NodeName.Term:
76 | {
77 | return new BulletNode(NodeName.Term);
78 | }
79 | case NodeName.Times:
80 | {
81 | return new BulletNode(NodeName.Times);
82 | }
83 | case NodeName.Direction:
84 | {
85 | return new DirectionNode();
86 | }
87 | case NodeName.Speed:
88 | {
89 | return new BulletNode(NodeName.Speed);
90 | }
91 | case NodeName.Param:
92 | {
93 | return new BulletNode(NodeName.Param);
94 | }
95 | case NodeName.Bulletml:
96 | {
97 | return new BulletMLNode(NodeName.Bulletml);
98 | }
99 | default:
100 | {
101 | throw new Exception("Unhandled type of NodeName: \"" + nodeType.ToString() + "\"");
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/Nodes/ActionNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Xml;
3 |
4 | namespace BulletMLLib
5 | {
6 | ///
7 | /// Action node... also the base class for actionref nodes
8 | ///
9 | public class ActionNode : BulletMLNode
10 | {
11 | #region Members
12 |
13 | ///
14 | /// Gets or sets the parent repeat node.
15 | /// This is the node immediately above this one that says how many times to repeat this action.
16 | ///
17 | /// The parent repeat node.
18 | public BulletNode ParentRepeatNode { get; private set; }
19 |
20 | #endregion //Members
21 |
22 | #region Methods
23 |
24 | ///
25 | /// Initializes a new instance of the class.
26 | ///
27 | public ActionNode() : this(NodeName.Action)
28 | {
29 | }
30 |
31 | ///
32 | /// Initializes a new instance of the class.
33 | /// this is the constructor used by sub classes
34 | ///
35 | /// the node type.
36 | public ActionNode(NodeName nodeType) : base(nodeType)
37 | {
38 | }
39 |
40 | ///
41 | /// Validates the node.
42 | /// Overloaded in child classes to validate that each type of node follows the correct business logic.
43 | /// This checks stuff that isn't validated by the XML validation
44 | ///
45 | public override void ValidateNode()
46 | {
47 | //Get our parent repeat node if we have one
48 | ParentRepeatNode = FindParentRepeatNode();
49 |
50 | //do any base class validation
51 | base.ValidateNode();
52 | }
53 |
54 | ///
55 | /// Finds the parent repeat node.
56 | /// This method is not recursive, since action and actionref nodes can be nested.
57 | ///
58 | /// The parent repeat node.
59 | private BulletNode FindParentRepeatNode()
60 | {
61 | //Parent node should never ever be empty on an action node
62 | if (Parent == null )
63 | {
64 | throw new NullReferenceException("Parent node cannot be empty on an action or actionRef node");
65 | }
66 |
67 | //If the parent is a repeat node, check how many times to repeat this action
68 | if (Parent.Name == NodeName.Repeat)
69 | {
70 | return Parent as BulletNode;
71 | }
72 |
73 | //This dude is not under a repeat node
74 | return null;
75 | }
76 |
77 | ///
78 | /// Get the number of times this action should be repeated.
79 | ///
80 | /// the task to get the number of repeat times for
81 | /// The number of times to repeat this node, as specified by a parent Repeat node.
82 | public int RepeatNum(ActionTask myTask)
83 | {
84 | if (null != ParentRepeatNode)
85 | {
86 | //Get the equation value of the repeat node
87 | return (int)ParentRepeatNode.GetChildValue(NodeName.Times, myTask);
88 | }
89 | else
90 | {
91 | //no repeat nodes, just repeat it once
92 | return 1;
93 | }
94 | }
95 |
96 | #endregion //Methods
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Tasks/ChangeSpeedTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | namespace BulletMLLib
3 | {
4 | ///
5 | /// This task changes the speed a little bit every frame.
6 | ///
7 | public class ChangeSpeedTask : BulletMLTask
8 | {
9 | private float _nodeSpeed;
10 |
11 | ///
12 | /// the type of speed change, pulled out of the node
13 | ///
14 | private NodeType _changeType;
15 |
16 | ///
17 | /// How long to run this task... measured in frames
18 | ///
19 | private float Duration { get; set; }
20 |
21 | ///
22 | /// How many frames this dude has ran
23 | ///
24 | private float RunDelta { get; set; }
25 |
26 | #region Methods
27 |
28 | ///
29 | /// Initializes a new instance of the class.
30 | ///
31 | /// Node.
32 | /// Owner.
33 | public ChangeSpeedTask(BulletMLNode node, BulletMLTask owner) : base(node, owner)
34 | {
35 |
36 | }
37 |
38 | ///
39 | /// this sets up the task to be run.
40 | ///
41 | /// Bullet.
42 | protected override void SetupTask(Bullet bullet)
43 | {
44 | //set the length of time to run this dude
45 | Duration = Node.GetChildValue(NodeName.Term, this);
46 |
47 | //check for divide by 0
48 | if (Math.Abs(Duration) < 0.01)
49 | {
50 | Duration = 1.0f;
51 | }
52 |
53 | _nodeSpeed = Node.GetChildValue(NodeName.Speed, this);
54 | _changeType = Node.GetChild(NodeName.Speed).NodeType;
55 | }
56 |
57 | ///
58 | /// Run this task and all subtasks against a bullet
59 | /// This is called once a frame during runtime.
60 | ///
61 | /// RunStatus: whether this task is done, paused, or still running
62 | /// The bullet to update this task against.
63 | public override RunStatus Run(Bullet bullet)
64 | {
65 | bullet.Speed += GetSpeed(bullet);
66 |
67 | RunDelta += 1.0f * bullet.TimeSpeed;
68 | if (Duration <= RunDelta)
69 | {
70 | TaskFinished = true;
71 | return RunStatus.End;
72 | }
73 |
74 | //since this task isn't finished, run it again next time
75 | return RunStatus.Continue;
76 |
77 | }
78 |
79 | private float GetSpeed(Bullet bullet)
80 | {
81 | switch (_changeType)
82 | {
83 | case NodeType.Sequence:
84 | return _nodeSpeed;
85 | case NodeType.Relative:
86 | return _nodeSpeed / Duration;
87 |
88 | default:
89 | return ((_nodeSpeed - bullet.Speed) / (Duration - RunDelta));
90 | }
91 | }
92 |
93 | #endregion //Methods
94 | }
95 | }
--------------------------------------------------------------------------------
/ExampleApplication/ExampleApplication.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D8719284-A3FC-461F-A39F-75177FEEE55D}
8 | Exe
9 | Properties
10 | ExampleApplication
11 | ExampleApplication
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | False
44 | C:\Program Files (x86)\Unity\Editor\Data\Managed\UnityEngine.dll
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | {09435b69-7af7-452d-8b19-984fcffed149}
60 | BulletMLLib4Unity
61 |
62 |
63 |
64 |
65 |
66 |
67 |
74 |
--------------------------------------------------------------------------------
/Emitter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace BulletMLLib
7 | {
8 |
9 | ///
10 | /// The enemy, or such, that is emitting the bullets
11 | ///
12 | public class Emitter
13 | {
14 | // This is not really a bullet, but its pattern holder. needed for x, y and such, for now at least.
15 | private readonly Bullet _rootBullet;
16 | public BulletPattern Pattern { get; private set; }
17 |
18 | private readonly IBulletManager _bulletManager;
19 |
20 | public Emitter(IBulletManager bulletManager, BulletPattern pattern, Bullet rootBullet)
21 | {
22 | _bulletManager = bulletManager;
23 | Pattern = pattern;
24 | _rootBullet = rootBullet;
25 | _rootBullet.Emitter = this;
26 | InitTopNode(pattern.RootNode);
27 | }
28 |
29 | public void ClearTasks()
30 | {
31 | _rootBullet.Tasks.Clear();
32 | }
33 | public void Update(float x, float y)
34 | {
35 | _rootBullet.X = x;
36 | _rootBullet.Y = y;
37 | _rootBullet.Update();
38 | }
39 |
40 | ///
41 | /// Initialize this bullet with a top level node
42 | ///
43 | /// This is a top level node... find the first "top" node and use it to define this bullet
44 | public void InitTopNode(BulletMLNode rootNode)
45 | {
46 |
47 | //okay find the item labelled 'top'
48 | bool bValidBullet = false;
49 | BulletMLNode topNode = rootNode.FindLabelNode("top", NodeName.Action);
50 | if (topNode != null)
51 | {
52 | //initialize with the top node we found!
53 | _rootBullet.InitNode(topNode);
54 | bValidBullet = true;
55 | _rootBullet.BulletSpawned();
56 | }
57 | else
58 | {
59 | //ok there is no 'top' node, so that means we have a list of 'top#' nodes
60 | for (int i = 1; i < 10; i++)
61 | {
62 | topNode = rootNode.FindLabelNode("top" + i, NodeName.Action);
63 | if (topNode != null)
64 | {
65 | if (!bValidBullet)
66 | {
67 | //Use this bullet!
68 | _rootBullet.InitNode(topNode);
69 | bValidBullet = true;
70 | _rootBullet.BulletSpawned();
71 | }
72 | else
73 | {
74 | //Create a new bullet
75 | Bullet b = _bulletManager.CreateBullet(this);
76 |
77 | //set the position to this dude's position
78 | b.X = _rootBullet.X;
79 | b.Y = _rootBullet.Y;
80 |
81 | //initialize with the node we found
82 | b.InitNode(topNode);
83 | b.BulletSpawned();
84 | }
85 | }
86 | }
87 | }
88 |
89 | if (!bValidBullet)
90 | {
91 | //We didnt find a "top" node for this dude, remove him from the game.
92 | _bulletManager.RemoveBullet(_rootBullet);
93 | }
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Tasks/ActionTask.cs:
--------------------------------------------------------------------------------
1 | namespace BulletMLLib
2 | {
3 | ///
4 | /// An action task, this dude contains a list of tasks that are repeated
5 | ///
6 | public class ActionTask : BulletMLTask
7 | {
8 | #region Members
9 |
10 | ///
11 | /// The max number of times to repeat this action
12 | ///
13 | public int RepeatNumMax { get; private set; }
14 |
15 | ///
16 | /// The number of times this task has been run.
17 | /// This starts at 0 and the task will repeat until it hits the "max"
18 | ///
19 | public int RepeatNum { get; private set; }
20 |
21 | #endregion //Members
22 |
23 | #region Methods
24 |
25 | ///
26 | /// Initializes a new instance of the class.
27 | ///
28 | /// Node.
29 | /// Owner.
30 | public ActionTask(ActionNode node, BulletMLTask owner) : base(node, owner)
31 | {
32 |
33 | //set the number of times to repeat this action
34 | RepeatNumMax = node.RepeatNum(this);
35 | }
36 |
37 | ///
38 | /// Parse a specified node and bullet into this task
39 | ///
40 | /// the bullet this dude is controlling
41 | public override void ParseTasks(Bullet bullet)
42 | {
43 | //is this an actionref task?
44 | if (NodeName.ActionRef == Node.Name)
45 | {
46 | //add a sub task under this one for the referenced action
47 | ActionRefNode myActionRefNode = Node as ActionRefNode;
48 |
49 | //create the action task
50 | ActionTask actionTask = new ActionTask(myActionRefNode.ReferencedActionNode, this);
51 |
52 | //parse the children of the action node into the task
53 | actionTask.ParseTasks(bullet);
54 |
55 | //store the task
56 | ChildTasks.Add(actionTask);
57 | }
58 |
59 | //call the base class
60 | base.ParseTasks(bullet);
61 | }
62 |
63 | ///
64 | /// this sets up the task to be run.
65 | ///
66 | /// Bullet.
67 | protected override void SetupTask(Bullet bullet)
68 | {
69 | RepeatNum = 0;
70 | }
71 |
72 | ///
73 | /// Run this task and all subtasks against a bullet
74 | /// This is called once a frame during runtime.
75 | ///
76 | /// RunStatus: whether this task is done, paused, or still running
77 | /// The bullet to update this task against.
78 | public override RunStatus Run(Bullet bullet)
79 | {
80 | //run the action until we hit the limit
81 | while (RepeatNum < RepeatNumMax)
82 | {
83 | RunStatus runStatus = base.Run(bullet);
84 |
85 | //What was the return value from running all teh child actions?
86 | switch (runStatus)
87 | {
88 | case RunStatus.End:
89 | {
90 | //The actions completed successfully, initialize everything and run it again
91 | RepeatNum++;
92 |
93 | //reset all the child tasks
94 | foreach (BulletMLTask task in ChildTasks)
95 | {
96 | task.InitTask(bullet);
97 | }
98 | }
99 | break;
100 |
101 | case RunStatus.Stop:
102 | {
103 | //Something in the child tasks paused this action
104 | return runStatus;
105 | }
106 |
107 | default:
108 | {
109 | //One of the child tasks needs to keep running next frame
110 | return RunStatus.Continue;
111 | }
112 | }
113 | }
114 |
115 | //if it gets here, all the child tasks have been run the correct number of times
116 | TaskFinished = true;
117 | return RunStatus.End;
118 | }
119 |
120 | #endregion //Methods
121 | }
122 | }
--------------------------------------------------------------------------------
/BulletMLLib4Unity.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {09435B69-7AF7-452D-8B19-984FCFFED149}
8 | Library
9 | Properties
10 | BulletMLLib4Unity
11 | BulletMLLib4Unity
12 | v3.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 | externals\Equationator.dll
36 |
37 |
38 |
39 |
40 |
41 | C:\Program Files (x86)\Unity\Editor\Data\Managed\UnityEngine.dll
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
84 |
--------------------------------------------------------------------------------
/Tasks/AccelTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | namespace BulletMLLib
5 | {
6 | ///
7 | /// This task adds acceleration to a bullet.
8 | ///
9 | public class AccelTask : BulletMLTask
10 | {
11 | ///
12 | /// How long to run this task... measured in frames
13 | ///
14 | public float Duration { get; private set; }
15 |
16 | ///
17 | /// The direction to accelerate in
18 | ///
19 | private Vector2 _acceleration = Vector2.zero;
20 |
21 | ///
22 | /// Gets or sets the acceleration.
23 | ///
24 | /// The acceleration.
25 | public Vector2 Acceleration
26 | {
27 | get
28 | {
29 | return _acceleration;
30 | }
31 | }
32 |
33 | ///
34 | /// Initializes a new instance of the class.
35 | ///
36 | /// Node.
37 | /// Owner.
38 | public AccelTask(BulletMLNode node, BulletMLTask owner) : base(node, owner)
39 | {
40 |
41 | }
42 |
43 | ///
44 | /// this sets up the task to be run.
45 | ///
46 | /// Bullet.
47 | protected override void SetupTask(Bullet bullet)
48 | {
49 | //set the accelerataion we are gonna add to the bullet
50 | Duration = Node.GetChildValue(NodeName.Term, this);
51 |
52 | //check for divide by 0
53 | if (Math.Abs(Duration) < 0.0f)
54 | {
55 | Duration = 1.0f;
56 | }
57 |
58 | //Get the horizontal node
59 | var horiz = Node.GetChild(NodeName.Horizontal) as BulletNode;
60 | if (null != horiz)
61 | {
62 | //Set the x component of the acceleration
63 | switch (horiz.NodeType)
64 | {
65 | case NodeType.Sequence:
66 | {
67 | //Sequence in an acceleration node means "add this amount every frame"
68 | _acceleration.x = horiz.GetValue(this);
69 | }
70 | break;
71 |
72 | case NodeType.Relative:
73 | {
74 | //accelerate by a certain amount
75 | _acceleration.x = horiz.GetValue(this) / Duration;
76 | }
77 | break;
78 |
79 | default:
80 | {
81 | //accelerate to a specific value
82 | _acceleration.x = (horiz.GetValue(this) - bullet.Acceleration.x) / Duration;
83 | }
84 | break;
85 | }
86 | }
87 |
88 | //Get the vertical node
89 | BulletNode vert = Node.GetChild(NodeName.Vertical) as BulletNode;
90 | if (null == vert) return;
91 |
92 | //set teh y component of the acceleration
93 | switch (vert.NodeType)
94 | {
95 | case NodeType.Sequence:
96 | {
97 | //Sequence in an acceleration node means "add this amount every frame"
98 | _acceleration.y = vert.GetValue(this);
99 | }
100 | break;
101 |
102 | case NodeType.Relative:
103 | {
104 | //accelerate by a certain amount
105 | _acceleration.y = vert.GetValue(this) / Duration;
106 | }
107 | break;
108 |
109 | default:
110 | {
111 | //accelerate to a specific value
112 | _acceleration.y = (vert.GetValue(this) - bullet.Acceleration.y) / Duration;
113 | }
114 | break;
115 | }
116 | }
117 |
118 | ///
119 | /// Run this task and all subtasks against a bullet
120 | /// This is called once a frame during runtime.
121 | ///
122 | /// RunStatus: whether this task is done, paused, or still running
123 | /// The bullet to update this task against.
124 | public override RunStatus Run(Bullet bullet)
125 | {
126 | //Add the acceleration to the bullet
127 | bullet.Acceleration += Acceleration;
128 |
129 | //decrement the amount if time left to run and return End when this task is finished
130 | Duration -= 1.0f * bullet.TimeSpeed;
131 | if (Duration <= 0.0f)
132 | {
133 | TaskFinished = true;
134 | return RunStatus.End;
135 | }
136 |
137 | //since this task isn't finished, run it again next time
138 | return RunStatus.Continue;
139 | }
140 | }
141 | }
--------------------------------------------------------------------------------
/BulletPattern.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Xml;
4 | using System.Xml.Schema;
5 |
6 | namespace BulletMLLib
7 | {
8 | ///
9 | /// This is a complete document that describes a bullet pattern.
10 | ///
11 | public class BulletPattern
12 | {
13 | public BulletPattern(string path)
14 | {
15 | var settings = new XmlReaderSettings { ProhibitDtd = false };
16 | var reader = XmlReader.Create(path, settings);
17 | ParseXML(reader, null);
18 | }
19 | public BulletPattern(XmlReader reader)
20 | {
21 | ParseXML(reader, null);
22 | }
23 | ///
24 | /// The root node of a tree structure that describes the bullet pattern
25 | ///
26 | public BulletMLNode RootNode { get; private set; }
27 |
28 | public string Filename { get; set; }
29 |
30 | ///
31 | /// the orientation of this bullet pattern: horizontal or veritcal
32 | /// this is read in from the xml
33 | ///
34 | /// The orientation.
35 | public PatternType Orientation { get; private set; }
36 |
37 |
38 | ///
39 | /// Initializes a new instance of the class.
40 | ///
41 | public BulletPattern()
42 | {
43 | RootNode = null;
44 | }
45 |
46 | ///
47 | /// convert a string to a pattern type enum
48 | ///
49 | /// The type to name.
50 | /// String.
51 | private static PatternType StringToPatternType(string str)
52 | {
53 | return (PatternType)Enum.Parse(typeof(PatternType), str, true);
54 | }
55 |
56 | ///
57 | /// Parses a bullet pattern from a BulletML Xml file
58 | ///
59 | /// The XmlReader that contains the xmlfile. Note that if you open it as a local file the web player will not work.
60 | /// You can use WWW-requests instead.
61 | /// A callback function for when the fileparsing is completed
62 | public void ParseXML(XmlReader reader, Action callback)
63 | {
64 |
65 | try
66 | {
67 | //Open the file.
68 | XmlDocument xmlDoc = new XmlDocument();
69 | xmlDoc.Load(reader);
70 | XmlNode rootXmlNode = xmlDoc.DocumentElement;
71 |
72 | //make sure it is actually an xml node
73 | if (rootXmlNode != null && rootXmlNode.NodeType == XmlNodeType.Element)
74 | {
75 | //eat up the name of that xml node
76 | string strElementName = rootXmlNode.Name;
77 | if ("bulletml" != strElementName)
78 | {
79 | //The first node HAS to be bulletml
80 | UnityEngine.Debug.Log("Error reading \"" + "\": XML root node needs to be \"bulletml\", found \"" + strElementName + "\" instead");
81 | throw new Exception("Error reading \"" + "\": XML root node needs to be \"bulletml\", found \"" + strElementName + "\" instead");
82 | }
83 |
84 | //Create the root node of the bulletml tree
85 | RootNode = new BulletMLNode(NodeName.Bulletml);
86 |
87 | //Read in the whole bulletml tree
88 | RootNode.Parse(rootXmlNode, null);
89 |
90 | //Find what kind of pattern this is: horizontal or vertical
91 | XmlNamedNodeMap mapAttributes = rootXmlNode.Attributes;
92 | for (int i = 0; i < mapAttributes.Count; i++)
93 | {
94 | //will only have the name attribute
95 | string strName = mapAttributes.Item(i).Name;
96 | string strValue = mapAttributes.Item(i).Value;
97 | if ("type" == strName)
98 | {
99 | //if this is a top level node, "type" will be veritcal or horizontal
100 | Orientation = StringToPatternType(strValue);
101 | }
102 | }
103 | }
104 | }
105 | catch (Exception ex)
106 | {
107 | //an error ocurred reading in the tree
108 | UnityEngine.Debug.Log("Error reading." + ex.Message);
109 | throw new Exception("Error reading \"" + "\"", ex);
110 | }
111 |
112 | reader.Close();
113 |
114 | //validate that the bullet nodes are all valid
115 | try
116 | {
117 | RootNode.ValidateNode();
118 | }
119 | catch (Exception ex)
120 | {
121 | //an error ocurred reading in the tree
122 | UnityEngine.Debug.Log("Error reading \"" + "\"" + ex.Message);
123 | throw new Exception("Error reading \"" + "\"", ex);
124 | }
125 |
126 | try
127 | {
128 | UnityEngine.Debug.Log("Loading done.");
129 | }
130 | catch (Exception)
131 | {
132 | // will throw if not running unity
133 | }
134 |
135 |
136 | if (callback != null)
137 | callback();
138 | }
139 |
140 | ///
141 | /// delegate method that gets called when a validation error occurs
142 | ///
143 | /// Sender.
144 | /// Arguments.
145 | public static void MyValidationEventHandler(object sender, ValidationEventArgs args)
146 | {
147 | throw new XmlSchemaException("Error validating bulletml document: " + args.Message,
148 | args.Exception,
149 | args.Exception.LineNumber,
150 | args.Exception.LinePosition);
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/Tasks/ChangeDirectionTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace BulletMLLib
4 | {
5 | ///
6 | /// This task changes the direction a little bit every frame
7 | ///
8 | public class ChangeDirectionTask : BulletMLTask
9 | {
10 |
11 | ///
12 | /// The amount pulled out of the node
13 | ///
14 | private float NodeDirection;
15 |
16 | ///
17 | /// the type of direction change, pulled out of the node
18 | ///
19 | private NodeType ChangeType;
20 |
21 | ///
22 | /// How long to run this task... measured in frames
23 | ///
24 | private float Duration { get; set; }
25 |
26 | ///
27 | /// How many frames this dude has ran
28 | ///
29 | private float RunDelta { get; set; }
30 |
31 | ///
32 | /// Initializes a new instance of the class.
33 | ///
34 | /// Node.
35 | /// Owner.
36 | public ChangeDirectionTask(BulletMLNode node, BulletMLTask owner) : base(node, owner)
37 | {
38 |
39 | }
40 |
41 | ///
42 | /// this sets up the task to be run.
43 | ///
44 | /// Bullet.
45 | protected override void SetupTask(Bullet bullet)
46 | {
47 | RunDelta = 0;
48 |
49 | //set the time length to run this dude
50 | Duration = Node.GetChildValue(NodeName.Term, this);
51 |
52 | //check for divide by 0
53 | if (Math.Abs(Duration) < 0.01)
54 | {
55 | Duration = 1.0f;
56 | }
57 |
58 | //Get the amount to change direction from the nodes
59 | DirectionNode dirNode = Node.GetChild(NodeName.Direction) as DirectionNode;
60 | if (dirNode != null)
61 | {
62 | NodeDirection = dirNode.GetValue(this) * (float)Math.PI / 180.0f; //also make sure to convert to radians
63 |
64 | //How do we want to change direction?
65 | ChangeType = dirNode.NodeType;
66 | }
67 | }
68 |
69 | public override RunStatus Run(Bullet bullet)
70 | {
71 | //change the direction of the bullet by the correct amount
72 | bullet.Direction += GetDirection(bullet);
73 |
74 | //decrement the amount if time left to run and return End when this task is finished
75 | RunDelta += 1.0f * bullet.TimeSpeed;
76 | if (Duration <= RunDelta)
77 | {
78 | TaskFinished = true;
79 | return RunStatus.End;
80 | }
81 |
82 | //since this task isn't finished, run it again next time
83 | return RunStatus.Continue;
84 |
85 | }
86 |
87 | private float GetDirection(Bullet bullet)
88 | {
89 | //How do we want to change direction?
90 | float direction;
91 | switch (ChangeType)
92 | {
93 | case NodeType.Sequence:
94 | {
95 | //We are going to add this amount to the direction every frame
96 | direction = NodeDirection;
97 | }
98 | break;
99 |
100 | case NodeType.Absolute:
101 | {
102 | //We are going to go in the direction we are given, regardless of where we are pointing right now
103 | direction = NodeDirection - bullet.Direction;
104 | }
105 | break;
106 |
107 | case NodeType.Relative:
108 | {
109 | //The direction change will be relative to our current direction
110 | direction = NodeDirection;
111 | }
112 | break;
113 |
114 | default:
115 | {
116 | //the direction change is to aim at the enemy
117 | direction = ((NodeDirection + bullet.GetAngleTowardsPlayer()) - bullet.Direction);
118 | }
119 | break;
120 | }
121 |
122 | //keep the direction between -180 and 180
123 | direction = WrapAngle(direction);
124 |
125 | //The sequence type of change direction is unaffected by the duration
126 | if (ChangeType == NodeType.Absolute)
127 | {
128 | //divide by the amount fo time remaining
129 | direction /= Duration - RunDelta;
130 | }
131 | else if (ChangeType != NodeType.Sequence)
132 | {
133 | //Divide by the duration so we ease into the direction change
134 | direction /= Duration;
135 | }
136 |
137 | return direction;
138 | }
139 |
140 | private static float WrapAngle(float direction)
141 | {
142 | float ret = direction;
143 |
144 | //keep the direction between 0-360
145 | if (ret > 2 * Math.PI)
146 | {
147 | ret -= (float)(2 * Math.PI);
148 | }
149 | else if (ret < 0)
150 | {
151 | ret += (float)(2 * Math.PI);
152 | }
153 | return ret;
154 | }
155 |
156 | }
157 | }
--------------------------------------------------------------------------------
/Bullet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | namespace BulletMLLib
6 | {
7 | ///
8 | /// This is the bullet class that outside assemblies will interact with.
9 | /// Just inherit from this class and override the abstract functions!
10 | ///
11 | public abstract class Bullet
12 | {
13 | ///
14 | /// A bullet manager that manages this bullet.
15 | ///
16 | /// My bullet manager.
17 | private readonly IBulletManager _bulletManager;
18 |
19 | ///
20 | /// The tree node that describes this bullet. These are shared between multiple bullets
21 | ///
22 | public BulletMLNode Node { get; private set; }
23 |
24 | ///
25 | /// How fast time moves in this game.
26 | /// Can be used to do slowdown, speedup, etc.
27 | ///
28 | /// The time speed.
29 | public float TimeSpeed { get; set; }
30 |
31 | ///
32 | /// Change the size of this bulletml script
33 | /// If you want to reuse a script for a game but the size is wrong, this can be used to resize it
34 | ///
35 | /// The scale.
36 | public float Scale { get; set; }
37 |
38 | ///
39 | /// The acceleration of this bullet
40 | ///
41 | /// The accel, in pixels/frame^2
42 | public Vector2 Acceleration { get; set; }
43 |
44 | ///
45 | /// Gets or sets the speed
46 | ///
47 | /// The speed, in pixels/frame
48 | public virtual float Speed { get; set; }
49 |
50 | ///
51 | /// A list of tasks that will define this bullets behavior
52 | ///
53 | public List Tasks { get; private set; }
54 |
55 | // X/Y position
56 | public abstract float X { get; set; }
57 | public abstract float Y { get; set; }
58 |
59 | ///
60 | /// Gets my bullet manager.
61 | ///
62 | /// My bullet manager.
63 | public IBulletManager MyBulletManager
64 | {
65 | get
66 | {
67 | return _bulletManager;
68 | }
69 | }
70 |
71 | // who is firing this? Needs to be set by the implementation of CreateBullet
72 | public Emitter Emitter { get; set; }
73 |
74 |
75 | private float _direction;
76 | ///
77 | /// Gets or sets the direction.
78 | ///
79 | /// The direction in radians.
80 | public virtual float Direction
81 | {
82 | get
83 | {
84 | return _direction;
85 | }
86 | set
87 | {
88 | _direction = value;
89 |
90 | //keep the direction between 0-360
91 | if (_direction > 2 * Math.PI)
92 | {
93 | _direction -= (float)(2 * Math.PI);
94 | }
95 | else if (_direction < 0)
96 | {
97 | _direction += (float)(2 * Math.PI);
98 | }
99 | }
100 | }
101 |
102 | ///
103 | /// Convenience property to get the label of a bullet.
104 | ///
105 | /// The label.
106 | public string Label
107 | {
108 | get
109 | {
110 | return Node.Label;
111 | }
112 | }
113 |
114 | ///
115 | /// Initializes a new instance of the class.
116 | ///
117 | /// My bullet manager.
118 | protected Bullet(IBulletManager myBulletManager)
119 | {
120 | _bulletManager = myBulletManager;
121 |
122 | Acceleration = Vector2.zero;
123 |
124 | Tasks = new List();
125 |
126 | //init these to the default
127 | TimeSpeed = 1.0f;
128 | Scale = 1.0f;
129 | }
130 |
131 |
132 | ///
133 | /// This bullet is fired from another bullet, initialize it from the node that fired it
134 | ///
135 | /// Sub node that defines this bullet
136 | public void InitNode(BulletMLNode subNode)
137 | {
138 | //clear everything out
139 | Tasks.Clear();
140 |
141 | //Grab that top level node
142 | Node = subNode;
143 |
144 | //found a top num node, add a task for it
145 | BulletMLTask task = new BulletMLTask(subNode, null);
146 |
147 | //parse the nodes into the task list
148 | task.ParseTasks(this);
149 |
150 | //initialize all the tasks
151 | task.InitTask(this);
152 |
153 | Tasks.Add(task);
154 | }
155 |
156 | ///
157 | /// Update this bullet.
158 | /// If you set timespeed to consider Time.deltaTime you can update as much as you want
159 | ///
160 | public virtual void Update()
161 | {
162 | if (Emitter != null) // when emitter is gone, let the bullet fly away without further actions
163 | Tasks.ForEach(x => x.Run(this));
164 |
165 | float speed = (Speed * TimeSpeed) * Scale;
166 | X += Acceleration.x + (float)(Math.Sin(Direction) * speed);
167 | Y += Acceleration.y + (float)(-Math.Cos(Direction) * speed);
168 | }
169 |
170 | ///
171 | /// Get player direction if we're aiming towards him
172 | ///
173 | /// angle to target the bullet
174 | public float GetAngleTowardsPlayer()
175 | {
176 | Vector2 shipPos = MyBulletManager.PlayerPosition(this);
177 | return (float)Math.Atan2((shipPos.x - X), -(shipPos.y - Y));
178 | }
179 |
180 | ///
181 | /// Finds the task by label.
182 | /// This recurses into child tasks to find the taks with the correct label
183 | /// Used only for unit testing!
184 | ///
185 | /// The task by label.
186 | /// String label.
187 | public BulletMLTask FindTaskByLabel(string strLabel)
188 | {
189 | //check if any of the child tasks have a task with that label
190 | foreach (BulletMLTask childTask in Tasks)
191 | {
192 | BulletMLTask foundTask = childTask.FindTaskByLabel(strLabel);
193 | if (null != foundTask)
194 | {
195 | return foundTask;
196 | }
197 | }
198 |
199 | return null;
200 | }
201 |
202 | ///
203 | /// Given a label and name, find the task that matches
204 | ///
205 | /// The task by label and name.
206 | /// String label of the task
207 | /// The name of the node the task should be attached to
208 | public BulletMLTask FindTaskByLabelAndName(string strLabel, NodeName name)
209 | {
210 | //check if any of teh child tasks have a task with that label
211 | foreach (BulletMLTask childTask in Tasks)
212 | {
213 | BulletMLTask foundTask = childTask.FindTaskByLabelAndName(strLabel, name);
214 | if (null != foundTask)
215 | {
216 | return foundTask;
217 | }
218 | }
219 |
220 | return null;
221 | }
222 |
223 |
224 | // Needs to be run after node init
225 | public abstract void BulletSpawned();
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/Nodes/BulletMLNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Xml;
5 |
6 |
7 | namespace BulletMLLib
8 | {
9 | ///
10 | /// This is a single node from a BulletML document.
11 | /// Used as the base node for all the other node types.
12 | ///
13 | public class BulletMLNode
14 | {
15 |
16 | internal string PatternName { get; set; }
17 | public string GetPatternName()
18 | {
19 | return !String.IsNullOrEmpty(PatternName) ? PatternName : GetPatternName(this);
20 | }
21 |
22 | private static string GetPatternName(BulletMLNode n)
23 | {
24 | while (true)
25 | {
26 | if (String.IsNullOrEmpty(n.PatternName) && n.Parent != null)
27 | {
28 | n = n.Parent;
29 | continue;
30 | }
31 |
32 | return n.PatternName;
33 | break;
34 | }
35 | }
36 |
37 | ///
38 | /// The XML node name of this item
39 | ///
40 | public NodeName Name { get; private set; }
41 |
42 | ///
43 | /// The type modifier of this node... like is it a sequence, or whatever
44 | ///
45 | private NodeType _nodeType = NodeType.None;
46 |
47 |
48 | public virtual NodeType NodeType
49 | {
50 | get
51 | {
52 | return _nodeType;
53 | }
54 | protected set
55 | {
56 | _nodeType = value;
57 | }
58 | }
59 |
60 | ///
61 | /// The label of this node
62 | /// This can be used by other nodes to reference this node
63 | ///
64 | public string Label { get; protected set; }
65 |
66 | ///
67 | /// An equation used to get a value of this node.
68 | ///
69 | /// The node value.
70 | private readonly BulletMLEquation _nodeEquation = new BulletMLEquation();
71 |
72 | ///
73 | /// A list of all the child nodes for this dude
74 | ///
75 | public List ChildNodes { get; private set; }
76 |
77 | ///
78 | /// pointer to the parent node of this dude
79 | ///
80 | public BulletMLNode Parent { get; set; }
81 |
82 |
83 | ///
84 | /// Initializes a new instance of the class.
85 | ///
86 | public BulletMLNode(NodeName nodeType)
87 | {
88 | ChildNodes = new List();
89 | Name = nodeType;
90 | NodeType = NodeType.None;
91 | }
92 |
93 | ///
94 | /// Convert a string to it's NodeType enum equivalent
95 | ///
96 | /// NodeType: the nuem value of that string
97 | /// The string to convert to an enum
98 | public static NodeType StringToType(string str)
99 | {
100 | if (String.IsNullOrEmpty(str))
101 | return NodeType.None;
102 |
103 | return (NodeType)Enum.Parse(typeof(NodeType), str, true);
104 |
105 | }
106 |
107 | ///
108 | /// Convert a string to it's NodeName enum equivalent
109 | ///
110 | /// NodeName: the nuem value of that string
111 | /// The string to convert to an enum
112 | public static NodeName StringToName(string str)
113 | {
114 | return (NodeName)Enum.Parse(typeof(NodeName), str, true);
115 | }
116 |
117 | ///
118 | /// Gets the root node.
119 | ///
120 | /// The root node.
121 | public BulletMLNode GetRootNode()
122 | {
123 | //recurse up until we get to the root node
124 | return Parent != null ? Parent.GetRootNode() : this;
125 |
126 | }
127 |
128 | ///
129 | /// Find a node of a specific type and label
130 | /// Recurse into the xml tree until we find it!
131 | ///
132 | /// The label node.
133 | /// Label of the node we are looking for
134 | /// name of the node we are looking for
135 | public BulletMLNode FindLabelNode(string strLabel, NodeName name)
136 | {
137 | //this uses breadth first search, since labelled nodes are usually top level
138 |
139 | //Check if any of our child nodes match the request
140 | for (int i = 0; i < ChildNodes.Count; i++)
141 | {
142 | if ((name == ChildNodes[i].Name) && (strLabel == ChildNodes[i].Label))
143 | {
144 | return ChildNodes[i];
145 | }
146 | }
147 |
148 | //recurse into the child nodes and see if we find any matches
149 | for (int i = 0; i < ChildNodes.Count; i++)
150 | {
151 | BulletMLNode foundNode = ChildNodes[i].FindLabelNode(strLabel, name);
152 | if (null != foundNode)
153 | {
154 | return foundNode;
155 | }
156 | }
157 |
158 | //didnt find a BulletMLNode with that name :(
159 | return null;
160 | }
161 |
162 | ///
163 | /// Find a parent node of the specified node type
164 | ///
165 | /// The first parent node of that type, null if none found
166 | /// Node type to find.
167 | public BulletMLNode FindParentNode(NodeName nodeType)
168 | {
169 | //first check if we have a parent node
170 | if (null == Parent) return null;
171 | return nodeType == Parent.Name ? Parent : Parent.FindParentNode(nodeType);
172 | }
173 |
174 | ///
175 | /// Gets the value of a specific type of child node for a task
176 | ///
177 | /// The child value. return 0.0 if no node found
178 | /// type of child node we want.
179 | /// Task to get a value for
180 | public float GetChildValue(NodeName name, BulletMLTask task)
181 | {
182 | return (from tree in ChildNodes where tree.Name == name select tree.GetValue(task)).FirstOrDefault();
183 | }
184 |
185 | ///
186 | /// Get a direct child node of a specific type. Does not recurse!
187 | ///
188 | /// The child.
189 | /// type of node we want. null if not found
190 | public BulletMLNode GetChild(NodeName name)
191 | {
192 | return ChildNodes.FirstOrDefault(node => node.Name == name);
193 | }
194 |
195 | ///
196 | /// Gets the value of this node for a specific instance of a task.
197 | ///
198 | /// The value.
199 | /// Task.
200 | public float GetValue(BulletMLTask task)
201 | {
202 | //send to the equation for an answer
203 | return _nodeEquation.Solve(task.GetParamValue);
204 | }
205 |
206 | ///
207 | /// Parse the specified bulletNodeElement.
208 | /// Read all the data from the xml node into this dude.
209 | ///
210 | /// Bullet node element.
211 | ///
212 | public void Parse(XmlNode bulletNodeElement, BulletMLNode parentNode)
213 | {
214 | // Handle null argument.
215 | if (null == bulletNodeElement)
216 | {
217 | throw new ArgumentNullException("bulletNodeElement");
218 | }
219 |
220 | //grab the parent node
221 | Parent = parentNode;
222 |
223 | //Parse all our attributes
224 | XmlNamedNodeMap mapAttributes = bulletNodeElement.Attributes;
225 |
226 | for (int i = 0; i < mapAttributes.Count; i++)
227 | {
228 | string name = mapAttributes.Item(i).Name;
229 | string value = mapAttributes.Item(i).Value;
230 |
231 | if (name == "type" && Name == NodeName.Bulletml) continue;
232 |
233 | switch (name)
234 | {
235 | case "type":
236 | NodeType = StringToType(value);
237 | break;
238 | case "label":
239 | Label = value; //label is just a text value
240 | break;
241 | case "name":
242 | PatternName = value;
243 | break;
244 | }
245 |
246 | }
247 |
248 | //parse all the child nodes
249 | if (bulletNodeElement.HasChildNodes)
250 | {
251 | for (XmlNode childNode = bulletNodeElement.FirstChild;
252 | null != childNode;
253 | childNode = childNode.NextSibling)
254 | {
255 | //if the child node is a text node, parse it into this dude
256 | if (XmlNodeType.Text == childNode.NodeType)
257 | {
258 | //Get the text of the child xml node, but store it in THIS bullet node
259 | _nodeEquation.Parse(childNode.Value);
260 | continue;
261 | }
262 | if (XmlNodeType.Comment == childNode.NodeType)
263 | {
264 | //skip any comments in the bulletml script
265 | continue;
266 | }
267 |
268 | //create a new node
269 | BulletMLNode childBulletNode = NodeFactory.CreateNode(StringToName(childNode.Name));
270 |
271 | //read in the node and store it
272 | childBulletNode.Parse(childNode, this);
273 | ChildNodes.Add(childBulletNode);
274 | }
275 | }
276 | }
277 |
278 | ///
279 | /// Validates the node.
280 | /// Overloaded in child classes to validate that each type of node follows the correct business logic.
281 | /// This checks stuff that isn't validated by the XML validation
282 | ///
283 | public virtual void ValidateNode()
284 | {
285 | //validate all the childe nodes
286 | foreach (BulletMLNode childnode in ChildNodes)
287 | {
288 | childnode.ValidateNode();
289 | }
290 | }
291 | }
292 | }
293 |
--------------------------------------------------------------------------------
/Tasks/BulletMLTask.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Diagnostics;
3 | using System;
4 |
5 | namespace BulletMLLib
6 | {
7 | ///
8 | /// This is a task..each task is the action from a single xml node, for one bullet.
9 | /// basically each bullet makes a tree of these to match its pattern
10 | ///
11 | public class BulletMLTask
12 | {
13 |
14 | ///
15 | /// A list of child tasks of this dude
16 | ///
17 | public List ChildTasks { get; private set; }
18 |
19 | ///
20 | /// The parameter list for this task
21 | ///
22 | public List ParamList { get; private set; }
23 |
24 | ///
25 | /// the parent task of this dude in the tree
26 | /// Used to fetch param values.
27 | ///
28 | public BulletMLTask Owner { get; set; }
29 |
30 | ///
31 | /// The bullet ml node that this dude represents
32 | ///
33 | public BulletMLNode Node { get; private set; }
34 |
35 | ///
36 | /// whether or not this task has finished running
37 | ///
38 | public bool TaskFinished { get; protected set; }
39 |
40 | #region Methods
41 |
42 | ///
43 | /// Initializes a new instance of the class.
44 | ///
45 | /// Node.
46 | /// Owner.
47 | public BulletMLTask(BulletMLNode node, BulletMLTask owner)
48 | {
49 | if (null == node)
50 | {
51 | throw new NullReferenceException("node argument cannot be null");
52 | }
53 |
54 | ChildTasks = new List();
55 | ParamList = new List();
56 | TaskFinished = false;
57 | Owner = owner;
58 | Node = node;
59 | }
60 |
61 | ///
62 | /// Parse a specified node and bullet into this task
63 | ///
64 | /// the node for this dude
65 | /// the bullet this dude is controlling
66 | public virtual void ParseTasks(Bullet bullet)
67 | {
68 | if (null == bullet)
69 | {
70 | throw new NullReferenceException("bullet argument cannot be null");
71 | }
72 |
73 | foreach (BulletMLNode childNode in Node.ChildNodes)
74 | {
75 | ParseChildNode(childNode, bullet);
76 | }
77 | }
78 |
79 | ///
80 | /// Parse a specified node and bullet into this task
81 | ///
82 | ///
83 | /// the bullet this dude is controlling
84 | public virtual void ParseChildNode(BulletMLNode childNode, Bullet bullet)
85 | {
86 |
87 | switch (childNode.Name)
88 | {
89 | case NodeName.Repeat:
90 | {
91 |
92 | //create a placeholder bulletmltask for the repeat node
93 | RepeatTask repeatTask = new RepeatTask(childNode, this);
94 |
95 | //parse the child nodes into the repeat task
96 | repeatTask.ParseTasks(bullet);
97 |
98 | //store the task
99 | ChildTasks.Add(repeatTask);
100 | }
101 | break;
102 |
103 | case NodeName.Action:
104 | {
105 | //convert the node to an ActionNode
106 | ActionNode myActionNode = childNode as ActionNode;
107 |
108 | //create the action task
109 | ActionTask actionTask = new ActionTask(myActionNode, this);
110 |
111 | //parse the children of the action node into the task
112 | actionTask.ParseTasks(bullet);
113 |
114 | //store the task
115 | ChildTasks.Add(actionTask);
116 | }
117 | break;
118 |
119 | case NodeName.ActionRef:
120 | {
121 | //convert the node to an ActionNode
122 | ActionRefNode myActionNode = childNode as ActionRefNode;
123 |
124 | //create the action task
125 | ActionTask actionTask = new ActionTask(myActionNode, this);
126 |
127 | //add the params to the action task
128 | foreach (BulletMLNode node in childNode.ChildNodes)
129 | {
130 | actionTask.ParamList.Add(node.GetValue(this));
131 | }
132 |
133 | //parse the children of the action node into the task
134 | actionTask.ParseTasks(bullet);
135 |
136 | //store the task
137 | ChildTasks.Add(actionTask);
138 | }
139 | break;
140 |
141 | case NodeName.ChangeSpeed:
142 | {
143 | ChildTasks.Add(new ChangeSpeedTask(childNode as BulletNode, this));
144 | }
145 | break;
146 |
147 | case NodeName.ChangeDirection:
148 | {
149 | ChildTasks.Add(new ChangeDirectionTask(childNode as BulletNode, this));
150 | }
151 | break;
152 |
153 | case NodeName.Fire:
154 | {
155 | //convert the node to a fire node
156 | FireNode myFireNode = childNode as FireNode;
157 |
158 | //create the fire task
159 | FireTask fireTask = new FireTask(myFireNode, this);
160 |
161 | //parse the children of the fire node into the task
162 | fireTask.ParseTasks(bullet);
163 |
164 | //store the task
165 | ChildTasks.Add(fireTask);
166 | }
167 | break;
168 |
169 | case NodeName.FireRef:
170 | {
171 | //convert the node to a fireref node
172 | FireRefNode myFireNode = childNode as FireRefNode;
173 |
174 | //create the fire task
175 | FireTask fireTask = new FireTask(myFireNode.ReferencedFireNode, this);
176 |
177 | //add the params to the fire task
178 | for (int i = 0; i < childNode.ChildNodes.Count; i++)
179 | {
180 | fireTask.ParamList.Add(childNode.ChildNodes[i].GetValue(this));
181 | }
182 |
183 | //parse the children of the action node into the task
184 | fireTask.ParseTasks(bullet);
185 |
186 | //store the task
187 | ChildTasks.Add(fireTask);
188 | }
189 | break;
190 |
191 | case NodeName.Wait:
192 | {
193 | ChildTasks.Add(new WaitTask(childNode as BulletNode, this));
194 | }
195 | break;
196 |
197 | case NodeName.Vanish:
198 | {
199 | ChildTasks.Add(new VanishTask(childNode as BulletNode, this));
200 | }
201 | break;
202 |
203 | case NodeName.Accel:
204 | {
205 | ChildTasks.Add(new AccelTask(childNode as BulletNode, this));
206 | }
207 | break;
208 | }
209 | }
210 |
211 | ///
212 | /// This gets called when nested repeat nodes get initialized.
213 | ///
214 | /// Bullet.
215 | public virtual void HardReset(Bullet bullet)
216 | {
217 | TaskFinished = false;
218 |
219 | foreach (BulletMLTask task in ChildTasks)
220 | {
221 | task.HardReset(bullet);
222 | }
223 |
224 | SetupTask(bullet);
225 | }
226 |
227 | ///
228 | /// Init this task and all its sub tasks.
229 | /// This method should be called AFTER the nodes are parsed, but BEFORE run is called.
230 | ///
231 | /// the bullet this dude is controlling
232 | public virtual void InitTask(Bullet bullet)
233 | {
234 | TaskFinished = false;
235 |
236 | foreach (BulletMLTask task in ChildTasks)
237 | {
238 | task.InitTask(bullet);
239 | }
240 |
241 | SetupTask(bullet);
242 | }
243 |
244 | ///
245 | /// this sets up the task to be run.
246 | ///
247 | /// Bullet.
248 | protected virtual void SetupTask(Bullet bullet)
249 | {
250 | //overload in child classes
251 | }
252 |
253 | ///
254 | /// Run this task and all subtasks against a bullet
255 | /// This is called once a frame during runtime.
256 | ///
257 | /// RunStatus: whether this task is done, paused, or still running
258 | /// The bullet to update this task against.
259 | public virtual RunStatus Run(Bullet bullet)
260 | {
261 | //run all the child tasks
262 | TaskFinished = true;
263 | foreach (BulletMLTask t in ChildTasks)
264 | {
265 | //is the child task finished running?
266 | if (!t.TaskFinished)
267 | {
268 | //Run the child task...
269 | RunStatus childStatus = t.Run(bullet);
270 | if (childStatus == RunStatus.Stop)
271 | {
272 | //The child task is paused, so it is not finished
273 | TaskFinished = false;
274 | return childStatus;
275 | }
276 |
277 | if (childStatus == RunStatus.Continue)
278 | {
279 | //child task needs to do some more work
280 | TaskFinished = false;
281 | }
282 | }
283 | }
284 |
285 | return (TaskFinished ? RunStatus.End : RunStatus.Continue);
286 | }
287 |
288 | ///
289 | /// Get the value of a parameter of this task.
290 | ///
291 | /// The parameter value.
292 | /// the index of the parameter to get
293 | public float GetParamValue(int iParamNumber)
294 | {
295 | //if that task doesn't have any params, go up until we find one that does
296 | if (ParamList.Count < iParamNumber)
297 | {
298 | //the current task doens't have enough params to solve this value
299 | return null != Owner ? Owner.GetParamValue(iParamNumber) : 0.0f;
300 | }
301 |
302 | //the value of that param is the one we want
303 | return ParamList[iParamNumber - 1];
304 | }
305 |
306 | ///
307 | /// Gets the node value.
308 | ///
309 | /// The node value.
310 | public float GetNodeValue()
311 | {
312 | return Node.GetValue(this);
313 | }
314 |
315 | ///
316 | /// Finds the task by label.
317 | /// This recurses into child tasks to find the taks with the correct label
318 | /// Used only for unit testing!
319 | ///
320 | /// The task by label.
321 | /// String label.
322 | public BulletMLTask FindTaskByLabel(string strLabel)
323 | {
324 | //check if this is the corretc task
325 | if (strLabel == Node.Label)
326 | {
327 | return this;
328 | }
329 |
330 | //check if any of teh child tasks have a task with that label
331 | foreach (BulletMLTask childTask in ChildTasks)
332 | {
333 | BulletMLTask foundTask = childTask.FindTaskByLabel(strLabel);
334 | if (null != foundTask)
335 | {
336 | return foundTask;
337 | }
338 | }
339 |
340 | return null;
341 | }
342 |
343 | ///
344 | /// given a label and name, find the task that matches
345 | ///
346 | /// The task by label and name.
347 | /// String label of the task
348 | /// the name of the node the task should be attached to
349 | public BulletMLTask FindTaskByLabelAndName(string strLabel, NodeName name)
350 | {
351 | //check if this is the corretc task
352 | if ((strLabel == Node.Label) && (name == Node.Name))
353 | {
354 | return this;
355 | }
356 |
357 | //check if any of teh child tasks have a task with that label
358 | foreach (BulletMLTask childTask in ChildTasks)
359 | {
360 | BulletMLTask foundTask = childTask.FindTaskByLabelAndName(strLabel, name);
361 | if (null != foundTask)
362 | {
363 | return foundTask;
364 | }
365 | }
366 |
367 | return null;
368 | }
369 |
370 | #endregion //Methods
371 | }
372 | }
--------------------------------------------------------------------------------
/Tasks/FireTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 |
4 | namespace BulletMLLib
5 | {
6 | ///
7 | /// A task to shoot a bullet
8 | ///
9 | public class FireTask : BulletMLTask
10 | {
11 | #region Members
12 |
13 | ///
14 | /// The direction that this task will fire a bullet.
15 | ///
16 | /// The fire direction.
17 | public float FireDirection { get; private set; }
18 |
19 | ///
20 | /// The speed that this task will fire a bullet.
21 | ///
22 | /// The fire speed.
23 | public float FireSpeed { get; private set; }
24 |
25 | ///
26 | /// The number of times init has been called on this task
27 | ///
28 | /// The number times initialized.
29 | public int NumTimesInitialized { get; private set; }
30 |
31 | ///
32 | /// Flag used to tell if this is the first time this task has been run
33 | /// Used to determine if we should use the "initial" or "sequence" nodes to set bullets.
34 | ///
35 | /// true if initial run; otherwise, false.
36 | public bool InitialRun
37 | {
38 | get
39 | {
40 | return NumTimesInitialized <= 0;
41 | }
42 | }
43 |
44 | ///
45 | /// If this fire node shoots from a bullet ref node, this will be a task created for it.
46 | /// This is needed so the params of the bullet ref can be set correctly.
47 | ///
48 | /// The bullet reference task.
49 | public BulletMLTask BulletRefTask { get; private set; }
50 |
51 | ///
52 | /// The node we are going to use to set the direction of any bullets shot with this task
53 | ///
54 | /// The dir node.
55 | public SetDirectionTask InitialDirectionTask { get; private set; }
56 |
57 | ///
58 | /// The node we are going to use to set the speed of any bullets shot with this task
59 | ///
60 | /// The speed node.
61 | public SetSpeedTask InitialSpeedTask { get; private set; }
62 |
63 | ///
64 | /// If there is a sequence direction node used to increment the direction of each successive bullet that is fired
65 | ///
66 | /// The sequence direction node.
67 | public SetDirectionTask SequenceDirectionTask { get; private set; }
68 |
69 | ///
70 | /// If there is a sequence direction node used to increment the direction of each successive bullet that is fired
71 | ///
72 | /// The sequence direction node.
73 | public SetSpeedTask SequenceSpeedTask { get; private set; }
74 |
75 | #endregion //Members
76 |
77 |
78 |
79 | ///
80 | /// Initializes a new instance of the class.
81 | ///
82 | /// Node.
83 | /// Owner.
84 | public FireTask(BulletMLNode node, BulletMLTask owner) : base(node, owner)
85 | {
86 | NumTimesInitialized = 0;
87 | }
88 |
89 | ///
90 | /// Parse a specified node and bullet into this task
91 | ///
92 | /// the bullet this dude is controlling
93 | public override void ParseTasks(Bullet bullet)
94 | {
95 | if (bullet == null)
96 | {
97 | throw new NullReferenceException("bullet argument cannot be null");
98 | }
99 |
100 | foreach (BulletMLNode childNode in Node.ChildNodes)
101 | {
102 | ParseChildNode(childNode, bullet);
103 | }
104 |
105 | //Setup all the direction nodes
106 | GetDirectionTasks(this);
107 | GetDirectionTasks(BulletRefTask);
108 |
109 | //setup all the speed nodes
110 | GetSpeedNodes(this);
111 | GetSpeedNodes(BulletRefTask);
112 | }
113 |
114 | ///
115 | /// Parse a specified node and bullet into this task
116 | ///
117 | ///
118 | /// the bullet this dude is controlling
119 | public override void ParseChildNode(BulletMLNode childNode, Bullet bullet)
120 | {
121 |
122 | switch (childNode.Name)
123 | {
124 | case NodeName.BulletRef:
125 | {
126 | //Create a task for the bullet ref
127 | BulletRefNode refNode = childNode as BulletRefNode;
128 | BulletRefTask = new BulletMLTask(refNode.ReferencedBulletNode, this);
129 |
130 | //populate the params of the bullet ref
131 | foreach (BulletMLNode node in childNode.ChildNodes)
132 | {
133 | BulletRefTask.ParamList.Add(node.GetValue(this));
134 | }
135 |
136 | BulletRefTask.ParseTasks(bullet);
137 | ChildTasks.Add(BulletRefTask);
138 | }
139 | break;
140 |
141 | case NodeName.Bullet:
142 | {
143 | //Create a task for the bullet ref
144 | BulletRefTask = new BulletMLTask(childNode, this);
145 | BulletRefTask.ParseTasks(bullet);
146 | ChildTasks.Add(BulletRefTask);
147 | }
148 | break;
149 |
150 | default:
151 | {
152 | //run the node through the base class if we don't want it
153 | base.ParseChildNode(childNode, bullet);
154 | }
155 | break;
156 | }
157 | }
158 |
159 | ///
160 | /// This gets called when nested repeat nodes get initialized.
161 | ///
162 | /// Bullet.
163 | public override void HardReset(Bullet bullet)
164 | {
165 | //This is the whole point of the hard reset, so the sequence nodes get reset.
166 | NumTimesInitialized = 0;
167 |
168 | base.HardReset(bullet);
169 | }
170 |
171 | ///
172 | /// this sets up the task to be run.
173 | ///
174 | /// Bullet.
175 | protected override void SetupTask(Bullet bullet)
176 | {
177 | //get the direction to shoot the bullet
178 |
179 | //is this the first time it has ran? If there isn't a sequence node, we don't care!
180 | if (InitialRun || (SequenceDirectionTask == null))
181 | {
182 | //do we have an initial direction node?
183 | if (InitialDirectionTask != null)
184 | {
185 | //Set the fire direction to the "initial" value
186 | float newBulletDirection = InitialDirectionTask.GetNodeValue() * (float) Math.PI / 180.0f;
187 | switch (InitialDirectionTask.Node.NodeType)
188 | {
189 | case NodeType.Absolute:
190 | {
191 | //the new bullet points right at a particular direction
192 | FireDirection = newBulletDirection;
193 | }
194 | break;
195 |
196 | case NodeType.Relative:
197 | {
198 | //the new bullet direction will be relative to the old bullet
199 | FireDirection = newBulletDirection + bullet.Direction;
200 | }
201 | break;
202 |
203 | default:
204 | {
205 | //aim the bullet at the player
206 | FireDirection = newBulletDirection + bullet.GetAngleTowardsPlayer();
207 | }
208 | break;
209 | }
210 | }
211 | else
212 | {
213 | //There isn't an initial direction task, so just aim at the bad guy.
214 | //aim the bullet at the player
215 | FireDirection = bullet.GetAngleTowardsPlayer();
216 | }
217 | }
218 | else if (null != SequenceDirectionTask)
219 | {
220 | //else if there is a sequence node, add the value to the "shoot direction"
221 | FireDirection += SequenceDirectionTask.GetNodeValue() * (float)Math.PI / 180.0f;
222 | }
223 |
224 | //Set the speed to shoot the bullet
225 |
226 | //is this the first time it has ran? If there isn't a sequence node, we don't care!
227 | if (InitialRun || (null == SequenceSpeedTask))
228 | {
229 | //do we have an initial speed node?
230 | if (null != InitialSpeedTask)
231 | {
232 | //set the shoot speed to the "initial" value.
233 | float newBulletSpeed = InitialSpeedTask.GetNodeValue();
234 | switch (InitialSpeedTask.Node.NodeType)
235 | {
236 | case NodeType.Relative:
237 | {
238 | //the new bullet speed will be relative to the old bullet
239 | FireSpeed = newBulletSpeed + bullet.Speed;
240 | }
241 | break;
242 |
243 | default:
244 | {
245 | //the new bullet shoots at a predeterminde speed
246 | FireSpeed = newBulletSpeed;
247 | }
248 | break;
249 | }
250 | }
251 | else
252 | {
253 | //there is no initial speed task, use the old dude's speed
254 | FireSpeed = bullet.Speed;
255 | }
256 | }
257 | else if (null != SequenceSpeedTask)
258 | {
259 | //else if there is a sequence node, add the value to the "shoot direction"
260 | FireSpeed += SequenceSpeedTask.GetNodeValue();
261 | }
262 |
263 | //make sure the direction is between 0 and 359
264 | while (FireDirection > Math.PI)
265 | {
266 | FireDirection -= (2.0f * (float)Math.PI);
267 | }
268 | while (-Math.PI > FireDirection)
269 | {
270 | FireDirection += (2.0f * (float)Math.PI);
271 | }
272 |
273 | //make sure we don't overwrite the initial values if we aren't supposed to
274 | NumTimesInitialized++;
275 | }
276 |
277 | ///
278 | /// Run this task and all subtasks against a bullet
279 | /// This is called once a frame during runtime.
280 | ///
281 | /// RunStatus: whether this task is done, paused, or still running
282 | /// The bullet to update this task against.
283 | public override RunStatus Run(Bullet bullet)
284 | {
285 | //Create the new bullet
286 | Bullet newBullet = bullet.MyBulletManager.CreateBullet(bullet.Emitter);
287 |
288 |
289 | if (newBullet == null || newBullet.Emitter == null)
290 | {
291 | //wtf did you do???
292 | TaskFinished = true;
293 | return RunStatus.End;
294 | }
295 |
296 | //set the location of the new bullet
297 | newBullet.X = bullet.X;
298 | newBullet.Y = bullet.Y;
299 |
300 | //set the direction of the new bullet
301 | newBullet.Direction = FireDirection;
302 |
303 | //set teh speed of the new bullet
304 | newBullet.Speed = FireSpeed;
305 |
306 | //initialize the bullet with the bullet node stored in the Fire node
307 | FireNode myFireNode = Node as FireNode;
308 |
309 | if (myFireNode != null) newBullet.InitNode(myFireNode.BulletDescriptionNode);
310 | newBullet.BulletSpawned();
311 | //set the owner of all the top level tasks for the new bullet to this dude
312 | foreach (BulletMLTask task in newBullet.Tasks)
313 | {
314 | task.Owner = this;
315 | }
316 |
317 | TaskFinished = true;
318 | return RunStatus.End;
319 | }
320 |
321 | ///
322 | /// Given a node, pull the direction nodes out from underneath it and store them if necessary
323 | ///
324 | /// task to check if has a child direction node.
325 | private void GetDirectionTasks(BulletMLTask taskToCheck)
326 | {
327 | if (taskToCheck == null)
328 | return;
329 |
330 | //check if the dude has a direction node
331 | DirectionNode dirNode = taskToCheck.Node.GetChild(NodeName.Direction) as DirectionNode;
332 | if (null == dirNode) return;
333 |
334 | //check if it is a sequence type of node
335 | if (NodeType.Sequence == dirNode.NodeType)
336 | {
337 | //do we need a sequence node?
338 | if (null == SequenceDirectionTask)
339 | {
340 | //store it in the sequence direction node
341 | SequenceDirectionTask = new SetDirectionTask(dirNode, taskToCheck);
342 | }
343 | }
344 | else
345 | {
346 | //else do we need an initial node?
347 | if (null == InitialDirectionTask)
348 | {
349 | //store it in the initial direction node
350 | InitialDirectionTask = new SetDirectionTask(dirNode, taskToCheck);
351 | }
352 | }
353 | }
354 |
355 | ///
356 | /// Given a node, pull the speed nodes out from underneath it and store them if necessary
357 | ///
358 | /// Task to check.
359 | private void GetSpeedNodes(BulletMLTask taskToCheck)
360 | {
361 | if (null == taskToCheck)
362 | {
363 | return;
364 | }
365 |
366 | //check if the dude has a speed node
367 | BulletNode spdNode = taskToCheck.Node.GetChild(NodeName.Speed) as BulletNode;
368 | if (null != spdNode)
369 | {
370 | //check if it is a sequence type of node
371 | if (NodeType.Sequence == spdNode.NodeType)
372 | {
373 | //do we need a sequence node?
374 | if (SequenceSpeedTask == null)
375 | {
376 | //store it in the sequence speed node
377 | SequenceSpeedTask = new SetSpeedTask(spdNode, taskToCheck);
378 | }
379 | }
380 | else
381 | {
382 | //else do we need an initial node?
383 | if (InitialSpeedTask == null)
384 | {
385 | //store it in the initial speed node
386 | InitialSpeedTask = new SetSpeedTask(spdNode, taskToCheck);
387 | }
388 | }
389 | }
390 | }
391 |
392 | }
393 | }
--------------------------------------------------------------------------------