175 lines
6.2 KiB
TypeScript
175 lines
6.2 KiB
TypeScript
/** 只负责领取反馈、轨道移动和新卡出现动画。 */
|
|
export default class JungleAnimator {
|
|
constructor(
|
|
private host: cc.Component,
|
|
private contentNode: cc.Node,
|
|
private cardFrame: cc.SpriteFrame,
|
|
) { }
|
|
|
|
public playClaimEffect(card: cc.Node, onComplete: () => void): void {
|
|
const button = card.getChildByName("button");
|
|
const buttonLabelNode = button && button.getChildByName("button_label");
|
|
const lock = button && button.getChildByName("lock");
|
|
if (button) {
|
|
button.getComponent(cc.Button).interactable = false;
|
|
cc.tween(button)
|
|
.to(0.08, { scale: 1.08 }, { easing: "quadOut" })
|
|
.to(0.1, { scale: 1 })
|
|
.start();
|
|
}
|
|
if (buttonLabelNode) {
|
|
buttonLabelNode.opacity = 0;
|
|
}
|
|
if (lock) {
|
|
lock.active = false;
|
|
}
|
|
|
|
const flash = this.createSpriteNode("claim_flash", this.cardFrame);
|
|
flash.parent = card;
|
|
flash.zIndex = 8;
|
|
flash.color = cc.color(255, 244, 160);
|
|
flash.opacity = 0;
|
|
cc.tween(flash)
|
|
.to(0.1, { opacity: 150 })
|
|
.to(0.18, { opacity: 0 })
|
|
.call(() => flash.destroy())
|
|
.start();
|
|
|
|
const check = new cc.Node("claim_check");
|
|
check.parent = button;
|
|
check.zIndex = 20;
|
|
check.setContentSize(84, 84);
|
|
check.scale = 0;
|
|
const checkGraphics = check.addComponent(cc.Graphics);
|
|
checkGraphics.fillColor = cc.color(93, 205, 52, 255);
|
|
checkGraphics.strokeColor = cc.color(255, 255, 255, 255);
|
|
checkGraphics.lineWidth = 7;
|
|
checkGraphics.circle(0, 0, 35);
|
|
checkGraphics.fill();
|
|
checkGraphics.stroke();
|
|
checkGraphics.lineWidth = 9;
|
|
checkGraphics.moveTo(-19, 1);
|
|
checkGraphics.lineTo(-5, -14);
|
|
checkGraphics.lineTo(23, 18);
|
|
checkGraphics.stroke();
|
|
cc.tween(check)
|
|
.to(0.16, { scale: 1.15 }, { easing: "backOut" })
|
|
.to(0.08, { scale: 1 })
|
|
.delay(0.18)
|
|
.to(0.1, { opacity: 0 })
|
|
.call(() => check.destroy())
|
|
.start();
|
|
|
|
const rewardsNode = card.getChildByName("rewards");
|
|
const rewardGroups = rewardsNode ? rewardsNode.children.slice() : [];
|
|
rewardGroups.forEach((group, index) => {
|
|
const flyNode = cc.instantiate(group);
|
|
const worldPosition = group.convertToWorldSpaceAR(cc.Vec2.ZERO);
|
|
flyNode.parent = this.contentNode;
|
|
flyNode.setPosition(this.contentNode.convertToNodeSpaceAR(worldPosition));
|
|
flyNode.zIndex = 30;
|
|
const horizontalOffset = (index - (rewardGroups.length - 1) * 0.5) * 42;
|
|
cc.tween(flyNode)
|
|
.delay(index * 0.035)
|
|
.parallel(
|
|
cc.tween().by(0.42, { x: horizontalOffset, y: 190 + index % 2 * 24 }, { easing: "quadOut" }),
|
|
cc.tween().to(0.42, { opacity: 0, scale: 1.12 }),
|
|
)
|
|
.call(() => flyNode.destroy())
|
|
.start();
|
|
});
|
|
|
|
this.host.scheduleOnce(onComplete, 0.5);
|
|
}
|
|
|
|
public playCardExit(card: cc.Node, onComplete: () => void): void {
|
|
cc.tween(card)
|
|
.parallel(
|
|
cc.tween().to(0.2, { scale: 0.78, opacity: 0 }),
|
|
cc.tween().by(0.2, { y: 55 }),
|
|
)
|
|
.call(onComplete)
|
|
.start();
|
|
}
|
|
|
|
public moveCardsWithOverlap(
|
|
cards: cc.Node[],
|
|
slotPositions: cc.Vec2[],
|
|
cardIndex: number,
|
|
onNewCardReady: () => void,
|
|
): void {
|
|
if (cardIndex >= cards.length) {
|
|
onNewCardReady();
|
|
return;
|
|
}
|
|
|
|
const movingCard = cards[cardIndex];
|
|
if (!movingCard.active) {
|
|
this.moveCardsWithOverlap(cards, slotPositions, cardIndex + 1, onNewCardReady);
|
|
return;
|
|
}
|
|
|
|
let nextCardIndex = cardIndex + 1;
|
|
while (nextCardIndex < cards.length && !cards[nextCardIndex].active) {
|
|
nextCardIndex++;
|
|
}
|
|
|
|
const targetPosition = slotPositions[cardIndex - 1];
|
|
const startPosition = cc.v2(movingCard.x, movingCard.y);
|
|
const brakePosition = startPosition.lerp(targetPosition, 0.75);
|
|
cc.tween(movingCard)
|
|
.to(0.13, { x: brakePosition.x, y: brakePosition.y }, { easing: "linear" })
|
|
.call(() => {
|
|
if (nextCardIndex < cards.length) {
|
|
this.moveCardsWithOverlap(cards, slotPositions, nextCardIndex, onNewCardReady);
|
|
} else {
|
|
onNewCardReady();
|
|
}
|
|
})
|
|
.to(0.5, { x: targetPosition.x, y: targetPosition.y }, { easing: "cubicOut" })
|
|
.start();
|
|
}
|
|
|
|
public showNewCard(card: cc.Node, targetCenter: cc.Vec2, onComplete: () => void): void {
|
|
card.setAnchorPoint(0.5, 0.5);
|
|
card.scale = 0.06;
|
|
card.setPosition(targetCenter);
|
|
card.opacity = 0;
|
|
card.active = true;
|
|
|
|
cc.tween(card)
|
|
.parallel(
|
|
cc.tween().to(0.2, { opacity: 255 }, { easing: "sineOut" }),
|
|
cc.tween()
|
|
.to(0.28, { scale: 1.07 }, { easing: "cubicOut" })
|
|
.to(0.1, { scale: 0.97 }, { easing: "sineOut" })
|
|
.to(0.09, { scale: 1.02 }, { easing: "sineOut" })
|
|
.to(0.08, { scale: 1 }, { easing: "sineOut" }),
|
|
)
|
|
.call(onComplete)
|
|
.start();
|
|
}
|
|
|
|
public playLockedFeedback(card: cc.Node): void {
|
|
card.stopAllActions();
|
|
const x = card.x;
|
|
cc.tween(card)
|
|
.to(0.05, { x: x - 9 })
|
|
.to(0.05, { x: x + 9 })
|
|
.to(0.05, { x: x - 5 })
|
|
.to(0.05, { x })
|
|
.start();
|
|
}
|
|
|
|
private createSpriteNode(name: string, frame: cc.SpriteFrame): cc.Node {
|
|
const node = new cc.Node(name);
|
|
const sprite = node.addComponent(cc.Sprite);
|
|
sprite.sizeMode = cc.Sprite.SizeMode.RAW;
|
|
sprite.spriteFrame = frame;
|
|
if (frame) {
|
|
node.setContentSize(frame.getOriginalSize());
|
|
}
|
|
return node;
|
|
}
|
|
}
|