SLG - 动效按钮

场景封装

现在的项目规划可比之前要干净清晰多了,这次为了实现按钮的动画效果,使用的办法是将 Button 和 Label 这两个节点封装为一个名为AnimatedButton.tscn的节点,然后在其他场景直接挂在节点即可,封装后的按钮会自动调用已经写好的脚本,无需再另行编写代码。具体架构如下:

assets
├── Label
├── LLabel(对应左括号)
└── RLabel(对应右括号)

动效代码

我就不大费周章去介绍设计思路了,直接看代码就是,现在写多了感觉代码也就那样,没什么好讲的。

在写的时候比较棘手的问题是关于两个括号的定位,当时实际运行时右括号总是要比左括号距离中心的位置远,后面研究了一下,问题有两个:一个是节点缩放后尺寸会大于容器,此时如果再使用 容器- 尺寸 的方法,相减之后会为负数;另一个是括号本身也有尺寸,右括号的距离应该加上两个括号的尺寸。

@tool
extends Button

@export var zoom := 1.2     ## 缩放比例
@export var duration := 0.1 ## 持续时间
@export var captions := "": ## 标题文本
  set(v): 
    captions = v
    if lbl: 
      lbl.text = v
      _update_layout()
@export var brackets := "[]": ## 括号符号
  set(v): 
    if v.length() > 1: 
      brackets = v
      if brkts.size() >= 2: 
        for i in 2: brkts[i].text = v[i]
        _update_layout()

@onready var lbl = $Label
@onready var brkts = [$LeftBracket, $RightBracket]
@onready var sfx = $AudioStreamPlayer
@onready var sound_select = preload("res://Assets/sounds/sfx/select.mp3")
@onready var sound_click = preload("res://Assets/sounds/sfx/click.mp3")

func _ready():
  lbl.set("horizontal_alignment", HORIZONTAL_ALIGNMENT_CENTER)
  lbl.set("vertical_alignment", VERTICAL_ALIGNMENT_CENTER)
  lbl.modulate = Color("#cccccc")
  
  for b in brkts: b.modulate.a = 0
  _set_props()

func _set_props():
  self.captions = captions
  self.brackets = brackets
  lbl.resized.connect(_update_layout)
  resized.connect(_update_layout)
  
  mouse_entered.connect(func(): 
    _hover(true)
    _play(sound_select)
  )
  mouse_exited.connect(func(): _hover(false))
  pressed.connect(func(): _play(sound_click))

func _update_layout():
  var txt_size = lbl.get_rect().size
  lbl.position = (size - txt_size) * 0.5
  lbl.pivot_offset = txt_size * 0.5

func _hover(hover: bool):
  var t = create_tween().set_parallel(true).set_trans(Tween.TRANS_QUAD)
  var pos = Vector2(size.x * 0.5, lbl.position.y)
  var bw = brkts[0].get_rect().size.x * int(hover)
  var targets = [Vector2(0, pos.y), Vector2(size.x - bw, pos.y)] if hover else [pos, pos]
  
  t.tween_property(lbl, "modulate", Color.WHITE if hover else Color("#cccccc"), duration)
  t.tween_property(lbl, "scale", Vector2.ONE * (zoom if hover else 1.0), duration)
  
  for i in 2:
    brkts[i].horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER if hover else 0
    t.tween_property(brkts[i], "position", targets[i], duration).set_ease(Tween.EASE_OUT if hover else Tween.EASE_IN)
    t.tween_property(brkts[i], "modulate:a", int(hover), duration * 0.6)

func _play(effect):
  sfx.stream = effect
  sfx.play()
本文作者:晝行燈

版权声明:本文采用 CC BY-NC 4.0 协议授权

转载需注明作者及原文链接: https://mansifield.pages.dev/kr2byg/