(你好,對不起,如果這是一個非常愚蠢的問題。我不擅長編碼,我可能不明白我在做什么)
我在 Unity 3D 上做 boids,我試圖在一個正方形區域中阻止它們。因此,我添加了 Forces,如果它們在 x 軸上移動很遠,另一個在 z 軸上。 但是我不明白如何產生一個力,這樣它們就不會在 -x 和 -z 軸上走得太遠。我如何扭轉力量,使那些小蟲留在我的區域內?
這是我的 x 和 z 邊界:
//Force x
float distX = Mathf.Max(0, transform.position.x);
if (distX > 20)
{
float forceReject = Mathf.Clamp(5, 1.0f - (distX / 2), 2) * forceRejectGround;
sumForces = new Vector3(-forceReject, 0, 0);
}
//Force z
float distZ = Mathf.Max(0, transform.position.z);
if (distZ > 20)
{
float forceReject = Mathf.Clamp(5, 1.0f - (distZ / 2), 2) * -forceRejectGround;
sumForces = new Vector3(0, 0, forceReject);
}
這是整個代碼,因為有人問過它(但抱歉是法語)
public class Boid : MonoBehaviour
{
public float zoneRepulsion = 2;
public float zoneAlignement = 9;
public float zoneAttraction = 30;
public float hauteurSol = 0;
public float forceRepulsion = 15;
public float forceAlignement = 3;
public float forceAttraction = 20;
public float forceRejetSol = 100;
public Vector3 target = new Vector3();
public float forceTarget = 15;
public bool goToTarget = false;
public bool stopToTarget = false;
private bool atTarget = false;
public Vector3 velocity = new Vector3();
public float maxSpeed = 10;
public float minSpeed = 5;
public bool drawGizmos = true;
public bool drawLines = true;
// Update is called once per frame
void Update()
{
Vector3 sumForces = new Vector3();
Color colorDebugForce = Color.black;
float nbForcesApplied = 0;
foreach (Boid otherBoid in BoidManager.sharedInstance.roBoids)
{
Vector3 vecToOtherBoid = otherBoid.transform.position - transform.position;
Vector3 forceToApply = new Vector3();
//Si on doit prendre en compte cet autre boid (plus grande zone de perception)
if (vecToOtherBoid.sqrMagnitude < zoneAttraction * zoneAttraction)
{
//Si on est entre attraction et alignement
if (vecToOtherBoid.sqrMagnitude > zoneAlignement * zoneAlignement)
{
//On est dans la zone d'attraction uniquement
forceToApply = vecToOtherBoid.normalized * forceAttraction;
float distToOtherBoid = vecToOtherBoid.magnitude;
float normalizedDistanceToNextZone = ((distToOtherBoid - zoneAlignement) / (zoneAttraction - zoneAlignement));
float boostForce = (4 * normalizedDistanceToNextZone);
if (!goToTarget) //Encore plus de cohésion si pas de target
boostForce *= boostForce;
forceToApply = vecToOtherBoid.normalized * forceAttraction * boostForce;
colorDebugForce = Color.green;
}
else
{
//On est dans alignement, mais est on hors de répulsion ?
if (vecToOtherBoid.sqrMagnitude > zoneRepulsion * zoneRepulsion)
{
//On est dans la zone d'alignement uniquement
forceToApply = otherBoid.velocity.normalized * forceAlignement;
colorDebugForce = Color.blue;
}
else
{
//On est dans la zone de repulsion
float distToOtherBoid = vecToOtherBoid.magnitude;
float normalizedDistanceToPreviousZone = 1 - (distToOtherBoid / zoneRepulsion);
float boostForce = (4 * normalizedDistanceToPreviousZone);
forceToApply = vecToOtherBoid.normalized * -1 * (forceRepulsion * boostForce);
colorDebugForce = Color.red;
}
}
sumForces = forceToApply;
nbForcesApplied ;
}
}
//On fait la moyenne des forces, ce qui nous rend indépendant du nombre de boids
sumForces /= nbForcesApplied;
//On ajoute le rejet du sol
float distSol = Mathf.Max(0,transform.position.y - hauteurSol);
if (distSol < 2)
{
float forceRejet = Mathf.Pow(1.0f - (distSol / 2), 2) * forceRejetSol;
sumForces = new Vector3(0, forceRejet, 0);
}
//Rejet du plafond
float distPlaf = Mathf.Max(5, transform.position.y);
if (distPlaf > 10)
{
float forceRejet = Mathf.Clamp(5, 1.0f - (distPlaf / 2), 2) * -forceRejetSol;
sumForces = new Vector3(0, forceRejet, 0);
}
//Rejet pour la limite d' x
float distX = Mathf.Max(0, transform.position.x);
if (distX > 20)
{
float forceRejet = Mathf.Clamp(5, 1.0f - (distX / 2), 2) * forceRejetSol;
sumForces = new Vector3(-forceRejet, 0, 0);
}
//Rejet pour la limite de -x
if (distX < -15)
{
float forceRejetXNeg = Mathf.Clamp(5, 1.0f - (distX / 2), 2) * forceRejetSol;
sumForces = new Vector3(forceRejetXNeg, 0, 0);
}
//Rejet pour la limite d' z
float distZ = Mathf.Max(0, transform.position.z);
if (distZ > 20)
{
float forceRejet = Mathf.Clamp(5, 1.0f - (distZ / 2), 2) * -forceRejetSol;
sumForces = new Vector3(0, 0, forceRejet);
}
//Rejet pour la limite de -z
if (distZ < -15)
{
float forceRejetZNeg = Mathf.Clamp(5, 1.0f - (distZ / 2), 2) * -forceRejetSol;
sumForces = new Vector3(0, 0, forceRejetZNeg);
}
//Si on a une target, on l'ajoute
float distToTarget = 0;
if (goToTarget)
{
Vector3 vecToTarget = target - transform.position;
distToTarget = vecToTarget.magnitude;
if (distToTarget < 0.5f)
{
goToTarget = false;
atTarget = true;
}
else
{
atTarget = false;
Vector3 forceToTarget = vecToTarget.normalized * forceTarget;
if (distToTarget < 5 && stopToTarget)
forceToTarget *= 10;
sumForces = forceToTarget;
colorDebugForce = Color.magenta;
nbForcesApplied ;
if (drawLines)
Debug.DrawLine(transform.position, target, Color.magenta);
}
}
//Debug
if (drawLines)
Debug.DrawLine(transform.position, transform.position sumForces, colorDebugForce / nbForcesApplied);
//On freine
velocity = -velocity * 10 * Vector3.Angle(sumForces, velocity) / 180.0f * Time.deltaTime;
//on applique les forces
velocity = sumForces * Time.deltaTime;
//On limite la vitesse
if (velocity.sqrMagnitude > maxSpeed * maxSpeed)
velocity = velocity.normalized * maxSpeed;
if (velocity.sqrMagnitude < minSpeed * minSpeed)
velocity = velocity.normalized * minSpeed;
//Si on doit freiner sur la cible, on limite la vitesse
if ((goToTarget || atTarget) && stopToTarget)
if (distToTarget < 3)
velocity = velocity.normalized * distToTarget/10.0f;
//On regarde dans la bonne direction
if (velocity.sqrMagnitude > 0)
transform.LookAt(transform.position velocity);
//Debug
if (drawLines)
Debug.DrawLine(transform.position, transform.position velocity, Color.blue);
//Deplacement du boid
transform.position = velocity * Time.deltaTime;
}
void OnDrawGizmosSelected()
{
if (drawGizmos)
{
// Répulsion
Gizmos.color = new Color(1, 0, 0, 1.0f);
Gizmos.DrawWireSphere(transform.position, zoneRepulsion);
// Alignement
Gizmos.color = new Color(0, 1, 0, 1.0f);
Gizmos.DrawWireSphere(transform.position, zoneAlignement);
// Attraction
Gizmos.color = new Color(0, 0, 1, 1.0f);
Gizmos.DrawWireSphere(transform.position, zoneAttraction);
}
}
}
uj5u.com熱心網友回復:
好吧,如果您說這對您有用并且您只是詢問“負面”方向,您可以簡單地反轉檢查。
然而,這
var forceReject = Mathf.Clamp(5, 1.0f - distX / 2, 2) * forceRejectGround;
對我來說似乎沒有什么意義。你已經知道了,distX > 20所以你基本上做到了
var forceReject = Mathf.Clamp(5, -9f /*or less*/, 2) * forceRejectGround;
2 * forceRejectGround當然,無論如何都會回傳。所以這要么是錯誤的,要么是完全多余的;)
還
distX < -15
永遠不可能是真的,因為你已經做到了
distX = Mathf.Max(0, transform.x);
所以它只能是0或積極的!
所以基本上你可以簡單地做類似的事情
//Force x
var x = transform.position.x;
if (Mathf.Abs(x) > 20)
// basically equals
//if(x > 20 || x < -20)
{
// will be positive if x > 20 and negative if x < -20
// (assuming forceRejectGround is positive of course)
var forceReject = forceRejectGround * Mathf.Sign(x);
sumForces -= Vector3.right * forceReject;
}
//Force z
var z = transform.position.z;
if (Mathf.Abs(z) > 20)
{
var forceReject = forceRejectGround * Mathf.Sign(z);
sumForces -= Vector3.up * forceReject;
}
但是,正如評論中所提到的,一般來說,您寧愿使用適當的,Rigidbody根本不做任何事情transform,而只是通過例如AddForce已經為您計算結果速度并與碰撞等做出反應的方法。
或者甚至更直接地使用粒子系統,例如將你的 boid 粒子封閉在力場中
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/461622.html
