作业六:物理系统与碰撞

1、改进飞碟(Hit UFO)游戏:

游戏内容要求:
按 adapter模式 设计图修改飞碟游戏
使它同时支持物理运动与运动学(变换)运动

这次的作业要求改进上次的UFO,上次的UFO游戏我没有采用动作分离,只采用了MVC模式,这次由于需要按照老师的要求实现adapter模式,所以我必须实现动作分离,动作分离的UML图根据老师的来:
在这里插入图片描述
适配器UML图:
在这里插入图片描述

SSActionMagnager:

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

public class SSActionManager : MonoBehaviour {  

    private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction> ();
    private List<SSAction> waitingAdd = new List<SSAction>();
    private List<int> waitingDelete = new List<int>();
    protected void Update() {
        foreach (SSAction ac in waitingAdd) {
            actions[ac.GetInstanceID()] = ac;
        }
        waitingAdd.Clear();
        foreach (KeyValuePair<int, SSAction> kv in actions) {
            SSAction ac = kv.Value;
            if (ac.destory) {
                waitingDelete.Add(ac.GetInstanceID());
            } else if (ac.enable) {
                ac.Update();
            }
        }
        foreach(int key in waitingDelete) {
            SSAction ac = actions[key];
            actions.Remove(key);
            DestroyObject(ac);
        }
        waitingDelete.Clear();
    }

    public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager) {
        action.gameobject = gameobject;
        action.transform = gameobject.transform;
        action.callback = manager;
        waitingAdd.Add(action);
        action.Start();
    }

    protected void Start() {}
}

SSAction:

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

public class SSAction : ScriptableObject {

    public bool enable = true;
    public bool destory = false;

    public GameObject gameobject{ get; set;}
    public Transform transform{ get; set; }
    public ISSActionCallback callback{ get; set; }

    protected SSAction() {}

    public virtual void Start () {
        throw new System.NotImplementedException();
    }

    public virtual void Update () {
        throw new System.NotImplementedException ();
    }
}

适配器:

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

public class Adapter : SSActionManager, ISSActionCallback
{
    public bool running;

    public virtual void fly(GameObject ufo,float speed){
        
    }

    public void SSActionEvent(SSAction source,SSActionEventType events = SSActionEventType.Completed,
        int intParam = 0,
        string strParam = null,
        Object objectParam = null) {
        
    }

    public void pause(){
        running=!running;
    }

    // Start is called before the first frame update
    void Start()
    {
        running=true;
    }

    // Update is called once per frame
    void Update()
    {
        if(running){
            base.Update();   
        }
    }
}

CCActionManager(第一个运动学):

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

public class CCActionManager : Adapter
{

    public override void fly(GameObject ufo,float speed){
        CCFlyAction action = CCFlyAction.GetSSAction(speed);
        this.RunAction(ufo, action, this);
    }

}

FlyActoin:

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

public class CCFlyAction : SSAction
{

    public float speed;

    // Start is called before the first frame update

    public static CCFlyAction GetSSAction(float speed){
        CCFlyAction action = ScriptableObject.CreateInstance<CCFlyAction>();
        action.speed=speed;
        return action;
    }

    public override void Start()
    {
        
    }

    // Update is called once per frame
    public override void Update()
    {
        // Debug.Log("asdasd");
        Vector3 v = new Vector3(this.gameobject.transform.localRotation.x,this.gameobject.transform.localRotation.y,this.gameobject.transform.localRotation.z);
        this.transform.position = Vector3.MoveTowards (this.transform.position, this.transform.position + v*1000000 , speed * Time.deltaTime);

            if(this.gameobject.transform.position.x > 10 || this.gameobject.transform.position.x < -10){
                this.destory=true;
                this.callback.SSActionEvent (this);
            }
            if(this.gameobject.transform.position.y > 10 || this.gameobject.transform.position.y < -10){
                this.destory=true;
                this.callback.SSActionEvent (this);
            }
            if(this.gameobject.transform.position.z < -10){
                this.destory=true;
                this.callback.SSActionEvent (this);
            }

    }
}

CCActionManager1(第二个动力学):

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

public class CCActionManager2 : Adapter
{
    public override void fly(GameObject ufo,float speed){
        CCFlyAction2 action = CCFlyAction2.GetSSAction(speed);
        this.RunAction(ufo, action, this);
    }

}

FlyAction2:

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

public class CCFlyAction2 : SSAction
{

    public float speed;

    // Start is called before the first frame update

