3D游戏编程3--牧师与恶魔动作分离版

操作与总结

参考 Fantasy Skybox FREE 构建自己的游戏场景

游戏场景

游戏场景如上,大部分还是天空盒的功劳,从网上找到素材,然后布局一下就好。

写一个简单的总结,总结游戏对象的使用

常见游戏对象及渲染

使用这些游戏对象构造场景

  • 常见游戏对象
  • Camera 摄像机
  • Skyboxes 天空盒
  • 3D 物体显示
  • 地形构造工具
  • 声音
  • 游戏资源库

具体的使用还要看游戏的属性和提供的方法,unity3d给了查看可用资源的功能,所以即使不确定,也可以查看一下,具体的方法比较多,细节也比较多,还是要在实战中积累。

编程实践

牧师与魔鬼 动作分离版

新添加文件

c#文件目录

文件目录

基本上是按照PPT中的格式写的,在以前的基础上添加了Action文件夹,及里面的6个文件,取代之前move文件的位置,所以move.cs是可以去掉的。
先看添加的6个新文件,因为对这个新模式理解不是很透彻,大概解释参照PPT中的。

CCMoveToAction

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

    public class CCMoveToAction : SSAction
    {
        public Vector3 target;
        public float speed;

        private CCMoveToAction() { }
        public static CCMoveToAction getAction(Vector3 target, float speed)
        {
            CCMoveToAction action = ScriptableObject.CreateInstance<CCMoveToAction>();
            action.target = target;
            action.speed = speed;
            return action;
        }

        public override void Update()
        {
            this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime);
            if (this.transform.position == target)
            {
                this.destroy = true;
                this.callback.actionDone(this);
            }
        }

        public override void Start()
        {
            //
        }

    }

CCSequenceAction

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

    public class CCSequenceAction : SSAction, ISSActionCallback
    {
        public List<SSAction> sequence;
        public int repeat = 1;
        public int currentActionIndex = 0;

        public static CCSequenceAction getAction(int repeat, int currentActionIndex, List<SSAction> sequence)
        {
            CCSequenceAction action = ScriptableObject.CreateInstance<CCSequenceAction>();
            action.sequence = sequence;
            action.repeat = repeat;
            action.currentActionIndex = currentActionIndex;
            return action;
        }

        public override void Update()
        {
            if (sequence.Count == 0) return;
            if (currentActionIndex < sequence.Count)
            {
                sequence[currentActionIndex].Update();
            }
        }

        public void actionDone(SSAction source)
        {
            source.destroy = false;
            this.currentActionIndex++;
            if (this.currentActionIndex >= sequence.Count)
            {
                this.currentActionIndex = 0;
                if (repeat > 0) repeat--;
                if (repeat == 0)
                {
                    this.destroy = true;
                    this.callback.actionDone(this);
                }
            }
        }

        public override void Start()
        {
            foreach (SSAction action in sequence)
            {
                action.gameObject = this.gameObject;
                action.transform = this.transform;
                action.callback = this;
                action.Start();
            }
        }

        void OnDestroy()
        {
            foreach (SSAction action in sequence)
            {
                DestroyObject(action);
            }
        }
    }

FirstSceneActionManager

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

    public class FirstSceneActionManager : SSActionManager
    {
        public void moveBoat(Boat boat)
        {
            CCMoveToAction action = CCMoveToAction.getAction(boat.getDestination(), boat.movingSpeed);
            this.addAction(boat.getGameobj(), action, this);
        }

        public void moveCharacter(Character characterCtrl, Vector3 destination)
        {
            Vector3 currentPos = characterCtrl.getPosition();
            Vector3 middlePos = currentPos;
            if (destination.y > currentPos.y)
            {
                middlePos.y = destination.y;
            }
            else
            {
                middlePos.x = destination.x;
            }
            SSAction action1 = CCMoveToAction.getAction(middlePos, characterCtrl.movingSpeed);
            SSAction action2 = CCMoveToAction.getAction(destination, characterCtrl.movingSpeed);
            SSAction seqAction = CCSequenceAction.getAction(1, 0, new List<SSAction> { action1, action2 });
            this.addAction(characterCtrl.getGameobj(), seqAction, this);
        }
    }

