首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在到达c#中数组的末尾或开始时环绕索引?

如何在到达c#中数组的末尾或开始时环绕索引?
EN

Stack Overflow用户
提问于 2021-08-31 12:32:22
回答 4查看 846关注 0票数 0

我目前正在为FPS编写一个武器脚本,我想用鼠标轮切换武器。我创建了一个包含武器的数组,每次我用鼠标滚动时,武器的索引就会增加1。我的问题是,当我到达最后一个武器时,我会得到IndexOutOfBounds错误消息。如果它位于数组的末尾,我尝试将武器索引重置为0,但由于某种原因,它不起作用。我也尝试用while循环,而不是if-语句来完成它,但这也不起作用。下面是代码:

代码语言:javascript
运行
复制
public class WeaponManager : MonoBehaviour
{

    [SerializeField]
    private WeaponHandler[] weapons;

    private int current_weapon_index;

    void Start()
    {
        current_weapon_index = 0;
        weapons[current_weapon_index].gameObject.SetActive(true);
    }

    
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Alpha1))
        {
            TurnOnSelectedWeapon(0);
        }

        if (Input.GetKeyDown(KeyCode.Alpha2))
        {
            TurnOnSelectedWeapon(1);
        }

        if (Input.GetKeyDown(KeyCode.Alpha3))
        {
            TurnOnSelectedWeapon(2);
        }

        if (Input.GetKeyDown(KeyCode.Alpha4))
        {
            TurnOnSelectedWeapon(3);
        }

        if (Input.GetKeyDown(KeyCode.Alpha5))
        {
            TurnOnSelectedWeapon(4);
        }

        if (Input.GetKeyDown(KeyCode.Alpha6))
        {
            TurnOnSelectedWeapon(5);
        }

        if(Input.mouseScrollDelta.y > 0)
        {
            SwitchToNextWeapon();
        }

        if (Input.mouseScrollDelta.y < 0)
        {
            SwitchToPreviousWeapon();
        }
    }

    void TurnOnSelectedWeapon(int weaponIndex)
    {
        weapons[current_weapon_index].gameObject.SetActive(false);

        weapons[weaponIndex].gameObject.SetActive(true);

        current_weapon_index = weaponIndex;
    }

    void SwitchToNextWeapon()
    {
        weapons[current_weapon_index].gameObject.SetActive(false);

        current_weapon_index++;
       
        weapons[current_weapon_index].gameObject.SetActive(true);

        if (current_weapon_index >= weapons.Length)
        {
            current_weapon_index = 0;
        }
    }

    void SwitchToPreviousWeapon()
    {
        weapons[current_weapon_index].gameObject.SetActive(false);

        current_weapon_index--;

        weapons[current_weapon_index].gameObject.SetActive(true);
    }
}
EN

回答 4

Stack Overflow用户

发布于 2021-08-31 12:40:45

实现一个为您处理这个问题的类非常简单,只需维护一个内部的List<>项。添加Current属性以读取当前选定的项,以及从鼠标轮处理程序中调用的MoveNext/MovePrevious方法

代码语言:javascript
运行
复制
public class ContinuousList<T>
{
    private List<T> internalList = new List<T>();
    private int currentIndex = 0;

    public void Add(T item) => internalList.Add(item);

    public T Current { get => internalList[currentIndex]; }

    public void MoveNext()
    {
       currentIndex++;
       if(currentIndex >= internalList.Count) currentIndex = 0;
    }

    public void MovePrevious()
    {
       currentIndex--;
       if(currentIndex <= 0) currentIndex = internalList.Count - 1;
    }
}

假设您可能有一些具有基类Weapon的武器

代码语言:javascript
运行
复制
var weaponList = new ContinuousList<Weapon>();
weaponList.Add(new Sword()); 
weaponList.Add(new Axe());
var currentWeapon = weaponList.Current; // gets Sword
weaponList.MoveNext();
var currentWeapon = weaponList.Current; // gets Axe
weaponList.MoveNext();
var currentWeapon = weaponList.Current; // Back to Sword

实例:https://dotnetfiddle.net/Ji7rkt

请注意,在这个IEnumerable<T>上实现ContinuousList非常容易,这样就可以在任何枚举和LINQ方法中使用它。我不想让一个简单的例子变得复杂,但是我想在这里查看一下:https://dotnetfiddle.net/NtdfDi

票数 1
EN

Stack Overflow用户

发布于 2021-08-31 12:45:45

代码语言:javascript
运行
复制
void SwitchToNextWeapon()
{
    weapons[current_weapon_index].gameObject.SetActive(false);
    var temp = current_weapon_index + 1;
    current_weapon_index = temp >= weapons.Count() ? 0 : temp;
    
    weapons[current_weapon_index].gameObject.SetActive(true);
}

void SwitchToPreviousWeapon()
{
    weapons[current_weapon_index].gameObject.SetActive(false);
    var temp = current_weapon_index - 1;
    current_weapon_index = temp < 0 ? weapons.Count() - 1 : temp;

    weapons[current_weapon_index].gameObject.SetActive(true);
}

只需在增加或减少当前武器索引之前添加检查即可。如果达到最大值,则恢复为0,如果达到min (0),则将索引设置为最大值。

票数 1
EN

Stack Overflow用户

发布于 2021-08-31 13:36:49

使用模(%)运算符很容易地处理循环值。

代码语言:javascript
运行
复制
int mod = 5;

for (int i = 0; i < 10; i++)
{
    Console.WriteLine(i % mod);
}

您将看到输出周期从0到mod-1:0,1,2,3,4,0,1,2,.

这涵盖了递增一次的情况:

代码语言:javascript
运行
复制
int index = 4;
int mod = myArray.Length; // assume 5 items in the array

// Increment and cycle
index = ++index % mod;

您将看到这个索引现在是0,因为您在列表的末尾,所以下一个项应该在列表的开头。

然而,周期性价值的下降也存在一些问题。出于一个我不明白的原因,C#选择了允许负模值,即:

代码语言:javascript
运行
复制
-1 % 5 = -1

..。而不是4,这正是您所期望的。

编辑:评论中认为,4并不是每个人都期望的那样。从我第一次处理这个问题时的经验来看,我在网上发现了很多关于负面模块化结果的困惑/烦恼,但我不能否认这是我的观察偏见。

我过去曾处理过这个问题,解决这个问题的最简单方法是:

  • 带上模组
  • 添加模块
  • 再来一次模

本质上,--如果第一步的结果是负值(例如-1),我们只需添加模块,从而将值推到零以上。然而,如果第一步已经是一个积极的结果,我们现在已经让这个值太高了。因此,通过再次采取模块化,我们可以抵消潜在的太高的价值。这涵盖了这两种情况。

这里有一个圆点小提琴来证明它是有效的。

换言之:

代码语言:javascript
运行
复制
public int Increment(int current, int mod)
{
    return ((++current % mod) + mod) % mod;
}

public int Decrement(int current, int mod)
{
    return ((--current % mod) + mod) % mod;
}

为了干燥,你可以重塑它,所以你只使用这个复杂的公式一次。

代码语言:javascript
运行
复制
public int Cycle(int current, int mod)
{
    return ((current % mod) + mod) % mod;
}

..。但是,您必须首先手动地输入/减少值。你喜欢哪个版本取决于你自己。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68998738

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档