elixir - Elixir:循环遍历地图,将其与自身进行比较并更新它
问题描述
我有一张台球桌的地图,如下:
ball_map = %{
"cue" => {"x":-15.0, "z": 0.0, "velocity_x": 0.0, "velocity_z": 0.0, "is_idle": true},
"ball_1" => {"x":15.0, "z": 0.0, "velocity_x": 0.0, "velocity_z": 0.0, "is_idle": true},
"ball_2" => {"x":17.0, "z": 1.1, "velocity_x": 0.0, "velocity_z": 0.0, "is_idle": true},
"ball_3" => {"x":17.0, "z": -1.1, "velocity_x": 0.0, "velocity_z": 0.0, "is_idle": true}
}
我需要对它应用碰撞。为了使其正常工作,必须将每个球与其他球进行检查,并且必须在检查时更新球的位置。在我之前的尝试中,我制作了一个“碰撞图”,然后在之后应用了新的位置,但这对随后的碰撞有问题。
所以我想做的是
- 循环遍历地图中的每个项目。
- 将该项目与其他所有项目进行比较,并对其进行碰撞检查(我有一个功能)。
- 在碰撞时更新这两个项目,同时保持
ball_map
.
我想出的代码是这样的:
collision_result = Enum.reduce(ball_map, fn {ball_a, body_a}, acc ->
new_result = Enum.map(ball_map, fn {ball_b, body_b} ->
has_collided = checkStaticCollisions(ball_a, body_a, ball_b, body_b, const_physics["billiard_ball_radius"])
# Takes in parameters (Key of Ball A, Value of Ball A, Key of Ball B, Value of Ball B, radius)
# Returns true or false depending if Ball A != Ball B and collisions happen
if has_collided == true do
calc = calculatePosAfterCollision(ball_a, body_a, ball_b, body_b, const_physics["billiard_ball_radius"])
# Takes in parameters (Key of Ball A, Value of Ball A, Key of Ball B, Value of Ball B, radius)
# Returns {"id_of_ball_a" => {new X and Z pos}, "id_of_ball_b" => {new X and Z pos}}
new_a_pos = calc[ball_a]
new_b_pos = calc[ball_b]
new_a = %{"x" => new_a_pos["x"], "z" => new_a_pos["z"], "velocity_x" => body_a["velocity_x"], "velocity_z" => body_a["velocity_z"], "is_idle" => body_a["is_idle"]}
new_b = %{"x" => new_b_pos["x"], "z" => new_b_pos["z"], "velocity_x" => body_b["velocity_x"], "velocity_z" => body_b["velocity_z"], "is_idle" => body_b["is_idle"]}
# Supposedly, Update both ball A and ball B, keep the rest
Map.put(acc, ball_a, new_a) #?
Map.put(acc, ball_b, new_b) #?
else
# Supposedly, No change for ball A or ball B
%{ball_a => body_a, ball_b => body_b}
end
end)
# Not sure what to output here, if any
end)
现在这不起作用,因为我得到了一个BadMapError
(我假设与acc
else 上的 s 有关),但我也很肯定这将导致列表中的列表。
我对 Elixir 还是很陌生,我不确定我还能做什么。我还有什么可以尝试的吗?是否有非枚举方法(递归算吗?)?
编辑:这是其他正在使用的功能:
def checkStaticCollisions(key_a, body_a, key_b, body_b, ball_radius) do
if (key_a == key_b) do
false
else
pos_a = PGS.Vector.new(body_a["x"], 0.0, body_a["z"])
pos_b = PGS.Vector.new(body_b["x"], 0.0, body_b["z"])
circle_a = PGS.Circle.new(pos_a, ball_radius)
circle_b = PGS.Circle.new(pos_b, ball_radius)
checkCircleCollision(circle_a, circle_b)
end
end
def checkCircleCollision(circleA, circleB) do
posA = circleA.position
posB = circleB.position
radiusA = circleA.radius
radiusB = circleB.radius
distance = PGS.Vector.distance(posA, posB)
circleDistance = radiusA + radiusB
if distance < circleDistance do
# collision occured
true
else
false
end
end
def calculatePosAfterCollision(id_a, ball_a, id_b, ball_b, radius) do
pos_a = PGS.Vector.new(ball_a["x"], 0.0, ball_a["z"])
pos_b = PGS.Vector.new(ball_b["x"], 0.0, ball_b["z"])
radius_a = radius
radius_b = radius
distance = PGS.Vector.distance(pos_a, pos_b)
pos_delta = PGS.Vector.sub(pos_a, pos_b)
overlap_dist = (distance - radius_a - radius_b) * 0.5
vector_difference = PGS.Vector.new(overlap_dist * pos_delta.x / distance, overlap_dist * pos_delta.y / distance, overlap_dist * pos_delta.z / distance)
new_pos_a = PGS.Vector.sub(pos_a, vector_difference)
new_pos_b = PGS.Vector.add(pos_b, vector_difference)
%{id_a => new_pos_a, id_b => new_pos_b}
end
Circle
和功能请Vector
参考这里。
解决方案
推荐阅读
- sql - 尝试使用 3 个主键更新行不起作用
- sql - 如何在“相同”条件下选择一个值?
- database - 如何在 DolphinDB 中删除磁盘上的 mvccTable?
- javascript - 如何根据json数据重复列以进行数据表显示
- pandas - tf.reduce_sum() 的非期望输出
- c# - 如何将 NUnit2XmlResultWriter.dll 放入我的项目中以使用它?
- javascript - 为什么我在 puppeteer 中得到 document is not defined 错误?
- scala - Play framework 2.6 数据库注入
- c# - HTTPModule 部分的 Azure 应用服务配置设置
- scala - 如何在 FUTURE 内发送 ACK?