基本上,当我的球员按下按钮跳跃时,会向球施加一种冲动使其跳跃。问题是当玩家在半空中使用操纵杆向左或向右移动时,球不会自然落到地面,而是需要一段时间才能落地。我希望有人能够帮助我稍微调整一下物理特性,使球仍然像在地面上一样表现,但也让它在跳跃后正常下落,而没有所有这些悬挂时间。
import UIKit
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
private var ball: SKShapeNode!
private var floor = SKSpriteNode()
private var wall = SKSpriteNode()
private var ceiling = SKSpriteNode()
private var wall2 = SKSpriteNode()
private var joystickHandleDefaultPosition: CGPoint!
let ballCategory:UInt32 = 0x1 << 0
let floorCategory:UInt32 = 0x1 << 2
let wallCategory:UInt32 = 0x1 << 3
var canJump = true
var canDash = false
var facing = "right"
var joystickLocation = CGPoint()
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
setupBall()
setupJoystick()
setupJumpButton()
addFloor()
ball = SKShapeNode(circleOfRadius: 20)
ball.position = CGPoint(x: frame.midX, y: frame.midY)
ball.fillColor = SKColor.red
ball.physicsBody = SKPhysicsBody(circleOfRadius: 22)
ball.physicsBody?.affectedByGravity = true
ball.physicsBody?.allowsRotation = false
ball.physicsBody?.restitution = 0.0
ball.physicsBody?.friction = 1.0
ball.physicsBody?.categoryBitMask = ballCategory
ball.physicsBody?.contactTestBitMask = floorCategory | wallCategory
ball.physicsBody?.collisionBitMask = floorCategory | wallCategory
addChild(ball)
let distance = (frame.maxX - 80) - (frame.minX + 80)
let floorWidth = distance // to cover the width of both walls
floor = SKSpriteNode(color: .white, size: CGSize(width: floorWidth, height: 20))
floor.position = CGPoint(x: frame.midX, y: -140)
floor.physicsBody = SKPhysicsBody(rectangleOf: floor.size)
floor.physicsBody?.isDynamic = false
floor.physicsBody?.categoryBitMask = floorCategory
floor.physicsBody?.friction = 1.0
floor.physicsBody?.restitution = 0.0
floor.physicsBody?.affectedByGravity = false
floor.physicsBody?.contactTestBitMask = ballCategory
floor.physicsBody?.collisionBitMask = ballCategory
addChild(floor)
print(floor.physicsBody?.node?.position as Any)
print(floor.physicsBody?.node?.frame.size as Any)
wall = SKSpriteNode(color: .white, size: CGSize(width: 20, height: 600))
wall.position = CGPoint(x: frame.maxX - 80 - (wall.size.width / 2), y: floor.position.y + (floor.size.height / 2) + (wall.size.height / 2))
wall.physicsBody = SKPhysicsBody(rectangleOf: wall.size)
wall.physicsBody?.isDynamic = false
wall.physicsBody?.categoryBitMask = wallCategory
wall.physicsBody?.friction = 1.0
wall.physicsBody?.restitution = 0.0
wall.physicsBody?.affectedByGravity = false
wall.physicsBody?.contactTestBitMask = ballCategory
wall.physicsBody?.collisionBitMask = ballCategory
addChild(wall)
wall2 = SKSpriteNode(color: .white, size: CGSize(width: 20, height: 600))
wall2.position = CGPoint(x: frame.minX + 80 + (wall2.size.width / 2), y: floor.position.y + (floor.size.height / 2) + (wall2.size.height / 2))
wall2.physicsBody = SKPhysicsBody(rectangleOf: wall2.size)
wall2.physicsBody?.isDynamic = false
wall2.physicsBody?.categoryBitMask = wallCategory
wall2.physicsBody?.friction = 1.0
wall2.physicsBody?.restitution = 0.0
wall2.physicsBody?.affectedByGravity = false
wall2.physicsBody?.contactTestBitMask = ballCategory
wall2.physicsBody?.collisionBitMask = ballCategory
addChild(wall2)
ceiling = SKSpriteNode(color: .white, size: CGSize(width: floorWidth, height: 20))
ceiling.position = CGPoint(x: frame.midX, y: wall.position.y + (wall.size.height / 2) + (ceiling.size.height / 2))
ceiling.physicsBody = SKPhysicsBody(rectangleOf: ceiling.size)
ceiling.physicsBody?.isDynamic = false
ceiling.physicsBody?.categoryBitMask = wallCategory
ceiling.physicsBody?.contactTestBitMask = ballCategory
addChild(ceiling)
physicsWorld.gravity = CGVector(dx: 0, dy: -9.8) // set the gravity vector
let origin = CGPoint(x: 0, y: 0)
// let frameyWidth: CGFloat = 200
// let frameyHeight: CGFloat = 300
// let framey = CGRect(x: 0, y: size.height - frameyHeight, width: frameyWidth, height: frameyHeight)
// physicsBody = SKPhysicsBody(edgeLoopFrom: framey) // add physics body to the scene's frame
}
private func setupBall() {
}
private func setupJoystick() {
let joystickBackground = SKShapeNode(circleOfRadius: 80)
joystickBackground.position = CGPoint(x: (frame.midX - 120), y: -350)
joystickBackground.strokeColor = SKColor.white
joystickBackground.lineWidth = 4.0
joystickBackground.name = "joystickBackground"
addChild(joystickBackground)
let joystickHandle = SKShapeNode(circleOfRadius: 50)
joystickHandle.position = CGPoint(x: (frame.midX - 120), y: -350)
joystickHandle.fillColor = SKColor.white
joystickHandle.strokeColor = SKColor.white
joystickHandle.lineWidth = 2.0
joystickHandle.name = "joystickHandle" // add name property
joystickHandleDefaultPosition = joystickHandle.position
addChild(joystickHandle)
}
private func setupJumpButton() {
let jumpButton = SKShapeNode(circleOfRadius: 60)
jumpButton.position = CGPoint(x: frame.midX + 160, y: -350)
jumpButton.fillColor = SKColor.green
jumpButton.name = "jumpButton" // add name property
addChild(jumpButton)
}
func addFloor() {
}
func activateDash(){
if facing == "right"{
let dashImpulse = CGVector(dx: 20, dy: 2)
ball.physicsBody?.applyImpulse(dashImpulse)
}else if facing == "left"{
let dashImpulse = CGVector(dx: -20, dy: 2)
ball.physicsBody?.applyImpulse(dashImpulse)
}
}
private func handleJumpButton() {
let jumpImpulse = CGVector(dx: 0, dy: 70.0) // adjust the impulse strength as needed
if canJump == true{
ball.physicsBody?.applyImpulse(jumpImpulse)
canJump = false
canDash = true
}else if canJump == false{
if canDash == true{
print("dash")
canDash = false
print(facing)
activateDash()
}
}
}
private func handleJoystick(_ location: CGPoint) {
let joystickPosition = CGPoint(x: (frame.midX - 120), y: -350)
let dx = location.x - joystickPosition.x
let dy = location.y - joystickPosition.y
let angle = atan2(dy, dx)
let length: CGFloat = 50.0
let xDist = length * cos(angle)
let yDist = length * sin(angle)
let joystickHandle = childNode(withName: "joystickHandle") as! SKShapeNode
joystickHandle.position = CGPoint(x: joystickPosition.x + xDist, y: joystickPosition.y + yDist)
let speed: CGFloat = 500.0
var velocity = CGVector(dx: 0, dy: 0)
if xDist >= 0 {
velocity.dx = speed
facing = "right"
} else {
velocity.dx = -speed
facing = "left"
}
ball.physicsBody?.velocity = velocity
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let joystickBackground = childNode(withName: "joystickBackground") as! SKShapeNode
let distance = location.distance(to: joystickBackground.position)
let angle = joystickBackground.position.angle(to: location)
let maxDistance: CGFloat = 50.0
if distance <= maxDistance {
handleJoystick(location)
} else {
let xDist = maxDistance * cos(angle)
let yDist = maxDistance * sin(angle)
let joystickHandle = childNode(withName: "joystickHandle") as! SKShapeNode
joystickHandle.position = CGPoint(x: joystickBackground.position.x + xDist, y: joystickBackground.position.y + yDist)
handleJoystick(joystickHandle.position)
}
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
let jumpButton = childNode(withName: "jumpButton")!
if jumpButton.contains(location) {
handleJumpButton()
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let joystickHandle = childNode(withName: "joystickHandle") as! SKShapeNode
let joystickPosition = CGPoint(x: (frame.midX - 120), y: -350)
// Snap the joystick handle back to its original position
let moveJoystickHandle = SKAction.move(to: joystickPosition, duration: 0.1)
joystickHandle.run(moveJoystickHandle)
}
func didBegin(_ contact: SKPhysicsContact) {
print("contact happened")
// print("didBeginContact entered for \(String(describing: contact.bodyA.node?.name)) and \(String(describing: contact.bodyB.node?.name))")
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case ballCategory | floorCategory:
print("ball and floor have contacted.")
let ballNode = contact.bodyA.categoryBitMask == ballCategory ? contact.bodyA.node : contact.bodyB.node
let floorNode = contact.bodyA.categoryBitMask == floorCategory ? contact.bodyA.node : contact.bodyB.node
canJump = true
default:
print ("default")
}
}
}
extension CGPoint {
func distance(to point: CGPoint) -> CGFloat {
return sqrt(pow(point.x - x, 2) + pow(point.y - y, 2))
}
func angle(to point: CGPoint) -> CGFloat {
return atan2(point.y - y, point.x - x)
}
}