物理系统与碰撞(中山大学3D游戏作业6)

物理系统与碰撞(中山大学3D游戏作业6)


bilibili:https://www.bilibili.com/video/BV1ad4y1x7uU/
gitee:https://gitee.com/lin-fengnian/3dgame/tree/master/UFO2/Assets

任务要求:

改进UFO,按 adapter模式 设计图修改飞碟游戏,使它同时支持物理运动与运动学(变换)运动。

实现过程:

  1. 添加新增 IActionManager.cs文件作为接口。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IActionManager
{
    void Fly(GameObject saucer, float speed, Vector3 direction);
}
  1. 新增 PhysisFlyAction.cs文件
    用钢体和物理引擎实现驱动。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhysisFlyAction : SSAction
{
    float speed;            
    Vector3 direction;      


    public static PhysisFlyAction GetSSAction(Vector3 direction, float speed)
    {
        PhysisFlyAction action = ScriptableObject.CreateInstance<PhysisFlyAction>();
        action.speed = speed;
        action.direction = direction;
        return action;
    }

    public override void Start()
    {
        gameObject.GetComponent<Rigidbody>().isKinematic = false;
        gameObject.GetComponent<Rigidbody>().velocity = speed * direction;
    }

    public override void Update()
    {
        if (this.transform.position.y < -6)
        {
            this.destroy = true;
            this.enable = false;
            this.callback.SSActionEvent(this);
        }

    }
}

