2019-10-15 19:45:40 wangwei19871103 阅读数 97
  • unity3D游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    13037 人正在学习 去看看 宋晓波

目的

最近在B站看到很多MMD的动画,觉得有点意思,所以想研究下,顺便看看在AR,VR能不能用上。这个视频应该是算渲染的很不错的啦。

MMD4Mecanim

这个是日本开发者开发的一款unity动作插件,可以直接把模型和动作相匹配,转换成unityFBX模型。他的网站是http://stereoarts.jp/。当然他还有其他的一些东西,基本都跟动画有关,挺不错的。

Demo

我是用Unity 2018.4.0f1 (64-bit)开发的,一些基本操作我就不说了,我就说下用这个插件的步骤,还有结合AR,VR的一些操作和一些解决的问题。

下载MMD4Mecanim 插件

我们需要到http://stereoarts.jp/下载插件:
在这里插入图片描述
解压后:
在这里插入图片描述
其实我们只要MMD4Mecanim.unitypackage这个就行,新建一个unity项目,然后把这个拖进去。这个只是个插件,我们还需要模型文件和动作文件,模型文件和动作文件可以去百度下MMD的模型下载,有很多的,我就不举例了,我这里下载了一个,下载解压后是下面这样的,.pmx结尾的是一些模型文件,就是可以用插件转成FBX的,.vmd结尾的是动作文件,比如你想要极乐净土的,也可以去下,这个刚好也自带了一个动作:
在这里插入图片描述
我们把这个拖进工程里,然后点击.MMD4Mecanim结尾的文件,有三个,随便点一个,然后会看到右边属性栏的一些协议:
在这里插入图片描述
在这里插入图片描述
往下拖,然后勾选,并点击agree按钮:
在这里插入图片描述
之后就看到:
在这里插入图片描述
然后把VMD动作文件拖入到这个属性栏里,要注意这个Sora动作好像有问题,所以我下了个极乐净土的:
在这里插入图片描述
点击Process
在这里插入图片描述
之后就会看到他在命令行里处理,可能比较慢:
在这里插入图片描述
处理完之后会看到输出窗口:
在这里插入图片描述
还会看到主要多了一个FBX模型和材质文件夹:
在这里插入图片描述
把模型拖到场景里:
在这里插入图片描述
模型属性栏是这样的:
在这里插入图片描述
可以看到有个动画,缺少控制器,所以我们需要创建一个控制器:
在这里插入图片描述
之后把模型内部的动作拖入到控制器窗口内:
在这里插入图片描述
然后把控制器拖入模型属性里:
在这里插入图片描述
然后点击play就可以看到在跳舞啦,这个时候你可以再加个极乐净土的音乐上去,基本是能同步上的,这个我就不说了,自己可以试下:
在这里插入图片描述

虽然这个在windows上没有问题,但是android上就渲染不出了,主要还是因为材质的shader的问题,比如看其中一个:
在这里插入图片描述
在这里插入图片描述
所以在移动端不支持,所以我们可以把所有的材质改成这个:
在这里插入图片描述
当然你改成其他的也可以,看看效果。至于AR,VR的话,我也不想多讲,AR可以用EasyAR,基本都有教程的,只要注意android的一些设置就可以。然后VR的话需要下载GoogleVRForUnity,unity2018版的应该没问题,基本就是看他的说明,在他的基本场景下放上模型就可以,没什么其他难点。当然你还可以加一些场景什么的,或者新的模型。

Demo网盘链接:https://pan.baidu.com/s/155N0PbKoLCXG1Rps2R1MHQ
提取码:im7w

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。

2019-07-21 17:41:32 moon_goes 阅读数 69
  • unity3D游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    13037 人正在学习 去看看 宋晓波

今天学习了Animator组件对动画播放的控制。

1.在需要控制的物体下创建一个Animator组件,再创建一个Animator Controller拖到Controller下。
在这里插入图片描述
2.进入Controller对要播放的动画顺序进行编辑,在此暂时只有三个动作动画的切换,分别是站立、行走和跑。创建一个参数speed用来界定动画播放。物体默认站立状态,当物体运动速度大于0,切换为行走,大于1,从行走切换为跑。
在这里插入图片描述

player_speed = this.GetComponent<CharacterController>().velocity.magnitude;//获取人物运动速度
    anima.SetFloat("speed", player_speed);

