最近做项目发现,一个模型的部分需要提示用户点击,但不知道做哪种效果。试验后发现呼吸活动光圈+点击放大效果不错。
逻辑很简单,就是在图像位置创建一个重复放大缩小的光圈,待用户点击图像时,将图像放大至120%并将光圈alpha=0,再次点击图像缩小时,将alpha恢复。
对应代码如下:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var label: SKLabelNode?
private var spinnyNode: SKShapeNode?
private var D: SKSpriteNode!
private var X: SKSpriteNode!
private var Y: SKSpriteNode!
private var enlargedNode: SKSpriteNode? // 记录当前放大的图像
private var glowNodes: [SKSpriteNode: SKShapeNode] = [:] // 记录每个图像的光圈效果
override func didMove(to view: SKView) {
self.backgroundColor = .gray // 设置背景色为灰色
D = self.childNode(withName: "D") as? SKSpriteNode
X = self.childNode(withName: "X") as? SKSpriteNode
Y = self.childNode(withName: "Y") as? SKSpriteNode
// 创建光圈动画
createGlowEffect(for: D)
createGlowEffect(for: X)
createGlowEffect(for: Y)
}
func createGlowEffect(for node: SKSpriteNode) {
// 创建一个圆,作为光圈效果
let glow = SKShapeNode(circleOfRadius: 50)
glow.strokeColor = .white
glow.fillColor = .clear
glow.lineWidth = 2
glow.alpha = 1
glow.position = node.position
glow.zPosition = 3 // 确保该层在图片上方
// 创建一个无限循环的动画
let pulseAction = SKAction.sequence([
SKAction.scale(to: 1.2, duration: 1.0),
SKAction.scale(to: 1.0, duration: 1.0)
])
let pulseLoop = SKAction.repeatForever(pulseAction)
glow.run(pulseLoop)
// 添加到场景
self.addChild(glow)
// 保存光圈效果与图像的关联
glowNodes[node] = glow
}
func hideGlowEffect(for node: SKSpriteNode) {
if let glow = glowNodes[node] {
glow.run(SKAction.fadeOut(withDuration: 0.2))
}
}
func showGlowEffect(for node: SKSpriteNode) {
if let glow = glowNodes[node] {
glow.run(SKAction.fadeIn(withDuration: 0.2))
}
}
func touchDown(atPoint pos: CGPoint) {
// 判断点击的位置和图像
let nodesAtTouch = [D, X, Y].compactMap { $0 }.filter { $0.contains(pos) }
if let clickedNode = nodesAtTouch.first {
// 如果已经有一个图像放大,则缩小它并恢复光圈提示效果
if let enlargedNode = enlargedNode {
enlargedNode.run(SKAction.scale(to: 1.0, duration: 0.2))
enlargedNode.zPosition = 1 // 恢复zPosition
showGlowEffect(for: enlargedNode) // 恢复效果
}
// 如果点击的是未放大的图像,则放大它并隐藏光圈提示效果
if clickedNode != enlargedNode {
clickedNode.run(SKAction.scale(to: 1.3, duration: 0.2))
clickedNode.zPosition = 4 // 放大时设置zPosition为4
enlargedNode = clickedNode // 更新当前放大的图像
// 隐藏放大图像的光圈提示效果
hideGlowEffect(for: clickedNode)
} else {
// 如果点击的是已经放大的图像,则缩小它并恢复光圈提示效果
clickedNode.run(SKAction.scale(to: 1.0, duration: 0.2))
clickedNode.zPosition = 1 // 恢复zPosition
enlargedNode = nil // 清空放大的图像记录
// 重新显示光圈提示效果
showGlowEffect(for: clickedNode)
}
} else {
// 如果点击了空白区域,则缩小当前放大的图像并恢复光圈提示效果
if let enlargedNode = enlargedNode {
enlargedNode.run(SKAction.scale(to: 1.0, duration: 0.2))
enlargedNode.zPosition = 1 // 恢复zPosition
self.enlargedNode = nil // 清空放大的图像记录
// 重新显示光圈提示效果
showGlowEffect(for: enlargedNode)
}
}
}
func touchUp(atPoint pos: CGPoint) {
// 不再需要缩小,放大与缩小在touchDown里处理
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let label = self.label {
label.run(SKAction.init(named: "Pulse")!, withKey: "fadeInOut")
}
for t in touches { self.touchDown(atPoint: t.location(in: self)) }
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// 触摸结束时不做任何操作
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
// 触摸取消时不做任何操作
}
func distance(from pointA: CGPoint, to pointB: CGPoint) -> CGFloat {
return hypot(pointA.x - pointB.x, pointA.y - pointB.y)
}
}
代码解释
-
场景初始化:在
didMove(to:)
方法中,我们首先设置了场景的背景色为灰色,然后通过childNode(withName:)
方法获取场景中的三个图像D
、X
和Y
。接着,调用createGlowEffect(for:)
方法为每个图像创建提示效果。 -
创建提示效果:
createGlowEffect(for:)
方法用于为指定的图像创建一个圆形的光圈,并为其添加一个无限循环的缩放动画,模拟提示效果。光圈的位置与图像的位置相同,并且通过zPosition
属性确保提示层在图像上方。最后,将光圈添加到场景中,并记录提示效果与图像的关联。 -
隐藏和显示提示效果:
hideGlowEffect(for:)
和showGlowEffect(for:)
方法分别用于隐藏和显示指定图像的提示效果。通过SKAction.fadeOut(withDuration:)
和SKAction.fadeIn(withDuration:)
方法实现渐变效果。 -
处理点击事件:
touchDown(atPoint:)
方法用于处理触摸事件。当玩家点击图像时,会判断点击的图像是否已经放大。如果已经放大,则缩小它并恢复提示效果;如果未放大,则放大它并隐藏提示效果。如果点击的是空白区域,则缩小当前放大的图像并恢复提示效果。 -
触摸事件处理:
touchesBegan(_:with:)
方法会在触摸开始时调用touchDown(atPoint:)
方法处理触摸事件。touchesEnded(_:with:)
和touchesCancelled(_:with:)
方法在触摸结束或取消时不做任何操作。