Unity3D学习(3)之基于鼠标点击的3D版牧师与魔鬼
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/ohmy.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/ohmy.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/ohmy.gif)
![](/assets/blank.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/smile.gif)
游戏角色:3个牧师、3个魔鬼
游戏场景:2个河岸、1艘小船,河
游戏的架构:
UserInterface 用来创建GUI对象接受玩家动作,处理GUI事件,使用 IUserActions 接口控制游戏。
GenGameObjec 作为场记用于载入资源,用来处理对象间通信和实现 IUserActions 接口和ISceneController接口
SSDirector 作为导演,含有场记对象及设置帧
首先我们先实现SSDirector
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public interface ISceneController
{void LoadResources();//void Pause ();//void Resume ();
}public class SSDirector : System.Object
{private static SSDirector _instance;public ISceneController currentScenceController { get; set; }public bool running { get; set; }public static SSDirector getInstance(){if (_instance == null){_instance = new SSDirector();}return _instance;}public int getFPS(){return Application.targetFrameRate;}public void setFPS(int fps){Application.targetFrameRate = fps;}
}
void Awake()//创建导演实例并载入资源{SSDirector director = SSDirector.getInstance();director.setFPS(60);director.currentScenceController = this;director.currentScenceController.LoadResources();}
public void LoadResources()//载入资源{// shore Instantiate(Resources.Load("prefabs/begin"), shoreStartPos, Quaternion.identity);Instantiate(Resources.Load("prefabs/end"), shoreEndPos, Quaternion.identity);Instantiate(Resources.Load("prefabs/water"), waterPos, Quaternion.identity);Instantiate(Resources.Load("prefabs/water"), waterPos1, Quaternion.identity);// boat boat_obj = Instantiate(Resources.Load("prefabs/Capsule"), boatStartPos, Quaternion.identity) as GameObject;// priests & devils for (int i = 0; i < 3; ++i){priests_start[i] = (Instantiate(Resources.Load("prefabs/Priest")) as GameObject);priests_end[i] = null;devils_start[i] = (Instantiate(Resources.Load("prefabs/Devil")) as GameObject);devils_end[i] = null;}}
begin为开始岸,end为结束岸,water为水,capsule为船,priest为牧师,devil为魔鬼。boat_obj为船的实体。priests_start[],priests_end[],devils_start[],devils_end[]分别是存储开始岸和结束岸的牧师对象,魔鬼对象。
![](/assets/blank.gif)
![](/assets/blank.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/smile.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/smile.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/smile.gif)
在继续编写 GenGameObject 脚本之前,我们要明确游戏允许玩家的所有动作。这里,我规定的玩家动作有7个:
项目 | 条件 |
开船 | 船在开始岸、船在结束岸 |
船的左方下船 | 船靠岸且船左方有人 |
船的右方下船 | 船靠岸且船右方有人 |
开始岸的牧师上船 | 船在开始岸,船有空位,开始岸有牧师 |
开始岸的魔鬼上船 | 船在开始岸,船有空位,开始岸有魔鬼 |
结束岸的牧师上船 | 船在结束岸,船有空位,结束岸有牧师 |
结束岸的魔鬼上船 | 船在结束岸,船有空位,结束岸有魔鬼 |
考虑到牧师和魔鬼的位置时刻要变化,因此先定义一个 setCharacterPositions 函数。该函数接受一个array[]参数,和一个Vector3坐标。我说明下这里为什么不使用栈,因为栈只能按顺序的pop和push,而我想实现的是通过鼠标点击响应,可能有乱序,所以我这里用array[].
void setCharacterPositions(GameObject[] array, Vector3 pos)//设置人物位置{for (int i = 0; i < 3; ++i){if(array[i] != null)array[i].transform.position = new Vector3(pos.x, pos.y, pos.z + gap * i);}}
void Update () {setCharacterPositions(priests_start, priestStartPos);setCharacterPositions(priests_end, priestEndPos);setCharacterPositions(devils_start, devilStartPos);setCharacterPositions(devils_end, devilEndPos);
现在,我们来考虑规则抽象的行为,分为3种: 上船 、 开船 、 下船 。
1. 上船:把一个游戏对象设为船的子对象。
定义 getOnTheBoat 函数,接受一个游戏对象为参数,只要船上有空位,就把游戏对象设置为船的子对象,这样游戏对象便能跟着船移动:
void getOnTheBoat(GameObject obj)//上船{print(obj.name);if (boatCapacity != 0){if (boat_position == 0){for (int i = 0; i < 3; ++i){if (devils_start[i] == obj){devils_start[i] = null;find = 1;}if (priests_start[i] == obj){priests_start[i] = null;find = 1;}}}else if (boat_position == 1){for (int i = 0; i < 3; ++i){if (devils_end[i] == obj){devils_end[i] = null;find = 1;}if (priests_end[i] == obj){priests_end[i] = null;find = 1;}}}if(find == 1)obj.transform.parent = boat_obj.transform;if (boat[0] == null && find == 1){boat[0] = obj;boat[0].transform.tag = obj.transform.tag;boatCapacity--;obj.transform.localPosition = new Vector3(0, 1.2f, 0.19f);}else if(boat[1] == null && find == 1){boat[1] = obj;boat[1].transform.tag = obj.transform.tag;boatCapacity--;obj.transform.localPosition = new Vector3(0, 1.2f, -0.12f);}}find = 0;}
getOnTheBoat接受一个GameObject,为鼠标点击的物体。首先判断boatCapacity是否不为0,即船上有空位。然后判断船的位置,boat_position是0(在开始岸),或是1(在结束岸)。然后检查该物体是否在所在岸上的牧师或者魔鬼数组里,若找到find为1.若是1,将该gameobject挂在船的子对象里,然后判断boat[0]或者boat[1]是否为空(boat数组用来存储在船上的对象),找到合适的位置,装进去,并且设置boat[i]的tag(用于鼠标点击)。boatCapacity减1,设置其相对位置(设置位置是最TMTMTM麻烦的,不断微调
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/smile.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/smile.gif)
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/smile.gif)
void Boatmoving(GameObject obj)//船的移动{if(boat_position == 1){boat_position = 0;while (obj.transform.position != boatStartPos)obj.transform.position = Vector3.MoveTowards(obj.transform.position, boatStartPos, 1);}else if(boat_position == 0){boat_position = 1;while (obj.transform.position != boatEndPos)obj.transform.position = Vector3.MoveTowards(obj.transform.position, boatEndPos, 1);}}
void getOffTheBoat(int side)//下船{if (boat[side] != null){boat[side].transform.parent = null;if (boat_position == 1){print(side);if (boat[side].transform.tag == "Priest"){for(int i = 0; i < 3; i++){if(priests_end[i] == null){priests_end[i] = boat[side];boatCapacity++;break;}}}else if (boat[side].transform.tag == "Devil"){for (int i = 0; i < 3; i++){if (devils_end[i] == null){devils_end[i] = boat[side];boatCapacity++;break;}}}}else if (boat_position == 0){if (boat[side].transform.tag == "Priest"){for (int i = 0; i < 3; i++){if (priests_start[i] == null){priests_start[i] = boat[side];boatCapacity++;break;}}}else if (boat[side].transform.tag == "Devil"){for (int i = 0; i < 3; i++){if (devils_start[i] == null){devils_start[i] = boat[side];boatCapacity++;break;}}}}boat[side] = null;}check();}
传入参数side,指明是在船上的哪一边。判断如果船上的那一边对象为非空,首先取消父子关系。判断船的位置和对象的tag压入数组里面的非空的位置,boat[side]置空,然后检查游戏是否结束了。
![](/assets/blank.gif)
![](/assets/blank.gif)
除此以外,还需要判断游戏的输赢,定义一个 check 函数:
void check()//检查游戏是否结束{int priests_s = 0, devils_s = 0, priests_e = 0, devils_e = 0;for(int i = 0; i < 3; i++){if(priests_start[i] != null){priests_s++;}if(devils_start[i] != null){devils_s++;}if(priests_end[i] != null){priests_e++;}if(devils_end[i] != null){devils_e++;}}if(((priests_s < devils_s) && (priests_s != 0))||((priests_e < devils_e) && (priests_e != 0))){print("you lose");game = 1;}else if (priests_s == 0 && devils_s == 0){print("you win!!!");game = 2;}}
if (Input.GetMouseButtonDown(0) && game == 0){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);RaycastHit hit;if (Physics.Raycast(ray, out hit)){if (hit.transform.tag == "Devil" || hit.transform.tag == "Priest"){if(hit.collider.gameObject == boat[0] || hit.collider.gameObject == boat[1]){if(hit.collider.gameObject == boat[0])getOffTheBoat(0);else getOffTheBoat(1);}else{print(hit.transform.tag);getOnTheBoat(hit.collider.gameObject);}}else if (hit.transform.tag == "Boat" && boatCapacity != 2){print(hit.transform.tag);Boatmoving(hit.collider.gameObject);check();}}}
Input.GetMouseButtonDown(0)是响应鼠标左键按下,game = 0表示游戏正在进行中,game = 1表示输,game = 2表示赢,game = 3表示暂停。鼠标点击是通过从鼠标位置引一条射线,如果遇到碰撞框即可获取该物体。判断hit.transform.tag == Devil 或者是 Priest 然后判断是否是在船上,在船上就下船,不在船上就下船(这里有一个小小的bug,假如你点击了对岸的devil或者是priest呢?难道跳上船?)如果hit.transform.tag == boat且船上有人就移动船,并且检查输赢。到此基本完成场景控制。
public interface IUserAction
{void Restart();void ShowDetail();void Pause();
}
private IUserAction action;// Use this for initializationvoid Start () {action = SSDirector.getInstance().currentScenceController as IUserAction;}
void OnGUI() {GUIStyle fontstyle1 = new GUIStyle();fontstyle1.fontSize = 50;fontstyle1.normal.textColor = new Color(255, 255, 255);if (GUI.Button(new Rect(0, 80, 80, 60), "RESTART")){action.Restart();}if (GUI.RepeatButton(new Rect(0, 0, 120, 60), "Priests and Devils")){action.ShowDetail();}if(GUI.Button(new Rect(0, 160, 80, 60), "Pause")){action.Pause();}}
public void Restart(){SceneManager.LoadScene("task2");}public void ShowDetail(){GUI.Label(new Rect(220, 20, 350, 250), "Priests and Devils is a puzzle game in which you will help the Priests and Devils to cross the river. There are 3 priests and 3 devils at one side of the river. They all want to get to the other side of this river, but there is only one boat and this boat can only carry two persons each time. And there must be one person steering the boat from one side to the other side. In the flash game, you can click on them to move them and click to move the boat to the other direction. If the priests are out numbered by the devils on either side of the river, they get killed and the game is over. You can try it in many ways. Keep all priests alive! Good luck!");}public void Pause(){if (game == 0){game = 3;}else if(game == 3){game = 0;}}
![](/assets/blank.gif)
private void OnGUI(){GUIStyle fontstyle1 = new GUIStyle();fontstyle1.fontSize = 50;fontstyle1.normal.textColor = new Color(255, 255, 255);if (game == 1){GUI.Label(new Rect(260, 180, 100, 100), "YOU LOSE!!!", fontstyle1);}else if(game == 2){GUI.Label(new Rect(260, 180, 100, 100), "YOU WIN!!!", fontstyle1);}}
自此游戏完成,虽然已经完成,但是感觉架构还是不很清晰,等待慢慢学习,慢慢理解。感觉还是有一段很长的路要走。欢迎大家回复提建议帮我改进。
有兴趣的同学请去GitHub看,这是传送门
Unity3D学习(3)之基于鼠标点击的3D版牧师与魔鬼相关推荐
- 鼠标点击器至尊版使用教程指导
鼠标点击器至尊版是目前网上功能最多一款软件,为什么这么说呢,软件以工具形式,用户只需要了解每个工具的作用,就可以像搭积木一样完成各种各样的点击任务.首先我们看下软件界面 可以看到软件提供了8个工具.下 ...
- Visual C C++ studio2019 自制鼠标点击器,窗口版和命令行版 210325
一 窗口版 1.h和cpp h: DesktopMouseClick1.h #pragma once#include "resource.h" #include <threa ...
- Unity3d HW4-动作分离版牧师与魔鬼
一.基本操作演练 下载 Fantasy Skybox FREE, 构建自己的游戏场景 首先上Assert Store下载Skybox,我下载的是这一个: 之后我在unity中,把下载好的天空盒拖入摄像 ...
- Unity3d使用鼠标点击控制人物走动无效的问题
Unity3d使用鼠标点击控制人物走动无效的问题 最近在自学Unity3d,在学到使用鼠标点击控制人物走动时,按照API上面将代码写好,如下: void Update () {// _clickLis ...
- cesium获取点击内容信息_Cesium获取鼠标点击位置(PickPosition)
cesium学习了这么长时间,有时候写鼠标点击事件时,想获取鼠标点击点位置,发现情况很多.比如以下情形: 1获取鼠标点的对应椭球面位置 2获取加载地形后对应的经纬度和高程 3获取倾斜摄影或模型点击处的 ...
- 【Unity3D基础】让物体动起来②--UGUI鼠标点击逐帧移动
背景 上一篇通过鼠标移动的代码很简单,所以看的人也不多,但是还是要感谢"武装三藏"在博客园给出的评论和支持,希望他也能看到第二篇,其实可以很简单,而且是精灵自控制,关键是代码少是我 ...
- Unity3d鼠标点击屏幕来控制人物的走动
今天呢,我们来一起实现一个在RPG中游戏中十分常见的功能,通过鼠标点击屏幕来控制人物的走动.首先来说一下原理,当我们点击屏幕时,我们按照一定的方法,将屏幕上的二维坐标转化为三维坐标,然后我们从摄像机位 ...
- 学习swing鼠标点击事件心得体会_西门子COMOS软件开发定制学习8-查询列表间的数据交互...
本篇在西门子COMOS软件开发定制学习6-管理界面定制基础上定制,简单介绍两个查询列表之间的数据交互. 实现效果: 在左侧列表中选择某一设备,右侧列表自动根据所选设备,显示该设备相关的设计图纸(如P ...
- 基于jQuery鼠标点击弹出登陆框效果
基于jQuery鼠标点击弹出登陆框效果.这是一款扁平样式风格的jQuery弹出层登陆框特效.效果图如下: 在线预览 源码下载 实现的代码. html代码: <input type=&quo ...
最新文章
- spring boot 下载
- python脚本实例手机端-用Python实现自动化操作Android手机
- python编程语言是什么-编程语言分类及python所属类型
- 【1024程序员节】都有什么?现场亲历者告诉你...
- [gic]-ARM gicv3/gicv2的总结和介绍-PPT
- 搭建servlet+jsp环境
- 图像超分工具,在线工具
- AcWing 143. 最大异或对
- Northwind 示例数据库
- 华光职业学院计算机专业,关于给予张庆俊等同学省高校计算机一级 考试成绩优秀奖励的通知...
- 软件工程阶段性总结(四)——测试和维护
- Java实现动态规划经典题目
- cannot lock ref问题的解决
- Fiddler跟F12
- Python 中File(文件) 方法?
- 【bat】验证是否安装某个软件
- 分治算法小结(附例题详解)
- AT89S51单片机硬件结构
- 小米路由器获得BSI物联网安全风筝标志认证;IDC最新数据显示浪潮分布式存储增速中国第一 | 全球TMT...
- java毕业设计_租房管理系统