Skip to content

Flocking Behaviour

zjy edited this page Jul 13, 2016 · 1 revision

Flocking Behaviour

  • 每次汇聚到战旗之后一起再运动会很怪,直接给所有单位一个方向让他们flocking运动好了
  • 单位的转向根据团队的速度,不然个体的速度参差不齐,转向会很乱

#代码

Boid.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class Boid : MonoBehaviour
{

    public BoidMgr mgr;
    public float delay;
    public float maxVelocity = 10.0f;
    public float maxVelocityAdd;
    void Start()
    {
        mgr = FindObjectOfType<BoidMgr>();
        delay = UnityEngine.Random.Range(.1f, 1.0f);
        maxVelocity = 10.0f;
        maxVelocityAdd = 0f;
    }
    
    public Vector3 velocity;
    public Vector3 steering;
    public Vector3 cohesion;
    public Vector3 speration;
    void Update()
    {
        if ((delay -= Time.deltaTime) > 0) return;

        velocity = mgr.dir * 10.0f;

        steering = Vector3.zero;

        //QuickLastOne(mgr.boids);

        flocking(mgr.boids, out  cohesion, out  speration);
        steering += (cohesion + speration);

        velocity = truncate(velocity + steering, maxVelocity * (1.0f + maxVelocityAdd));
        transform.position += velocity * Time.deltaTime;

        if (maxVelocityAdd > 0f) maxVelocityAdd -= (.1f * Time.deltaTime);
    }

    void OnDrawGizmos()
    {
        // Draw a yellow sphere at the transform's position
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(transform.position, 1);

        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(transform.position, 3);
    }


    public int tooclose_neighborCount;
    public int tooaway_neighbourCount;
    public void flocking(List<Boid> boids, out Vector3 cohesion, out Vector3 speration)
    {
        cohesion = Vector3.zero;
        speration = Vector3.zero;

        tooclose_neighborCount = 0;

        tooaway_neighbourCount = 0;

        foreach (Boid item in boids)
        {
            ///离自己太远的
            //self radius + tolerate radius
            if (item != this && Vector3.SqrMagnitude(item.transform.position - transform.position) > (3.0f * 3.0f))
            {
                cohesion += item.transform.position;
                tooaway_neighbourCount++;
            }

            //self radius + neighbour radius
            if (item != this && Vector3.SqrMagnitude(item.transform.position - transform.position) < (2.0f * 2.0f))
            {
                speration += item.transform.position - transform.position;

                tooclose_neighborCount++;
            }
        }

        if (tooclose_neighborCount != 0)
        {
            speration = ((speration / tooclose_neighborCount) * -1.0f).normalized;
        }
        else
        {
            speration = Vector3.zero;
        }
           
        
        ///全都远离你?
        if (tooaway_neighbourCount > 5)
        {
            maxVelocityAdd = 0.1f;
            cohesion = ((cohesion / tooaway_neighbourCount) - transform.position).normalized * (1 + maxVelocityAdd);
        }
        else
        {
            cohesion = Vector3.zero;
        }
    }



    #region util
    public Vector3 truncate(Vector3 vector, float  max)
    {
        float rate = vector.magnitude / max;
        return rate <= 1.0f ? vector : vector.normalized * max;       
    }
    #endregion
}

BoidMgr.cs

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
public class BoidMgr : MonoBehaviour
{

    public List<Boid> boids;

    public Vector3 dir;

    void Start()
    {
        boids = FindObjectsOfType<Boid>().ToList();
        dir = Vector3.right;
    }

    public enum Dir
    {
        left,
        right,
        up,
        down,
        left_up,
        left_down,
        right_up,
        right_down
    }

    void OnGUI()
    {
        for (int i = 0; i < 8; i++)
        {
            if (GUI.Button(new Rect(10 + i * 60, 10, 50, 40), ((Dir)i).ToString()))
            {
                Dir curDir = (Dir)i;

                switch (curDir)
                {
                    case Dir.left: dir = Vector3.left;
                        break;
                    case Dir.right: dir = Vector3.right;
                        break;
                    case Dir.up: dir = Vector3.up;
                        break;
                    case Dir.down: dir = Vector3.down;
                        break;
                    case Dir.left_up: dir = (Vector3.left + Vector3.up);
                        break;
                    case Dir.left_down: dir = (Vector3.left + Vector3.down);
                        break;
                    case Dir.right_up: dir = (Vector3.right + Vector3.up);
                        break;
                    case Dir.right_down: dir = (Vector3.right + Vector3.down);
                        break;
                    default:
                        break;
                }
            }
        }
    }
}

#参考文献

  • local-avoidance

  • steering-behaviors

  • flocking-behaviors

    public function computeAlignment(myAgent:Agent):Point { var v:Point = new Point(); var neighborCount = 0; for each (var agent:Agent in agentArray) { if (agent != myAgent) { if (myAgent.distanceFrom(agent) < 300) { v.x += agent.velocity.x; v.y += agent.velocity.y; neighborCount++;

      	    }
    
      	}
      }
    
      if (neighborCount == 0) return v;
    
      v.x /= neighborCount;
      v.y /= neighborCount;
      v.normalize(1);
      return v;
    

    }


v.x += agent.x;
v.y += agent.y;

if (neighborCount == 0) return v;
v.x /= neighborCount;
v.y /= neighborCount;
v = new Point(v.x - myAgent.x, v.y - myAgent.y);
v.normalize(1);
return v;

v.x += agent.x - myAgent.x;
v.y += agent.y - myAgent.y;

if (neighborCount == 0) return v;
v.x /= neighborCount;
v.y /= neighborCount;
v.x *= -1;
v.y *= -1;
v.normalize(1);
return v;

#示例工程

Clone this wiki locally