Street Trick Pinball Game

pinball.gif

I am participating in the individual competition of the Nuggets Community Game Creativity Contest. For details, please see: Game Creativity Contest

foreword

I don't know if you have encountered this pinball game on the street. When you try it out, you can play it as soon as you play it. You can't play it as long as you pay for it. I remember that the first time I came into contact with this game, I was in junior high school. I saw this game on the street. My friends and I were deeply attracted by this game, so all our belongings were included. Happy to go home. At that time, the Internet was not yet developed, and I didn't know that this thing still had a mechanism. After understanding the principle , I feel that I am xxx. Next, we will use it SpriteKitto implement a pinball game without routines

Install

1. Use and install TestFlightthe same as the previous Airplane Wars game installation

testflight.apple.com/join/YCDnN4…

2. You can run the code to install, the demo address is here

game introduction

Pull the spring rod, so that the ball is subjected to different elastic forces to make it enter the grid. The gameplay is very simple, I won't say much, let's implement it below.

accomplish

1. The range (boundary) that the ball can move

IMG_1029.PNGWe can see that the range of activity of the ball is the red area, so how can we make the ball only in the red area? In fact, the SpriteKitsystem provides us with boundary-type physical bodies, including the following

// 在两点之间创建边
public /*not inherited*/ init(edgeFrom p1: CGPoint, to p2: CGPoint)

// 从路径创建边链
public /*not inherited*/ init(edgeChainFrom path: CGPath)

// 从路径创建循环边
public /*not inherited*/ init(edgeLoopFrom path: CGPath)

// 从矩形创建循环边
public /*not inherited*/ init(edgeLoopFrom rect: CGRect)
复制代码

We use the initialization method of creating edge loops from paths to physicsBodycreate a boundary for the current scene, here we use Bezier curves to draw the path

private func setupPhysicsBody() {
    let path = UIBezierPath()
    path.lineWidth = 2
    path.move(to: CGPoint(x: 0, y: size.height-size.width-topOffset))
    path.addLine(to: CGPoint(x: 0, y: size.height-size.width/2-topOffset))
    path.addArc(withCenter: CGPoint(x: size.width/2, y: size.height-size.width/2-topOffset), radius: size.width/2, startAngle: -.pi, endAngle: 0, clockwise: false)
    path.addLine(to: CGPoint(x: size.width, y: size.height-size.width/2-topOffset))
    path.addLine(to: CGPoint(x: size.width, y: size.height-size.width-topOffset))
    path.close()
    physicsBody = SKPhysicsBody(edgeLoopFrom: path.cgPath)
}
复制代码
2. Pull the spring to make the ball pop out

2.1. First, we touchesBeganjudge whether the touch is a spring in the method, if so, record the starting point of the touch, and set the gravitational acceleration of the current physical world to (0,0)

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    isTouch = false
    offsetY = 0
    physicsWorld.gravity = .zero
    guard let touch = (touches as NSSet).anyObject() as? UITouch else { return }
    let point = touch.location(in: self)
    let node = atPoint(point)
    switch node.name {
    case "back":
        view?.presentScene(MenuScene(size: size), transition: .fade(withDuration: 0.5))
    case "tanhuang" where reward >= 50:
        isTouch = true
        startTouchPoint = point
    default:
        break
    }
}
复制代码

2.2. touchesMovedCalculate the offset of the finger movement in the method

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    guard let touch = (touches as NSSet).anyObject() as? UITouch else { return }
    let point = touch.location(in: self)
    if isTouch {
        offsetY = point.y-startTouchPoint.y
        if offsetY >= -80, offsetY <= 0 {
            springNode.size = CGSize(width: 28, height: 120+offsetY)
            ballNode.position = CGPoint(x: gridWidth * 8.5+3.5, y: size.height-size.width+74-topOffset+offsetY/2)
        }
    }
}
复制代码

touchesEnded2.3. Calculate the required pulling force of the ball according to the offset in the method of releasing the spring , and set a gravitational acceleration for the current physical world. The default is (0,-9.8), here we change it to (0,- 3.5)

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    if isTouch {
        springNode.size = CGSize(width: 28, height: 120)
        physicsWorld.gravity = CGVector(dx: 0, dy: -3.5)
        let dy = 300 * -(offsetY/2) * 0.1
        // 给小球添加一个向上的拉力
        ballNode.physicsBody?.applyForce(CGVector(dx: 0, dy: dy))
        offsetY = 0
        view?.isUserInteractionEnabled = false
        reward -= 50
    }
}
复制代码
3. Detect the drop area of ​​the ball

Screenshot 2022-04-13 14.42.59.pngThere are 9 areas where the ball finally falls, which are the area where the 8 ores are located and the area where the spring is located. Here we use the proxy didBeginside to detect the drop area of ​​the ball

extension PinballScene: SKPhysicsContactDelegate {

    func didBegin(_ contact: SKPhysicsContact) {
        // 弹簧所在的区域
        let springArea = CGRect(x: CGFloat(8)*gridWidth, y: size.height-size.width-topOffset, width: gridWidth, height: 28)
        if springArea.contains(ballN ode.position) {
            view?.isUserInteractionEnabled = true
            return
        }
        if let v = view, v.isUserInteractionEnabled {
            return
        }
        for model in rewards {
            if model.rewardArea.contains(ballNode.position) {
                reward += model.reward
                view?.isUserInteractionEnabled = true
            }
        }
    }
}
复制代码

At this point, the realization of this game is over

my other games

SpriteKit's Plane Wars

Guess you like

Origin juejin.im/post/7085979787340021791