Unity C#入门:单脚本实现多球体碰撞交互的方案咨询
问题背景
我是C#和Unity入门新手,仅学习3周。为练习开发能力我为自己设置了实操任务并尝试独立解决:第一个任务是模拟单个球体落地效果,已顺利完成;第二个任务是模拟多球体落地及球体间的互相碰撞效果,此时我发现现有知识储备不足以完成该需求:单个球体时逻辑完全正常,但存在多个"Player"对象时就出现了问题。
问题描述
我为每个球体都挂载了同一个脚本,但每个球体实例都处于独立的运行环境中,无法感知其他球体的存在。我尝试使用静态变量存储所有球体数据,仅部分解决了问题:运行时只有部分球体可以触发互相碰撞,无法实现全部球体的碰撞交互。
我需要了解正确的多对象交互组织逻辑,即如何正确获取并处理所有球体的相关数据,实现完整的碰撞效果。
我已将实现球体间碰撞的相关代码做了高亮标注:
// +++++++++++++++++++++++++ // +++++++++++++++++++++++++ some code // +++++++++++++++++++++++++ // +++++++++++++++++++++++++
完整实现代码
using System; using UnityEngine; public class Movement : MonoBehaviour { public Transform player; public Transform ground; public float mass; // 其他作用力和方向参数 private float force = 3f; private float directionForceRad = 45 * (float)Math.PI / 180; private Vector2 acceleration; private Vector2 movementSpeed; private Vector2 delta; private Vector2 normal; // 地面参数 private float leftEdge; private float rightEdge; private float groundAngle; private float cosGroundAngle; private float sinGroundAngle; private Boolean IsGrounded() { bool isGrounded = false; float dX = cosGroundAngle * (ground.localScale.x / 2); float dY = sinGroundAngle * (ground.localScale.x / 2); Vector2 distance = new Vector2(dX, dY) + (Vector2)ground.position - (Vector2)player.position; Vector2 projectionDistance = Vector2.Dot(distance, normal) * normal; if (projectionDistance.magnitude - 0.1 <= player.localScale.y / 2) { isGrounded = true; } return isGrounded; } // +++++++++++++++++++++++++ // +++++++++++++++++++++++++ public class Ball { public string name; public Vector2 movement; public float mass; public float radius; public Vector2 position; public Ball(GameObject obj, Vector2 mov, float weight) { name = obj.name; radius = obj.transform.localScale.x / 2; position = obj.transform.position; movement = mov; mass = weight; } } static Ball[] allBalls; static GameObject[] balloons; private void CollisionOfBalloons() { Vector2 first, second; for (int i = 0; i < allBalls.Length; i++) { for (int j = i; j < allBalls.Length; j++) { if (i != j) { if (Vector2.Distance(allBalls[i].position, allBalls[j].position) <= allBalls[i].radius + allBalls[j].radius) { first = (allBalls[j].mass * allBalls[j].movement) / allBalls[i].mass; second = (allBalls[i].mass * allBalls[i].movement) / allBalls[j].mass; allBalls[i].movement = first; allBalls[j].movement = second; Debug.Log("allBalls[i] = " + allBalls[i]); Debug.Log("allBalls[j] = " + allBalls[j]); } } } } } // +++++++++++++++++++++++++ // +++++++++++++++++++++++++ void Start() { Vector2 gravity = new Vector2(0, -10); groundAngle = ground.transform.rotation.eulerAngles.z * (float)Math.PI / 180; cosGroundAngle = (float)Math.Cos(groundAngle); sinGroundAngle = (float)Math.Sin(groundAngle); leftEdge = ground.position.x - (ground.localScale.x * cosGroundAngle) / 2; rightEdge = ground.position.x + (ground.localScale.x * cosGroundAngle) / 2; normal = new Vector2(1 * sinGroundAngle, -1 * cosGroundAngle); // 启动前组件参数初始化 acceleration = new Vector2( (force / mass) * (float)Math.Cos(directionForceRad), (force / mass) * (float)Math.Sin(directionForceRad) + gravity.y ); // +++++++++++++++++++++++++ // +++++++++++++++++++++++++ balloons = GameObject.FindGameObjectsWithTag("Player"); allBalls = new Ball[balloons.Length]; foreach (var item in balloons) { int ind = Array.IndexOf(balloons, item); allBalls[ind] = new Ball(balloons[ind], acceleration, mass); } // +++++++++++++++++++++++++ // +++++++++++++++++++++++++ } void FixedUpdate() { foreach (var item in allBalls) { if (item.name == player.name) movementSpeed = item.movement; } // 计算速度和位移 movementSpeed += acceleration * Time.deltaTime; delta = movementSpeed * Time.deltaTime; player.position = (Vector2)player.position + delta; // +++++++++++++++++++++++++ // +++++++++++++++++++++++++ foreach (var item in allBalls) { if (item.name == player.name) { item.position = player.position; item.movement = movementSpeed; } } CollisionOfBalloons(); // +++++++++++++++++++++++++ // +++++++++++++++++++++++++ // 检测碰撞并改变方向 if ((player.position.x > (leftEdge - player.localScale.x / 2)) && (player.position.x < (rightEdge + player.localScale.x / 2)) && IsGrounded()) { foreach (var item in allBalls) { if (item.name == player.name) { item.movement -= 2 * (Vector2.Dot(movementSpeed, normal) * normal); } } } } }
内容的提问来源于stack exchange,提问作者Максим Можейко
相关产品推荐
相关产品推荐

