3d游戏作业4
牧师与魔鬼——动作分离版
1.增加一个裁判类,当游戏达到结束条件时,通知场景控制器。
裁判类JudgeController,该裁判类中定义了更新游戏状态的函数UpdateGameState(原本在FirstController中的GetAndSetGameState函数)。FirstController在初始化的时候会初始化一个裁判类对象,然后每次需要检测游戏状态的时候就调用该对象的UpdateGameState函数,在该项目中会在每次移动船的时候调用该函数检验游戏是否结束。
public class JudgeController{
FirstController firstCtrl;
public JudgeController(){
firstCtrl = SSDirector.GetInstance().CurrentSceneController as FirstController;
}
//判断游戏状态
public int UpdadeGameState(){
if(firstCtrl.gameState != FirstController.PLAYING) return firstCtrl.gameState;
//判断是否失败
int[,] roleplace = new int[2, 3]{
{0, 0, 0}, {0, 0, 0}};
foreach(RoleController r in firstCtrl.rolectrl_list){
roleplace[r.roleType, r.roleState]++;
}
if((roleplace[0,0]>0 && roleplace[0,0]<roleplace[1,0]) ||
(roleplace[0,1]>0 && roleplace[0,1]<roleplace[1,1]) ||
(roleplace[0,2]>0 && roleplace[0,2] < roleplace[1,2])){
return FirstController.FAILED;
}
//判断是否成功
foreach(RoleController r in firstCtrl.rolectrl_list){
if(r.roleType == 0 && r.roleState != FirstController.RIGHTLAND){
return FirstController.PLAYING;
}
}
return FirstController.WIN;
}
}
2.设计动作分离
设计要求
-
通过门面模式(控制器模式)输出组合好的几个动作,供原来程序调用。
在本项目中是CCActionManager,用于提供给FirstController调用。
-
通过组合模式实现动作组合,按组合模式设计方法。
-
必须有一个抽象事物表示该类事物的共性,例如SSAction。
在本项目中是move,表示事物移动的抽象。
-
基本动作,用户设计的基本动作类。
在本项目中是CCMoveToAction,定义了对象移动的动作。
-
组合动作,由动作组合的类。
在本项目中只有移动一个动作,不需要进行动作组合。
-
在上次项目中,FirstController中有部分用于管理角色动作的代码,现在通过动作分离将动作的具体实现分离到CCActionManager中。本项目不采用SSAction作为抽象事物表示事物共性,而采用move表示。
move
继承了MonoBehavior,是表示事物移动特性的抽象脚本。动作分离版与上个项目的不同之处还有一点就是移动的时候不是直接平移,而是先上升,然后平移,再下降。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
public static int single = 0;
public static int sequence = 1;
public bool isMoving;
bool initialized;
public int moveobj;
public bool doneMoving;
public float speed = 5;
int n_seq;
public Vector3[] dest_list;
public Vector3 destination;
public CCMoveToAction moveAction;
public Move(){
n_seq = 0;
isMoving = false;
initialized = false;
moveobj = -1;
}
void Update()
{
if(moveobj == -1) return;
if(!initialized){
if(moveobj == single){
dest_list = new Vector3[1];
dest_list[0] = destination;
}
else if(moveobj == sequence){
dest_list = new Vector3[3];
dest_list[0] = transform.localPosition + new Vector3(0, 1, 0);
dest_list[1] = destination + new Vector3(0, 1, 0);
dest_list[2] = destination;
}
else{
Debug.Log("ERROR!");
}
initialized = true;
}
isMoving = true;
if(n_seq >= dest_list.Length){
n_seq = 0;
moveobj = -1;
initialized = false;
isMoving = false;
return;
}
if(transform.localPosition == dest_list[n_seq]){
n_seq += 1;
return;
}
transform.localPosition = Vector3.MoveTowards(transform.localPosition, dest_list[n_seq], speed * Time.deltaTime);
}
}
CCMoveToAction
实现具体动作,其中moveto函数引入了一个gameobject对象以及一个vector3数组,会把gameobject对应的对象移到vector3数组对应的位置。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCMoveToAction
{
GameObject moveObject;
public bool IsMoving(){
return(this.moveObject != null && this.moveObject.GetComponent<Move>().isMoving == true);
}
public void MoveTo(GameObject moveObject, Vector3 destination){
Move test;
this.moveObject = moveObject;
if (!moveObject.TryGetComponent<Move>(out test)) {
moveObject.AddComponent<Move>();
}
this.moveObject.GetComponent<Move>().moveAction = this;
this.moveObject.GetComponent<Move>().destination = destination;
this.moveObject.GetComponent<Move>().moveobj = Move.single;
}
public void MoveSeqTo(GameObject moveObject, Vector3 destination){
Move test;
this.moveObject = moveObject;
if (!moveObject.TryGetComponent<Move>(out test)) {
moveObject.AddComponent<Move>();
}
this.moveObject.GetComponent<Move>().moveAction = this;
this.moveObject.GetComponent<Move>().destination = destination;
this.moveObject.GetComponent<Move>().moveobj = Move.sequence;
}
}
CCActionManager
动作管理器,对所有动作进行管理,其中定义了两个函数,一个是moverole函数,用于管理角色的移动,另一个是moveboat函数,用于管理船的移动。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CCActionManager
{
public CCMoveToAction moveBoatAction;
public CCMoveToAction moveRoleAction;
public FirstController controller;
public CCActionManager(){
controller = SSDirector.GetInstance().CurrentSceneController as FirstController;
controller.actionManager = this;
moveBoatAction = new CCMoveToAction();
moveRoleAction = new CCMoveToAction();
}
public bool IsMoving(){
return moveRoleAction.IsMoving() || moveBoatAction.IsMoving();
}
//移动人物
public void MoveRole(BoatController BoatCtrl, RoleController rolectrl_list, int destination, int seat){
Vector3 finalPos;
if(destination == FirstController.RIGHTLAND){
finalPos = Position.roleRightPos[seat];
}
else if(destination == FirstController.LEFTLAND){
finalPos = Position.roleLeftPos[seat];
}
else{
if(BoatCtrl.onLeftside){
finalPos = Position.seatLeftPos[seat];
}
else{
finalPos = Position.seatRightPos[seat];
}
}
moveRoleAction.MoveSeqTo(rolectrl_list.GetModelGameObject(), finalPos);
}
//移动船
public void MoveBoat(BoatController BoatCtrl, int destination){
if(destination == FirstController.RIGHTLAND){
moveBoatAction.MoveTo(BoatCtrl.GetModelGameObject(), Position.boatRightPos);
for(int i = 0; i < 2; i++){
if(BoatCtrl.seat[i] != -1){
RoleController r = controller.rolectrl_list[controller.IDToNumber(BoatCtrl.seat[i])];
moveRoleAction.MoveTo(r.GetModelGameObject(), Position.seatRightPos[i]);
}
}
}
else{
moveBoatAction.MoveTo(BoatCtrl.GetModelGameObject(), Position.boatLeftPos);
for(int i = 0; i < 2; i++){
if(BoatCtrl.seat[i] != -1){
RoleController r = controller.rolectrl_list[controller.IDToNumber(BoatCtrl.seat[i])];
moveRoleAction.MoveTo(r.GetModelGameObject(), Position.seatLeftPos[i]);
}
}
}
}
}
FirstController
该函数与上次动作不分离版的牧师与魔鬼相比有了一些改变。主要的区别是会在初始化的时候初始化一个JudgeController以及一个CCActionManager,其中JudgeController用于在每次移动船之前对游戏的状态进行判断,如果结束则将游戏状态置为结束。而CCActionManager用于在需要使物体移动时调用其函数,使物体移动。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FirstController : MonoBehaviour, ISceneController, IUserAction
{
public static int LEFTLAND = 0;
public static int RIGHTLAND = 1;
public static int BOAT = 2;
public static bool flag = false;
public static bool flag1=false;
public static int PRIEST = 0;
public static int DEVIL = 1;
public static int PLAYING = 0;
public static int WIN = 1;
public CCActionManager actionManager;
public static int FAILED = 2;
Water water1;
BoatController BoatCtrl;
public List<RoleController> rolectrl_list=new List<RoleController>();
public List<LandController> landctrl_list=new List<LandController>();
public JudgeController JudgeCtrl;
int[] rolesID = new int[6]{0,1,2,3,4,5};
public int gameState;
void Awake(){
SSDirector director = SSDirector.GetInstance();
director.CurrentSceneController = this;
director.CurrentSceneController.LoadResources();
}
public void Initialize()
{
LoadResources();
}
public void LoadResources(){
//由于有重新开始按钮,所以如果不是第一次加载得把之前的物体摧毁
if(flag){
for(int i = 0; i < 6; i++){
if(rolectrl_list[i] != null){
Destroy(rolectrl_list[i].GetModelGameObject());
}
}
for(int i = 0; i < 2; i++){
if(landctrl_list[i] != null){
Destroy(landctrl_list[i].GetModelGameObject());
}
}
if(BoatCtrl != null){
Destroy(BoatCtrl.GetModelGameObject());
}
}
// 加载控制器和模型
rolectrl_list=new List<RoleController>();
landctrl_list=new List<LandController>();
BoatCtrl = new BoatController();
BoatCtrl.CreateModel();
water1=new Water(new Vector3(0,-3.5f,12));
for(int i = 0; i < 6; i++){
int roleType = (i < 3) ? PRIEST : DEVIL;
RoleController tmp=new RoleController(roleType, rolesID[i]);
rolectrl_list.Add(tmp);
rolectrl_list[i].CreateModel();
}
LandController tmp1 = new LandController(LEFTLAND, rolesID);
landctrl_list.Add(tmp1);
LandController tmp2 = new LandController(RIGHTLAND, rolesID);
landctrl_list.Add(tmp2);
landctrl_list[0].CreateModel();
landctrl_list[1].CreateModel();
JudgeCtrl = new JudgeController();
actionManager = new CCActionManager();
flag=true;
flag1=false;
//开始游戏
gameState = PLAYING;
}
//将角色的ID转换成数组的下标
public int IDToNumber(int ID){
for(int i = 0; i < 6; i++){
if(rolesID[i] == ID){
return i;
}
}
return -1;
}
//点击船时执行
public void MoveBoat(){
if(BoatCtrl.isempty()){
flag1=true;
return;
}
flag1=false;
if(gameState != PLAYING || actionManager.IsMoving()) return;
gameState = JudgeCtrl.UpdateGameState();
if(BoatCtrl.onLeftside){
actionManager.MoveBoat(BoatCtrl, RIGHTLAND);
}
else{
actionManager.MoveBoat(BoatCtrl, LEFTLAND);
}
BoatCtrl.onLeftside = !BoatCtrl.onLeftside;
}
//点击角色时执行
public void MoveRole(int id){
flag1=false;
int num = IDToNumber(id);
if(gameState != PLAYING || actionManager.IsMoving()) return;
int seat;
switch(rolectrl_list[num].roleState){
case 0: // LEFTLAND
if(!BoatCtrl.onLeftside) return;
seat = BoatCtrl.getonboat(id);
if(seat == -1) return;
landctrl_list[0].getoffLand(id);
rolectrl_list[num].GoTo(BOAT);
actionManager.MoveRole(BoatCtrl, rolectrl_list[num], BOAT, seat);
break;
case 1: // RIGHTLAND
if(BoatCtrl.onLeftside) return;
seat = BoatCtrl.getonboat(id);
if(seat == -1) return;
landctrl_list[1].getoffLand(id);
rolectrl_list[num].GoTo(BOAT);
actionManager.MoveRole(BoatCtrl, rolectrl_list[num], BOAT, seat);
break;
case 2: //BOAT
if(BoatCtrl.onLeftside){
seat = landctrl_list[0].getEmptySeat();
BoatCtrl.getoffboat(id);
landctrl_list[0].GoOnLand(id);
rolectrl_list[num].GoTo(LEFTLAND);
actionManager.MoveRole(BoatCtrl, rolectrl_list[num], LEFTLAND, seat);
}
else{
seat = landctrl_list[1].getEmptySeat();
BoatCtrl.getoffboat(id);
landctrl_list[1].GoOnLand(id);
rolectrl_list[num].GoTo(RIGHTLAND);
actionManager.MoveRole(BoatCtrl, rolectrl_list[num], RIGHTLAND, seat);
}
break;
default: break;
}
}
//重置
public void Restart(){
LoadResources();
gameState = PLAYING;
}
//获取游戏当前状态
public int GetGameState(){
return gameState;
}
}
代码位置:代码仓库 hw4