这个类可以参照之前的move。

ISSActionCallback

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

    public interface ISSActionCallback
    {
        void actionDone(SSAction source);
    }

SSAction

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

    public class SSAction : ScriptableObject
    {

        public bool enable = true;
        public bool destroy = false;

        public GameObject gameObject;
        public Transform transform;
        public ISSActionCallback callback;

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

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

SSActionManager

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


    public class SSActionManager : MonoBehaviour, ISSActionCallback
    {
        private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();
        private List<SSAction> waitingToAdd = new List<SSAction>();
        private List<int> watingToDelete = new List<int>();

        protected void Update()
        {
            foreach (SSAction ac in waitingToAdd)
            {
                actions[ac.GetInstanceID()] = ac;
            }
            waitingToAdd.Clear();

            foreach (KeyValuePair<int, SSAction> kv in actions)
            {
                SSAction ac = kv.Value;
                if (ac.destroy)
                {
                    watingToDelete.Add(ac.GetInstanceID());
                }
                else if (ac.enable)
                {
                    ac.Update();
                }
            }

            foreach (int key in watingToDelete)
            {
                SSAction ac = actions[key];
                actions.Remove(key);
                DestroyObject(ac);
            }
            watingToDelete.Clear();
        }

        public void addAction(GameObject gameObject, SSAction action, ISSActionCallback whoToNotify)
        {
            action.gameObject = gameObject;
            action.transform = gameObject.transform;
            action.callback = whoToNotify;
            waitingToAdd.Add(action);
            action.Start();
        }

        public void actionDone(SSAction source)
        {

        }

    }

原文件修改

修改大部分就是把以前涉及到move的代码去掉,举个例子

Character

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

public class Character {
    private GameObject character;
    public int TypeOfCharacter;//1代表魔鬼,0代表牧师
    //private move Cmove;
    public int characterStatus;//0代表在岸上,1代表在船上
    Coast coast;
    Click click;
    public float movingSpeed = 20;

    public Character(int input)
    {
        if(input == 0)
        {
            character = Object.Instantiate(Resources.Load("Perfabs/Priest", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
            TypeOfCharacter = 0;
        }
        else
        {
            character = Object.Instantiate(Resources.Load("Perfabs/Devil", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
            TypeOfCharacter = 1;
        }

        //Cmove = character.AddComponent(typeof(move)) as move;
        click = character.AddComponent(typeof(Click)) as Click;
        click.setGameObj(this);
    }

    public string getName()
    {
        return character.name;
    }

    public void setName(string input)
    {
        character.name = input;
    }

    public Vector3 getPosition()
    {
        return character.transform.position;
    }
    public void setPosition(Vector3 input)
    {
        character.transform.position = input;
    }

    public void getOnBoat(Boat input)
    {
        character.transform.parent = input.getGameobj().transform;
        characterStatus = 1;
    }

    public void getOnCoast(Coast input)
    {
        character.transform.parent = null;
        characterStatus = 0;
        coast = input;
    }

    public void reset()
    {
        //Cmove.reset();
        coast = (Director.getInstance().currentSceneController as main).RightCoast;
        getOnCoast(coast);
        setPosition(coast.getEmptyPosition());
        coast.getOnCoast(this);
    }
    /*
    public void moveToPosition(Vector3 input)
    {
        Cmove.setDestination(input);
    }*/

    public Coast getCoast()
    {
        return coast;
    }

    public GameObject getGameobj()
    {
        return this.character;
    }
}

其中注释掉的就是修改的部分,为了后面的main好写,里面新加了一些基本简单的功能。其他的coast以及boat大同小异。

main

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


public class main : MonoBehaviour,SceneController,ClickAction {

    private Coast LeftCoast;
    public Coast RightCoast;
    private Boat boat;
    private Character[] characters;
    private Water water;
    public simpleGUI simplegui;
    private FirstSceneActionManager actionManager;

    void Awake()
    {
        Director director = Director.getInstance();
        director.currentSceneController = this;
        characters = new Character[6];
        loadResources();
        simplegui = gameObject.AddComponent<simpleGUI>() as simpleGUI;
        actionManager = GetComponent<FirstSceneActionManager>();
    }

    public void loadResources()
    {
        LeftCoast = new Coast(-1);
        RightCoast = new Coast(1);
        boat = new Boat();
        //water = new Water();
        for (int i = 0; i < 3; i++)
        {
            Debug.Log("ok");
            Character newCharacter = new Character(0);
            newCharacter.setName("priest" + i);
            newCharacter.setPosition(RightCoast.getEmptyPosition());
            newCharacter.getOnCoast(RightCoast);
            RightCoast.getOnCoast(newCharacter);

            characters[i] = newCharacter;
        }
        for (int i = 0; i < 3; i++)
        {
            Character newCharacter = new Character(1);
            newCharacter.setName("devil" + i);
            newCharacter.setPosition(RightCoast.getEmptyPosition());
            newCharacter.getOnCoast(RightCoast);
            RightCoast.getOnCoast(newCharacter);

            characters[i+3] = newCharacter;
        }
    }

    public void ClickBoat()
    {
        if (boat.isEmpty())
        {
            return;
        }
        else
        {
            actionManager.moveBoat(boat);
            boat.newMove();
        }
        simplegui.status = gameStatus();
    }

    public void ClickCharacter(Character input)
    {
        if (input.characterStatus == 1)//0在岸上,1在船上
        {
            Coast coast;
            Debug.Log(boat.BoatPosStatus);
            if (boat.BoatPosStatus == -1)
            {
                coast = LeftCoast;
            }
            else
            {
                coast = RightCoast;
            }
            boat.GetOffBoat(input.getName());

            //input.moveToPosition(coast.getEmptyPosition());
            actionManager.moveCharacter(input, coast.getEmptyPosition());
            input.getOnCoast(coast);
            coast.getOnCoast(input);

        }
        else
        {
            Coast coast = input.getCoast();

            if (boat.getEmptyIndex() == -1)
            {
                return;
            }
            if (coast.TypeOfCoast != boat.BoatPosStatus)
            {
                return;
            }
            coast.getOffCoast(input.getName());

            actionManager.moveCharacter(input, boat.getEmptyPosition());
            input.getOnBoat(boat);
            boat.GetOnBoat(input);
        }

        simplegui.status = gameStatus();
    }
    public void ClickReset()
    {
        boat.reset();
        LeftCoast.reset();
        RightCoast.reset();
        for (int i = 0; i < characters.Length; i++)
        {
            characters[i].reset();
        }
    }

    public int gameStatus()
    {
        int from_priest = 0;
        int from_devil = 0;
        int to_priest = 0;
        int to_devil = 0;

        int[] fromCount = RightCoast.getCharacterNum();
        from_priest += fromCount[0];
        from_devil += fromCount[1];

        int[] toCount = LeftCoast.getCharacterNum();
        to_priest += toCount[0];
        to_devil += toCount[1];

        if (to_priest + to_devil == 6)      
            return 2;

        int[] boatCount = boat.getCharacterNum();
        if (boat.BoatPosStatus == -1)
        {   
            to_priest += boatCount[0];
            to_devil += boatCount[1];
        }
        else
        {   
            from_priest += boatCount[0];
            from_devil += boatCount[1];
        }

        if (from_priest < from_devil && from_priest > 0)
        {

            return 1;
        }
        if (to_priest < to_devil && to_priest > 0)
        {
            return 1;
        }
        return 0;
    }
}

main中修改的部分也不算很多,首先是加入变量private FirstSceneActionManager actionManager;,然后在start里面初始化,loadSource中去掉了water,因为我用了游戏资源库中的贴图,所以直接放在场景中了,也就是说water这个类也可以去掉了。然后下面把move的语句换成用actionManager的语句即可。

资源

资源文件

猜你喜欢

转载自blog.csdn.net/yaoxh6/article/details/79859162