1、分析需求文案策划
阅读Unity3D保龄球案例设计和积分规则,最后整理游戏规则:
2、搭建游戏场景
导入场景资源包,发现运行资源包的场景发现报错,原因大体是因为网格内陷导致网格碰撞器出现了些小问题,这通常出现在早期Unity版本资源包。
通过勾选每个保龄球的Collider中Convex选项,将不报错。
加载各种模型资源,一系列的操作,最后搭建将场景搭建完毕。把所有的保龄球放在一个AllBowls空物体下,把AllBowls和ball制作成一个预制体。
3、编写保龄球的控制脚本
新建一个BallController.cs脚本组件,用来管理球的发射方法。普通情况下,正常情况玩保龄球,会有以下几种操作:
- 捡球
- 带球到到发球线
- 给球施加一个方向的力
用射线的方式可以达到需求,但是具体如何实现还得需要分析:
我们可以通过射线找到两个关键点扔球点和发球点,两点确定发球方向。在扔球点捡起球,在发球点发射。
根据场景我选择世界坐标Z=8这个轴作为发球面,这有很大的瑕疵,以后会逐渐修正。
BallController.cs代码:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 /// <summary> 5 /// 保龄球的控制 6 /// </summary> 7 public class BallController : MonoBehaviour 8 { 9 10 #region 射线相关 11 12 /// <summary> 13 /// 射线碰撞信息 14 /// </summary> 15 private RaycastHit hit; 16 /// <summary> 17 /// 图层遮罩 18 /// </summary> 19 private LayerMask mask; 20 /// <summary> 21 /// 球的位置 22 /// </summary> 23 public Transform ballTrans; 24 25 #endregion 26 27 /// <summary> 28 /// 推力范围 29 /// </summary> 30 public Transform pushArea; 31 /// <summary> 32 /// 球的半径 33 /// </summary> 34 [SerializeField] 35 private float ballRadius; 36 /// <summary> 37 /// 扔球点 38 /// </summary> 39 private Vector3 ballPushOrgin; 40 /// <summary> 41 /// 球左右方向差量 42 /// </summary> 43 private Vector3 ballPushDir; 44 45 //是否推出去 46 static bool pushed = false; 47 private void Start() 48 { 49 //获取球的半径 50 ballRadius = ballTrans.GetComponent<SphereCollider>().radius; 51 GetComponent<Rigidbody>().isKinematic =true; 52 } 53 54 private void Update() 55 { 56 //发射一条射线 57 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 58 //如果还没有推出去这个球 59 if (!pushed) 60 { 61 //推球逻辑 62 if (Physics.Raycast(ray, out hit, 1000, LayerMask.GetMask("AreaFloor"))) 63 { 64 //推出去 65 Vector3 _ballPushTrans = new Vector3(hit.point.x, 0.558f + ballRadius * 0.01f, 8.026f); 66 if (hit.transform == pushArea) 67 { 68 _ballPushTrans = new Vector3(hit.point.x, hit.point.y + 0.3f, hit.point.z);//球的位置 69 ballTrans.position = _ballPushTrans; 70 ballPushOrgin = hit.point; ;//记录球的起点 71 //Debug.Log(hit.point.x + "," + hit.point.y + "," + hit.point.z); 72 } 73 else 74 { 75 if (!pushed && hit.point.z < 8f && ballPushOrgin != Vector3.zero)//捡起保龄球并且它的发射距离超过世界坐标Z=8f(没有) 76 { 77 Vector3 _ballPushDir = hit.point;//记录一下球的终点 78 Debug.Log(ballPushOrgin); 79 ballPushDir = _ballPushDir - ballPushOrgin; 80 pushed = true; 81 ballTrans.position = new Vector3(hit.point.x, 0.558f + ballRadius * 0.01f, 8.026f); 82 GetComponent<Rigidbody>().isKinematic = false; 83 ballTrans.GetComponent<Rigidbody>().AddForce((transform.forward + ballPushDir) * 20, ForceMode.Impulse); 84 85 } 86 } 87 } 88 } 89 } 90 }