SetFloat方法接收两个参数,一个是animator中的参数名,另外一个是你要传递给它的参数。我的理解是方法把传递的参数作为它的实参套用到前者的约束中。
获取物体移动速度可以从CharacterController组件中获取,通过velocity,注意要用magnitude获取数值大小。
可以添加的参数有四种类型,可以按需选择不同类型
可以添加的参数有四种类型,可以按需求选择。

7/22
做控制人物攻击动画的时候先是使用了Bool类型的参数,true播放攻击动画,false返回原状态。

  if (Input.GetKey(KeyCode.Q))//按下Q键触发动画播放
        {
            attack();
        }

    void attack()//攻击动画
    {
        anima.SetBool("attack", true);
    }

animator中转换条件是attack为true转为攻击状态。
在这里插入图片描述
但是此处出现了一个bug(目前未解决),就是attack动画会反复播放,并不会返回原先的状态。改错思路尝试过计算attack动画长度,采用一个float类型的变量存储动画时长,timer-=Time.deltaTime timer<=0则设置attack为false,并没有如期运行。

随后学习了trigger变量,trigger变量在按下按键时变更为true,然后动画播放完自动返回false状态,于是攻击动画采用了trigger实现。

if (Input.GetKey(KeyCode.Q))
        {
            attack();
        }
    void attack()//攻击方法
    {
        anima.SetTrigger("attack");//SetTrigger只接受参数名,不用设置true or false
    }

7/23
控制攻击动画播放还存在两个问题,一是动画会播放了一小段又从头开始播放,这个问题通过修改GetKey为GetKeyDonw后得到解决,但这引发第二问题,触发的动画循环播放,不返回原状态。是因为没有取消动画的Loop Time。
在这里插入图片描述
在动画设置界面将Loop Time取消即可解决。

2012-11-30 15:17:20 miaoweiye 阅读数 2733
  • unity3D游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    13037 人正在学习 去看看 宋晓波

          先说说Unity3D关于动画方便的东西,Animation Mixing (动画混合),什么是动画混合呢?举个简单的例子吧,一个模型现在又3种动作,分别是idle、walk、shoot,在Unity3D中一个Layer只能播放二种动画,shoot动作只影响左肩膀的骨骼,而不会影响腿部的动作,所有这里就可以把shoot和walk进行Mixing。

 

function Start ()
{

//增加一个动画剪辑片段

//
 animation.AddClip(animation["shoot"].clip, "shootUpperBody");
 animation["shootUpperBody"].AddMixingTransform(transform.Find("mover/gun")); //@parm 路径
 animation["shootUpperBody"].AddMixingTransform(transform.Find("mover/roothandle/spine1"));
//设置动画模式 
 animation.wrapMode = WrapMode.Loop;

 animation["jump"].wrapMode = WrapMode.Clamp;
 animation["shoot"].wrapMode = WrapMode.Clamp;
 animation["shootUpperBody"].wrapMode = WrapMode.Clamp;
 
 // Put idle and run in a lower layer. They will only animate if our action animations are not playing
 animation["idle"].layer = -1;
 animation["run"].layer = -1;
 
 animation.Stop();
}


