四、游戏对象与图形基础

编程入门 行业动态 更新时间:2024-10-10 05:21:45

四、游戏对象与<a href=https://www.elefans.com/category/jswz/34/1770818.html style=图形基础"/>

四、游戏对象与图形基础

文章目录

  • 1、基本操作演练【建议做】
    • 1.1 下载 Fantasy Skybox FREE, 构建自己的游戏场景
    • 1.2 写一个简单的总结,总结游戏对象的使用
      • 创建
      • 获取
      • 修改属性
      • 添加组件与修改组件
      • 克隆
  • 2、编程实践
    • 动作分离
    • 裁判类
    • 处理历史遗留问题(注意细节,例如:船未靠岸,牧师与魔鬼上下船运动中,均不能接受用户事件!

1、基本操作演练【建议做】

1.1 下载 Fantasy Skybox FREE, 构建自己的游戏场景

  • 下载 Fantasy Skybox FREE

  • 给主摄像机添加skybox组件

  • 将skybox添加到场景

  1. 从菜单栏中选择 Window > Rendering > Lighting > Environment。
  2. 把天空盒拖到天空盒材质中
  • 构建一个地形
  • 最终效果

1.2 写一个简单的总结,总结游戏对象的使用

创建

  1. 通过图形界面创建

  2. 使用GameObject.CreatPrimitive()函数来创建Unity自带的模型

GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
  1. 使用Instantiate()函数进行游戏物体的实例化
Instantiate(GameObject,Position,Rotition)
Instantiate(brick, new Vector3(x, y, 0), Quaternion.identity);
  1. 动态加载预制。将预制件放在目录Resouces\下在脚本中通过Resources.Load加载:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class LoadCube : MonoBehaviour {// Use this for initializationvoid Start () {GameObject hp_bar = (GameObject)Resources.Load("Cube");hp_bar = Instantiate(hp_bar); hp_bar.name = "Cube";}// Update is called once per framevoid Update () {}
}

获取

  1. 在代码里声明public类型Gameobject,在Inspector属性栏中指定游戏对象
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Find_GameObject : MonoBehaviour {public GameObject obj;
}

  1. 通过对象名称获取对象
obj = GameObject.Find("Sphere");
  1. 通过对象tag获取对象
GameObject.FindWithTag("Atag")                         //返回一个游戏对象
GameObject.FindGameObjectsWithTag("Atag")    //返回多个游戏对象

修改属性

gameobject.transform.position = new Vector3(2, (float)-0.5, 0);

添加组件与修改组件

  1. 在inspector界面手动添加

  2. 通过脚本添加,并设定组件中的某些值

cube.AddComponent<Rigidbody>();
cube.GetComponent<Rigidbody>().useGravity = false;
cube.GetComponent<Renderer>().material.color = Color.red;

克隆

克隆产生的新的对象会具有原对象的所有属性与组件
原对象被保存为文件类型则称为预制体

GameObject hp_bar = (GameObject)Resources.Load("Cube"); //动态加载预制
hp_bar = Instantiate(hp_bar); //克隆

2、编程实践

牧师与魔鬼 动作分离版
【2019开始的新要求】:设计一个裁判类,当游戏达到结束条件时,通知场景控制器游戏结束

动作分离

在此前版本中,使用抽象出来的一个类Move挂载脚本组件,实现角色的移动功能(上船、下船)和船的移动功能(开向对岸)
现在希望将动作分离,由FirstController直接管理所有的动作,而在BoatController和CharacterController中只需处理好自己的逻辑关系

新增如下类

  • IActionCallback
    一个接口。接口回调(函数回调)实现管理者与被管理者解耦。实现了这个接口的类,就可以知道“某个动作已完成”(动作一完成ActionEvent方法就会被调用),并对这个事件做出反应。

  • Action
    所有动作的基类,包括单个直线action和复合action。

  • MoveToAction
    Action的一个子类。基本动作,用户设计的基本动作类。表示直线移动。

  • SequenceAction
    Action的另一个子类。合动作,由(基本或组合)动作组合的类。表示多个直线移动组成的复合动作。

  • SSActionManager
    代理Action,实现了所有动作的基本管理,在管理动作的时候不用关心是直线还是复合动作,一并处理。【组合模式】

  • CCActionManager
    SSActionManager的子类,封装了一些函数,使得FirstController调用起来更简洁。通过模板方法,让使用者减少对动作管理过程细节的要求。【门面模式(控制器模式)】

现对BoatController和CharactersController进行修改,修改后的BoatController和CharactersController不再管理和使用move

BoatController

public class Move : MonoBehaviour
{public float moveSpeed = 20;//public Move move;.../* public void moveToAnotherBank(){if (boatState == 1){Vector3 target = boat.transform.position + new Vector3(8, 0, 0);move.setDestination(target);this.boatState = 2;}else if (boatState == 2){Vector3 target = boat.transform.position - new Vector3(8, 0, 0);move.setDestination(target);this.boatState = 1;}}*/public Vector3 getDestination(){Vector3 target = Vector3.zero;if (boatState == 1){target = boat.transform.position + new Vector3(8, 0, 0);this.boatState = 2;}else if (boatState == 2){target = boat.transform.position - new Vector3(8, 0, 0);this.boatState = 1;}return target;}public GameObject getGameobj(){return this.boat;}}

CharactersController

public class CharacterController
{public float moveSpeed = 20;//public Move move;...public void setPositionOnLeftBank(){this.state = 1;//move.setDestination(new Vector3(-20 + index*2, 2f, 0));}public Vector3 getPosOnLeftBank(){return new Vector3(-20 + index * 2, 2f, 0);}public void setPositionOnRightBank(){this.state = 2;//move.setDestination(new Vector3(10 + index*2, 2f, 0));}public Vector3 getPosOnRightBank(){return new Vector3(10 + index * 2, 2f, 0);}public void setPositionOnBoat()//Vector3 pos{this.state = 0;//move.setDestination(pos);}
/*public void moveOnBoat(int boatState, int posOnBoat){if (boatState == 1){Vector3 target = character.transform.position + new Vector3(8, 0, 0);move.setDestination(target);}else if (boatState == 2){Vector3 target = character.transform.position + new Vector3(-8, 0, 0);move.setDestination(target);}}
*/public Vector3 getDestinationOnBoat(int boatState, int posOnBoat){if (boatState == 1){return character.transform.position + new Vector3(8, 0, 0);}else if (boatState == 2){return character.transform.position - new Vector3(8, 0, 0);}return Vector3.zero;}public Vector3 getPos(){return this.character.transform.position;}public GameObject getGameobj(){return this.character;}

FirstController
不需要实例化Move,用CCActionManager管理动作

	public class FirstController : MonoBehaviour, ISceneController, IUserAction {private CCActionManager myActionManager;public void LoadResources () {myActionManager = gameObject.AddComponent<CCActionManager>() as CCActionManager;}public void moveBoat(){if (boat.getNumEmptyPos() == 2) return;       //没人在船上,船不动int[] personOnBoat = boat.getPersonOnBoat();  //得到在船上的人的编号//boat.moveToAnotherBank();myActionManager.moveBoat(boat);for (int i = 0; i < 2; i++){if (personOnBoat[i] == -1) continue;//characters[personOnBoat[i]].moveOnBoat((boat.getState() == 1 ? 2 : 1), i);   //先移动船再移动人,船的state先变,让char得到移动后的statemyActionManager.moveCharacter(characters[personOnBoat[i]], characters[personOnBoat[i]].getDestinationOnBoat((boat.getState() == 1 ? 2 : 1), i));}if (judgment.checkLose(boat, leftBank, rightBank) == true){for(int i = 0; i < 7; i++){clickGUI[i].click = false;}userGUI.gameState = -1;return;}}public void moveCharacter(int index){if (characters[index].getState() == 1 && boat.getState() == 1 && boat.getNumEmptyPos() > 0)   //人在左岸,船在左岸,船有空位{characters[index].setPositionOnBoat();myActionManager.moveCharacter(characters[index], boat.getEmptyPos());  ;leftBank.removeACharacter(characters[index]);boat.putACharacter(characters[index]);}else if (characters[index].getState() == 2 && boat.getState() == 2 && boat.getNumEmptyPos() > 0)   //人在右岸,船在右岸,船有空位{characters[index].setPositionOnBoat();myActionManager.moveCharacter(characters[index], boat.getEmptyPos());   rightBank.removeACharacter(characters[index]);boat.putACharacter(characters[index]);}else if (characters[index].getState() == 0 && boat.getState() == 1)       //人在船上,船靠左岸{characters[index].setPositionOnLeftBank();myActionManager.moveCharacter(characters[index], characters[index].getPosOnLeftBank());   boat.removeACharacter(characters[index]);leftBank.putACharacter(characters[index]);}else if (characters[index].getState() == 0 && boat.getState() == 2)       //人在船上,船靠右岸{characters[index].setPositionOnRightBank();myActionManager.moveCharacter(characters[index], characters[index].getPosOnRightBank()); boat.removeACharacter(characters[index]);rightBank.putACharacter(characters[index]);}if (judgment.checkWin(boat, leftBank, rightBank) == true){for (int i = 0; i < 7; i++){clickGUI[i].click = false;}userGUI.gameState = 1;return;}}

裁判类

FirstController需要管理的事情太多,所以需要将判断游戏输赢的任务分离出来,交给单独的一个类管理,在前一个作业的基础上简单改一下即可。

Judgment
把之前用来判断游戏输赢的checkWincheckLose函数分离出来,单独放在一个类Judgment中。

由于这些函数需要boatleftBankrightBank的信息,所以需要传入相应的controller作为参数。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Judgment
{public bool checkWin(BoatController boat, BankController leftBank, BankController rightBank){if (boat.getNumEmptyPos() == 2 && (leftBank.getNumDevil() + leftBank.getNumPriest() == 0) && (rightBank.getNumDevil() + rightBank.getNumPriest() == 6))return true;return false;}public bool checkLose(BoatController boat, BankController leftBank, BankController rightBank){int countDevilLeft = leftBank.getNumDevil(), countPriestLeft = leftBank.getNumPriest();int countDevilRight = rightBank.getNumDevil(), countPriestRight = rightBank.getNumPriest();int[] personOnBoat = boat.getPersonOnBoat();   int d = 0, p = 0;for (int i = 0; i < 2; i++){if (personOnBoat[i] < 3 && personOnBoat[i] >= 0) d++;else if (personOnBoat[i] >= 3) p++;}if (boat.getState() == 1){countDevilLeft += d;countPriestLeft += p;}else if (boat.getState() == 2){countDevilRight += d;countPriestRight += p;}if ((countDevilLeft > countPriestLeft && countPriestLeft != 0) || (countDevilRight > countPriestRight && countPriestRight != 0)){return true;}return false;}
}

FirstController
增加一个类型为Judgment的变量judgment,在loadResource中实例化
在原来使用checkWincheckLose的地方改成judgment.checkWinjudgment.checkLose

public Judgment judgment;public void loadResources()
{...judgment = new Judgment();
}
public void moveBoat()
{...if (judgment.checkLose(boat, leftBank, rightBank) == true){...}
}
public void moveCharacter(int index)
{...if (judgment.checkWin(boat, leftBank, rightBank) == true){...}
}

代码传送门

效果与上一次的代码相同
失败

成功

处理历史遗留问题(注意细节,例如:船未靠岸,牧师与魔鬼上下船运动中,均不能接受用户事件!

SSDirector.cs
增加变量

public bool moving=false;

仅当变量moving为false时接收用户事件
UserGUI.cs

    void OnMouseDown(){if (click&&!SSDirector.getInstance().moving){//接收用户事件并处理}}

动作开始时设置moving为true,动作完成后设置moving为false
CCActionManager.cs

    public void moveBoat(BoatController boat){MoveToAction action = MoveToAction.getAction(boat.getDestination(), boat.moveSpeed);this.RunAction(boat.getGameobj(), action, this);SSDirector.getInstance().moving = true;}public void moveCharacter(CharacterController characterCtrl, Vector3 destination){...this.RunAction(characterCtrl.getGameobj(), seqAction, this);SSDirector.getInstance().moving = true;}public void ActionEvent(Action source, ActionEventType events = ActionEventType.Competeted){if (events == ActionEventType.Competeted) SSDirector.getInstance().moving = false;}

更多推荐

四、游戏对象与图形基础

本文发布于:2024-02-07 10:47:29,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1756223.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:图形   对象   基础   游戏

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!