    public static CCFlyAction2 GetSSAction(float speed){
        CCFlyAction2 action = ScriptableObject.CreateInstance<CCFlyAction2>();
        action.speed=speed;
        return action;
    }

    public override void Start()
    {
        
    }

    // Update is called once per frame
    public override void Update()
    {
        // Debug.Log("asdasd");
        Vector3 v = new Vector3(this.gameobject.transform.localRotation.x,this.gameobject.transform.localRotation.y,this.gameobject.transform.localRotation.z);
        // if(this.gameobject.GetComponent<Rigidbody>())
        //     Debug.Log(1238888);
        this.gameobject.GetComponent<Rigidbody>().AddForce(v*1f*speed);
        // this.gameobject.GetComponent<Rigidbody>().AddForce(9.8f * Vector3.down);

            if(this.gameobject.transform.position.x > 10 || this.gameobject.transform.position.x < -10){
                this.destory=true;
                this.callback.SSActionEvent (this);
            }
            if(this.gameobject.transform.position.y > 10 || this.gameobject.transform.position.y < -10){
                this.destory=true;
                this.callback.SSActionEvent (this);
            }
            if(this.gameobject.transform.position.z < -10){
                this.destory=true;
                this.callback.SSActionEvent (this);
            }

    }
}

以上是这次改进的一些代码,其他诸如MVC架构的基本代码都没有大改动,单例工厂模式的代码也进行了一些小的改动。

我的动力学构思是这样的:
给每个UFO设置好mesh碰撞体,并分配一个钢体组件,该碰撞体全部设置为trigger属性,在运动学操控时,不对碰撞行为进行控制,而在动力学时,会相互反弹,并且在运动学时给的是恒定速度,而动力学给的是一个动力,这就是他们的区别。
演示视频见bilibili

2、打靶游戏(可选作业):

游戏内容要求:
靶对象为 5 环,按环计分;
箭对象,射中后要插在靶上
增强要求:射中后,箭对象产生颤抖效果,到下一次射击 或 1秒以后
游戏仅一轮,无限 trials;
增强要求:添加一个风向和强度标志,提高难度

先制作五层靶子
在这里插入图片描述
有五个圆柱体构成,每个圆柱体都有自己的mesh碰撞体来判断碰撞事件,打靶游戏采用了简单的MVC模式。
箭的构成:
在这里插入图片描述
钢体的重心集中在箭头,判断脚本也挂在箭头。
Controller:

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

public interface IUserAction
{
    void GameOver();
}

public class View : MonoBehaviour
{
    private Model action;
    private GUIStyle fontstyle = new GUIStyle();
    private GUIStyle fontstyle1 = new GUIStyle();

    // Start is called before the first frame update
    void Start()
    {
        action = Controller.getInstance().currentModel as Model;
        fontstyle.fontSize = 30;
        fontstyle.normal.textColor = Color.yellow;
        fontstyle1.fontSize = 30;
        fontstyle1.normal.textColor = Color.yellow;
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void OnGUI(){
        GUI.Label(new Rect(10,40,200,200),"Score: " + Model.score, fontstyle);
        if(Model.wind_direction == 0){
            GUI.Label(new Rect(10,100,200,200),"Wind: Left with strength " + Model.strength, fontstyle);
        }
        else{
            GUI.Label(new Rect(10,100,200,200),"Wind: Right with strength " + Model.strength, fontstyle);
        }
    }

}

Model:

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

public interface ForModel{
    void LoadResources();
    void Pause();
    void Resume();
}

public class Model : MonoBehaviour, ForModel
{
    public static int score;
    public static bool shooted=false;
    public static int wind_direction = 0;
    public static int strength = 0;
    Controller controller;

    void Awake(){
        controller = Controller.getInstance();
        controller.setFPS(60);
        controller.currentModel = this;
        controller.running=true;
        LoadResources();
        score=0;
    }

    public void Start(){
        float num = Random.Range(0f,5f);
        float num2 = Random.Range(0f, 2f);
        if(num<1){
            strength = 1;
        }
        else if(num < 2){
            strength = 2;
        }
        else if(num < 3){
            strength = 3;
        }
        else if(num < 4){
            strength = 4;
        }
        else if(num < 5){
            strength = 5;
        }
        if(num2 < 1){
            wind_direction = 0;
        }
        else{
            wind_direction = 1;
        }
    }

    public void Restart(){

    }

    public void Resume(){

    }

    public void Pause(){
        controller.running=!controller.running;
    }

    public void LoadResources(){

    }


    // Start is called before the first frame update

