我如何确定一个正方形是否可以在不与其他精灵接触的情况下到达位置?
how can I determine if a square can reach position without contact with other sprites?
根据上图,给定初始位置b0(x, y)、结束位置b1(x, y) 以及位置a(x, y) 和c(x, y)。如何预先确定正方形 B0 是否会从 b0(x, y) 移动到 b1(x, y) 而不接触矩形 A 和 C?我相信这个角度是需要的。
一些观察...
如果盒子B的初始位置在结束位置的右边(空隙中),那么只有当theta为a时,盒子B才能成功移动到结束位置而不会与其他盒子发生碰撞counter-clockwise角(见下图)。对于此测试,使用框 B 的 top-right 角和 C 的 bottom-left 角。
同理,如果盒子B的初始位置在结束位置的左边,那么只要θ为counter-clockwise角,它就可以成功移动到结束位置而不会与其他盒子发生碰撞(见图以下)。对于此测试,使用框 B 的 top-left 角和 A 的 bottom-right 角。
一些代码...
首先,扩展 CGPoint
以确定盒子的角。
extension CGPoint {
func bottomLeftCorner(size:CGSize) -> CGPoint {
return CGPoint (x:x - size.width/2.0, y:y - size.height/2.0)
}
func bottomRightCorner(size:CGSize) -> CGPoint {
return CGPoint(x:x + size.width/2.0, y:y - size.height/2.0)
}
func topLeftCorner(size:CGSize) -> CGPoint {
return CGPoint (x:x - size.width/2.0, y:y + size.height/2.0)
}
func topRightCorner(size:CGSize) -> CGPoint {
return CGPoint(x:x + size.width/2.0, y:y + size.height/2.0)
}
}
下面的代码允许用户 drop/drag 框 B。当用户移动框时,代码执行 on-the-fly 测试以查看框是否可以移动到间隙中而不与其他箱子。
class GameScene: SKScene {
let size1 = CGSize(width: 100, height: 50)
let size2 = CGSize(width: 50, height: 50)
let size3 = CGSize(width: 100, height: 50)
var boxA:SKSpriteNode!
var boxB:SKSpriteNode!
var boxC:SKSpriteNode!
var center:CGPoint!
override func didMove(to view: SKView) {
// This is box B's ending position
center = CGPoint (x:0,y:0)
// Define and add the boxes to the scene
boxA = SKSpriteNode(color: SKColor.yellow, size: size1)
boxB = SKSpriteNode(color: SKColor.red, size: size2)
boxC = SKSpriteNode(color: SKColor.blue, size: size3)
boxA.position = CGPoint(x: -size1.width, y: 0)
boxB.position = CGPoint(x: 0, y: 0)
boxC.position = CGPoint(x: size3.width, y: 0)
boxB.zPosition = 1
addChild(boxA)
addChild(boxB)
addChild(boxC)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
// Allow user to drag box to a new location
boxB.position = location
// Find the appropriate corners
var cornerA:CGPoint!
var cornerB:CGPoint!
var cornerC:CGPoint!
if (boxB.position.x < center.x) {
cornerA = boxA.position.bottomRightCorner(size: boxA.size)
cornerB = boxB.position.topLeftCorner(size: boxB.size)
cornerC = center.topLeftCorner(size: boxB.size)
}
else {
cornerA = center.topRightCorner(size: boxB.size)
cornerB = boxB.position.topRightCorner(size: boxB.size)
cornerC = boxC.position.bottomLeftCorner(size: boxC.size)
}
// Test if box B can move in the gap without colliding
if isCounterClockwise(A: cornerA, B: cornerB, C: cornerC) {
boxB.color = SKColor.green
}
else {
boxB.color = SKColor.red
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// Move box B to the ending position
let action = SKAction.move(to: center, duration: 2)
boxB.run(action)
}
// Test direction of angle between line segments AB and AC
func isCounterClockwise (A:CGPoint, B:CGPoint, C:CGPoint) -> Bool {
return (C.y-A.y)*(B.x-A.x) > (B.y-A.y)*(C.x-A.x)
}
}
和一个视频剪辑...
如果方块 B 可以进入缝隙而不发生碰撞,则它变为绿色,否则变为红色。
根据上图,给定初始位置b0(x, y)、结束位置b1(x, y) 以及位置a(x, y) 和c(x, y)。如何预先确定正方形 B0 是否会从 b0(x, y) 移动到 b1(x, y) 而不接触矩形 A 和 C?我相信这个角度是需要的。
一些观察...
如果盒子B的初始位置在结束位置的右边(空隙中),那么只有当theta为a时,盒子B才能成功移动到结束位置而不会与其他盒子发生碰撞counter-clockwise角(见下图)。对于此测试,使用框 B 的 top-right 角和 C 的 bottom-left 角。
同理,如果盒子B的初始位置在结束位置的左边,那么只要θ为counter-clockwise角,它就可以成功移动到结束位置而不会与其他盒子发生碰撞(见图以下)。对于此测试,使用框 B 的 top-left 角和 A 的 bottom-right 角。
一些代码...
首先,扩展 CGPoint
以确定盒子的角。
extension CGPoint {
func bottomLeftCorner(size:CGSize) -> CGPoint {
return CGPoint (x:x - size.width/2.0, y:y - size.height/2.0)
}
func bottomRightCorner(size:CGSize) -> CGPoint {
return CGPoint(x:x + size.width/2.0, y:y - size.height/2.0)
}
func topLeftCorner(size:CGSize) -> CGPoint {
return CGPoint (x:x - size.width/2.0, y:y + size.height/2.0)
}
func topRightCorner(size:CGSize) -> CGPoint {
return CGPoint(x:x + size.width/2.0, y:y + size.height/2.0)
}
}
下面的代码允许用户 drop/drag 框 B。当用户移动框时,代码执行 on-the-fly 测试以查看框是否可以移动到间隙中而不与其他箱子。
class GameScene: SKScene {
let size1 = CGSize(width: 100, height: 50)
let size2 = CGSize(width: 50, height: 50)
let size3 = CGSize(width: 100, height: 50)
var boxA:SKSpriteNode!
var boxB:SKSpriteNode!
var boxC:SKSpriteNode!
var center:CGPoint!
override func didMove(to view: SKView) {
// This is box B's ending position
center = CGPoint (x:0,y:0)
// Define and add the boxes to the scene
boxA = SKSpriteNode(color: SKColor.yellow, size: size1)
boxB = SKSpriteNode(color: SKColor.red, size: size2)
boxC = SKSpriteNode(color: SKColor.blue, size: size3)
boxA.position = CGPoint(x: -size1.width, y: 0)
boxB.position = CGPoint(x: 0, y: 0)
boxC.position = CGPoint(x: size3.width, y: 0)
boxB.zPosition = 1
addChild(boxA)
addChild(boxB)
addChild(boxC)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
// Allow user to drag box to a new location
boxB.position = location
// Find the appropriate corners
var cornerA:CGPoint!
var cornerB:CGPoint!
var cornerC:CGPoint!
if (boxB.position.x < center.x) {
cornerA = boxA.position.bottomRightCorner(size: boxA.size)
cornerB = boxB.position.topLeftCorner(size: boxB.size)
cornerC = center.topLeftCorner(size: boxB.size)
}
else {
cornerA = center.topRightCorner(size: boxB.size)
cornerB = boxB.position.topRightCorner(size: boxB.size)
cornerC = boxC.position.bottomLeftCorner(size: boxC.size)
}
// Test if box B can move in the gap without colliding
if isCounterClockwise(A: cornerA, B: cornerB, C: cornerC) {
boxB.color = SKColor.green
}
else {
boxB.color = SKColor.red
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// Move box B to the ending position
let action = SKAction.move(to: center, duration: 2)
boxB.run(action)
}
// Test direction of angle between line segments AB and AC
func isCounterClockwise (A:CGPoint, B:CGPoint, C:CGPoint) -> Bool {
return (C.y-A.y)*(B.x-A.x) > (B.y-A.y)*(C.x-A.x)
}
}
和一个视频剪辑...
如果方块 B 可以进入缝隙而不发生碰撞,则它变为绿色,否则变为红色。