App Inventor 2 拖拽物体教程 - 按住移动与碰撞检测

« 返回首页

概述

已有文档canvas_game.md 介绍了Canvas游戏基础。本文聚焦拖拽物体的实现。

ImageSprite拖拽

方法一:Dragged事件

当 ImageSprite1.被拖动(被拖动, 起X, 起Y, 当X, 当Y, 上X, 上Y)
  如果 被拖动
    设 ImageSprite1.X坐标 = ImageSprite1.X坐标 + (当X - 上X)
    设 ImageSprite1.Y坐标 = ImageSprite1.Y坐标 + (当Y - 上Y)

注意:Dragged事件的坐标是相对于Canvas的,不是相对于Sprite的。需要计算偏移量。

方法二:Touched + Moved(更精确)

设 正在拖拽 = false
设 偏移X = 0
设 偏移Y = 0

当 Canvas1.触摸按下(X, Y)
  ' 检查是否触摸到了Sprite
  设 碰撞 = ImageSprite1.碰到点(X, Y)
  如果 碰撞
    设 正在拖拽 = true
    设 偏移X = X - ImageSprite1.X坐标
    设 偏移Y = Y - ImageSprite1.Y坐标

当 Canvas1.拖动(被拖动, 起X, 起Y, 当X, 当Y, 上X, 上Y)
  如果 正在拖拽 且 被拖动
    设 ImageSprite1.X坐标 = 当X - 偏移X
    设 ImageSprite1.Y坐标 = 当Y - 偏移Y

当 Canvas1.触摸释放(X, Y)
  设 正在拖拽 = false

碰撞检测

Sprite与Sprite碰撞

当 ImageSprite1.碰到(ImageSprite2)
  ' 碰撞触发
  标签_状态.文本 = "碰撞!"
  ' 反弹效果
  设 ImageSprite1.速度 = -ImageSprite1.速度

Sprite与边界碰撞

当 ImageSprite1.到达边界(边缘)
  如果 边缘 = "左" 或 边缘 = "右"
    设 ImageSprite1.水平方向 = -ImageSprite1.水平方向
  否则 如果 边缘 = "上" 或 边缘 = "下"
    设 ImageSprite1.垂直方向 = -ImageSprite1.垂直方向

自定义碰撞区域

定义 矩形碰撞(x1, y1, w1, h1, x2, y2, w2, h2) 返回 是否碰撞
  如果 x1 < x2 + w2 且 x1 + w1 > x2 且 y1 < y2 + h2 且 y1 + h1 > y2
    返回 true
  返回 false

实战案例:拼图游戏

设 目标位置 = [
  创建字典("x" → 50, "y" → 50),
  创建字典("x" → 150, "y" → 50),
  创建字典("x" → 50, "y" → 150),
  创建字典("x" → 150, "y" → 150)
]
设 吸附距离 = 30
设 完成数 = 0

当 Canvas1.触摸释放(X, Y)
  设 正在拖拽 = false
  ' 检查是否到达目标位置
  设 i = 当前拖拽索引
  设 目标X = 从字典 列表第i项(目标位置) 获取 "x"
  设 目标Y = 从字典 列表第i项(目标位置) 获取 "y"
  设 距离 = 数学.平方根((X-目标X)^2 + (Y-目标Y)^2)
  
  如果 距离 < 吸附距离
    ' 吸附到目标位置
    设 当前Sprite.X坐标 = 目标X
    设 当前Sprite.Y坐标 = 目标Y
    设 完成数 = 完成数 + 1
    如果 完成数 = 4
      标签_状态.文本 = "🎉 拼图完成!"

实战案例:地球围绕太阳旋转

设 角度 = 0
设 轨道半径 = 150
设 太阳X = Canvas1.宽度 / 2
设 太阳Y = Canvas1.高度 / 2
设 旋转速度 = 2  ' 度/帧

当 Clock_旋转.计时
  设 角度 = (角度 + 旋转速度) 模 360
  设 弧度 = 角度 * 数学.PI / 180
  设 地球X = 太阳X + 轨道半径 * 数学.余弦(弧度)
  设 地球Y = 太阳Y + 轨道半径 * 数学.正弦(弧度)
  
  ' 更新地球位置
  设 ImageSprite_地球.X坐标 = 地球X - ImageSprite_地球.宽度/2
  设 ImageSprite_地球.Y坐标 = 地球Y - ImageSprite_地球.高度/2
  
  ' 绘制轨道线(可选)
  调用 Canvas1.清除()
  调用 Canvas1.画圆(太阳X, 太阳Y, 轨道半径, 灰色)

常见问题

Q1: 拖动时有跳跃?

确保在Touched时记录偏移量,Dragged时减去偏移量。

Q2: Sprite飞出Canvas边界?

' 限制Sprite在Canvas范围内
设 新X = 数学.最大值(0, 数学.最小值(Canvas1.宽度 - Sprite.宽度, 新X))
设 新Y = 数学.最大值(0, 数学.最小值(Canvas1.高度 - Sprite.高度, 新Y))
设 Sprite.X坐标 = 新X
设 Sprite.Y坐标 = 新Y

Q3: 多个Sprite同时拖动?

Canvas不支持多点触控拖动多个Sprite。只能同时拖一个。

总结

需求 方法
拖动Sprite Dragged事件 + 偏移量
碰撞检测 碰到事件 / 碰到点
轨道旋转 三角函数计算位置
吸附效果 距离判断 + 自动定位

版权声明:MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权,本文档由 ai2claw 🐝 整理。

文档反馈