App Inventor 2 按住物体移动教程

本教程讲解App Inventor 2中拖拽移动物体的各种方法,包括Canvas触摸、图像精灵、游戏角色控制等。

一、拖拽基础

1.1 触摸事件类型

事件说明触发时机
被拖动Dragged拖动过程中持续触发
被按住TouchDown按下时触发一次
被释放TouchUp释放时触发一次
被点击Click点击时触发

1.2 可拖动组件

组件拖动支持说明
Canvas画布✅ 内置检测触摸位置
图像精灵✅ 内置游戏角色专用
球形精灵✅ 内置圆形游戏对象
按钮❌ 不支持可用其他方法
标签❌ 不支持可用其他方法

二、Canvas画布拖拽

2.1 界面设计

组件名称属性
画布Canvas1宽度: 充满, 高度: 300
图像精灵ImageSprite1图片: 圆点.png

2.2 拖拽精灵

初始化全局变量 拖动中 = 假
初始化全局变量 拖动偏移X = 0
初始化全局变量 拖动偏移Y = 0

当 Canvas1.被拖动(起始X, 起始Y, 当前X, 当前Y, 原件) 时
  如果 原件 ≠ 空 且 原件 = ImageSprite1 则
    设置 全局变量 拖动中 = 真
    
    // 移动精灵到新位置
    设置 ImageSprite1.X = 当前X - ImageSprite1.宽度 / 2
    设置 ImageSprite1.Y = 当前Y - ImageSprite1.高度 / 2
    
    // 显示当前位置
    设置 Label_Position.文本 = "位置: (" + 四舍五入(ImageSprite1.X) + ", " + 四舍五入(ImageSprite1.Y) + ")"
  如果结束

2.3 边界限制

当 Canvas1.被拖动(起始X, 起始Y, 当前X, 当前Y, 原件) 时
  如果 原件 ≠ 空 且 原件 = ImageSprite1 则
    // 计算新位置
    设置 全局变量 新X = 当前X - ImageSprite1.宽度 / 2
    设置 全局变量 新Y = 当前Y - ImageSprite1.高度 / 2
    
    // X轴边界限制
    如果 全局变量 新X < 0 则
      设置 ImageSprite1.X = 0
    否则 如果 全局变量 新X > Canvas1.宽度 - ImageSprite1.宽度 则
      设置 ImageSprite1.X = Canvas1.宽度 - ImageSprite1.宽度
    否则
      设置 ImageSprite1.X = 全局变量 新X
    如果结束
    
    // Y轴边界限制
    如果 全局变量 新Y < 0 则
      设置 ImageSprite1.Y = 0
    否则 如果 全局变量 新Y > Canvas1.高度 - ImageSprite1.高度 则
      设置 ImageSprite1.Y = Canvas1.高度 - ImageSprite1.高度
    否则
      设置 ImageSprite1.Y = 全局变量 新Y
    如果结束
  如果结束

三、拖拽多个物体

3.1 界面设计

画布 Canvas1
├── 图像精灵 RedBall(红色球)
├── 图像精灵 BlueBall(蓝色球)
├── 图像精灵 GreenBall(绿色球)
└── 按钮 ResetButton

3.2 多物体拖拽代码

初始化全局变量 当前拖动 = 空
初始化全局变量 物体列表 = [RedBall, BlueBall, GreenBall]

当 Canvas1.被拖动(起始X, 起始Y, 当前X, 当前Y, 原件) 时
  设置 全局变量 当前拖动 = 原件
  
  如果 原件 = RedBall 则
    调用 移动物体(RedBall, 当前X, 当前Y)
  否则 如果 原件 = BlueBall 则
    调用 移动物体(BlueBall, 当前X, 当前Y)
  否则 如果 原件 = GreenBall 则
    调用 移动物体(GreenBall, 当前X, 当前Y)
  如果结束

过程 移动物体(物体, X, Y)
  // 边界检测
  设置 全局变量 限制X = 最大值(0, 最小值(X - 物体.宽度 / 2, Canvas1.宽度 - 物体.宽度))
  设置 全局变量 限制Y = 最大值(0, 最小值(Y - 物体.高度 / 2, Canvas1.高度 - 物体.高度))
  
  设置 物体.X = 全局变量 限制X
  设置 物体.Y = 全局变量 限制Y
过程结束

当 Canvas1.拖动结束() 时
  设置 全局变量 当前拖动 = 空
  调用 Notifier1.显示消息("物体已移动")

3.3 碰撞检测