    // Update is called once per frame
    void Update()
    {


    }
}

View:

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

public interface IUserAction
{
    void GameOver();
}

public class View : MonoBehaviour
{
    private Model action;
    private GUIStyle fontstyle = new GUIStyle();
    private GUIStyle fontstyle1 = new GUIStyle();

    // Start is called before the first frame update
    void Start()
    {
        action = Controller.getInstance().currentModel as Model;
        fontstyle.fontSize = 30;
        fontstyle.normal.textColor = Color.yellow;
        fontstyle1.fontSize = 30;
        fontstyle1.normal.textColor = Color.yellow;
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    public void OnGUI(){
        GUI.Label(new Rect(10,40,200,200),"Score: " + Model.score, fontstyle);
        if(Model.wind_direction == 0){
            GUI.Label(new Rect(10,100,200,200),"Wind: Left with strength " + Model.strength, fontstyle);
        }
        else{
            GUI.Label(new Rect(10,100,200,200),"Wind: Right with strength " + Model.strength, fontstyle);
        }
    }

}

挂在箭上面的判断脚本:

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

public class Tit : MonoBehaviour
{
    public Transform tf;
    public bool shooted;
    // Start is called before the first frame update
    void Start()
    {
        // Vector3 v = new Vector3(5,1,1);
        this.gameObject.GetComponent<Rigidbody>().centerOfMass = tf.localPosition;
        shooted=false;
        // this.gameObject.GetComponent<Rigidbody>().AddForce(1f*v);
        // this.transform.LookAt(this.transform.position+v*100);
        // this.gameObject.GetComponent<Rigidbody>().AddTorque(v*1f);
    }

    // Update is called once per frame
    void Update()
    {
        if(this.transform.position.z > 0.5){
            Model.shooted = true;
        }

        if (Input.GetKeyDown(KeyCode.Space) && Model.shooted==true){
            this.gameObject.GetComponent<Rigidbody>().isKinematic = true;
            Vector3 v = new Vector3(0, 0, -10);
            Model.shooted=false;
            this.gameObject.GetComponent<Rigidbody>().useGravity = false;
            this.gameObject.GetComponent<Rigidbody>().isKinematic = false;
            this.transform.position=v;


        float num = Random.Range(0f,5f);
        float num2 = Random.Range(0f, 2f);
        if(num<1){
            Model.strength = 1;
        }
        else if(num < 2){
            Model.strength = 2;
        }
        else if(num < 3){
            Model.strength = 3;
        }
        else if(num < 4){
            Model.strength = 4;
        }
        else if(num < 5){
            Model.strength = 5;
        }
        if(num2 < 1){
           Model.wind_direction = 0;
        }
        else{
            Model.wind_direction = 1;
        }

        }

        if(Model.shooted==false){
            Vector3 v = Camera.main.ScreenPointToRay(Input.mousePosition).direction;
            this.transform.LookAt(v);
        }
        if (Input.GetButtonDown("Fire1")) {
            this.gameObject.GetComponent<Rigidbody>().useGravity = true;
            Vector3 v = Camera.main.ScreenPointToRay(Input.mousePosition).direction;
            this.gameObject.GetComponent<Rigidbody>().AddForce(10f*v,ForceMode.Impulse);
            if(Model.wind_direction == 0){
                Vector3 vv = new Vector3(-1, 0,0);
                this.gameObject.GetComponent<Rigidbody>().AddForce(25f*Model.strength*vv,ForceMode.Force);
            }
            else if(Model.wind_direction == 1){
                Vector3 vv = new Vector3(1, 0,0);
                this.gameObject.GetComponent<Rigidbody>().AddForce(25f*Model.strength*vv,ForceMode.Force);
            }
            this.transform.LookAt(v);
			Debug.Log (v);

		}
    }

    void OnTriggerEnter(Collider other)
    {

        this.gameObject.GetComponent<Rigidbody>().isKinematic = true;
        // gameObject.SetActive(false);
        // Debug.Log(1111);
        // if(other.gameObject.tag == "target")
        // {
        //     gameObject.transform.parent.gameObject.GetComponent<Rigidbody>().isKinematic = true;
        //     gameObject.SetActive(false);
        //     int points = other.gameObject.name[other.gameObject.name.Length - 1] - '0';
        //     scene.showTips(points);
        //     scene.addScore(points);
        // }
    }

}

游戏仅一轮,通过按空格回收弓箭,演示视频在bilibili(还没过审核。。。)
游戏射箭是通过对弓箭施加瞬间力实现的,弓箭收左右风力的影响,游戏中有提示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值