一、加载Fantasy Skybox FREE,构建自己的游戏场景
- 这是我10分钟构建游戏场景的视频,视频五倍速链接: Unity制作游戏场景——5倍速
- 主要是运用老师课件上讲的知识,包括Terrain内工具的使用
- 以及一些Unity基础知识,熟练掌握快捷键会更好
二、写一个简单的总结,总结游戏对象的使用
-
游戏对象:游戏中的一切东西都可以是游戏对象,游戏对象初始化带有必要的Tranformer组件,用来定位
-
创建GameObject
- 通过编辑器GameObject可视化添加:可以直接拖拽到场景中或者添加在左侧栏
- 脚本添加:Object.Instantiate()
-
获取GameObject
- 在脚本中定义public变量,可以直接拖拽
- 通过对象名字Find函数
- 其他方法:(由于没有测试过,谨慎使用)
- 通过标签获取单个游戏对象(FindWithTag方法)
- 通过标签获取多个游戏对象(FindGameObjectsWithTags方法)
- 通过类型获取单个游戏对象(FindObjectOfType方法)
- 通过类型获取多个游戏对象(FindObjectsOfType方法)
-
为GameObject添加或者删除组件
- 在Inspector中点击右上角的三个点可以手动添加删除
- AddComponent<>()或者GetComponent<>()
-
发送广播和信息(查询资料得知:Message相关有3条指令)
- SendMessage (“函数名”,参数,SendMessageOptions) //GameObject自身的Script
- BroadcastMessage (“函数名”,参数,SendMessageOptions) //自身和子Object的Script
- SendMessageUpwards (“函数名”,参数,SendMessageOptions) //自身和父Object的Script
-
克隆和预设
- 将你设计好的GameObject拖到底栏(最好是perfabs文件夹中)可以得到你自己的预设
- 将预设和其他GameObject一样拖出使用
- 脚本:
- 这里的"Perfabs/Ocean"是预设存储路径
- typeof(GameObject))是类型
- ocean_pos是预先定义好放置预设的位置
- Quaternion.identity是预设的角度
Ocean = Object.Instantiate(Resources.Load("Perfabs/Ocean", typeof(GameObject)), ocean_pos, Quaternion.identity, null) as GameObject;
- 运动、旋转和缩放
这些都可以通过快捷栏的工具可视化拖拽
- 运动
- 可视化直接修改物体的position
- transform.Translate(Vector3)
- transform.position += Vector3
- 旋转
- 自身:transform.Rotate()
- 公转:transform.RotateAround()
- 缩放:transform.localScale = Vector(x, y, z)
- 销毁GameObject
- GameObject.Destroy
- Destroy(gameObject);
- 更多操作参考: Unity3D官方中文手册
三、魔鬼与牧师 动作分离版
依据老师上课讲的框架,实现了魔鬼与牧师动作分离版
扫描二维码关注公众号,回复:
15331672 查看本文章
1. 解决方案
游戏运行时只需要将GameController.cs挂载在摄像机上就可以啦
2. 主要更新
- InterfaceApplication.cs: 将所有接口类独立出来放在一起
- SceneController
- UserAction
- ISSActionCallback
- SSActionController.cs: 分离动作
- SSAction
- SSMoveToAction
- SequenceAction
- SSActionManager:动作管理基类
- ActionManager:动作管理类
- moveBoat:控制船的移动
- moveRole:控制角色的移动
SSActionController.cs
这里参考了师兄师姐的代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using interfaceApplication;
public class SSAction : ScriptableObject
{
public bool enable = true;//是否存在
public bool destory = false;//是否删除
public GameObject gameobject;//动作对象
public Transform transform;//动作对象的transformer
public ISSActionCallback callback;//回调函数
protected SSAction() { }
public virtual void Start()
{
//是指在无法实现请求的方法或操作时引发的异常。
throw new System.NotImplementedException();
}
public virtual void Update()
{
throw new System.NotImplementedException();
}
}
public class SSMoveToAction : SSAction
{
public Vector3 target; //desitination
public float speed;
private SSMoveToAction() { }
public static SSMoveToAction GetSSAction(Vector3 _target, float _speed)
{
//创建一个方法 方法中传入一个类的名称 然后就能返回一个这个类的实例
SSMoveToAction action = ScriptableObject.CreateInstance<SSMoveToAction>();
action.target = _target;
action.speed = _speed;
return action;
}
public override void Start()
{
}
public override void Update()
{
//这里只是把该perfas从当前位置移动到目标位置
this.transform.position = Vector3.MoveTowards(this.transform.position, target, speed * Time.deltaTime);
//完成
if (this.transform.position == target)
{
this.destory = true;
this.callback.SSActionEvent(this);
}
}
}
//动作组合,比如说角色的移动要先平移到岸边,再平移到船上或者岸上
public class SequenceAction : SSAction, ISSActionCallback
{
public List<SSAction> sequence; //动作列表
public int repeat = -1; //-1就是无限循环做组合中的动作
public int start = 0; //当前做的动作的索引
public static SequenceAction GetSSAcition(int repeat, int start, List<SSAction> sequence)
{
SequenceAction action = ScriptableObject.CreateInstance<SequenceAction>();
action.sequence = sequence;
action.repeat = repeat;
action.start = start;
return action;
}
public override void Start()
{
//执行每个动作
foreach (SSAction action in sequence)
{
action.gameobject = this.gameobject;
action.transform = this.transform;
action.callback = this; //每一个动作的回调函数为该动作组合
action.Start();
}
}
public override void Update()
{
if (sequence.Count == 0) return;
if (start < sequence.Count)
{
sequence[start].Update(); //start在回调函数中递加
}
}
//实现接口
public void SSActionEvent(
SSAction source, SSActionEventType events = SSActionEventType.competeted,
int intParam = 0, string strParam = null, Object objectParam = null
)
{
source.destory = false;
this.start++; //下一个动作
if (this.start >= sequence.Count)
{
this.start = 0;
if (repeat > 0) repeat--;
if (repeat == 0)
{ //动作组合结束
this.destory = true;
this.callback.SSActionEvent(this);
}
}
}
}
//动作管理基类
public class SSActionManager : MonoBehaviour, ISSActionCallback {
private Dictionary<int, SSAction> actions = new Dictionary<int, SSAction>(); //动作字典
private List<SSAction> waitingAdd = new List<SSAction>(); //等待执行
private List<int> waitingDelete = new List<int>(); //等待删除
protected void Update() {
foreach (SSAction ac in waitingAdd) {
actions[ac.GetInstanceID()] = ac;
}
waitingAdd.Clear();
//对于字典中每一个pair,看是执行还是删除
foreach (KeyValuePair<int, SSAction> kv in actions) {
SSAction ac = kv.Value;
if (ac.destory) {
waitingDelete.Add(ac.GetInstanceID());
}else if (ac.enable) {
ac.Update();
}
}
//删除所有已完成的动作并清空待删除列表
foreach (int key in waitingDelete) {
SSAction ac = actions[key];
actions.Remove(key);
Object.Destroy(ac);
}
waitingDelete.Clear();
}
public void RunAction(GameObject gameobject, SSAction action, ISSActionCallback manager) {
action.gameobject = gameobject;
action.transform = gameobject.transform;
action.callback = manager;
waitingAdd.Add(action);
action.Start();
}
public void SSActionEvent(
SSAction source, SSActionEventType events = SSActionEventType.competeted,
int intParam = 0, string strParam = null, Object objectParam = null) {
}
}
//动作管理类
public class ActionManager : SSActionManager {
public GameController sceneController;
private SequenceAction boatMove;
private SequenceAction roleMove;
protected void Start() {
sceneController = (GameController)Director.getInstance().currentSceneController;
sceneController.actionManager = this;
}
protected new void Update() {
base.Update();
}
//移动船的动作
public void moveBoat(GameObject boat, Vector3 endPos, float speed) {
SSAction action1 = SSMoveToAction.GetSSAction(endPos, speed);
boatMove = SequenceAction.GetSSAcition(0, 0, new List<SSAction> { action1 });
this.RunAction(boat, boatMove, this);
}
//移动角色
public void moveRole(GameObject role, Vector3 middlePos, Vector3 endPos, float speed) {
//两段移动
SSAction action1 = SSMoveToAction.GetSSAction(middlePos, speed);
SSAction action2 = SSMoveToAction.GetSSAction(endPos, speed);
//两个动作
roleMove = SequenceAction.GetSSAcition(1, 0, new List<SSAction> { action1, action2 });
this.RunAction(role, roleMove, this);
}
}
动作管理的使用
-
定义接口
-
在GameController.cs中使用actionManager来管理动作
public void PAndVIsClicked(PAndVController POrVCtrl)
{
Vector3 middlePos,endPos;
//下船上岸
if (POrVCtrl.isOnBoat())
{
//先判断现在是哪一个岸
CoastController whichCoast;
if (boat.get_which_coast() == 1)
{
whichCoast = rightCoast;
}
else
{
whichCoast = leftCoast;
}
//目的地
endPos = whichCoast.getAvailablePosition();
//中间位置
middlePos = new Vector3(POrVCtrl.getGameObject().transform.position.x,endPos.y, endPos.z);
//动作
boat.GetOffBoat(POrVCtrl.getName());
/*动作管理器管理*/
actionManager.moveRole(POrVCtrl.getGameObject(),middlePos,endPos,boat.boatSpeed);
//其他操作
//POrVCtrl.setPosition(whichCoast.getAvailablePosition());
POrVCtrl.getOnCoast(whichCoast);
whichCoast.getOnCoast(POrVCtrl);
}
else//下岸上船
{
CoastController whichCoast = POrVCtrl.getCoastController();
if (boat.getEmptyIndex() == -1)
{ //船满了
return;
}
else if(whichCoast.get_which_coast() != boat.get_which_coast())
{
//船没靠岸
return;
}
else
{
//目的地
endPos = boat.getAvailablePosition();
//中间位置
middlePos = new Vector3( endPos.x, POrVCtrl.getGameObject().transform.position.y, endPos.z);
//动作
whichCoast.getOffCoast(POrVCtrl.getName());
/*动作管理器管理*/
actionManager.moveRole(POrVCtrl.getGameObject(),middlePos,endPos ,POrVCtrl.speed);
//其他操作
//POrVCtrl.setPosition(endPos);
POrVCtrl.getOnBoat(boat);
boat.GetOnBoat(POrVCtrl);
}
}
//检查游戏状态
userGUI.status = judge.endGame();
}
//移动船的组件
public void moveBoat()
{
if (boat.isEmpty())
return;
//boat.Move();
//动作管理器管理
actionManager.moveBoat(boat.getGameobject(), boat.getToPosition(), boat.boatSpeed);
boat.changeCoast();
//检查游戏状态
userGUI.status = judge.endGame();
}
- 本次代码还更新了水的波浪和船的摇晃,因为这个是伴随整个游戏的,所以没有使用动作管理,而是直接在GameObject更新
在GameController.cs中Update
void Update()
{
//这两个状态整个游戏都有,不需要动作类的管理
Ocean.WaterWave();
boat.Shake();
}
波浪
public enum Superposition
{
//周期叠加
Cycle,
//振幅叠加
Amplitude
}
public class WaterController
{
//水的位置
readonly Vector3 ocean_pos = new Vector3(0, .4F, 0);
//Ocean
GameObject Ocean;
//水波振幅
public float amplitude = .7f;
//波动的速度
public float speed = 2.8f;
//振幅叠加方式
public Superposition superpositon = Superposition.Amplitude;
//模型网格
private Mesh sharedMesh;
//网格初始顶点坐标数组
private Vector3[] baseVertex;
//网格修改后的顶点坐标数组(也就是每一次update之后)
private Vector3[] nowVertex;
public WaterController(string _name)
{
Ocean = Object.Instantiate(Resources.Load("Perfabs/Ocean", typeof(GameObject)), ocean_pos, Quaternion.identity, null) as GameObject;
Ocean.name = "ocean";
//初始化
sharedMesh = Ocean.GetComponent<MeshFilter>().sharedMesh;
baseVertex = sharedMesh.vertices;
nowVertex = sharedMesh.vertices;
}
//GameObject的Update调用
public void WaterWave()
{
//更新波浪顶点
for (int i = 0; i < baseVertex.Length; i++)
{
nowVertex[i] = baseVertex[i];
switch (superpositon)
{
case Superposition.Cycle:
nowVertex[i].y += Mathf.Sin(Time.time * speed + baseVertex[i].x + baseVertex[i].z) * amplitude;
break;
case Superposition.Amplitude:
nowVertex[i].y += Mathf.Sin(Time.time * speed + baseVertex[i].x) * amplitude + Mathf.Sin(Time.time * speed + baseVertex[i].z) * amplitude;
break;
}
}
sharedMesh.vertices = nowVertex;
}
}
船的摇晃
//绕z轴摇摆的速度
float z_Speed = 3f;
//绕x轴摇摆的速度
float x_Speed = 3f;
//绕y轴摇摆的速度
float y_Speed = 3f;
public void Shake()
{
//MoveComponent.setAngle();
// 绕Z轴摇晃
if (boat.transform.eulerAngles.z >= 3 && boat.transform.eulerAngles.z <= 180)
{
z_Speed = -z_Speed;
}
else if (boat.transform.eulerAngles.z <= (360 - 3) && boat.transform.eulerAngles.z >= 180)
{
z_Speed = -z_Speed;
}
// 绕X轴摇晃
if (boat.transform.eulerAngles.x >= 3 && boat.transform.eulerAngles.x <= 180)
{
x_Speed = -x_Speed;
}
else if (boat.transform.eulerAngles.x >= 180 && boat.transform.eulerAngles.x <= (360 - 3))
{
x_Speed = -x_Speed;
}
boat.transform.Rotate(z_Speed * Time.deltaTime, 0, z_Speed * Time.deltaTime);
}
3. 链接
实现效果参考:Unity3D-牧师与魔鬼(升级版)
项目地址:项目地址