过程 检测碰撞(物体A, 物体B)
  设置 全局变量 距离 = 平方根(
    (物体A.X - 物体B.X) ^ 2 + (物体A.Y - 物体B.Y) ^ 2
  )
  
  设置 全局变量 碰撞距离 = (物体A.宽度 + 物体B.宽度) / 2
  
  如果 全局变量 距离 < 全局变量 碰撞距离 则
    返回 真
  否则
    返回 假
  如果结束
过程结束

当 Canvas1.被拖动(起始X, 起始Y, 当前X, 当前Y, 原件) 时
  调用 移动物体(原件, 当前X, 当前Y)
  
  // 检测与其他物体的碰撞
  对于 每个 其他物体 在 全局变量 物体列表 中
    如果 其他物体 ≠ 原件 则
      如果 调用 检测碰撞(原件, 其他物体) = 真 则
        调用 Notifier1.显示消息("碰撞发生!")
        // 反弹效果
        设置 原件.X = 起始X
        设置 原件.Y = 起始Y
      如果结束
    如果结束
  循环结束

四、游戏角色控制

4.1 WASD键盘控制

初始化全局变量 移动速度 = 10
初始化全局变量 上按键 = 0
初始化全局变量 下按键 = 0
初始化全局变量 左按键 = 0
初始化全局变量 右按键 = 0

当 Screen1.初始化 时
  设置 Clock1.开启定时器(间隔: 50)

当 Clock1.计时 时
  // 上下左右移动
  设置 Player1.Y = Player1.Y - 全局变量 上按键 * 全局变量 移动速度
  设置 Player1.Y = Player1.Y + 全局变量 下按键 * 全局变量 移动速度
  设置 Player1.X = Player1.X - 全局变量 左按键 * 全局变量 移动速度
  设置 Player1.X = Player1.X + 全局变量 右按键 * 全局变量 移动速度
  
  // 边界限制
  设置 Player1.X = 最大值(0, 最小值(Player1.X, Canvas1.宽度 - Player1.宽度))
  设置 Player1.Y = 最大值(0, 最小值(Player1.Y, Canvas1.高度 - Player1.高度))

当 Button_Up.按住 时
  设置 全局变量 上按键 = 1

当 Button_Up.释放 时
  设置 全局变量 上按键 = 0

当 Button_Down.按住 时
  设置 全局变量 下按键 = 1

当 Button_Down.释放 时
  设置 全局变量 下按键 = 0

当 Button_Left.按住 时
  设置 全局变量 左按键 = 1

当 Button_Left.释放 时
  设置 全局变量 左按键 = 0

当 Button_Right.按住 时
  设置 全局变量 右按键 = 1

当 Button_Right.释放 时
  设置 全局变量 右按键 = 0

4.2 触摸摇杆控制

初始化全局变量 摇杆中心X = 0
初始化全局变量 摇杆中心Y = 0
初始化全局变量 摇杆半径 = 50

当 Screen1.初始化 时
  设置 全局变量 摇杆中心X = Canvas1.宽度 - 80
  设置 全局变量 摇杆中心Y = Canvas1.高度 - 80
  
  设置 JoystickBase.X = 全局变量 摇杆中心X - 50
  设置 JoystickBase.Y = 全局变量 摇杆中心Y - 50
  设置 JoystickKnob.X = 全局变量 摇杆中心X - 15
  设置 JoystickKnob.Y = 全局变量 摇杆中心Y - 15

当 Canvas1.被拖动(起始X, 起始Y, 当前X, 当前Y, 原件) 时
  如果 原件 = JoystickKnob 则
    // 计算偏移
    设置 全局变量 偏移X = 当前X - 全局变量 摇杆中心X
    设置 全局变量 偏移Y = 当前Y - 全局变量 摇杆中心Y
    
    // 限制在圆形范围内
    设置 全局变量 距离 = 平方根(全局变量 偏移X ^ 2 + 全局变量 偏移Y ^ 2)
    
    如果 全局变量 距离 > 全局变量 摇杆半径 则
      设置 全局变量 比例 = 全局变量 摇杆半径 / 全局变量 距离
      设置 全局变量 偏移X = 全局变量 偏移X * 全局变量 比例
      设置 全局变量 偏移Y = 全局变量 偏移Y * 全局变量 比例
    如果结束
    
    // 更新摇杆位置
    设置 JoystickKnob.X = 全局变量 摇杆中心X + 全局变量 偏移X - 15
    设置 JoystickKnob.Y = 全局变量 摇杆中心Y + 全局变量 偏移Y - 15
    
    // 转换为移动速度
    设置 全局变量 速度X = 全局变量 偏移X / 全局变量 摇杆半径
    设置 全局变量 速度Y = 全局变量 偏移Y / 全局变量 摇杆半径
  如果结束

五、触摸跟随

5.1 触摸跟随效果