function Update () {
 if (Mathf.Abs(Input.GetAxis("Vertical")) > 0.1)
 {
  animation.CrossFade("run");
  animation["run"].speed = Mathf.Sign(Input.GetAxis("Vertical"));
 }
 else
  animation.CrossFade("idle");

 if (Input.GetButtonDown ("Jump"))
 {
  animation.CrossFade("jump", 0.3);
 }
  if (Input.GetButtonDown ("Fire1"))
 {
  if (animation["run"].weight > 0.5)
   animation.CrossFadeQueued("shootUpperBody", 0.3, QueueMode.PlayNow);
  else
   animation.CrossFadeQueued("shoot", 0.3, QueueMode.PlayNow);
 }

 

2013-11-20 20:12:45 huangfe1 阅读数 882
  • unity3D游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    13037 人正在学习 去看看 宋晓波



那抱歉,上次那个Unity+kinect还没有更新,最近在深一步研究,不久将更新(绝对不负众望)!现在进入正题,十分钟带你打造unity3D第一人称射击游戏!

看完本篇博客,你将学会第一人称控制,粒子的添加,碰撞的检测,鼠标的监听,画2d图像,预制物体克隆,添加力,添加声音等等!(本篇博客假设你已经对unity稍微有点了解)

一,打开unity,创建一个场景,添加一个plane,(gameobject->createother->plane)。

二,添加虚拟第一人称任务(现在没搞模型,模型后面可以自己添加);Assert->importpackages->Charactercontroll,之后你将Project面板里面看到这个资源包,打开里面的charactercontroll文件,将里面的first Person controll拖动到合适的位置。

三,然后我们将添加一个虚拟的枪口,作为子弹的发生点!这个你可以创建一个椭圆,放在摄像机的最中间


 然后要将椭圆设置为摄像机的子物体,这样他将随着摄像机运动(不能设置为任务模型的子物体,因为任务模型的不能上下移动,也就不是这样后不能上下射击)。也就是在hierahcry面板中点击你创建椭圆,拖到摄像机上,这样他就成了摄像机的子物体。可以点击运行测试下,你会发现这东西只是虚拟枪口,所以我们设置它看不见,点击椭圆,在修改面板上,有个MeshRender,你单击下,椭圆就看不见了,但是它存在,然后再点击CapsuleColisder,取消他的碰撞(以免影响子弹的射击);
三,子弹的射击

我们首先创建一个圆,(用这个圆来模拟子弹,如果你自己有子弹模型,就用子弹模型),然后在project中创建一个prefab,用于之后的克隆子弹,现在我们来子弹一点火焰效果,Assert->importpackage->particles导入粒子,点击里面的fire,将里面的Flame拖到游戏中,位置和你创建的球(子弹)一样,然后将你设置的,然后同样的方法,将火焰设置为,子弹的子物体,这样,火焰将和子弹一起运动,自己在属性面板里 修改火焰的大小,然后将子弹拖到你创建的prefab中,修改prefab的名字为balls!添加一个刚体属性,Rigidbody(Addcomment->ragidbody)然后删除游戏中的子弹(嗯,删除)!现在子弹的预制物体已经创建好了,现在我们来射击!

四 ,点击鼠标,发生子弹

现在 就是敲代码码的时候了

var aim:Transform;
//克隆子弹
private var ball:Transform;
//绘制准星的材质
var material:Material;
function Start () {

}

function Update () {
//将鼠标的图标隐藏
Screen.showCursor=false;
//var zj=Vector3(Screen.width/2,Screen.height/2,0);
//var ray:Ray=Camera.main.ScreenPointToRay(Input.mousePosition);
//定义一个方向,为发射点y轴方向
var dir=aim.transform.TransformDirection(Vector3.up);
//var dir=ray.direction;
//按下鼠标左键
if(Input.GetMouseButtonDown(0)){
//实列化一个球,发射点的位置,
ball=Instantiate(balls,aim.position,Quaternion.identity);
//在某一个方向加一个力
ball.rigidbody.AddForce(dir.normalized*1000);
print("----------->>>");
//三秒后删除小球
Destroy(ball.gameObject,3);
}
}

 这里用到了,Screen.showCursor=false;将鼠标隐藏,要将他放在updatae中,放在start中不行var dir=aim.transform.TransformDirection(Vector3.up);这是定义一个方向,子弹将以这个方向射击

其他的没什么解释的了,注释很详细了,方法里面传入的参数,查一下API文档就行

五 ,现在们开始绘制准星

 

//绘制准星的材质

var material:Material;

先定义 一个材质,用来绘制图像

 

//绘制准星
function OnPostRender(){
DrawRecent(Screen.width/2,Screen.height/2,10,10);
}
//绘制四边形的方法
function DrawRecent(x:float,y:float,width:float,height:float){
//材质通道设置为默认的0
 material.SetPass(0);
 //绘制2D图形
  GL.LoadOrtho();
 //绘制长方体
 GL.Begin(GL.QUADS);
 //传入四个点的相对屏幕的坐标,先后分别是左上角,左下角,右下角,右上角
  GL.Vertex(new Vector3(x/Screen.width,y/Screen.height,0));
  GL.Vertex(new Vector3(x/Screen.width,(y+height)/Screen.height,0));
  GL.Vertex(new Vector3((x+width)/Screen.width,(y+height)/Screen.height,0));
  GL.Vertex(new Vector3((x+width)/Screen.width,y/Screen.height,0));
  //结束绘画
  GL.End();
}

 这个没什么好解释的,注释有,按照各个规则就是

 

然后就是,如果你射击到了敌人,敌人就着火

四,射击敌人

首先我们,创建几个cube,这个用来模拟敌人,如果你有好的模型,就用模型。给cube创建ridibody

然后给它一个标签,在属性面板上面有个Tag,点击,选择player,给个player标签,你也可以点击addTag自己添加一个Tag,现在我们创建一个prefab预制火火焰,创建一个空物体,将先前导入的fires拖到空物体中

将空物体放入prefab中,改名为fires

现在 我们添加碰撞事件

新建一个脚本,

 

#pragma strict
//预制火焰
var fires:Transform;
//克隆火焰
private var fire:Transform;
function Start () {

}

function Update () {

}//碰撞监听
function OnCollisionEnter(other:Collision){
//如果碰到的事cube(先前我们将cube的tag设置成了player)
if(other.transform.tag=="Player"){
//克隆一个火焰
fire=Instantiate(fires,other.transform.position,Quaternion.identity);
//设置火焰的父对象为箱子,这样火焰将和物体一起运动,
fire.transform.parent=other.transform;}
}

 五,你想加入声音嘛?如果你想,接着看两种方式添加音乐,首先添加背景音乐,点击摄像机,AddCommpent->aduio->aduiosource

 

首先 下载你需要的背景音乐,将音乐拖进Asset文件夹中,然后将音乐拖进刚才添加的aduiosource的中

然后 教你添加动作音效,在第一和代码中加入var music:AudioClip;

然后再发生子弹的那个方法中,AudioSource.PlayClipAtPoint(music,transform.position);播放,

六:挂载脚本

你首先将以第一个脚本,挂到摄像机上面,然后将第一个frefab(balls)拖到变量中

第二个脚本放在balls上,将fires和音乐拖到变量中!!

OK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 现在开火!!!!!!!!!

 

 

 

源码下载

2019-09-28 12:32:38 wangzh297 阅读数 67
  • unity3D游戏/AR/VR在线就业班

    本套课程是一套完整的 Unity3D-游戏/AR/VR 学习课程,具体的课程内容包括《C#语言》、《Unity引擎》、《编程思想》,《商业级项目实践》等开发课程,引导您一步步循序渐进、由易到难,终获得Unity 3D/游戏/AR/VR工程师的岗位技能。

    13037 人正在学习 去看看 宋晓波

基本操作演练

  • 下载 Fantasy Skybox FREE, 构建自己的游戏场景
  • 写一个简单的总结,总结游戏对象的使用

下载Fantasy Skybox FREE 构建场景

(1)在Asset Store搜索Fantasy Skybox FREE并下载。
在这里插入图片描述
(2)将Fantasy Skybox FREE导入项目,查看相关资源。主要是Asset\Fantasy Skybox FREE\Demo\Prefabs文件夹中的预制和Asset\Fantasy Skybox FREE\Demo\Terrain文件夹下已经做好的场地场景。
在这里插入图片描述
在这里插入图片描述
(3)利用已有的预制和场景构建自己的游戏场景,主要需要完成的也只是将已有的游戏对象拖入Scene。
在这里插入图片描述

总结游戏对象的使用

作为程序员,我们大多对美工没有成熟的想法和技术,所以由我们自己完成对游戏场景的塑造确实有点强人所难,但是美好的场景对于一款游戏来说却又是必须的,因此,我们有必要借助别人已经做好的模型,用这些已经成熟的组件完成对场景的构建,具体的行为和交互由我们自己编写的程序完成,通过简单的拖动或创建完成场景在生产过程是简化生产流程和生产成本的一个有效途径。

编程实践

  • 牧师与魔鬼 动作分离版
  • 设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束

动作分离

(1)首先查看UML图,SSAction类是动作类,负责所有动作的具体信息以及实施;SSActionManager类是动作管理类,负责控制动作的执行;XXSceneController类是场景管理类,当有游戏对象需要移动时,需要将该信号传递给CCActionManager类CCActionManager类派生自SSActionManager类,接收来自场记的信号,并完成对动作的调配和执行;CCSequenceAction类CCMoveToAction类都派生自SSAction类,前者代表组合动作,后者代表移动到某一目的地的动作;SSActionEvent是一个接口,交由SSAction类实现。
在这里插入图片描述
(2)其次需要对现有类做一些补充,使得功能更为完善和安全,确保系统的健壮性。添加ISSActionCallback类,用于标识动作是否已经完成,将完成的消息返回给动作管理类,以便动作管理类执行下一个动作。所以该类将会成为SSAction类的一个属性,作为callback被调用,告诉SSActionManager类,动作完成。根本原理是,ISSActionCallback类包含唯一的方法,用于对一个已结束的动作做处理,所以动作管理类都必须对该类继承;而动作类又必须有该类的属性,以便于在动作结束后调用。

(3)查看师姐的代码,发现一个小缺陷,在动作管理类中,因为没有对其管理的动作的callback的函数定义,所以在Update函数中使用enable属性来判断动作是否正在进行中是不合理的,毕竟所有动作的enable属性都被赋值为true并且不会被修改。

遇到的一些问题:
1.列表List<>在声明后必须用new List,<>()初始化,否则就没有创建实例,无法使用,C#语言特性,类似Java。
2.对于Start()Update()这样的方法。当他们存在于父类中时,子类中即便不需要,也必须实现,否则,他们会在运行过程中自动调用父类的版本,可能引起错误。
3.派生自MonoBehaviour类的类必须通过AddComponent方法才能加入到场景中,或者说加入到游戏对象上。

ActionManager.cs 代码如下:

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

namespace ActionManager
{
    public enum SSActionEventType : int { Started, Competeted }

    public interface ISSActionCallback/* 动作事件调用接口,由动作、动作类型和参数构成事件 */
    {
        void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
            int intParam = 0, string strParam = null, Object objectParam = null);
    }

    public class SSAction : ScriptableObject            /* 动作 */
    {

        public bool enable = true;                      /* 是否正在进行此动作 */
        public bool destroy = false;                    /* 是否需要被销毁 */

        public GameObject gameobject;                   /* 动作对象 */
        public Transform transform;                     /* 动作对象的transform */
        public ISSActionCallback callback;              /* 回调函数 */

        protected SSAction() { }                        /* 保证SSAction不会被new */

        public virtual void Start()                     /* 子类可以使用这两个函数 */
        {
            throw new System.NotImplementedException();
        }

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

    public class CCSequenceAction : SSAction, ISSActionCallback/* 组合动作类 */
    {
        List<SSAction> sequence;                        /* 动作列表 */
        int repeat;                                     /* 标识动作是否进入循环 */
        int start;                                      /* 动作列表中需要执行的下一个动作 */

        public static CCSequenceAction GetCCSequenceAction(List<SSAction> actions, int repeat, int start)
        {                                               /* 连续动作类的实例化 */
            CCSequenceAction SeqAction = ScriptableObject.CreateInstance<CCSequenceAction>();
            SeqAction.sequence = actions;
            SeqAction.repeat = repeat;
            SeqAction.start = start;
            return SeqAction;
        }

        public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
            int intParam = 0, string strParam = null, Object objectParam = null)
        {
            source.destroy = false;
            this.start++;
            if (this.start >= sequence.Count)
            {
                this.start = 0;
                if (repeat > 0) repeat--;                /* 组合动作循环执行的次数 */
                else
                {
                    this.destroy = true;               /* 所有动作执行完毕,组合动作等待销毁 */
                    this.callback.SSActionEvent(this); /* 向上调用动作管理类的ISSActionCallback类方法,进行结束操作 */
                }
            }
        }

        public override void Start()
        {
            //base.Start();
            for (int i = 0; i < sequence.Count; i++)
            {
                sequence[i].gameobject = this.gameobject;/* 所有组合动作的子动作拥有同一个作用对象 */
                sequence[i].callback = this;             /* 所有组合动作的子动作需要在结束时通知组合动作对象 */
                sequence[i].transform = this.transform;
                sequence[i].Start();                     /* 子动作进行 */
            }
        }

        public override void Update()
        {
            //base.Update();
            if (start < sequence.Count)                  /* start值只有子动作结束时才会改变,所以这里的Update是子动作的 */
            {
                sequence[start].Update();
            }
        }
    }

    public class CCMoveToAction : SSAction
    {
        int speed = 50;
        Vector3 destPos;
        bool canMove = true;

        public static CCMoveToAction GetCCMoveToAction(Vector3 destPos)   /* 类同与原Move类中的moveTo函数,用于确定目的地 */
        {
            CCMoveToAction moveToAction = ScriptableObject.CreateInstance<CCMoveToAction>(); ;
            moveToAction.destPos = destPos;
            return moveToAction;
        }

        public override void Start()                    /*  必须实现,否则自动调用父类 */
        {
            //base.Start();
        }

        public override void Update()                   /* 移动到目的地 */
        {
            //base.Update();
            if (canMove)
            {
                transform.position = Vector3.MoveTowards(transform.position, destPos, speed * Time.deltaTime);
                if (transform.position == destPos)
                {
                    canMove = false;
                    destroy = true;
                    this.callback.SSActionEvent(this);
                }
            }
        }
    }

    public class SSActionManager : MonoBehaviour, ISSActionCallback
    {
        List<SSAction> actionList=new List<SSAction>();       /* 必须初始化!!!! */

        public void SSActionEvent(SSAction source, SSActionEventType events = SSActionEventType.Competeted,
            int intParam = 0, string strParam = null, Object objectParam = null)
        {
            source.enable = false;                            /* 动作完成执行 */
        }

        public void RunAction(GameObject gameObject, SSAction action)
        {
            action.gameobject = gameObject;                   /* 为需要执行的动作初始化 */
            action.transform = gameObject.transform;
            action.callback = this;                           /* 提交给动作管理类的动作自然由此类管理 */
            actionList.Add(action);                           /* 加入动作列表,等待循环遍历,有的动作可能反复执行 */
            action.Start();                                   /* 主要针对组合动作,需要对子动作都进行初始化 */
        }

        protected void Update()
        {
            for (int i = 0; i < actionList.Count; i++)
            {
                if (actionList[i].destroy)
                    actionList.Remove(actionList[i]);
                else if (actionList[i].enable)
                    actionList[i].Update();
            }
        }
    }
}

