物体碰撞和检测——Hit UFO改进版射箭游戏
文章目录
- Hit UFO改进版
- 一、改进要求
- 二、MVC图
- 三、gitee
- 四、程序实现
- 4.1 FirstController
- 4.2 Interface
- 4.3 ActionManagerAdapter
- 4.4 PhsisFlyActionManager
- 4.5 PhysisUFOFlyAction
- 4.5 DiskFactory
- 五、效果展示
- 射箭游戏
- 一、实现功能:
- 二、程序实现:
- 2.1 SceneController & interface
- 2.2 GameStateController
- 2.3 UserInterface
- 2.4 ArrowFactory
- 2.5 ArrowCollider
- 2.6 ArrowController
- 2.7 bodytremble
- 三、实现效果
Hit UFO改进版
一、改进要求
- 按 adapter模式 设计图修改飞碟游戏
- 使它同时支持物理运动与运动学(变换)运动
二、MVC图
三、gitee
gitee
四、程序实现
本次作业使用上一次作业Hit UFO来进行改进,主要实现部分为增加了适配器和物理模式的切换,其余部分几乎没有改变,详情见上一次博客 hit ufo 基础版
4.1 FirstController
沿用之前的代码,只不过增加了一个用户操作changeStyle,在其中要调用飞碟工厂类中的rmgrivity函数来取消调刚体重力,和刚体速度
public void changeStyle(){if (isPhy){disk_factory.rmgrivity();}isPhy = !isPhy;}
4.2 Interface
增加了用户操作changeStyle
public interface IUserAction
{void Hit(Vector3 pos);int GetScore();void GameOver();void ReStart();void BeginGame();void changeStyle();
}
4.3 ActionManagerAdapter
作为插入到原有的动作管理类上层的一个文件,决定着调用哪一种动作完成请求
public class ActionManagerAdapter : MonoBehaviour, IActionManager
{public FlyActionManager action_manager;public PhysisFlyActionManager phy_action_manager;public void playDisk(GameObject disk, float angle, float power, bool isPhy){Debug.Log("phy is : !" + isPhy);if (isPhy){Debug.Log("phy");//disk.AddComponent<>phy_action_manager.UFOFly(disk, angle, power);}else{Debug.Log("not phy");action_manager.UFOFly(disk, angle, power);}}// Use this for initializationvoid Start(){action_manager = gameObject.AddComponent<FlyActionManager>() as FlyActionManager;phy_action_manager = gameObject.AddComponent<PhysisFlyActionManager>() as PhysisFlyActionManager;}}
4.4 PhsisFlyActionManager
物理动作管理类,用于管理物理动作
public class PhysisFlyActionManager : SSActionManager
{public PhysisUFOFlyAction fly; //飞碟飞行的动作//public FirstController scene_controller; //当前场景的场景控制器protected void Start(){}//飞碟飞行public void UFOFly(GameObject disk, float angle, float power){fly = PhysisUFOFlyAction.GetSSAction(disk.GetComponent<DiskData>().direction, angle, power);this.RunAction(disk, fly, this);}
}
4.5 PhysisUFOFlyAction
设定飞碟物理模式下的运动,这里通过添加重力以及velocity实现
public class PhysisUFOFlyAction : SSAction
{private Vector3 start_vector; //初速度向量public float power;private PhysisUFOFlyAction() { }public static PhysisUFOFlyAction GetSSAction(Vector3 direction, float angle, float power){//初始化物体将要运动的初速度向量PhysisUFOFlyAction action = CreateInstance<PhysisUFOFlyAction>();if (direction.x == -1){action.start_vector = Quaternion.Euler(new Vector3(0, 0, -angle)) * Vector3.left * power;}else{action.start_vector = Quaternion.Euler(new Vector3(0, 0, angle)) * Vector3.right * power;}action.power = power;return action;}public override void FixedUpdate(){//判断是否超出范围if (this.transform.position.y < -10){this.destroy = true;this.callback.SSActionEvent(this);}}public override void Update() { }public override void Start(){//使用重力以及给一个初速度gameobject.GetComponent<Rigidbody>().velocity = power / 20 * start_vector;gameobject.GetComponent<Rigidbody>().useGravity = true;}
}
4.5 DiskFactory
工厂类中增加了rmgrivity函数,用于从物理模式切换到运动学模式时,消除物理学的刚体组件中的参数
public void rmgrivity(){for (int i = 0; i < used.Count; i++){used[i].GetComponent<Rigidbody>().useGravity = false;used[i].GetComponent<Rigidbody>().velocity = 0*Vector3.zero;}for (int i = 0; i < free.Count; i++){free[i].GetComponent<Rigidbody>().useGravity = false;free[i].GetComponent<Rigidbody>().velocity = 0 * Vector3.zero;}}
五、效果展示
- 物理模式:
- 运动学模式:
射箭游戏
一、实现功能:
- 靶对象为 5 环,按环计分;
- 箭对象,射中后要插在靶上
- 射中后,箭对象产生颤抖效果,持续八秒
- 游戏仅一轮,无限 trials
- 添加一个风向和强度标志,提高难度
- 模拟真实射箭过程
- 按住右键调整弓箭方向
- 按住左键进行蓄力,松开后发射,根据蓄力时间决定力度
二、程序实现:
2.1 SceneController & interface
首先定义用户动作,并在SceneController中定义动作调用
namespace Scene
{public interface IUserAction{void getArrow();void shootArrow(Vector3 mousePos,float xuli);void changeArrowpos(Vector3 mousePos);}public interface ISceneController{void addScore(int point);//void showTips(int point);void changeWind();int getWindDirection();int getWindStrength();bool ifReadyToShoot();}public class SceneController : System.Object, IUserAction, ISceneController{private static SceneController instance;private GameStateController gameStateController;private ArrowController arrowController;public static SceneController getInstance(){if (instance == null) instance = new SceneController();return instance;}public void setGameController(GameStateController gsc){gameStateController = gsc;}public void setArrowController(ArrowController _arrowController){arrowController = _arrowController;}public void addScore(int point){gameStateController.addScore(point);}public void changeWind(){gameStateController.changeWind();}public void getArrow(){arrowController.getArrow();}public int getWindDirection(){return gameStateController.getWindDirec();}public int getWindStrength(){return gameStateController.getWindStrength();}public bool ifReadyToShoot(){return arrowController.ifReadyToShoot();}public void shootArrow(Vector3 mousePos,float xuli){arrowController.shootArrow(mousePos,xuli);}public void changeArrowpos(Vector3 mousePos){arrowController.changeArrowpos(mousePos);}}
2.2 GameStateController
这里完成积分工作和风向提示,在OnGUI中更新数据
public class GameStateController : MonoBehaviour {public int i = 0;private int score = 0, windDir = 0, windStrength = 0;GUIStyle bold_style = new GUIStyle();GUIStyle score_style = new GUIStyle();GUIStyle text_style = new GUIStyle();GUIStyle over_style = new GUIStyle();private int high_score = 0;//private const float TIPS_SHOW_TIME = 0.5f;//private GameObject canvas, scoreText, tipsText, windText;private SceneController scene;private string[] windDirectionArray;// Use this for initializationvoid Start () {scene = SceneController.getInstance();scene.setGameController(this);windDirectionArray = new string[8] { "↑", "↗", "→", "↘", "↓", "↙", "←", "↖" };changeWind();}public void changeWind(){windDir = UnityEngine.Random.Range(0,8);windStrength = UnityEngine.Random.Range(0, 8);}internal void addScore(int point){i++;if (i % 2 == 0)high_score += point;changeWind();}// Update is called once per framevoid Update () {}void OnGUI(){bold_style.normal.textColor = new Color(1, 0, 0);bold_style.fontSize = 16;text_style.normal.textColor = new Color(0, 0, 0, 1);text_style.fontSize = 16;score_style.normal.textColor = new Color(1, 0, 1, 1);score_style.fontSize = 16;over_style.normal.textColor = new Color(1, 0, 0);over_style.fontSize = 25;GUI.Label(new Rect(10, 5, 200, 50), "分数:" +high_score, text_style);GUI.Label(new Rect(10, 105, 200, 50), "Wind: " + windDirectionArray[windDir] + " x" + windStrength, text_style);}internal int getWindDirec(){return windDir;}internal int getWindStrength(){return windStrength;}}
2.3 UserInterface
检测鼠标的动作,这里定义了一个时间用于判断蓄力,并检测鼠标左右键的按下和松开,来进行角度调整和拉弓射箭,模拟真实射箭环境
public class UserInterface : MonoBehaviour {private IUserAction action;private ISceneController scene;bool gameStart = false;int timeCount = 0;bool left = false;bool right = false;bool timeflag;float xuli;// Use this for initializationvoid Start () {action = SceneController.getInstance() as IUserAction;scene = SceneController.getInstance() as ISceneController;}void Update () {if (!gameStart){action.getArrow();gameStart = true;}if (timeCount%75==0) action.getArrow();if (Input.GetMouseButtonUp(1)){right = false;}if (scene.ifReadyToShoot()){//if (Input.GetMouseButtonDown(1)){right = true;}if (right){Vector3 mousePos = Camera.main.ScreenPointToRay(Input.mousePosition).direction;action.changeArrowpos(mousePos);}if (Input.GetMouseButtonDown(0)){timeflag = true;xuli = 0;}//左键松开,射出弓箭if (Input.GetMouseButtonUp(0)){Vector3 mousePos = Camera.main.ScreenPointToRay(Input.mousePosition).direction;action.shootArrow(mousePos,xuli);timeCount = 0;timeflag = false;}if (timeflag){xuli += Time.deltaTime;}}timeCount++;}}
2.4 ArrowFactory
弓箭的工厂类,定义弓箭的产生和获取
public class ArrowFactory : System.Object
{private static ArrowFactory instance;private GameObject ArrowPrefabs;private List<GameObject> usingArrowList = new List<GameObject>();private List<GameObject> freeArrowList = new List<GameObject>();private Vector3 INITIAL_POS = new Vector3(0, 0, -19);public static ArrowFactory getInstance(){if (instance == null) instance = new ArrowFactory();return instance;}public void init(GameObject _arrowPrefabs){ArrowPrefabs = _arrowPrefabs;}internal void detectArrowsReuse(){for(int i = 0; i < usingArrowList.Count; i++){if(usingArrowList[i].transform.position.y <= -8){usingArrowList[i].GetComponent<Rigidbody>().isKinematic = true;usingArrowList[i].SetActive(false);usingArrowList[i].transform.position = INITIAL_POS;freeArrowList.Add(usingArrowList[i]);usingArrowList.Remove(usingArrowList[i]);i--;SceneController.getInstance().changeWind();}} }internal GameObject getArrow(){if(freeArrowList.Count == 0){GameObject newArrow = Camera.Instantiate(ArrowPrefabs);usingArrowList.Add(newArrow);return newArrow;}else{GameObject oldArrow = freeArrowList[0];freeArrowList.RemoveAt(0);oldArrow.SetActive(true);usingArrowList.Add(oldArrow);return oldArrow;}}
}
2.5 ArrowCollider
放在箭头上的脚本,用于判断是否碰触到板子,然后为弓箭添加颤抖组件
public class ArrowCollider : MonoBehaviour {private ISceneController scene;float radian = 0; // 弧度 float per_radian = 3f; // 每次变化的弧度 float radius = 0.01f; // 半径 Vector3 old_pos; // 开始时候的坐标 public float left_time = 8f; //动作持续时间void Start () {scene = SceneController.getInstance() as ISceneController;}void Update () {}[System.Obsolete]void OnTriggerEnter(Collider other){if (other.gameObject.tag == "target"){gameObject.transform.parent.gameObject.GetComponent<Rigidbody>().isKinematic = true;gameObject.SetActive(false);int points = 0;if(other.gameObject.name.ToString() == "1"){points = 1;}if (other.gameObject.name.ToString() == "2"){points = 2;}if (other.gameObject.name.ToString() == "3"){points = 3;}if (other.gameObject.name.ToString() == "4"){points = 4;}if (other.gameObject.name.ToString() == "5"){points = 5;}if (other.gameObject.name.ToString() == "6"){points = 6;}scene.addScore(points);//scene.showTips(points);gameObject.transform.parent.FindChild("Body").gameObject.AddComponent<bodytremble>();Debug.Log("pengzhuang");}}
}
2.6 ArrowController
增加风力,并控制弓箭和靶子的产生和选择
public class ArrowController : MonoBehaviour {public GameObject TargetPrefabs, ArrowPrefabs;private GameObject holdingArrow, target;private const int SPEED = 40;private SceneController scene;private Vector3[] winds = new Vector3[8]{new Vector3(0, 1, 0), new Vector3(1,1,0), new Vector3(1,0,0), new Vector3(1,-1,0), new Vector3(0,-1,0), new Vector3(-1,-1,0), new Vector3(-1,0,0), new Vector3(-1,1,0)};private void Awake(){ArrowFactory.getInstance().init(ArrowPrefabs);}// Use this for initializationvoid Start () {scene = SceneController.getInstance();scene.setArrowController(this);target = Instantiate(TargetPrefabs);}// Update is called once per framevoid Update () {ArrowFactory.getInstance().detectArrowsReuse();}public bool ifReadyToShoot(){return (holdingArrow != null);}internal void getArrow(){if (holdingArrow == null) holdingArrow = ArrowFactory.getInstance().getArrow();}internal void shootArrow(Vector3 mousePos,float xuli){holdingArrow.transform.LookAt(mousePos * 30);holdingArrow.GetComponent<Rigidbody>().isKinematic = false;addWind(); //箭在射出过程中会持续受到一个风力if(xuli <= 2){holdingArrow.GetComponent<Rigidbody>().AddForce(mousePos * 30 * xuli, ForceMode.Impulse);}else{holdingArrow.GetComponent<Rigidbody>().AddForce(mousePos * 60, ForceMode.Impulse);}holdingArrow = null;}internal void changeArrowpos(Vector3 mousePos){holdingArrow.transform.LookAt(mousePos * 30);}private void addWind(){int windDir = scene.getWindDirection();int windStrength = scene.getWindStrength();Vector3 windForce = winds[windDir]*50;holdingArrow.GetComponent<Rigidbody>().AddForce(windForce, ForceMode.Force);}
}
2.7 bodytremble
颤抖脚本,以原来位置为基础,进行7弧度的颤抖
public class bodytremble : MonoBehaviour
{float radian = 0; // 弧度 float per_radian = 7f; // 每次变化的弧度 float radius = 0.01f; // 半径 Vector3 old_pos; // 开始时候的坐标 public float left_time = 8f; //动作持续时间// Start is called before the first frame updatevoid Start(){old_pos = transform.position;}// Update is called once per framevoid Update(){left_time -= Time.deltaTime;if (left_time <= 0){//颤抖后回到初始位置transform.position = old_pos;}// 弧度每次增加radian += per_radian;//y轴的位置变化,上下颤抖float dy = Mathf.Cos(radian) * radius;transform.position = old_pos + new Vector3(0, dy, 0);Debug.Log("tremble");}
}
三、实现效果
- 左上摄像机用于观察颤抖效果,右上摄像机用于观察中靶情况
- 动画演示:右键移动瞄准,左键按住蓄力,松开发射,这里设定了颤抖8秒,所以左上一直在抖,有点鬼畜
物体碰撞和检测——Hit UFO改进版射箭游戏相关推荐
- 与游戏世界交互——Hit UFO
目录 Hit UFO 一.游戏规则 二.gitee 三.程序实现 3.1 SSDirector.cs 3.2 SSAction.cs 3.3 SSActionManager.cs 3.4 Sequen ...
- Unity实现简易打飞碟改进版(Hit UFO)
Unity实现简易打飞碟改进版(Hit UFO) 前言 这是中山大学数据科学与计算机学院2019年3D游戏编程与设计的第六次作业 所有项目与代码已上传至github当中,欢迎大家访问. github个 ...
- 3D游戏编程与设计作业6-Unity实现打飞碟游戏改进版(Hit UFO)
改进飞碟(Hit UFO)游戏 游戏内容要求 按adapter模式设计图修改飞碟游戏 使它同时支持物理运动与运动学(交换)运动 编程实践 本次作业直接在上一次打飞碟游戏的基础上增加adapter设计模 ...
- Unity 3D学习笔记(5)物体的碰撞/触发检测
前言 在学习了刚体组件后,我们看到了物体的物理效果,比如重力,碰撞等等,那么该如何检测他们之间的碰撞呢? 在Unity中,有碰撞检测和触发检测两种类型,他们的简单概括如下: 一.碰撞检测 1.如何使用 ...
- Unity 2D检测物体碰撞
文章目录 添加物理脚本 使用脚本检测碰撞 添加物理脚本 Unity2D中,检测物体碰撞首相要给物体添加两个属性分别是: rigibody和collider,刚体和碰撞器. collider有不同的形状 ...
- 六、改进版(Hit UFO)
文章目录 1.改进飞碟(Hit UFO)游戏: 游戏内容要求: 2.实现 类图 adapter(适配器)模式 改进 IActionManager PhysisActionManager RoundAc ...
- Unity 判断两物体碰撞方向
Unity 判断两物体碰撞方向 问题描述:游戏玩家可以在两个平面之间不断进行跳跃,且出现玩家顶着上面平面飞着走的情况. 问题原因:玩家碰撞体与平面不断进行碰撞体检测,导致游戏玩家可以不断进行跳跃. 解 ...
- 改进飞碟(Hit UFO)游戏
1.改进飞碟(Hit UFO)游戏: 游戏内容要求: 按 adapter模式 设计图修改飞碟游戏 使它同时支持物理运动与运动学(变换)运动 新增的类或者有修改的类如下: ActionManagerAd ...
- 【30分钟学完】canvas动画|游戏基础(7):动量守恒与多物体碰撞
前言 一路沿着本系列教程学习的朋友可能会发现,前面教程中都尽量避免提及质量的概念,很多运动概念也时刻提醒大家这不是真实的物体运动.因为真实的物体运动其实跟质量都是密不可分的,而且质量的引入自然必须提及 ...
最新文章
- 记住:永远不要在 MySQL 中使用 UTF-8
- 基于 GraphQL 实践的一点思考
- Java中常见数据结构Map之HashMap
- linux高级运维要会的,linux高级运维必会命令
- 阿里云华北3超大规模数据中心开服 ECS全系列降价20%
- 小程序上让随机的两个点都显示在地图可视区域
- NTU 课程笔记:MAS 714(16) 图灵机
- mysql 事务日志备份_事务日志备份与恢复 5
- 变量不合法的表达式JAVA_Java8中lambda表达式的语法,别人都会的,你还不会吗?「一」...
- 深度学习笔记(47) 神经风格迁移
- ssm项目的maven-pom.xml
- 2021-10-26
- 深度学习 黑白图片 着色
- php输出26个大小写英文字母
- stm32wb55 flash
- C语言习题:编程序将”China”译成密码[C语言]
- Visual Paradigm在 Windows系统电脑上安装
- CPU不同字母的意思
- Android Studio 连接夜神模拟器的方法
- MATLAB 矢量场