如何制作更好的落块?
How to make better falling blocks?
我和一个朋友正在尝试学习 Unity 和 c#,以便我们尝试制作游戏。我的朋友在使用逻辑运算符时遇到了麻烦,所以我正在尝试制作一个简单的程序,当您按下某些组合键时,该程序会导致方块掉落。(他在没有视觉帮助的情况下非常专注于某些事情)我能够将一些东西放在一起但它很乱,我觉得有很多更好的方法来解决它。这是我经过大量试验和错误设法写出来的。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Falling : MonoBehaviour {
public float fallspeed = 8.0f;
bool a;
bool b;
private GameObject box_0;
private GameObject box_2;
private GameObject box_3;
private GameObject box_4;
private GameObject box_5;
private GameObject box_6;
private GameObject clone;
private GameObject clone1;
private GameObject clone2;
private GameObject clone3;
private GameObject clone4;
private GameObject clone5;
// Use this for initialization
void Start () {
a = false;
b = false;
box_0 = GameObject.Find("box_0");
box_2 = GameObject.Find("box_2");
box_3 = GameObject.Find("box_3");
box_4 = GameObject.Find("box_4");
box_5 = GameObject.Find("box_5");
box_6 = GameObject.Find("box_6");
}
// Update is called once per frame
void Update () {
// makes box_0 fall if a key is pressed
if (Input.GetKeyDown (KeyCode.A)) {
a = true;
if (a) {
clone = Instantiate (box_0, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.B) || Input.GetKeyDown (KeyCode.C)) {
a = true;
if (a) {
clone1 = Instantiate (box_2, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.Q) && Input.GetKeyDown (KeyCode.E)) {
a = true;
if (a) {
clone2 = Instantiate (box_3, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.R) || (Input.GetKey (KeyCode.LeftShift) && Input.GetKeyDown (KeyCode.S)) ) {
a = true;
if (a) {
clone3 = Instantiate (box_4, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.U)) {
a = true;
if (a) {
clone4 = Instantiate (box_5, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.I)) {
a = true;
if (a) {
clone5 = Instantiate (box_6, transform.position, Quaternion.identity);
a = false;
}
}
//makes clones fall if they exist
if (clone != null) {
clone.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone1 != null) {
clone1.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone2 != null) {
clone2.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone3 != null) {
clone3.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone4 != null) {
clone4.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else {
if (clone5 != null) {
clone5.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
}
}
}
}
代码可以正常运行,但有问题。一方面,如果我生成多个相同的克隆体,它们就会卡住,而且我认为我根本没有很好地处理空游戏对象。谁能给我一些关于如何做得更好的建议?
(如果相关的话,屏幕顶部排列着六个彩色块,当按下某些键时,将创建一个正在引用的块的克隆并使其下降。该块有一个对撞机,当它撞到屏幕底部时,它会撞到另一个对撞机并被摧毁。)
"for one if I spawn more then one of the same clone they get stuck and I dont think I handled the null gameobject very well at all."
将此附加到每个框并从 Falling-script 中删除 clone.transform.Translate 部分:
public class BoxScript : MonoBehaviour {
public float fallspeed = 8.0f;
public bool fall = false;
void Update () {
if (fall) {
transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
}
}
}
...然后在创建新框时:
clone = Instantiate (box_0, transform.position, Quaternion.identity);
clone.fall = true;
我认为你可以制作一个盒子和克隆的列表,这样你就可以分解你的代码(我不熟悉 unity 所以可能会有拼写错误,但总体思路是:
var clones = new List<GameObject>();
GameObject box = null;
if (Input.GetKeyDown(KeyCode.A))
{
box = box_0
}
// else if ... box = box_1 ...
// end of your series of else if
if (box != null)
{
clone = Instantiate(box, transform.position, Quaternion.identity);
clones.Add(clone);
}
box = null;
//
foreach (GameObject clone in clones)
{
clone.transform.Translate(Vector3.down * fallspeed * Time.deltaTime, Space.World)
}
首先,变数太多了。当您发现自己复制并粘贴代码时,您可能做错了什么。只需将所有这些坏男孩放在一些 List<GameObject>
中,您就可以获得相同的结果。
我推荐的是 Mikko Koivisto 回答的内容,那就是制作另一个脚本来处理盒子的实际掉落效果。但是为了将所有内容都保存在一个脚本中,我采用了不同的处理方式。
我稍微更改了您的代码,使其更加清晰易读。评论基本上说出了所有的变化。
至于为什么老盒子卡住了。当你创建一个新的克隆时,你一直在覆盖你的克隆变量。因此,在更新中,您的旧克隆将不再更新,因为它们不再在变量中定义,因此它们停止下降。
Note: In order for this to work you'll have to add the boxes to your script in the editor, you could also do it in code but it's a lot messier. Just click on the script in the editor, open the boxes list, put size on six and drag them all in there.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Falling : MonoBehaviour
{
public float fallspeed = 8.0f;
//removed bool a, b because they never get used anymore
//"boxes" is public so you can add the boxes in the editor instead of having to do it in your start function
public List<GameObject> boxes; //Instead of 6 different variables you could just throw them all in a list
private List<GameObject> clones; //Same here
// Update is called once per frame
void Update()
{
// makes box_0 fall if a key is pressed
//Not sure why you were checking if(a) constantly when you set it true 1 line ahead, how could it be false? I took the liberty to remove that
if (Input.GetKeyDown(KeyCode.A))
{
clones.Add(Instantiate(boxes[0], transform.position, Quaternion.identity)); //No need for different variables, just throw them all in one list
}
if (Input.GetKeyDown(KeyCode.B) || Input.GetKeyDown(KeyCode.C))
{
clones.Add(Instantiate(boxes[1], transform.position, Quaternion.identity));
}
if (Input.GetKeyDown(KeyCode.Q) && Input.GetKeyDown(KeyCode.E))
{
clones.Add(Instantiate(boxes[2], transform.position, Quaternion.identity));
}
if (Input.GetKeyDown(KeyCode.R) || (Input.GetKey(KeyCode.LeftShift) && Input.GetKeyDown(KeyCode.S)))
{
clones.Add(Instantiate(boxes[3], transform.position, Quaternion.identity));
}
if (Input.GetKeyDown(KeyCode.U))
{
clones.Add(Instantiate(boxes[4], transform.position, Quaternion.identity));
}
if (Input.GetKeyDown(KeyCode.I))
{
clones.Add(Instantiate(boxes[5], transform.position, Quaternion.identity));
}
//Instead of checking if any of them exist you can just loop through the list with clones and make them all fall
foreach (GameObject clone in clones)
{
clone.transform.Translate(Vector3.down * fallspeed * Time.deltaTime, Space.World);
}
}
}
您绝对可以改进的几件事...
- 当您拥有实例集合时,请使用适合集合的数据结构。
而不是这个:
private GameObject box_0;
private GameObject box_2; //<<<That typo tho!
private GameObject box_3;
private GameObject box_4;
private GameObject box_5;
private GameObject box_6;
//...
你可以而且应该这样做:
private GameObject[] boxes = new GameObject[6];
private List<GameObject> clones = new List<GameObject>();
分别是array
和list
;许多 C# 集合数据类型中的两种。
- 数组非常适合 固定 数量的特定对象类型的元素。
- 列表非常适合动态 数量的元素。
其他类型包括:Set<>
、Dictionary<>
、Queue<>
、Stack<>
等;每个都有自己的最佳用例。
- 请记住,您正在编程。只要有可能,尽量让 机器 成为最辛苦的人。
而不是这个:
box_0 = GameObject.Find("box_0");
box_2 = GameObject.Find("box_2"); //<<<That typo tho!
box_3 = GameObject.Find("box_3");
box_4 = GameObject.Find("box_4");
box_5 = GameObject.Find("box_5");
box_6 = GameObject.Find("box_6");
你可以拥有这个:
for(int i=0; i<6; i++)
boxes[i] = GameObject.Find("box_"+i);
这称为循环。当您需要多次完成重复性任务时,这是执行此操作的方法。更具体地说,这是一个 for
循环。
还有:
while
(while(/*condition evaluated before loop*/){/*some code*/}
)
do-while
(do{/*some code*/}while(/*condition evaluated after loop*/)
)
for-each
(foreach(var element in someCollection){/*some code*/}
)
- 还有其他人。
- 注意冗余!
a
变量在:
if (Input.GetKeyDown (KeyCode.A)) {
a = true;
if (a) {
clone = Instantiate (box_0, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.B) || Input.GetKeyDown (KeyCode.C)) {
a = true;
if (a) {
clone1 = Instantiate (box_2, transform.position, Quaternion.identity);
a = false;
}
}
//...
什么都没有! b
甚至没有被使用!
- 如果你克隆是动态的(有时可以是空的,有时不是),你可以动态地处理它们!
如果您将 clones
list 作为 existing 克隆的列表,而不是 可能个克隆,以后自动化东西会容易得多!
if (Input.GetKeyDown (KeyCode.A))
clones.Add(Instantiate(boxes[0], transform.position, Quaternion.identity));
if (Input.GetKeyDown (KeyCode.B) || Input.GetKeyDown (KeyCode.C))
clones.Add(Instantiate(boxes[1], transform.position, Quaternion.identity);
//...
稍后,而不是这个:
if (clone != null) {
clone.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone1 != null) {
clone1.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone2 != null) {
clone2.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone3 != null) {
clone3.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone4 != null) {
clone4.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else {
if (clone5 != null) {
clone5.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
}
}
你可以这样做:
foreach(var clone in clones)
clone.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
- 你应该保持一致。
private GameObject box_0;
private GameObject box_2; //<<<NOPE! should be box_1!
//And others should follow the sequence from 1!
private GameObject box_3;
private GameObject box_4;
private GameObject box_5;
private GameObject box_6;
private GameObject clone; //<<<NOPE! Should be 'clone_0', 'clone_1' etc...
private GameObject clone1;
private GameObject clone2;
private GameObject clone3;
private GameObject clone4;
private GameObject clone5;
我和一个朋友正在尝试学习 Unity 和 c#,以便我们尝试制作游戏。我的朋友在使用逻辑运算符时遇到了麻烦,所以我正在尝试制作一个简单的程序,当您按下某些组合键时,该程序会导致方块掉落。(他在没有视觉帮助的情况下非常专注于某些事情)我能够将一些东西放在一起但它很乱,我觉得有很多更好的方法来解决它。这是我经过大量试验和错误设法写出来的。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Falling : MonoBehaviour {
public float fallspeed = 8.0f;
bool a;
bool b;
private GameObject box_0;
private GameObject box_2;
private GameObject box_3;
private GameObject box_4;
private GameObject box_5;
private GameObject box_6;
private GameObject clone;
private GameObject clone1;
private GameObject clone2;
private GameObject clone3;
private GameObject clone4;
private GameObject clone5;
// Use this for initialization
void Start () {
a = false;
b = false;
box_0 = GameObject.Find("box_0");
box_2 = GameObject.Find("box_2");
box_3 = GameObject.Find("box_3");
box_4 = GameObject.Find("box_4");
box_5 = GameObject.Find("box_5");
box_6 = GameObject.Find("box_6");
}
// Update is called once per frame
void Update () {
// makes box_0 fall if a key is pressed
if (Input.GetKeyDown (KeyCode.A)) {
a = true;
if (a) {
clone = Instantiate (box_0, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.B) || Input.GetKeyDown (KeyCode.C)) {
a = true;
if (a) {
clone1 = Instantiate (box_2, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.Q) && Input.GetKeyDown (KeyCode.E)) {
a = true;
if (a) {
clone2 = Instantiate (box_3, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.R) || (Input.GetKey (KeyCode.LeftShift) && Input.GetKeyDown (KeyCode.S)) ) {
a = true;
if (a) {
clone3 = Instantiate (box_4, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.U)) {
a = true;
if (a) {
clone4 = Instantiate (box_5, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.I)) {
a = true;
if (a) {
clone5 = Instantiate (box_6, transform.position, Quaternion.identity);
a = false;
}
}
//makes clones fall if they exist
if (clone != null) {
clone.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone1 != null) {
clone1.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone2 != null) {
clone2.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone3 != null) {
clone3.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone4 != null) {
clone4.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else {
if (clone5 != null) {
clone5.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
}
}
}
}
代码可以正常运行,但有问题。一方面,如果我生成多个相同的克隆体,它们就会卡住,而且我认为我根本没有很好地处理空游戏对象。谁能给我一些关于如何做得更好的建议?
(如果相关的话,屏幕顶部排列着六个彩色块,当按下某些键时,将创建一个正在引用的块的克隆并使其下降。该块有一个对撞机,当它撞到屏幕底部时,它会撞到另一个对撞机并被摧毁。)
"for one if I spawn more then one of the same clone they get stuck and I dont think I handled the null gameobject very well at all."
将此附加到每个框并从 Falling-script 中删除 clone.transform.Translate 部分:
public class BoxScript : MonoBehaviour {
public float fallspeed = 8.0f;
public bool fall = false;
void Update () {
if (fall) {
transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
}
}
}
...然后在创建新框时:
clone = Instantiate (box_0, transform.position, Quaternion.identity);
clone.fall = true;
我认为你可以制作一个盒子和克隆的列表,这样你就可以分解你的代码(我不熟悉 unity 所以可能会有拼写错误,但总体思路是:
var clones = new List<GameObject>();
GameObject box = null;
if (Input.GetKeyDown(KeyCode.A))
{
box = box_0
}
// else if ... box = box_1 ...
// end of your series of else if
if (box != null)
{
clone = Instantiate(box, transform.position, Quaternion.identity);
clones.Add(clone);
}
box = null;
//
foreach (GameObject clone in clones)
{
clone.transform.Translate(Vector3.down * fallspeed * Time.deltaTime, Space.World)
}
首先,变数太多了。当您发现自己复制并粘贴代码时,您可能做错了什么。只需将所有这些坏男孩放在一些 List<GameObject>
中,您就可以获得相同的结果。
我推荐的是 Mikko Koivisto 回答的内容,那就是制作另一个脚本来处理盒子的实际掉落效果。但是为了将所有内容都保存在一个脚本中,我采用了不同的处理方式。
我稍微更改了您的代码,使其更加清晰易读。评论基本上说出了所有的变化。
至于为什么老盒子卡住了。当你创建一个新的克隆时,你一直在覆盖你的克隆变量。因此,在更新中,您的旧克隆将不再更新,因为它们不再在变量中定义,因此它们停止下降。
Note: In order for this to work you'll have to add the boxes to your script in the editor, you could also do it in code but it's a lot messier. Just click on the script in the editor, open the boxes list, put size on six and drag them all in there.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Falling : MonoBehaviour
{
public float fallspeed = 8.0f;
//removed bool a, b because they never get used anymore
//"boxes" is public so you can add the boxes in the editor instead of having to do it in your start function
public List<GameObject> boxes; //Instead of 6 different variables you could just throw them all in a list
private List<GameObject> clones; //Same here
// Update is called once per frame
void Update()
{
// makes box_0 fall if a key is pressed
//Not sure why you were checking if(a) constantly when you set it true 1 line ahead, how could it be false? I took the liberty to remove that
if (Input.GetKeyDown(KeyCode.A))
{
clones.Add(Instantiate(boxes[0], transform.position, Quaternion.identity)); //No need for different variables, just throw them all in one list
}
if (Input.GetKeyDown(KeyCode.B) || Input.GetKeyDown(KeyCode.C))
{
clones.Add(Instantiate(boxes[1], transform.position, Quaternion.identity));
}
if (Input.GetKeyDown(KeyCode.Q) && Input.GetKeyDown(KeyCode.E))
{
clones.Add(Instantiate(boxes[2], transform.position, Quaternion.identity));
}
if (Input.GetKeyDown(KeyCode.R) || (Input.GetKey(KeyCode.LeftShift) && Input.GetKeyDown(KeyCode.S)))
{
clones.Add(Instantiate(boxes[3], transform.position, Quaternion.identity));
}
if (Input.GetKeyDown(KeyCode.U))
{
clones.Add(Instantiate(boxes[4], transform.position, Quaternion.identity));
}
if (Input.GetKeyDown(KeyCode.I))
{
clones.Add(Instantiate(boxes[5], transform.position, Quaternion.identity));
}
//Instead of checking if any of them exist you can just loop through the list with clones and make them all fall
foreach (GameObject clone in clones)
{
clone.transform.Translate(Vector3.down * fallspeed * Time.deltaTime, Space.World);
}
}
}
您绝对可以改进的几件事...
- 当您拥有实例集合时,请使用适合集合的数据结构。
而不是这个:
private GameObject box_0;
private GameObject box_2; //<<<That typo tho!
private GameObject box_3;
private GameObject box_4;
private GameObject box_5;
private GameObject box_6;
//...
你可以而且应该这样做:
private GameObject[] boxes = new GameObject[6];
private List<GameObject> clones = new List<GameObject>();
分别是array
和list
;许多 C# 集合数据类型中的两种。
- 数组非常适合 固定 数量的特定对象类型的元素。
- 列表非常适合动态 数量的元素。
其他类型包括:Set<>
、Dictionary<>
、Queue<>
、Stack<>
等;每个都有自己的最佳用例。
- 请记住,您正在编程。只要有可能,尽量让 机器 成为最辛苦的人。
而不是这个:
box_0 = GameObject.Find("box_0");
box_2 = GameObject.Find("box_2"); //<<<That typo tho!
box_3 = GameObject.Find("box_3");
box_4 = GameObject.Find("box_4");
box_5 = GameObject.Find("box_5");
box_6 = GameObject.Find("box_6");
你可以拥有这个:
for(int i=0; i<6; i++)
boxes[i] = GameObject.Find("box_"+i);
这称为循环。当您需要多次完成重复性任务时,这是执行此操作的方法。更具体地说,这是一个 for
循环。
还有:
while
(while(/*condition evaluated before loop*/){/*some code*/}
)do-while
(do{/*some code*/}while(/*condition evaluated after loop*/)
)for-each
(foreach(var element in someCollection){/*some code*/}
)- 还有其他人。
- 注意冗余!
a
变量在:
if (Input.GetKeyDown (KeyCode.A)) {
a = true;
if (a) {
clone = Instantiate (box_0, transform.position, Quaternion.identity);
a = false;
}
}
if (Input.GetKeyDown (KeyCode.B) || Input.GetKeyDown (KeyCode.C)) {
a = true;
if (a) {
clone1 = Instantiate (box_2, transform.position, Quaternion.identity);
a = false;
}
}
//...
什么都没有! b
甚至没有被使用!
- 如果你克隆是动态的(有时可以是空的,有时不是),你可以动态地处理它们!
如果您将 clones
list 作为 existing 克隆的列表,而不是 可能个克隆,以后自动化东西会容易得多!
if (Input.GetKeyDown (KeyCode.A))
clones.Add(Instantiate(boxes[0], transform.position, Quaternion.identity));
if (Input.GetKeyDown (KeyCode.B) || Input.GetKeyDown (KeyCode.C))
clones.Add(Instantiate(boxes[1], transform.position, Quaternion.identity);
//...
稍后,而不是这个:
if (clone != null) {
clone.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone1 != null) {
clone1.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone2 != null) {
clone2.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone3 != null) {
clone3.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else if (clone4 != null) {
clone4.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
} else {
if (clone5 != null) {
clone5.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
}
}
你可以这样做:
foreach(var clone in clones)
clone.transform.Translate (Vector3.down * fallspeed * Time.deltaTime, Space.World);
- 你应该保持一致。
private GameObject box_0;
private GameObject box_2; //<<<NOPE! should be box_1!
//And others should follow the sequence from 1!
private GameObject box_3;
private GameObject box_4;
private GameObject box_5;
private GameObject box_6;
private GameObject clone; //<<<NOPE! Should be 'clone_0', 'clone_1' etc...
private GameObject clone1;
private GameObject clone2;
private GameObject clone3;
private GameObject clone4;
private GameObject clone5;