C# WinForm实现多动画矩形碰边移动效果及问题修复
问题根因
动画完全不动是几个基础逻辑错误导致的:
- 所有鱼对象初始化时
speed用的是无参构造的Size,X/Y轴速度都是0,坐标永远不会变化,自然没有移动效果 Pike类(以及结构相同的Carp类)里定义的私有坐标字段coordinates从未被正确赋值,构造函数只给基类的Data属性传了值,但绘制、位置更新逻辑全用的是coordinates,这个字段默认始终是(0,0)- 点击按钮添加鱼时传的初始坐标是
new Point()也就是(0,0),就算速度正常,所有鱼都会堆在左上角,而且没有随机初始速度/位置,看不到位移 - 边界判断逻辑有冗余:用
bounds.Contains(coordinates + speed)判断点是否在区域内是错的,你绘制的是40*40的图形,点在边界内不代表整个图形不会越界,这个判断还会和后面的边缘检测冲突,容易出现卡边问题
修复方案
- 修改
Pike类构造函数,初始化坐标和随机速度,不要让速度为0
// 建议把随机数实例放在Fish基类做静态成员,避免短时间new Random()生成重复值 private static Random rand = new Random(); public Pike(Point data, AquariumForm aquariumForm) : base(Color.Green, aquariumForm) { Data = data; coordinates = data; // 给私有坐标字段赋初始值 // 生成2-6之间的随机速度,随机正负方向 speed = new Size( rand.Next(2, 7) * (rand.Next(2) == 0 ? 1 : -1), rand.Next(2, 7) * (rand.Next(2) == 0 ? 1 : -1) ); }
- 重写
UpdateLocation的边界判断逻辑,去掉冗余判断,增加位置修正避免卡边
public void UpdateLocation(Rectangle bounds) { Point nextPos = new Point(coordinates.X + speed.Width, coordinates.Y + speed.Height); // 左右边界碰撞检测 if (nextPos.X < bounds.Left || nextPos.X > bounds.Right - size.Width) { speed.Width *= -1; nextPos.X = coordinates.X + speed.Width; } // 上下边界碰撞检测 if (nextPos.Y < bounds.Top || nextPos.Y > bounds.Bottom - size.Height) { speed.Height *= -1; nextPos.Y = coordinates.Y + speed.Height; } coordinates = nextPos; }
- 修改添加按钮的点击逻辑,生成随机初始位置,不要固定传(0,0)
private void Add_pike_button_Click(object sender, EventArgs e) { Point initPos = new Point( rand.Next(0, ClientSize.Width - 40), rand.Next(0, ClientSize.Height - 40) ); aquarium.pikeFlock.Add(initPos, this); } // 鲤鱼添加按钮逻辑同步修改即可
- 按照Pike的修改逻辑同步调整Carp类,保证Carp的speed、coordinates字段正确初始化。
可选优化
- 计时器间隔从100ms改成30ms左右,动画会更流畅,100ms人眼能明显感觉到卡顿
- 没必要自己实现链表存鱼,直接用C#内置的
List<Pike>、List<Carp>即可,代码更简洁也不容易出遍历、增删的bug - 窗体构造函数里初始化Aquarium时传的ClientRectangle是窗体未加载完成时的尺寸,如果要支持窗体拉伸,建议在Timer_Tick里每次把当前ClientRectangle传给UpdateLocation,不要用初始化时存的固定值
内容的提问来源于stack exchange,提问作者vitkuz573
相关产品推荐
相关产品推荐

