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
相关产品推荐
相关产品推荐