设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束

(1)一个裁判类需要完成的任务是持续监视当前场景是否会触发结束条件,在该游戏中表现为“船上魔鬼加上船所靠的岸上的魔鬼数目和大于船上牧师加船所靠岸上的牧师数目和”。所以裁判类必然需要接收当前场景的信息用于判断。

(2)设计裁判类的命名空间,包括一个接口ISSJudge、一个类SSJudgeSSJudge类包括几个方法:GetSSJudge()用于活动的一个裁判类的实例;judge()用于根据现有的对象信息,进行结束条件判断;最重要的是Update()方法,在裁判类中实现Update()方法即可使游戏结束判断与场景控制器分离。

Judge.cs 代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Models;
using SceneController;
using View;
using Director;

namespace Judge
{
    public interface ISSJudge
    {
        bool jude(Role[] roles);
    }

    public class SSJudge: MonoBehaviour, ISSJudge
    {
        pageImage gameGUI = (SSDirector.getInstance().currentSceneController as Controller).gameGUI;
        Role[] roles = (SSDirector.getInstance().currentSceneController as Controller).roles;
        Boat boat = (SSDirector.getInstance().currentSceneController as Controller).boat;

        public static SSJudge GetSSJudge()
        {
            SSJudge judger = new SSJudge();
            return judger;
        }

