地图上汽车避障移动动画实现技术问询
实现带碰撞检测的汽车移动动画
现有条件
- 一张包含若干物体的地图
- 一张可在地图上按指定速度移动的汽车图片
需求说明
当用户点击地图时,代码需实现以下逻辑:
- 检查点击点颜色是否在禁止颜色列表中(汽车无法穿过建筑);
- 汽车将向点击点移动,移动过程中需持续检查前方区域是否为禁止颜色,若是则停止移动,否则继续前进。
核心实现代码
map.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { // 获取地图上的点击位置 float clickedX = event.getX(); float clickedY = event.getY(); // 获取汽车当前位置 float carX = point.getX(); float carY = point.getY(); // 检查点击像素是否为禁止颜色 int pixelColor = getPixelColor((int) clickedX, (int) clickedY); int[] forbiddenColors = {Color.rgb(102,112,127), Color.rgb(76, 76, 76)}; // 可添加其他禁止颜色 // 如果点击点是禁止颜色,将目标点替换为最近的可通行点 if (isForbiddenColor(pixelColor, forbiddenColors)) { PointF nearestPoint = findNextNonForbiddenPoint(carX, carY, clickedX, clickedY, forbiddenColors, screenWidth, screenHeight); clickedX = nearestPoint.x; clickedY = nearestPoint.y; } // 计算汽车到目标点的距离 float distance = calculateDistance(carX, carY, clickedX, clickedY); // 计算移动时长:速度为50像素/秒 long duration = (long) (distance / 50 * 1000); // 创建ValueAnimator实现移动动画 ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); animator.setDuration(duration); final float startX = carX; final float startY = carY; final float endX = clickedX; final float endY = clickedY; // 设置动画更新监听器,实时更新汽车位置 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float fraction = animation.getAnimatedFraction(); float x = startX + fraction * (endX - startX); float y = startY + fraction * (endY - startY); point.setX(x); point.setY(y); } }); // 启动动画 animator.start(); } return true; } });
辅助方法
// 检查颜色是否在禁止列表中 private boolean isForbiddenColor(int color, int[] forbiddenColors) { for (int c : forbiddenColors) { if (color == c) { return true; } } return false; } // 获取指定坐标的像素颜色 private int getPixelColor(int x, int y) { Bitmap bitmap = ((BitmapDrawable) map.getDrawable()).getBitmap(); return bitmap.getPixel(x, y); } // 计算两点间距离(勾股定理) private float calculateDistance(float x1, float y1, float x2, float y2) { float dx = x2 - x1; float dy = y2 - y1; return (float) Math.sqrt(dx * dx + dy * dy); } // 查找从起点到终点方向上最近的可通行点 private PointF findNextNonForbiddenPoint(float startX, float startY, float endX, float endY, int[] forbiddenColors, int screenWidth, int screenHeight) { // 计算方向向量 PointF direction = new PointF(endX - startX, endY - startY); // 归一化方向向量 float distance = (float) Math.sqrt(direction.x * direction.x + direction.y * direction.y); if (distance > 0) { direction.set(direction.x / distance, direction.y / distance); } // 沿方向逐像素检查,找到第一个可通行点 PointF nextPoint = new PointF(startX, startY); while (isForbiddenColor(getPixelColor((int) nextPoint.x, (int) nextPoint.y), forbiddenColors)) { nextPoint.offset(direction.x, direction.y); // 超出边界则返回null if (nextPoint.x < 0 || nextPoint.x >= screenWidth || nextPoint.y < 0 || nextPoint.y >= screenHeight) { return null; } } return nextPoint; }
内容的提问来源于stack exchange,提问作者Dmytro Parkhomenko
相关产品推荐
相关产品推荐

