游戏对象与图形基础(中山大学3d游戏第4次作业)
文章目录
仓库地址:https://github.com/linfn3/3dunity/tree/main/devils_and_priests_2
视频地址:https://www.bilibili.com/video/BV1mm4y1w7xy/
备注:考虑到每次上传速度,后面每次仓库只上传assert文件!
一、天空盒
assertstore中下载资源
导入资源:
天空盒设置:
效果:
二、游戏对象总结
GameObject是所有组件 Component 的容器。游戏中所有的对象都可认为是游戏对象(GameObject)。它可以被制作成预制反复使用。它拥有众多属性,例如材质、Transform,它可以被实例化,并且通过c#脚本控制。
三、牧师与魔鬼 动作分离版
1.首先在interface中添加新的接口
我们需要添加接口ActionCallback,代码如下:
public interface ActionCallback
{
void ActionDone(SSAction source);
}
2.ActionController文件
我们需要编写动作基类SSAction,移动类Moveaction和组合类ConstituteAction(实现ActionCallback接口,主要完成上下船操作)以及管理类ActionManager(实现ActionCallback接口,用于管理和整合动作)
代码如下:
using System.Collections.Generic;
using UnityEngine;
using MyNamespace;
public class SSAction : ScriptableObject
{
public bool enable = true;
public bool destroy = false;
public GameObject GameObject { get; set; }
public Transform Transform { get; set; }
public ActionCallback Callback { get; set; }
public virtual void Start()
{
throw new System.NotImplementedException();
}
public virtual void Update()
{
throw new System.NotImplementedException();
}
}
public class Moveaction : SSAction
{
public Vector3 target;
public float speed;
private Moveaction() { }
public static Moveaction GetSSMoveToAction(Vector3 goal, float speed)
{
Moveaction action = CreateInstance<Moveaction>();
action.target = goal;
action.speed = speed;
return action;
}
public override void Start() { }
public override void Update()
{
Transform.position = Vector3.MoveTowards(Transform.position, target, speed * Time.deltaTime);
if (Transform.position == target)
{
destroy = true;
Callback.ActionDone(this);
}
}
}
public class ConstituteAction : SSAction, ActionCallback
{
public int tmp = -1;
public int ActionIndex = 0;
public List<SSAction> sequence;
public static ConstituteAction GetConstitueAction(int repeat, int currentActionIndex, List<SSAction> sequence)
{
ConstituteAction action = CreateInstance<ConstituteAction>();
action.sequence = sequence;
action.tmp = repeat;
action.ActionIndex = currentActionIndex;
return action;
}
public override void Update()
{
if (sequence.Count == 0) return;
if (ActionIndex < sequence.Count)
{
sequence[ActionIndex].Update();
}
}
public override void Start()
{
foreach (SSAction action in sequence)
{
action.GameObject = GameObject;
action.Transform = Transform;
action.Callback = this;
action.Start();
}
}
void OnDestroy()
{
foreach (SSAction action in sequence)
{
Destroy(action);
}
}
public void ActionDone(SSAction source)
{
source.destroy = false;
ActionIndex++;
if (ActionIndex >= sequence.Count)
{
ActionIndex = 0;
if (tmp > 0) tmp--;
if (tmp == 0)
{
destroy = true;
Callback.ActionDone(this);
}
}
}
}
public class ActionManager : MonoBehaviour, ActionCallback
{
private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>();
private List<int> deletelist = new List<int>();
private List<SSAction> addlist = new List<SSAction>();
protected void Update()
{
foreach (SSAction action in addlist)
{
actions[action.GetInstanceID()] = action;
}
addlist.Clear();
foreach (KeyValuePair<int, SSAction> kv in actions)
{
SSAction action = kv.Value;
if (action.destroy)
{
deletelist.Add(action.GetInstanceID());
}
else if (action.enable)
{
action.Update();
}
}
foreach (int key in deletelist)
{
SSAction action = actions[key];
actions.Remove(key);
Destroy(action);
}
deletelist.Clear();
}
public void AddAction(GameObject gameObject, SSAction action, ActionCallback callback)
{
action.Transform = gameObject.transform;
action.Callback = callback;
action.GameObject = gameObject;
addlist.Add(action);
action.Start();
}
public void ActionDone(SSAction source) { }
}
3. 移除Moveable类
因为已经有了动作管理类ActionController,就不再需要移动控制类Moveable了。
4. 编写SceneController
这是一个场景控制类,用于控制船、恶魔、牧师的运动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MyNamespace;
public class SceneController : ActionManager
{
public void MoveBoat(BoatController boatController)
{
Moveaction action = Moveaction.GetSSMoveToAction(boatController.GetDestination(), boatController.boat.movingSpeed);
AddAction(boatController.boat.boatObject, action, this);
}
public void MoveCharacter(MyNamespace.CharacterController characterController, Vector3 destination)
{
Vector3 curpos = characterController.character.Role.transform.position;
Vector3 midpos = curpos;
if (curpos.y < destination.y ) midpos.y = destination.y;
else
{
midpos.x = destination.x;
}
SSAction action1 = Moveaction.GetSSMoveToAction(midpos, characterController.character.movingSpeed);
SSAction action2 = Moveaction.GetSSMoveToAction(destination, characterController.character.movingSpeed);
SSAction seqAction = ConstituteAction.GetConstitueAction(1, 0, new List<SSAction> { action1, action2 });
AddAction(characterController.character.Role, seqAction, this);
}
}
5. 编写裁判类check.cs
这个类用于判断游戏是否结束及输赢,游戏胜利返回2,游戏失败返回1,游戏未结束返回0.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace MyNamespace
{
public class Check : MonoBehaviour
{
public FirstController sceneController;
protected void Start()
{
sceneController = (FirstController)Director.GetInstance().CurrentSecnController;
sceneController.gameStatusManager = this;
}
public int CheckGame()
{
int leftPriests = (sceneController.leftStones.GetCharacterNum())[0];
int leftDevils = (sceneController.leftStones.GetCharacterNum())[1];
int rightPriests = (sceneController.rightStones.GetCharacterNum())[0];
int rightDevils = (sceneController.rightStones.GetCharacterNum())[1];
if (leftPriests + leftDevils == 6) return 2;
if ((rightPriests < rightDevils && rightPriests > 0) || (leftPriests < leftDevils && leftPriests > 0))
{
return 1;
}
return 0;
}
}
}
6. 修改boat.cs和Charactor.cs
这里我们需要把所有和之前moveable类相关联的代码全部删除
boat.cs:
using UnityEngine;
namespace MyNamespace
{
public class Boat
{
public readonly Vector3 destination;
public readonly Vector3 departure;
public readonly float movingSpeed = 20;
public readonly Vector3[] departures;
public readonly Vector3[] destinations;
public CharacterController[] passengers = new CharacterController[2];
public GameObject boatObject { get; set; }
public loc loc { get; set; }
public Boat()
{
// 船的起点和终点
departure = new Vector3(5, 1, 0);
destination = new Vector3(-5, 1, 0);
loc = loc.right;
departures = new Vector3[] { new Vector3(4.5f, 1.5f, 0), new Vector3(5.5f, 1.5f, 0) };
destinations = new Vector3[] { new Vector3(-5.5f, 1.5f, 0), new Vector3(-4.5f, 1.5f, 0) };
boatObject = Object.Instantiate(Resources.Load("Prefabs/Boat", typeof(GameObject)), departure, Quaternion.identity, null) as GameObject;
boatObject.name = "boat";
boatObject.AddComponent(typeof(UserGUI));
}
}
}
charactor.cs:
using UnityEngine;
namespace MyNamespace
{
public class Character
{
public CoastController stone { get; set; }
public bool IsOnBoat { get; set; }
public GameObject Role { get; set; }
public readonly float movingSpeed = 20;
public string Name
{
get
{
return Role.name;
}
set
{
Role.name = value;
}
}
public Character(string objectName)
{
if(objectName.Contains("devil"))
{
Role = Object.Instantiate(Resources.Load("Prefabs/Devil", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
}
else
{
Role = Object.Instantiate(Resources.Load("Prefabs/Priest", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
}
Name = objectName;
IsOnBoat = false;
}
}
}
以上为所有代码编写内容,展示结果如下: