Lazarus/FreePascal中移动角色与行星碰撞接触点求解
解决行星跳跃游戏的着陆定位问题
我来帮你梳理下着陆逻辑的问题,结合你的代码和变量说明,给你一套可行的解决方案:
核心问题分析
你的代码里存在两个关键问题:
- 弧度与度数/自定义单位的转换混淆:FreePascal的三角函数(
cos/sin/arccos)都是基于弧度计算的,但你用了自定义的1130单位一圈,转换逻辑没对应上; - 角度计算的象限缺失:
arccos只能返回0~π的角度,无法区分上下/左右象限,导致着陆位置偏移。
具体修正方案
1. 统一角度转换逻辑
先明确单位对应关系:
- 标准圆周:
2π弧度 = 360度 = 你的1130自定义旋转单位 - 转换公式:
自定义单位 = 弧度值 * (1130 / (2 * Pi))
2. 修正着陆角度与位置计算
当玩家需要着陆到目标行星(notplanump1对应的行星)时,用ArcTan2计算向量角度(能覆盖所有象限),再定位到行星圆周上:
var dx, dy: Integer; targetAngleRad: Double; targetPlanetRadius: Integer; targetPlanetX, targetPlanetY: Integer; begin // 获取目标行星的核心参数 targetPlanetX := xorigins[notplanump1]; targetPlanetY := yorigins[notplanump1]; targetPlanetRadius := rs[notplanump1]; // 计算玩家当前位置到目标行星中心的向量 dx := GTR.Left - targetPlanetX; dy := GTR.Top - targetPlanetY; // 计算向量对应的弧度角度(ArcTan2处理所有象限,比arccos可靠) targetAngleRad := ArcTan2(dy, dx); // 将弧度转换为你的自定义1130单位旋转值 currotp1 := Round(targetAngleRad * (1130 / (2 * Pi))); // 将玩家定位到目标行星的圆周上 GTR.Left := targetPlanetX + Round(Cos(targetAngleRad) * targetPlanetRadius); GTR.Top := targetPlanetY + Round(Sin(targetAngleRad) * targetPlanetRadius); // 维持自定义旋转单位的循环范围(0~1130) while currotp1 > 1130 do currotp1 := currotp1 - 1130; while currotp1 < 0 do currotp1 := currotp1 + 1130; end;
3. 优化原移动代码的角度计算
你的原移动代码里的角度转坐标逻辑可以简化,避免冗余的符号运算:
// 原代码的坐标计算可以简化为: GTR.Left := curplaxp1 + Round(Cos(DegToRad(currotp1 * (360 / 1130))) * r); GTR.Top := curplayp1 + Round(Sin(DegToRad(currotp1 * (360 / 1130))) * r);
这里先把自定义1130单位转成度数,再转成弧度,逻辑更清晰。
为什么之前的尝试失败?
- 你用
DegToRad时,可能错误地将已经是弧度的数值再次转换,导致角度完全混乱; arccos无法区分象限,比如相同的y值会对应左右两个不同的点,导致着陆位置错误;- 自定义旋转单位和标准弧度的转换关系没明确,计算时的比例系数错误。
内容的提问来源于stack exchange,提问作者Zekeste42
相关产品推荐
相关产品推荐

