3D游戏第三次作业
一、简答题
1. 游戏对象运动的本质是什么?
游戏对象在每一帧画面中position和rotation的变化。
2. 请用三种方法以上方法,实现物体的抛物线运动。
- 使用Transform的Translate函数改变position
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class parabola : MonoBehaviour {
public int xSpeed = 1;
public int ySpeed = 1;
public int T = 1;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
transform.Translate(Vector3.right * Time.deltaTime * xSpeed + Vector3.down * Time.deltaTime * ySpeed * Time.deltaTime * T);
T++;
}
}
- 使用Vector3
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class parabola : MonoBehaviour {
public int xSpeed = 1;
public int ySpeed = 1;
public int T = 1;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
transform.position += Vector3.right * Time.deltaTime * xSpeed;
transform.position += Vector3.down * Time.deltaTime * ySpeed * Time.deltaTime * T;
T++;
}
}
- 直接修改Transform
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class parabola : MonoBehaviour {
public int speed = 2;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
transform.position += new Vector3(Time.deltaTime * speed, -Time.deltaTime * speed * (2 * transform.position.x + Time.deltaTime * speed), 0);
}
}
3.写一个程序,实现一个完整的太阳系, 其他星球围绕太阳的转速必须不一样,且不在一个法平面上
- 制作太阳和八个大小不一的球体代表八大行星,其中 太阳在原点
- 将此脚本挂载到每一个行星上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SolarSystem : MonoBehaviour
{
public Transform sun;
public int x,y,z,speed;
// Start is called before the first frame update
void Start() {
speed=Random.Range(100,200);
x=Random.Range(-50,50);
y=Random.Range(-50,50);
z=Random.Range(-50,50);
}
// Update is called once per frame
void Update() {
Vector3 axis=new Vector3(x,y,z);
transform.RotateAround(sun.position,axis,speed*Time.deltaTime);
}
}
- 将太阳作为参数传入,运行即可
二、编程实践牧师与魔鬼
1. 列出游戏中提及的事物
人物有牧师和魔鬼,还有船、水、出发岸和目标岸
2. 用表格列出玩家动作表
3. 请将游戏中对象做成预制
以下为本游戏的预制,有牧师、魔鬼、船、水,出发岸和目标岸由石头组成使用石头预制
定义Director类
同时定义两个接口
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame;
namespace Com.Mygame
{
public class Director : System.Object
{
private static Director _instance;
public SceneController currentSceneController { get; set; }
public static Director getInstance()
{
if (_instance == null)
{
_instance = new Director();
}
return _instance;
}
}
public interface SceneController
{
void loadResources();
}
public interface UserAction
{
void moveBoat();
void characterIsClicked(MyCharacterController characterCtrl);
void restart();
}
定义FirstController类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame;
public class FirstController : MonoBehaviour, SceneController, UserAction {
readonly Vector3 water_pos = new Vector3(0,0.5F,0);
UserGUI userGUI;
public CoastController fromCoast;
public CoastController toCoast;
public BoatController boat;
private MyCharacterController[] characters;
void Awake() {
Director director = Director.getInstance ();
director.currentSceneController = this;
userGUI = gameObject.AddComponent <UserGUI>() as UserGUI;
characters = new MyCharacterController[6];
loadResources ();
}
public void loadResources() {
GameObject water = Instantiate (Resources.Load ("Perfabs/Water", typeof(GameObject)), water_pos, Quaternion.identity, null) as GameObject;
water.name = "water";
fromCoast = new CoastController ("from");
toCoast = new CoastController ("to");
boat = new BoatController ();
loadCharacter ();
}
private void loadCharacter() {
for (int i = 0; i < 3; i++) {
MyCharacterController cha = new MyCharacterController ("priest");
cha.setName("priest" + i);
cha.setPosition (fromCoast.getEmptyPosition ());
cha.getOnCoast (fromCoast);
fromCoast.getOnCoast (cha);
characters [i] = cha;
}
for (int i = 0; i < 3; i++) {
MyCharacterController cha = new MyCharacterController ("devil");
cha.setName("devil" + i);
cha.setPosition (fromCoast.getEmptyPosition ());
cha.getOnCoast (fromCoast);
fromCoast.getOnCoast (cha);
characters [i+3] = cha;
}
}
public void moveBoat() {
if (boat.isEmpty ())
return;
boat.Move ();
userGUI.status = check_game_over ();
}
public void characterIsClicked(MyCharacterController characterCtrl) {
if (characterCtrl.isOnBoat ()) {
CoastController whichCoast;
if (boat.get_to_or_from () == -1) { // to->-1; from->1
whichCoast = toCoast;
} else {
whichCoast = fromCoast;
}
boat.GetOffBoat (characterCtrl.getName());
characterCtrl.moveToPosition (whichCoast.getEmptyPosition ());
characterCtrl.getOnCoast (whichCoast);
whichCoast.getOnCoast (characterCtrl);
} else { // character on coast
CoastController whichCoast = characterCtrl.getCoastController ();
if (boat.getEmptyIndex () == -1) { // boat is full
return;
}
if (whichCoast.get_to_or_from () != boat.get_to_or_from ()) // boat is not on the side of character
return;
whichCoast.getOffCoast(characterCtrl.getName());
characterCtrl.moveToPosition (boat.getEmptyPosition());
characterCtrl.getOnBoat (boat);
boat.GetOnBoat (characterCtrl);
}
userGUI.status = check_game_over ();
}
int check_game_over() { // 0->not finish, 1->lose, 2->win
int from_priest = 0;
int from_devil = 0;
int to_priest = 0;
int to_devil = 0;
int[] fromCount = fromCoast.getCharacterNum ();
from_priest += fromCount[0];
from_devil += fromCount[1];
int[] toCount = toCoast.getCharacterNum ();
to_priest += toCount[0];
to_devil += toCount[1];
if (to_priest + to_devil == 6) // win
return 2;
int[] boatCount = boat.getCharacterNum ();
if (boat.get_to_or_from () == -1) { // boat at toCoast
to_priest += boatCount[0];
to_devil += boatCount[1];
} else { // boat at fromCoast
from_priest += boatCount[0];
from_devil += boatCount[1];
}
if (from_priest < from_devil && from_priest > 0) { // lose
return 1;
}
if (to_priest < to_devil && to_priest > 0) {
return 1;
}
return 0; // not finish
}
public void restart() {
boat.reset ();
fromCoast.reset ();
toCoast.reset ();
for (int i = 0; i < characters.Length; i++) {
characters [i].reset ();
}
}
}
定义Mancontroller类来加载和控制牧师和魔鬼
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame;
public class ManController
{
readonly GameObject character;
readonly Moveable moveableScript;
readonly ClickGUI clickGUI;
readonly int characterType;
bool _isOnBoat;
CoastController coastController;
public ManController(string which_character)
{
if (which_character == "priest")
{
character = Object.Instantiate(Resources.Load("Perfabs/Priest", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
characterType = 0;
}
else
{
character = Object.Instantiate(Resources.Load("Perfabs/Devil", typeof(GameObject)), Vector3.zero, Quaternion.identity, null) as GameObject;
characterType = 1;
}
moveableScript = character.AddComponent(typeof(Moveable)) as Moveable;
clickGUI = character.AddComponent(typeof(ClickGUI)) as ClickGUI;
clickGUI.setController(this);
}
public void setName(string name)
{
character.name = name;
}
public void setPosition(Vector3 pos)
{
character.transform.position = pos;
}
public void moveToPosition(Vector3 destination)
{
moveableScript.setDestination(destination);
}
public int getType()
{
return characterType;
}
public string getName()
{
return character.name;
}
public void getOnBoat(BoatController boatCtrl)
{
coastController = null;
character.transform.parent = boatCtrl.getGameobj().transform;
_isOnBoat = true;
}
public void getOnCoast(CoastController coastCtrl)
{
coastController = coastCtrl;
character.transform.parent = null;
_isOnBoat = false;
}
public bool isOnBoat()
{
return _isOnBoat;
}
public CoastController getCoastController()
{
return coastController;
}
public void reset()
{
moveableScript.reset();
coastController = (Director.getInstance().currentSceneController as FirstController).fromCoast;
getOnCoast(coastController);
setPosition(coastController.getEmptyPosition());
coastController.getOnCoast(this);
}
}
定义Boatcontroller类来加载和控制船
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame;
public class BoatController
{
readonly GameObject boat;
readonly Moveable moveableScript;
readonly Vector3 fromPosition = new Vector3(5, 1, 0);
readonly Vector3 toPosition = new Vector3(-5, 1, 0);
readonly Vector3[] from_positions;
readonly Vector3[] to_positions;
int to_or_from;
MyCharacterController[] passenger = new MyCharacterController[2];
public BoatController()
{
to_or_from = 1;
from_positions = new Vector3[] { new Vector3(4.5F, 1.5F, 0), new Vector3(5.5F, 1.5F, 0) };
to_positions = new Vector3[] { new Vector3(-5.5F, 1.5F, 0), new Vector3(-4.5F, 1.5F, 0) };
boat = Object.Instantiate(Resources.Load("Perfabs/Boat", typeof(GameObject)), fromPosition, Quaternion.identity, null) as GameObject;
boat.name = "boat";
moveableScript = boat.AddComponent(typeof(Moveable)) as Moveable;
boat.AddComponent(typeof(ClickGUI));
}
public void Move()
{
if (to_or_from == -1)
{
moveableScript.setDestination(fromPosition);
to_or_from = 1;
}
else
{
moveableScript.setDestination(toPosition);
to_or_from = -1;
}
}
public int getEmptyIndex()
{
for (int i = 0; i < passenger.Length; i++)
{
if (passenger[i] == null)
{
return i;
}
}
return -1;
}
public bool isEmpty()
{
for (int i = 0; i < passenger.Length; i++)
{
if (passenger[i] != null)
{
return false;
}
}
return true;
}
public Vector3 getEmptyPosition()
{
Vector3 pos;
int emptyIndex = getEmptyIndex();
if (to_or_from == -1)
{
pos = to_positions[emptyIndex];
}
else
{
pos = from_positions[emptyIndex];
}
return pos;
}
public void GetOnBoat(MyCharacterController characterCtrl)
{
int index = getEmptyIndex();
passenger[index] = characterCtrl;
}
public MyCharacterController GetOffBoat(string passenger_name)
{
for (int i = 0; i < passenger.Length; i++)
{
if (passenger[i] != null && passenger[i].getName() == passenger_name)
{
MyCharacterController charactorCtrl = passenger[i];
passenger[i] = null;
return charactorCtrl;
}
}
Debug.Log("Cant find passenger in boat: " + passenger_name);
return null;
}
public GameObject getGameobj()
{
return boat;
}
public int get_to_or_from()
{
return to_or_from;
}
public int[] getCharacterNum()
{
int[] count = { 0, 0 };
for (int i = 0; i < passenger.Length; i++)
{
if (passenger[i] == null)
continue;
if (passenger[i].getType() == 0)
{
count[0]++;
}
else
{
count[1]++;
}
}
return count;
}
public void reset()
{
moveableScript.reset();
if (to_or_from == -1)
{
Move();
}
passenger = new MyCharacterController[2];
}
}
}
定义CoastController类来加载和控制岸边
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame;
public class CoastController
{
readonly GameObject coast;
readonly Vector3 from_pos = new Vector3(9, 1, 0);
readonly Vector3 to_pos = new Vector3(-9, 1, 0);
readonly Vector3[] positions;
readonly int to_or_from;
MyCharacterController[] passengerPlaner;
public CoastController(string _to_or_from)
{
positions = new Vector3[] {new Vector3(6.5F,2.25F,0), new Vector3(7.5F,2.25F,0), new Vector3(8.5F,2.25F,0),
new Vector3(9.5F,2.25F,0), new Vector3(10.5F,2.25F,0), new Vector3(11.5F,2.25F,0)};
passengerPlaner = new MyCharacterController[6];
if (_to_or_from == "from")
{
coast = Object.Instantiate(Resources.Load("Perfabs/Stone", typeof(GameObject)), from_pos, Quaternion.identity, null) as GameObject;
coast.name = "from";
to_or_from = 1;
}
else
{
coast = Object.Instantiate(Resources.Load("Perfabs/Stone", typeof(GameObject)), to_pos, Quaternion.identity, null) as GameObject;
coast.name = "to";
to_or_from = -1;
}
}
public int getEmptyIndex()
{
for (int i = 0; i < passengerPlaner.Length; i++)
{
if (passengerPlaner[i] == null)
{
return i;
}
}
return -1;
}
public Vector3 getEmptyPosition()
{
Vector3 pos = positions[getEmptyIndex()];
pos.x *= to_or_from;
return pos;
}
public void getOnCoast(MyCharacterController characterCtrl)
{
int index = getEmptyIndex();
passengerPlaner[index] = characterCtrl;
}
public MyCharacterController getOffCoast(string passenger_name)
{
for (int i = 0; i < passengerPlaner.Length; i++)
{
if (passengerPlaner[i] != null && passengerPlaner[i].getName() == passenger_name)
{
MyCharacterController charactorCtrl = passengerPlaner[i];
passengerPlaner[i] = null;
return charactorCtrl;
}
}
Debug.Log("cant find passenger on coast: " + passenger_name);
return null;
}
public int get_to_or_from()
{
return to_or_from;
}
public int[] getCharacterNum()
{
int[] count = { 0, 0 };
for (int i = 0; i < passengerPlaner.Length; i++)
{
if (passengerPlaner[i] == null)
continue;
if (passengerPlaner[i].getType() == 0)
{
count[0]++;
}
else
{
count[1]++;
}
}
return count;
}
public void reset()
{
passengerPlaner = new MyCharacterController[6];
}
}
定义MoveController类控制对象的移动
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame;
public class MoveController : MonoBehaviour
{
readonly float move_speed = 20;
int moving_status;
Vector3 dest;
Vector3 middle;
void Update()
{
if (moving_status == 1)
{
transform.position = Vector3.MoveTowards(transform.position, middle, move_speed * Time.deltaTime);
if (transform.position == middle)
{
moving_status = 2;
}
}
else if (moving_status == 2)
{
transform.position = Vector3.MoveTowards(transform.position, dest, move_speed * Time.deltaTime);
if (transform.position == dest)
{
moving_status = 0;
}
}
}
public void setDestination(Vector3 _dest)
{
dest = _dest;
middle = _dest;
if (_dest.y == transform.position.y)
{
moving_status = 2;
}
else if (_dest.y < transform.position.y)
{
middle.y = transform.position.y;
}
else
{
middle.x = transform.position.x;
}
moving_status = 1;
}
public void reset()
{
moving_status = 0;
}
}
定义UserGUI类完善游戏UI
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Com.Mygame;
public class UserGUI : MonoBehaviour {
private UserAction action;
public int status = 0;
GUIStyle style;
GUIStyle buttonStyle;
void Start() {
action = Director.getInstance ().currentSceneController as UserAction;
style = new GUIStyle();
style.fontSize = 40;
style.alignment = TextAnchor.MiddleCenter;
buttonStyle = new GUIStyle("button");
buttonStyle.fontSize = 20;
}
void OnGUI() {
if (status == 1) {
GUI.Label(new Rect(Screen.width/2-50, Screen.height/2-85, 100, 50), "You lose!", style);
if (GUI.Button(new Rect(Screen.width/2-70, Screen.height/2, 140, 70), "Play Again", buttonStyle)) {
status = 0;
action.restart ();
}
} else if(status == 2) {
GUI.Label(new Rect(Screen.width/2-50, Screen.height/2-85, 100, 50), "You win!", style);
if (GUI.Button(new Rect(Screen.width/2-70, Screen.height/2, 140, 70), "Play Again", buttonStyle)) {
status = 0;
action.restart ();
}
}
}
}
代码->https://github.com/Choitempo/3DGame3
效果如下: