unity 简易游戏打飞碟V2

unity 简易游戏打飞碟V2

一、简介

在上一个游戏简易打飞碟的基础上,根据Adapter模式对场景控制器调用的接口作了如下图修改:
在这里插入图片描述
保留CCActionManager的同时增加了PhysicActionManager,它们实现了同一个接口IActionManager,分别表示运动学运动(不考虑刚体)与物理运动(考虑刚体)。
接下来对增加或作了修改的代码进行介绍。

二、代码
1. PhysicFlyAction

与CCFlyAction同样继承自SSAction,不过现在只需要一个水平方向的初速度,垂直方向因为有重力作用所以不用额外给它速度。
Update函数里可以看到两种运动的明显差别,CCFlyAction在Update函数中通过position.translate来改变物体的位置,而PhysicFlyAction什么都不用做,物体自身带有的物理属性(重力和初速度)会使它动起来。
另外需要注意的是做物理运动时要将isKinematic设为false,反之要设为true(这是CCFlyAction唯一需要修改的地方,在此顺带一提)。

public class PhysicFlyAction : SSAction
{
    public float speedX;
    public static PhysicFlyAction GetSSAction(float x) {
        PhysicFlyAction action = ScriptableObject.CreateInstance<PhysicFlyAction>();
        action.speedX = x;
        return action;
    }
    // Start is called before the first frame update
    public override void Start()
    {
        gameObject.GetComponent<Rigidbody>().isKinematic = false;
        gameObject.GetComponent<Rigidbody>().velocity = new Vector3(speedX * 10, 0, 0);
        gameObject.GetComponent<Rigidbody>().drag = 1;
    }

    // Update is called once per frame
    public override void Update()
    {
        //Debug.Log("flyaction update");
        if (this.transform.gameObject.activeSelf == false) {//飞碟已经被"销毁"
            //Debug.Log("1");
            this.destroy = true;
            this.callback.SSActionEvent(this);
            return;
        }
        
        Vector3 vec3 = Camera.main.WorldToScreenPoint (this.transform.position);
        if (vec3.x < -100 || vec3.x > Camera.main.pixelWidth + 100 || vec3.y < -100 || vec3.y > Camera.main.pixelHeight + 100) {
            //Debug.Log("2");
            this.destroy = true;
            this.callback.SSActionEvent(this);
            return;
        }
    }
}

2. IActionManager

提供了一个最简单的接口给主场景控制器调用,原先主场景控制器调用的是SSActionManager即动作管理器基类中的RunAction函数,现在被Fly替代了。
另一个接口其实是版本一中SSActionManager的同名函数,用于返回当前回合剩余的飞碟数。因为现在主场景控制器只能使用IActionManager提供的接口,所以将其移动到这里。

public interface IActionManager
{
    void Fly(GameObject disk);
    int RemainActionCount() ;
}
3. PhysicActionManager

SSActionManager类没有变,CCActionManager和PhysicActionManager两个动作管理器依然继承自它,主要包含一些动作的管理。
另一方面,两个动作管理器又继承并实现了IActionManager接口。
鉴于前面版本中动作管理器已经实现了RunAction这个类似于接口但不是接口的虚函数,所以为了省事直接将RunAction嵌在Fly的里面。
可以这样做的原因是两个动作管理类都继承自基本动作管理类,本质上是同一样东西,本就可以用同一个接口。如果要更好地体现Adapter模式的话,最好有另一个不继承自SSActionManager的类同样实现Fly接口,但我们游戏中不需要罢了(道理懂就行)。

public class PhysicActionManager : SSActionManager, IActionCallback, IActionManager
{
    public RoundController sceneController;
    public PhysicFlyAction action;
    public DiskFactory factory;
    
    // Start is called before the first frame update
    protected new void Start()
    {
        sceneController = (RoundController)SSDirector.getInstance().currentSceneController;
        sceneController.actionManager = this as IActionManager;
        factory = Singleton<DiskFactory>.Instance;
    }

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

    public override void MoveDisk(GameObject disk) {
        action = PhysicFlyAction.GetSSAction(disk.GetComponent<DiskAttributes>().speedX);
        RunAction(disk, action, this);

    }

    public void Fly(GameObject disk) {
        MoveDisk(disk);
    }

	public int RemainActionCount() {
        return actions.Count;
    }
}

4. UserGUI

增加了一个成员变量isKinematic表示当前是否为运动学运动。
以及一个按钮提供给用户用于设置isKinematic。

public bool isKinematic;
if (GUI.Button(new Rect(Screen.width / 2 - menu_width * 0.9f, 0, menu_width * 1.8f, menu_height), "Kinematic/Not Kinematic")) {
    isKinematic = !isKinematic;
}
5. RoundController

第一个改变自然是actionManager的类型由SSActionManager变为IActionManager。
Update时根据UserGUI中的isKinematic来设置actionManager。
由飞碟工厂得到飞碟后用actionManager中的Fly函数使其运动。

public class RoundController : MonoBehaviour, ISceneController, IUserAction
{
    int round = 0;
    int max_round = 5;
    float timer = 0.5f;
    GameObject disk;
    DiskFactory factory ;
    public IActionManager actionManager;
    public ScoreController scoreController;
    public UserGUI userGUI;
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (userGUI.mode == 0) return;
        if (userGUI.isKinematic == false) {
            actionManager = gameObject.GetComponent<PhysicActionManager>() as IActionManager;
        }
        else {
            actionManager = gameObject.GetComponent<CCActionManager>() as IActionManager;
        }
        GetHit();
        gameOver();
        if (round > max_round) {
            return;
        }
        
        timer -= Time.deltaTime;
        if (timer <= 0 && actionManager.RemainActionCount() == 0) {
        //if (timer <= 0) {
            //从工厂中得到10个飞碟,为其加上动作
            for (int i = 0; i < 10; ++i) {
                disk = factory.GetDisk(round);
                actionManager.Fly(disk);
                //Thread.Sleep(100);
            }
            round += 1;
            if (round <= max_round) {
                userGUI.round = round;
            }
            timer = 4.0f;
        }
        
    }
    void Awake() {
        SSDirector director = SSDirector.getInstance();
        director.currentSceneController = this;
        director.currentSceneController.LoadSource();
        gameObject.AddComponent<UserGUI>();
        gameObject.AddComponent<PhysicActionManager>();
        gameObject.AddComponent<CCActionManager>();
        gameObject.AddComponent<ScoreController>();
        gameObject.AddComponent<DiskFactory>();
        factory = Singleton<DiskFactory>.Instance;
        userGUI = gameObject.GetComponent<UserGUI>();
        
    }

    public void LoadSource() 
    {

    }

    public void gameOver() 
    {
        if (round > max_round && actionManager.RemainActionCount() == 0)
        //if (round > max_round)
            userGUI.gameMessage = "Game Over!";
    }

    public void GetHit() {
        if (Input.GetButtonDown("Fire1")) {
			Camera ca = Camera.main;
			Ray ray = ca.ScreenPointToRay(Input.mousePosition);

			//Return the ray's hit
			RaycastHit hit;
			if (Physics.Raycast(ray, out hit)) {
                scoreController.Record(hit.transform.gameObject);
                hit.transform.gameObject.SetActive(false);
			}
		}
    }
}

三、效果

游戏进行时点击屏幕中间按钮可以切换物体的运动模式(作用到下一个round)
可以看出不同运动模式下的明显差别,物理模式下飞碟会相互碰撞。

在这里插入图片描述

四、项目地址

github地址

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值