You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#游戏开发:如何让敌人获取独立的随机移动坐标?

问题描述

我正在制作一款游戏原型,目标是实现:

  • 敌人在随机位置生成
  • 每个敌人拥有独立的随机X、Y目标坐标,到达后自动前往新的随机坐标

目前遇到的问题:所有敌人共享同一个移动坐标,到达目标后也无法更新为各自的新坐标。


现有代码实现

1. 随机数初始化

Random randNum = new Random();

2. 创建敌人的函数

private void MakeShootEnemies()                                 //creates the function for shootEnemy creation
{
    PictureBox shootEnemy = new PictureBox();                   //initialises the creation of picturebox
    shootEnemy.Tag = "shootEnemy";                              //tags the picturebox
    shootEnemy.Image = Properties.Resources.RangeScientistTransparent;     //inserts the scientist image to the picture box
    shootEnemy.Left = randNum.Next(100, 1820);                  //creates a random x coordinate for the enemy to spawn on
    shootEnemyLeft = shootEnemy.Left;
    shootEnemy.Top = randNum.Next(100, 920);                    //creates a random y coordinate for the enemy to spawn on
    shootEnemyTop = shootEnemy.Top;
    Size size = new Size(75, 100);                              //creates a size for the box to be
    shootEnemy.Size = size;                                     //sets the box to said size
    shootEnemy.SizeMode = PictureBoxSizeMode.StretchImage;      //makes the image fit to the picturebox
    shootEnemy.BackColor = Color.Transparent;                   //should make the background transparent (doesnt work and will probably remove)
  
    shootEnemiesList.Add(shootEnemy);                           //adds enemy to enemies list
    this.Controls.Add(shootEnemy);                              //adds the controls for the enemy to the form
    player.BringToFront();                                      //brings the player to the front of the screen
    healthBar.BringToFront();
    shootXDestination = randNum.Next(100, 1820);
    shootYDestination = randNum.Next(100, 920);
}

3. 尝试生成新目标的函数

private void ShootEnemyMovement()
{
    foreach (Control y in this.Controls)
            {               
            
                shootXDestination = randNum.Next(0, 1820);
                shootYDestination = randNum.Next(100, 920);
            
            }
}

4. 敌人生成调用代码(测试用)

for (int i = 0; i < 2; i++)               //spawns the number of shoot enemies needed to take the total enemy count to 10
{
    MakeShootEnemies();
    shootXDestination = randNum.Next(100, 1820);
    shootYDestination = randNum.Next(100, 920);
}

5. 移动逻辑代码

foreach (Control y in this.Controls)                            //makes the shoot enemies easier to control
{
    if (y is PictureBox && (string)y.Tag == "shootEnemy")
    {
        if ((y.Left == shootXDestination && y.Top == shootYDestination) || (y.Left == shootEnemyLeft && y.Top == shootEnemyTop))
        {
            ShootEnemyMovement();
        }

        if (y.Left > shootXDestination)
        {
            y.Left -= enemySpeed;
        }

        if (y.Left < shootXDestination)
        {
            y.Left += enemySpeed;
        }

        if (y.Top > shootYDestination)
        {
            y.Top -= enemySpeed;
        }

        if (y.Top < shootYDestination)
        {
            y.Top += enemySpeed;
        }
    }
}

解决方案

问题根源

你用全局变量shootXDestination、shootYDestination存储目标坐标,所有敌人共享这两个值,自然会同步移动。而且ShootEnemyMovement遍历敌人时不断覆盖全局变量,最终所有敌人都会使用最后一次生成的坐标。另外,用y.Left == shootXDestination判断到达目标存在逻辑漏洞——敌人按enemySpeed步进移动,很可能跳过目标坐标,永远触发不了更新。

具体修复步骤

1. 给每个敌人绑定独立目标坐标

创建自定义类存储敌人专属数据,替代全局变量:

public class ShootEnemyData
{
    public int TargetX { get; set; }
    public int TargetY { get; set; }
}

修改MakeShootEnemies函数,给每个敌人分配独立初始目标:

private void MakeShootEnemies()
{
    PictureBox shootEnemy = new PictureBox();
    shootEnemy.Image = Properties.Resources.RangeScientistTransparent;
    // 随机出生位置
    int spawnX = randNum.Next(100, 1820);
    int spawnY = randNum.Next(100, 920);
    shootEnemy.Left = spawnX;
    shootEnemy.Top = spawnY;
    shootEnemy.Size = new Size(75, 100);
    shootEnemy.SizeMode = PictureBoxSizeMode.StretchImage;
    shootEnemy.BackColor = Color.Transparent;
  
    // 绑定专属目标数据
    ShootEnemyData enemyData = new ShootEnemyData();
    enemyData.TargetX = randNum.Next(100, 1820);
    enemyData.TargetY = randNum.Next(100, 920);
    shootEnemy.Tag = enemyData;
  
    shootEnemiesList.Add(shootEnemy);
    this.Controls.Add(shootEnemy);
    player.BringToFront();
    healthBar.BringToFront();
}

2. 修改移动逻辑,使用敌人专属目标

更新移动循环,用范围判断替代精确相等,到达后生成新目标:

foreach (Control ctrl in this.Controls)
{
    if (ctrl is PictureBox pb && pb.Tag is ShootEnemyData enemyData)
    {
        // 用误差范围判断是否到达目标,避免步进跳过
        bool isAtTarget = Math.Abs(pb.Left - enemyData.TargetX) <= enemySpeed && 
                          Math.Abs(pb.Top - enemyData.TargetY) <= enemySpeed;
        
        if (isAtTarget)
        {
            // 生成新随机目标
            enemyData.TargetX = randNum.Next(100, 1820);
            enemyData.TargetY = randNum.Next(100, 920);
        }

        // 向自身目标移动
        if (pb.Left > enemyData.TargetX)
        {
            pb.Left -= enemySpeed;
        }
        else if (pb.Left < enemyData.TargetX)
        {
            pb.Left += enemySpeed;
        }

        if (pb.Top > enemyData.TargetY)
        {
            pb.Top -= enemySpeed;
        }
        else if (pb.Top < enemyData.TargetY)
        {
            pb.Top += enemySpeed;
        }
    }
}

3. 清理无用代码

删除全局变量shootXDestination、shootYDestination、shootEnemyLeft、shootEnemyTop,以及ShootEnemyMovement函数。

4. 简化敌人生成代码

for (int i = 0; i < 2; i++)
{
    MakeShootEnemies();
}

额外优化建议

  • 后续扩展敌人类型时,可将ShootEnemyData继承自基类EnemyData,统一管理属性
  • 移动时可加入平滑逻辑,根据距离调整移动比例,提升自然度
  • 生成目标坐标时增加边界检查,避免敌人移出屏幕

内容的提问来源于stack exchange,提问作者nat_to_han

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 07:57:57