/// <summary> /// Helper function for creating behaviours based on strings of matching names. /// </summary> /// <param name="behaviourType">The name of the behaviour class we are creating.</param> /// <param name="fileName">The name of the file containing the behaviour definition.</param> /// <returns>The newly created behaviour.</returns> protected virtual Behaviour.Behaviour CreateBehaviourByName(String behaviourType, String fileName) { // Allow the client a chance to create non-engine behaviours. for (Int16 i = 0; i < mBehaviourCreators.Count; i++) { Behaviour.Behaviour b = mBehaviourCreators[i].CreateBehaviourByName(this, behaviourType, fileName); // Once the behaviour has been created there is no reason to continue. if (b != null) { return(b); } } switch (behaviourType) { case "MBHEngine.Behaviour.SpriteRender": { return(new MBHEngine.Behaviour.SpriteRender(this, fileName)); } case "MBHEngine.Behaviour.SimulatedPhysics": { return(new MBHEngine.Behaviour.SimulatedPhysics(this, fileName)); } case "MBHEngine.Behaviour.TileMapRender": { return(new MBHEngine.Behaviour.TileMapRender(this, fileName)); } case "MBHEngine.Behaviour.FrameRateDisplay": { return(new MBHEngine.Behaviour.FrameRateDisplay(this, fileName)); } case "MBHEngine.Behaviour.Level": { return(new MBHEngine.Behaviour.Level(this, fileName)); } case "MBHEngine.Behaviour.TileCollision": { return(new MBHEngine.Behaviour.TileCollision(this, fileName)); } case "MBHEngine.Behaviour.PathFind": { return(new MBHEngine.Behaviour.PathFind(this, fileName)); } case "MBHEngine.Behaviour.PathFollow": { return(new MBHEngine.Behaviour.PathFollow(this, fileName)); } case "MBHEngine.Behaviour.RemoveTileOnDeath": { return(new MBHEngine.Behaviour.RemoveTileOnDeath(this, fileName)); } case "MBHEngine.Behaviour.Health": { return(new MBHEngine.Behaviour.Health(this, fileName)); } case "MBHEngine.Behaviour.SpawnOnDeath": { return(new MBHEngine.Behaviour.SpawnOnDeath(this, fileName)); } case "MBHEngine.Behaviour.SimpleMomentum": { return(new MBHEngine.Behaviour.SimpleMomentum(this, fileName)); } case "MBHEngine.Behaviour.Magnetic": { return(new MBHEngine.Behaviour.Magnetic(this, fileName)); } case "MBHEngine.Behaviour.ShapeRender": { return(new MBHEngine.Behaviour.ShapeRender(this, fileName)); } case "MBHEngine.Behaviour.FaceForward": { return(new MBHEngine.Behaviour.FaceForward(this, fileName)); } case "MBHEngine.Behaviour.HealNearby": { return(new MBHEngine.Behaviour.HealNearby(this, fileName)); } default: { System.Diagnostics.Debug.Assert(false, "Attempting to create unknown behaviour type, " + behaviourType + " linked to file " + fileName + "!"); return(null); } } }
/// <summary> /// Call this to initialize an GameObject with data supplied in a file. /// </summary> /// <param name="fileName">The file to load from.</param> public virtual void LoadContent(String fileName) { // Give this object a unique id and increment the counter so that the next // object gets a unique id as well. mID = mUniqueIDCounter++; mDirection = new Direction(); mFactoryInfo = new GameObjectFactory.FactoryInfo(); mClassifications = new List <GameObjectDefinition.Classifications>(); mCollisionRectangle = new Math.Rectangle(); mRenderRectangle = new Math.Rectangle(); mTemplateFileName = fileName; if (null != fileName) { GameObjectDefinition def = GameObjectManager.pInstance.pContentManager.Load <GameObjectDefinition>(fileName); mRenderPriority = def.mRenderPriority; mDoUpdate = def.mDoUpdate; mDoRender = def.mDoRender; mPosition = def.mPosition; mRotation = def.mRotation; mScale = def.mScale; mIsStatic = def.mIsStatic; mCollisionRectangle = new Math.Rectangle(def.mCollisionBoxDimensions); mCollisionRectangle.pCenterPoint = mPosition; // Being lazy for now. Just assume that a scaler of collision box is big enough to always show character. mRenderRectangle = new Math.Rectangle(def.mCollisionBoxDimensions * 4f); mRenderRectangle.pCenterPoint = mPosition; mMotionRoot = def.mMotionRoot; if (def.mCollisionRoot == null) { mCollisionRoot = Vector2.Zero; } else { mCollisionRoot = def.mCollisionRoot; } for (Int32 i = 0; def.mClassifications != null && i < def.mClassifications.Count; i++) { mClassifications.Add(def.mClassifications[i]); } mBlendMode = def.mBlendMode; for (Int32 i = 0; i < def.mBehaviourFileNames.Count; i++) { String goRootPath = System.IO.Path.GetDirectoryName(fileName); Behaviour.Behaviour temp = CreateBehaviourByName(def.mBehaviourClassNames[i], goRootPath + "\\Behaviours\\" + def.mBehaviourFileNames[i]); mBehaviours.Add(temp); } } else { mRenderPriority = 50; mDoUpdate = true; mDoRender = true; mBlendMode = GameObjectDefinition.BlendMode.STANDARD; } }
/// <summary> /// Attaches an already exisiting behaviour to this game object. This is handy for manually /// creating GameObjects, instead of through the usually xml definitions. /// </summary> /// <param name="b">The behaviour to attach.</param> public virtual void AttachBehaviour(Behaviour.Behaviour b) { // Add the behaviour to the list of behaviours. mBehaviours.Add(b); }
/// <summary> /// Must be called once every update to check which objects are being picked. /// </summary> /// <param name="gameTime"></param> /// <param name="showDebugInfo">True if debug information should be shown this frame.</param> public void Update(GameTime gameTime, Boolean showDebugInfo) { #if DEBUG // Get the current state of the mouse. MouseState ms = Mouse.GetState(); // Only count mouse clicks that happen after the button was previously released. Boolean clickChanged = (mPreviousMouseState.LeftButton != ms.LeftButton); // Temp storing which object the mouse is currently over top of (if any). GameObject mousedObject = null; const String dbgLayer = "GameObjectPicker"; // If while hovering over an object, the user presses the mouse button, that object // not becomes the new "selected" object. if (ms.LeftButton == ButtonState.Pressed && clickChanged) { // Project that mouse position into 2D world space so that it can be tested for collision. Vector2 proj = CameraManager.pInstance.ProjectMouseToWorldSpace(new Vector2(ms.X, ms.Y)); // Reposition the collision rect of the mouse pointer to the position of the actual // mouse in world space. mMouseRect.pCenterPoint = proj; // Clear any objects that might still be stored from the previous frame. mCollidedObjects.Clear(); // Check if any objects are colliding with the mouse. // NOTE: This is a really expensive call right now, so we don't want to be doing // it every frame. Instead we only do it when you click. GameObjectManager.pInstance.GetGameObjectsInRange(mMouseRect, ref mCollidedObjects); // Did the mouse actually collide with any objects? if (mCollidedObjects.Count > 0) { // We just use index 0 for now. Eventually we might need to determine some sort // of sorting order, perhaps based on rect size, or render order. mousedObject = mCollidedObjects[0]; if (mousedObject != mSelectedGameObject) { DebugMessageDisplay.pInstance.pCurrentTag = dbgLayer; mSelectedGameObject = mousedObject; } else { DebugMessageDisplay.pInstance.pCurrentTag = null; // If they click the same object which is already selected, consider that an // attempt to unselect the GameObject. mSelectedGameObject = null; } } } else { // If the user clicks while not over any GameObject, unselect the currently selected. if (ms.LeftButton == ButtonState.Pressed && clickChanged) { DebugMessageDisplay.pInstance.pCurrentTag = null; mSelectedGameObject = null; } } #if ALLOW_GARBAGE /* Removing this functionality for now because it is too expensive to search for collisions with * every object in the world, every frame. * * // Display some information about the object we are hovering over. * // * if (null != mousedObject) * { * DebugMessageDisplay.pInstance.AddDynamicMessage("Picked GO (over): " + mousedObject.pID); * DebugShapeDisplay.pInstance.AddAABB(mousedObject.pCollisionRect, Color.Orange); * } * else * { * DebugMessageDisplay.pInstance.AddDynamicMessage("Picked GO (over): --"); * } */ // The Behaviour and GameObject classes expose a bunch of debug information through the GetDebugInfo // functions. If there is an object currently selected, we want to get that info about the selected // object and print it on screen for real-time debugging. if (null != mSelectedGameObject && showDebugInfo) { // So the user knows what is going on, highlight the object. DebugShapeDisplay.pInstance.AddAABB(mSelectedGameObject.pCollisionRect, Color.Red); // The the GameObject debug info. Every GameObject has this. String [] goInfo = mSelectedGameObject.GetDebugInfo(); // Print the class name and the info. DebugMessageDisplay.pInstance.AddDynamicMessage(mSelectedGameObject.GetType().ToString(), dbgLayer); for (Int32 i = 0; i < goInfo.Length; i++) { DebugMessageDisplay.pInstance.AddDynamicMessage(" - " + goInfo[i], dbgLayer); } // Loop through every Behaviour attached to this GameObject and call the corisponding // GetDebugInfo functions. for (Int32 i = 0; i < mSelectedGameObject.pBehaviours.Count; i++) { Behaviour.Behaviour b = mSelectedGameObject.pBehaviours[i]; // Show the behaviour even if the GetDebugInfo isn't implmented for it since we // may just want to know which behaviours it has.5 DebugMessageDisplay.pInstance.AddDynamicMessage(b.GetType().ToString(), dbgLayer); String [] dbgInfo = b.GetDebugInfo(); // Not every Behaviour overrides the GetDebugInfo function. In those cases the // default implementation will return null. if (null != dbgInfo) { for (Int32 j = 0; j < dbgInfo.Length; j++) { DebugMessageDisplay.pInstance.AddDynamicMessage(" - " + dbgInfo[j], dbgLayer); } } } } #endif // ALLOW_GARBAGE // Update the previous state with the current state. mPreviousMouseState = Mouse.GetState(); #endif // DEBUG }