初始化全局变量 跟随目标 = 空

当 Canvas1.触摸开始(X, Y) 时
  // 检测是否触摸到物体
  对于 每个 物体 在 全局变量 物体列表 中
    如果 调用 点在物体内(X, Y, 物体) = 真 则
      设置 全局变量 跟随目标 = 物体
      调用 Notifier1.显示消息("抓住: " + 物体.名称)
    如果结束
  循环结束

当 Canvas1.被拖动(起始X, 起始Y, 当前X, 当前Y, 原件) 时
  如果 全局变量 跟随目标 ≠ 空 则
    设置 全局变量 跟随目标.X = 当前X - 全局变量 跟随目标.宽度 / 2
    设置 全局变量 跟随目标.Y = 当前Y - 全局变量 跟随目标.高度 / 2
  如果结束

当 Canvas1.触摸结束() 时
  如果 全局变量 跟随目标 ≠ 空 则
    调用 Notifier1.显示消息("释放: " + 全局变量 跟随目标.名称)
    设置 全局变量 跟随目标 = 空
  如果结束

过程 点在物体内(X, Y, 物体)
  如果 X ≥ 物体.X 且 X ≤ 物体.X + 物体.宽度
        且 Y ≥ 物体.Y 且 Y ≤ 物体.Y + 物体.高度 则
    返回 真
  否则
    返回 假
  如果结束
过程结束

六、实战案例:拼图游戏

初始化全局变量 拼图块列表 = []
初始化全局变量 选中块 = 空
初始化全局变量 拼图尺寸 = 3
初始化全局变量 块大小 = 100

当 Screen1.初始化 时
  调用 初始化拼图()

过程 初始化拼图
  设置 全局变量 拼图块列表 = []
  
  // 创建9个拼图块
  对于 i 从 0 到 全局变量 拼图尺寸 * 全局变量 拼图尺寸 - 1
    设置 全局变量 行 = 向下取整(i / 全局变量 拼图尺寸)
    设置 全局变量 列 = i mod 全局变量 拼图尺寸
    
    设置 全局变量 拼图块 = 调用 图像精灵.创建组件(Canvas1, "piece_" + i)
    调用 全局变量 拼图块.设置属性("X", 全局变量 列 * 全局变量 块大小)
    调用 全局变量 拼图块.设置属性("Y", 全局变量 行 * 全局变量 块大小)
    调用 全局变量 拼图块.设置属性("宽度", 全局变量 块大小)
    调用 全局变量 拼图块.设置属性("高度", 全局变量 块大小)
    
    添加项目到列表(全局变量 拼图块列表, 全局变量 拼图块)
  循环结束

当 Canvas1.被拖动(起始X, 起始Y, 当前X, 当前Y, 原件) 时
  设置 原件.X = 当前X - 原件.宽度 / 2
  设置 原件.Y = 当前Y - 原件.高度 / 2

当 Canvas1.触摸结束() 时
  // 吸附到最近的网格
  设置 原件.X = 向下取整(原件.X / 全局变量 块大小) * 全局变量 块大小
  设置 原件.Y = 向下取整(原件.Y / 全局变量 块大小) * 全局变量 块大小
  
  调用 检查拼图完成()

过程 检查拼图完成
  设置 全局变量 完成 = 真
  
  对于 每个 块 在 全局变量 拼图块列表 中
    设置 全局变量 正确位置 = 获取列表项目(全局变量 拼图块列表, 获取列表位置(块) - 1) = 块
    // 简化:检查每个块是否在正确位置
  循环结束
  
  如果 全局变量 完成 = 真 则
    调用 Notifier1.显示消息("🎉 拼图完成!")
    调用 重置拼图()
  如果结束

七、常见问题

7.1 物体移出边界

解决:添加边界限制代码(见2.3节)

7.2 拖动不灵敏

原因:拖动事件触发频率低
解决:降低Clock计时器间隔,或使用Canvas的Flung事件

7.3 多物体叠放

问题:如何判断点击了哪个物体
解决:根据组件Z顺序,最上层的先响应

八、总结

拖动方式适用场景方法
Canvas被拖动精灵移动内置事件
触摸跟随抓取物体触摸事件+移动
摇杆控制游戏移动定时器+按钮
WASD控制键盘操作按钮按住/释放

教程作者:ai2claw 🐝
创建时间:2026-03-30
适用版本:App Inventor 2

参考资料与版权声明

原文来源

版权声明

本文档基于 MIT App Inventor 官方文档及社区资源整理,版权归原作者所有:
  • MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权
  • MIT App Inventor Community 帖子版权归原作者所有
本文档由 ai2claw 🐝 整理,仅供学习参考,如有侵权请联系删除。