Как реализовать лучевое вещание внутри Spritekit - PullRequest
0 голосов
/ 13 июня 2019

Я хочу проверить, проходит ли лазерный луч (линия) сквозь объекты и в каких точках. В настоящее время я воссоздаю проект Asteroids от grapefrukt. Для более подробной информации вы посмотрите это видео (https://www.youtube.com/watch?v=MeJ76z2Ncyg&t=622s).

В SceneKit есть метод, называемый hitTestWithSegmentFromPoint .. но я хочу добиться эффекта только с помощью Spritekit.

enter image description here Редактировать 1: мне нужно знать положение черных кругов (точки пересечения). Астероид красного цвета, луч зеленый.

Редактировать 2: Я надеялся, что решение @ Knight0fDragon будет работать .. но это не так. Поскольку линия появляется через поле, она не определяет правильно первый контакт ... ни второй (при выходе из окна)

Белый круг - это точка контакта. Фиолетовые стрелки указывают, где должны быть точки контакта. Синий круг - это корабль:)

Я также сделал, когда столкновение обнаружено, чтобы сделать физические тела ящиков не динамическими (останавливая их движение)

enter image description here

Редактировать 3: Изображение ближе, чтобы увидеть, где физические тела используют showsPhysics

enter image description here

Редактировать 4: Как я делаю белый круг

let firstBody = contact.bodyA.categoryBitMask > contact.bodyB.categoryBitMask ? contact.bodyB : contact.bodyA
 let secondBody = contact.bodyA == firstBody ? contact.bodyB : contact.bodyA

if firstBody.categoryBitMask == UInt32(1){

    secondBody.isDynamic = false;

    // run only once 
    print(contact.contactPoint);
    createCircleDebug(x: contact.contactPoint.x, y: contact.contactPoint.y, radius: 5)

}


func createCircleDebug (x:CGFloat, y:CGFloat, radius:CGFloat){

    let shape = SKShapeNode.init(circleOfRadius: radius);
    shape.strokeColor = SKColor.white;
    shape.position = CGPoint(x: x, y: y);

    self.addChild(shape);

}

Редактировать 5: Относительный путь линии. Круг все еще выключен.

enter image description here

Редактировать 6: теперь линия представляет собой прямоугольник, использующий новый код для ее создания

enter image description here

Редактировать 7: Использование Spritenode вместо круга

enter image description here

Ответы [ 2 ]

0 голосов
/ 13 июня 2019

Обычно я делал бы то, что сказал Форд (это был ответ, который я собирался дать после того, как вы ответили на мой вопрос), но если вам нужно узнать точки пересечения, я бы создал SKNode с SKPhysicsBody(polygonFrom:) и использовал быcontactBegins, чтобы получить точку пересечения

func rayCast(start:CGPoint,end:CGPoint){

        let mid = CGPoint((end.x + start.x) / 2,(end.y + start.y) / 2)
        let relativeStart1 = CGPoint(start.x - mid.x - 1,start.y - mid.y)
        let relativeEnd1 = CGPoint(end.x - mid.x - 1,end.y - mid.y-1)
        let relativeStart2 = CGPoint(start.x - mid.x + 1,start.y - mid.y)
        let relativeEnd2 = CGPoint(end.x - mid.x + 1,end.y - mid.y)

        let node = SKNode()
        let linePath = UIBezierPath()
        linePath.move(to: relativeStart1)
        linePath.addLine(to: relativeEnd1)
        linePath.addLine(to: relativeEnd2)
        linePath.addLine(to: relativeStart2)
        linePath.closeSubPath()    
        if let physicsBody = SKPhysicsBody(polygonFrom:linePath.cgPath){
            physicsBody.categoryBitMask = 0x80000000  //whatever you want it to be
            physicsBody.contactBitMask = ~physicsBody.categoryBitMask //touch everything but the line
            physicsBody.collisionBitMask = 0
            physicsBody.affectedByGravity = false
            node.physicsBody = physicsBody
        }
        scene.addChild(node)
        node.position = mid
}



func didBegin(_ contact: SKPhysicsContact) {

    let firstBody = contact.bodyA.categeroyBitMask > contact.bodyB.categoryBitMask ? contact.bodyA : contact.bodyB
    let secondBody = contact.bodyA = firstBody ? contact.bodyB : contact.bodyA

    if firstBody.categoryBitMask == 0x80000000{
       //use contact at this point to check intersection points
       //https://developer.apple.com/documentation/spritekit/skphysicscontact
    }

}
0 голосов
/ 13 июня 2019

Документация Apple включает руководство по лучевой отливке с SKPhysics:

В поисках мира физических тел

Чтобы найти ближайшее физическое тело, в которое попадает луч, вы можете использовать body(alongRayStart:end:). Это метод для SKPhysicsWorld.

Существует также enumerateBodies(alongRayStart:end:using:), если вы хотите получить все тел, которые были поражены лучом и где они были поражены. Этот метод вызывает ваш блок для каждого физического тела, к которому прикасается луч, со следующими аргументами:

  • body: Физическое тело, которое пересек луч.
  • point: Точка в координатах сцены, где луч контактировал с физическим телом.
  • normal: Нормальный вектор для физического тела в точке контакта.
  • stop: указатель на логическую переменную. Ваш блок может установить значение true, чтобы завершить перечисление.
...