注意在此处添加缸体rigidBody
在这里插入图片描述

  1. 新增 PhysisActionManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhysisActionManager : SSActionManager, ISSActionCallback, IActionManager
{
    PhysisFlyAction flyAction;
    FirstController controller;

    protected new void Start()
    {
        controller = (FirstController)SSDirector.GetInstance().CurrentScenceController;
    }

    public void Fly(GameObject disk, float speed, Vector3 direction)
    {
        flyAction = PhysisFlyAction.GetSSAction(direction, speed);
        RunAction(disk, flyAction, this);
    }

    public void SSActionEvent(SSAction source,
                              SSActionEventType events = SSActionEventType.Competed,
                              int intParam = 0,
                              string strParam = null,
                              Object objectParam = null)
    {
        controller.FreeSaucer(source.gameObject);
    }
}
  1. 新增 RController.cs,用于代替原先FirstController 每回合发射飞盘、计分、轮次增加等功能。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RController : MonoBehaviour
{
    FirstController controller;
    IActionManager actionManager;                   
    SaucerFactory saucerFactory;                         
    UserGUI userGUI;
    int[] roundDisks;           
    int mode;                   
    int points;                 
    int round;                  
    int count;                
    float sendTime;             

    void Start()
    {
        controller = (FirstController)SSDirector.GetInstance().CurrentScenceController;
        actionManager = Singleton<ActionManager>.Instance;
        saucerFactory = Singleton<SaucerFactory>.Instance;
        userGUI = Singleton<UserGUI>.Instance;
        roundDisks = new int[] { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 };
        points = 0;
        round = 1;
        count = 0;
        sendTime = 0;
        mode = 1;

    }

    public int GetPoints()
    {
        return points;
    }

    public void SetMode(int mode)
    {
        this.mode = mode;
    }

    public void Reset()
    {
        round = 1;
        count = 0;
        sendTime = 0;
        mode = 1;
        points = 0;

    }

    public void Record(SaucerData disk)
    {
        points += disk.points;
    }



    public void SetFlyMode(int flyMode)
    {
        actionManager = flyMode == 1 ? Singleton<PhysisActionManager>.Instance : Singleton<ActionManager>.Instance as IActionManager;
    }

    public void SendDisk(int mode)
    {
        GameObject saucer = saucerFactory.GetSaucer(round);

        saucer.transform.position = new Vector3(-saucer.GetComponent<SaucerData>().direction.x * 7, UnityEngine.Random.Range(0f, 8f), 0);
        saucer.SetActive(true);
        if (mode == 0)
        {
            actionManager.Fly(saucer, saucer.GetComponent<SaucerData>().speed * 0.5f, saucer.GetComponent<SaucerData>().direction);
        }
        else if (mode == 2)
        {
            actionManager.Fly(saucer, saucer.GetComponent<SaucerData>().speed * 1.5f, saucer.GetComponent<SaucerData>().direction);
        }
        else
        {
            actionManager.Fly(saucer, saucer.GetComponent<SaucerData>().speed, saucer.GetComponent<SaucerData>().direction);
        }

    }

    void Update()
    {
        sendTime += Time.deltaTime;
        if (sendTime > 1)
        {
            sendTime = 0;
            for (int i = 0; i < 5 && count < roundDisks[round - 1]; i++)
            {
                count++;
                SendDisk(mode);
            }

            if (count == roundDisks[round - 1] && round < roundDisks.Length)
            {
                round++;
                count = 0;

                userGUI.SetRound(round);
            }

            if (count == roundDisks[round - 1] && round == roundDisks.Length)
            {
                if (mode == 3)
                {
                    round = 1;
                    count = 0;
                    userGUI.SetResult("");
                }
                else
                {
                    userGUI.SetResult("Game Over!");
                }
            }

        }
    }
}


  1. 修改 FlyAction.cs文件
    飞盘到达游戏界面时通过摄像机监视,需要进行回收,竖直方向我们需要添加重力加速度
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FlyAction : SSAction
{
    float gravity;          
    float speed;            
    float time;             
    Vector3 direction;      

    public static FlyAction GetSSAction(Vector3 direction, float speed)
    {
        FlyAction action = ScriptableObject.CreateInstance<FlyAction>();
        action.gravity = 10;
        action.time = 0;
        action.speed = speed;
        action.direction = direction;
        return action;
    }

    public override void Start()
    {
        gameObject.GetComponent<Rigidbody>().isKinematic = true;
    }

    public override void Update()
    {
        time += Time.deltaTime;
        transform.Translate(Time.deltaTime * gravity * time * Vector3.down);
        transform.Translate(direction * speed * Time.deltaTime);
        if (this.transform.position.y < -7) 
        {
            this.destroy = true;
            this.enable = false;
            this.callback.SSActionEvent(this);
        } 
    }
}
  1. 修改 ActionManager.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ActionManager : SSActionManager, ISSActionCallback, IActionManager
{
    public FlyAction flyAction;
    public FirstController controller;

    protected new void Start()
    {
        controller = (FirstController)SSDirector.GetInstance().CurrentScenceController;
        controller.actionManager = this;
    }

    public void Fly(GameObject disk, float speed, Vector3 direction)
    {
        flyAction = FlyAction.GetSSAction(direction, speed);
        RunAction(disk, flyAction, this);
    }
    public void SSActionEvent(SSAction source,
                              SSActionEventType events = SSActionEventType.Competed,
                              int para = 0,
                              string parastr = null,
                              Object obj = null)
    {
        controller.saucerFactory.FreeDisk(source.gameObject);
    }
}

  1. 修改 IUserAction.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IUserAction
{
    void Hit(Vector3 position); 
    void Restart(); 
    void SetMode(int mode);
    void SetFlyMode(int flyMode);
}
  1. 修改 FirstController.cs
    添加hit函数处理点击事件,并添加分数记录。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FirstController : MonoBehaviour, ISceneController, IUserAction
{
    public ActionManager actionManager;                   
    public SaucerFactory saucerFactory;
    RController roundController;
    UserGUI userGUI;

    void Start()
    {
        LoadResources();
    }

    public void LoadResources()
    {
        SSDirector.GetInstance().CurrentScenceController = this;
        gameObject.AddComponent<SaucerFactory>();
        gameObject.AddComponent<ActionManager>();
        gameObject.AddComponent<PhysisActionManager>();
        gameObject.AddComponent<RController>();
        gameObject.AddComponent<UserGUI>();

        saucerFactory = Singleton<SaucerFactory>.Instance;
        roundController = Singleton<RController>.Instance;
        userGUI = Singleton<UserGUI>.Instance;

    }



    public void Hit(Vector3 position)
    {
        RaycastHit[] Rayhits;
        Camera camera = Camera.main;
        Ray ray = camera.ScreenPointToRay(position);


        Rayhits = Physics.RaycastAll(ray);

        for (int i = 0; i < Rayhits.Length; i++)
        {
            RaycastHit ratCastHit = Rayhits[i];
            if (ratCastHit.collider.gameObject.GetComponent<SaucerData>() != null)
            {
                ratCastHit.collider.gameObject.transform.position = new Vector3(0, -7, 0);
                roundController.Record(ratCastHit.collider.gameObject.GetComponent<SaucerData>());
                userGUI.SetPoints(roundController.GetPoints());
            }
        }
    }

    public void Restart()
    {
        userGUI.SetRound(0);
        userGUI.SetMode(1);
        userGUI.SetResult("");
        userGUI.SetPoints(0);
        userGUI.SetFlyMode(0);
        roundController.Reset();


    }

    void Update()
    {

    }

    public void SetMode(int mode)
    {
        roundController.SetMode(mode);
    }

    public void SetFlyMode(int flyMode)
    {
        roundController.SetFlyMode(flyMode);
    }

    public void FreeSaucer(GameObject disk)
    {
        saucerFactory.FreeDisk(disk);
    }

}

  1. 修改 UserGUI.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UserGUI : MonoBehaviour
{
    private IUserAction userAction;
    public string result;
    public int points;
    public int round;
    public int mode;

    public void SetResult(string result)
    {
        this.result = result;
    }

    public void SetPoints(int points)
    {
        this.points = points;
    }

    public void SetRound(int round)
    {
        this.round = round;
    }

    public void SetMode(int mode)
    {
        this.mode = mode;
    }

    public void SetFlyMode(int flyMode)
    {
        this.mode = flyMode;
    }


    void Start()
    {
        points = 0;
        round = 1;
        mode = 1;
        result = "";
        userAction = SSDirector.GetInstance().CurrentScenceController as IUserAction;
    }

    void OnGUI()
    {
        GUIStyle guiStyle = new GUIStyle();
        guiStyle.fontSize = 50;
        guiStyle.normal.textColor = Color.blue;
        

        GUIStyle style = new GUIStyle();
        style.normal.textColor = Color.white;
        style.fontSize = 30;

        GUIStyle resultStyle = new GUIStyle();
        resultStyle.fontSize = 50;
        resultStyle.normal.textColor = Color.green;
        
        GUI.Label(new Rect(20, 10, 100, 50), "scores: " + points, style);
        GUI.Label(new Rect(220, 10, 100, 50), "Round: " + round, style);
        GUI.Label(new Rect(350, 100, 50, 200), result, resultStyle);

        if (GUI.Button(new Rect(750, 50, 100, 50), "Restart"))
        {
            userAction.Restart();
        }
        if (GUI.Button(new Rect(1300, 425, 100, 50), "Kinematics"))
        {
            userAction.SetFlyMode(0);
        }
        //物理模式
        if (GUI.Button(new Rect(1300, 500, 100, 50), "Physis"))
        {
            userAction.SetFlyMode(1);
        }





        if (Input.GetButtonDown("Fire1"))
        {
            userAction.Hit(Input.mousePosition);
        }
    }
}

效果:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值