        public bool jude(Role[] roles)
        {
            int priestNumAtStart = 0;
            int priestNumAtEnd = 0;
            int devilNumAtStart = 0;
            int devilNumAtEnd = 0;
            int priestNumAtBoat = 0;
            int devilNumAtBoat = 0;
            for (int i = 0; i < 6; i++)
            {
                switch (roles[i].getRolePos())
                {
                    case 0:
                        if (roles[i].getRoleId())
                        {
                            priestNumAtBoat++;
                        }
                        else
                        {
                            devilNumAtBoat++;
                        }
                        break;
                    case 1:
                        if (roles[i].getRoleId())
                        {
                            priestNumAtStart++;
                        }
                        else
                        {
                            devilNumAtStart++;
                        }
                        break;
                    case 2:
                        if (roles[i].getRoleId())
                        {
                            priestNumAtEnd++;
                        }
                        else
                        {
                            devilNumAtEnd++;
                        }
                        break;
                    default:
                        break;
                }
            }
            Debug.Log("priestNumAtBoat:" + priestNumAtBoat);
            Debug.Log("priestNumAtStart:" + priestNumAtStart);
            Debug.Log("devilNumAtBoat:" + devilNumAtBoat);
            Debug.Log("devilNumAtStart:" + devilNumAtStart);
            Debug.Log("priestNumAtEnd:" + priestNumAtEnd);
            Debug.Log("devilNumAtEnd:" + devilNumAtEnd);
            Debug.Log("");
            
            if (((boat.getBoatPos() ? priestNumAtBoat : 0) + priestNumAtStart < (boat.getBoatPos()?devilNumAtBoat:0) + devilNumAtStart)&&(priestNumAtStart!=0) || ((boat.getBoatPos() ? 0 : priestNumAtBoat) + priestNumAtEnd < (boat.getBoatPos() ? 0:devilNumAtBoat) + devilNumAtEnd)&&(priestNumAtEnd!=0))
            {
                return false;
            }
            else
                return true;
        }

        protected void Update()
        {
            gameGUI.isOver = jude(roles);
        }
    }

}

游戏演示视频传送门

Github详尽代码传送门

没有更多推荐了,返回首页