当精灵在AI的一定距离内时,如何让AI跟随精灵

How to make AI follow the sprite, when the sprite is within a certain distance of AI

我在这里要达到的目的是当白球(精灵)在一定距离内向黑球(AI)移动时,黑球将跟随白球。

我做到了让AI自动走向精灵,但我不知道当只有精灵在一定距离内时该怎么做。

主游戏class

这是主游戏class

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System.IO;

namespace PickUpTheCrewGame
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class PickUpTheCrewGame : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        SpriteFont messageFont;
        Texture2D backgroundTexture;
        Rectangle backgroundRectangle;
        Sprite BlueBall;
        Sprite GreenBall;
        Sprite OrangeBall;
        Sprite PinkBall;
        Sprite RedBall;
        Sprite c;
        Sprite YellowBall;

        //---player scores
        int playerScore = 0;


        //List<Sprite> sprite = new List<Sprite>();
        List<sharks> sharks = new List<sharks>();
        List<Sprite> crew = new List<Sprite>();
        //Sprite Background;


        public PickUpTheCrewGame()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            //sreen size
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            //enable the mousepointer
            IsMouseVisible = true;
            base.Initialize();
        }

        public void Save(string filename)
        {
            System.IO.TextWriter textOut = null;
            try
            {
                textOut = new System.IO.StreamWriter(filename);
                Save(textOut);
            }
            catch (Exception e)
            {
                throw e;
            }
            finally
            {
                if (textOut != null) textOut.Close();
            }
        }

        private void Save(TextWriter textOut)
        {
            try
            {
                foreach (Sprite crew1 in crew)
                {
                    textOut.WriteLine(crew1.location.X);
                    textOut.WriteLine(crew1.location.Y);

                }

                foreach (sharks enemySprite in sharks)
                {
                    textOut.WriteLine("Shark");
                    textOut.WriteLine(enemySprite.location.X);
                    textOut.WriteLine(enemySprite.location.Y);
                }
            }
            catch
            {

            }
        }

        public void Load(string filename)
        {
            System.IO.TextReader textIn = null;
            //try
            //{
                textIn = new System.IO.StreamReader(filename);
                Load(textIn);
            //}
            //catch (Exception e)
            //{
            //    throw e;
            //}
            //finally
            //{
                if (textIn != null) textIn.Close();
            //}
        }

        private void Load(TextReader textIn)
        {
            foreach (Sprite crew1 in crew)
            {

                crew1.location.X = int.Parse(textIn.ReadLine());
                crew1.location.Y = int.Parse(textIn.ReadLine());

            }
            foreach (sharks enemySprite in sharks)
            {
               enemySprite.location.X = int.Parse(textIn.ReadLine());
                enemySprite.location.Y = int.Parse(textIn.ReadLine());

            }
            throw new NotImplementedException();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            backgroundTexture = Content.Load<Texture2D>("Background");
            backgroundRectangle = new Rectangle(
             0, 0, // top left hand corner
             Window.ClientBounds.Width,
             Window.ClientBounds.Height); // size of screen display



            //-------Captains crew-------

            c = new Sprite(new Vector2(0, 0), new Vector2(0, 0),
                  Content.Load<Texture2D>("WhiteBall"), Color.White);

            BlueBall = new Sprite(new Vector2(640, 450),
                Content.Load<Texture2D>("BlueBall"));
            crew.Add(BlueBall);

            GreenBall = new Sprite(new Vector2(250, 600),
                Content.Load<Texture2D>("GreenBall"));
            crew.Add(GreenBall);

            OrangeBall = new Sprite(new Vector2(115, 400),
                Content.Load<Texture2D>("OrangeBall"));
            crew.Add(OrangeBall);

            RedBall = new Sprite(new Vector2(500, 600),
                Content.Load<Texture2D>("RedBall"));
            crew.Add(RedBall);

            YellowBall = new Sprite(new Vector2(800, 400),
                Content.Load<Texture2D>("YellowBall"));
            crew.Add(YellowBall);

            PinkBall = new Sprite(new Vector2(25, 175),
                Content.Load<Texture2D>("PinkBall"));
            crew.Add(PinkBall);

            //--------Sharks------
            sharks s = new sharks(new Vector2(1000, 200),
                Content.Load<Texture2D>("BlackBall"));
            sharks.Add(s);
            s = new sharks(new Vector2(900, 200),
                Content.Load<Texture2D>("BlackBall"));
            sharks.Add(s);
            s = new sharks(new Vector2(800, 200),
                Content.Load<Texture2D>("BlackBall"));
            sharks.Add(s);



            messageFont = Content.Load<SpriteFont>("messageFont");


            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to `enter code here`unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {

            //----------This gets the time value---------
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            //--------------keyboard input---------------
            //Exit
            if (Keyboard.GetState().IsKeyDown(Keys.Back))
                this.Exit();
            //Save
            if (Keyboard.GetState().IsKeyDown(Keys.S))
                Save("test.txt");
            //Load
            if (Keyboard.GetState().IsKeyDown(Keys.L))
                Load("test.txt");

            //Directional Movement
            if (Keyboard.GetState().IsKeyDown(Keys.Left))
                c.velocity.X = -350;

            if (Keyboard.GetState().IsKeyDown(Keys.Right))
                c.velocity.X = 350;

            if (Keyboard.GetState().IsKeyDown(Keys.Down))
                c.velocity.Y = 350;

            if (Keyboard.GetState().IsKeyDown(Keys.Up))
                c.velocity.Y = -350;

            c.Update(elapsed);
            foreach (Sprite cr in crew)
            {
                cr.Update(elapsed);
            }


            c.col = Color.White;

            //----sharks intersects with whiteball----
            foreach (sharks s in sharks)
            {
                if (c.bounds.Intersects(s.bounds))
                {
                    c.col = Color.Red;
                    break;
                }
            }

            foreach (sharks s in sharks)
            {
                s.Update(elapsed, c.location);
            }

            //----sprites intersect with whiteball----
            foreach (Sprite crew1 in crew)
            {
                if (c.bounds.Intersects(crew1.bounds))
                {
                    c.col = Color.Red;
                    playerScore += 1;
                    crew1.bounds.X = 10000;
                    crew1.bounds.Y = 10000;
                    crew1.location.Y = 10000;
                    crew1.location.X = 10000;
                    break;
                }

            }

            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();
            spriteBatch.Draw(backgroundTexture, backgroundRectangle,
 Color.White);


            //Background.Draw(spriteBatch);
            c.Draw(spriteBatch);
            foreach (Sprite cr in crew)
            {
                cr.Draw(spriteBatch);
            }


            foreach (sharks s in sharks)
            {
                s.Draw(spriteBatch);
            }
            //---------messsage font succussfully saved----------

            spriteBatch.DrawString(messageFont, playerScore.ToString(),
                new Vector2(145, 0),
                Color.White);

            spriteBatch.DrawString(messageFont, " Player Scores",
                new Vector2(0, 0), Color.White);


            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

雪碧class

Sprite class 控制动作,限制一切

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace PickUpTheCrewGame
{
    class Sprite
    {
        public Vector2 location;
        public Vector2 velocity;//this hold the sprite movement
        public Texture2D image;
        public Rectangle bounds;//inventing the boundaries using rectange variable
        public Color col = Color.White;
        int maxVel = 600;


        public Sprite(Vector2 location, Texture2D image, Color clr)
        {
            this.location = location;
            this.image = image;
            this.col = clr;
            //----setting the boundaries of the screen to match the window-----
            bounds = new Rectangle((int)location.X, (int)location.Y, 64, 64);

        }
        public Sprite(Vector2 location, Texture2D image)
        {
            this.location = location;
            this.image = image;

            //----setting the boundaries of the screen to match the window-----
            bounds = new Rectangle((int)location.X, (int)location.Y, 64, 64);

        }

        public Sprite(Vector2 location,Vector2 vel, Texture2D image, Color clr)
        {
            this.location = location;
            this.velocity = vel;
            this.image = image;
            this.col = clr;
            //----setting the boundaries of the screen to match the window-----
            bounds = new Rectangle((int)location.X, (int)location.Y, 64, 64);

        }
        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(image, location, col);
        }

        public void Update(float elapsed)
        {
            //----sets the speed for the players----
            location += velocity * elapsed;



            //-------initialising the boundaries for the screen-----
            bounds.X = (int)location.X;
            bounds.Y = (int)location.Y;

            //--------Posotive velocity---------
            if (velocity.X > maxVel)
                velocity.X = maxVel;

            if (velocity.Y > maxVel)
                velocity.Y = maxVel;

            //----Negative velocity-------
            if (velocity.X < -maxVel)
                velocity.X = -maxVel;

            if (velocity.Y < -maxVel)
                velocity.Y = -maxVel;

            //------adding friction to the AI------
            velocity = velocity * 0.9f;

            //-------Assigning the boundaries-----
            if (bounds.Left < 0)
                location.X = 0;

            if (bounds.Top < 0)
                location.Y = 0;

            if (bounds.Right > 1280)
                location.X = 1280 - bounds.Width;

            if (bounds.Bottom > 720)
                location.Y = 720 - bounds.Height;
        }
        public void Accelerate(Vector2 direction)
        {
            //-----normalises is to get a unit vector (40 is force), normal is direction
            velocity += 15 * Vector2.Normalize(direction);
        }

    }
}

AI class

简单的敌人精灵(AI)class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;


namespace PickUpTheCrewGame
{
    class sharks:Sprite
    {
        public sharks(Vector2 location, Texture2D image)
            :base(location,image)
        {

        }
        public void Update(float elapsed, Vector2 playerLoc)
        {
            Accelerate(playerLoc - location);//should make the ai go towards the player all the time

            base.Update(elapsed);
        }
    }
}

你可以通过减去它们的位置向量来检查白球和黑球之间的距离。这给你一个向量,代表你的两个球之间的 "gap"。

你已经这样做了(当你调用 Accelerate 时)来获得方向。如果你想要距离,只需通过减法得到那个Vector2的Lenght:它实际上是2个球之间的距离。

设置此距离条件(在我的示例中为 SharkVision),只有当距离低于 SharkVision 时,您的鲨鱼才会移动。调整 SharkVision 以获得最适合您的结果。

class sharks:Sprite
{
    public const float SharkVision = 500f;
    ...
    public void Update(float elapsed, Vector2 playerLoc)
    {
        if ((playerLoc - location).Length() < SharkVision) 
            Accelerate(playerLoc - location);

        base.Update(elapsed);
    }
}

带有模式的演示

在此图像中,"a" 是白球的位置向量,"b" 是黑球的位置向量。 如果减去它们,您将获得向量 "a-b"。它的长度等于两个球之间的距离,它的方向给了你移动的方向。

警告:减法的方向可以反转移动的方向。总是这样做:destinationLocation - startLocation