三连胜完结
This commit is contained in:
@@ -2324,7 +2324,11 @@ export default class SceneManager extends cc.Component {
|
||||
// this.node.addChild(reddemCodeNode);
|
||||
}
|
||||
update(dt) {
|
||||
|
||||
if (this.threeWinsPanel) {
|
||||
this.threeWinsPanel.refreshInventory(this.threeWinsData());
|
||||
const transition = this.node.getChildByName("zhuanchang");
|
||||
if (!transition || !transition.active) this.threeWinsPanel.playEntry();
|
||||
}
|
||||
}
|
||||
|
||||
public setPic(url, node) {
|
||||
|
||||
@@ -3,10 +3,14 @@ import { applyRocketCut } from "./RocketCut";
|
||||
import NumberToImage from "./NumberToImage";
|
||||
import { StartBoostLoadout, StartBoostProp, startBoostRewards } from "./StartBoostLoadout";
|
||||
|
||||
const ENTRY_SECONDS = 0.9;
|
||||
const ENTRY_SECONDS = 0.65;
|
||||
const ENTRY_HOLD_SECONDS = 0.3;
|
||||
const LAUNCH_CLOUD_SECONDS = 0.65;
|
||||
const HOURGLASS_SPEED = 1100;
|
||||
const ROCKET_SPEED = 700;
|
||||
const ROCKET_SPEED = 950;
|
||||
const ROCKET_ARC_HEIGHT = 480;
|
||||
// 复用炸弹的爆炸段,跳过火箭命中后不需要的引爆前摇。
|
||||
const ROCKET_IMPACT_START_SECONDS = 0.3333;
|
||||
const HOURGLASS_FLIGHT_SCALE = 0.7;
|
||||
|
||||
function flightPoint(from: cc.Vec2, control: cc.Vec2, to: cc.Vec2, t: number): cc.Vec2 {
|
||||
@@ -145,7 +149,7 @@ export default class StartBoostOpening {
|
||||
if (this.elapsed >= ENTRY_SECONDS + ENTRY_HOLD_SECONDS) this.beginFlights();
|
||||
return false;
|
||||
}
|
||||
this.updateLaunchCloud(Math.min(1, this.elapsed / 0.25), true);
|
||||
this.updateLaunchCloud(Math.min(1, this.elapsed / LAUNCH_CLOUD_SECONDS), true);
|
||||
this.updateTimeDisplay(dt);
|
||||
for (const flight of this.flights) {
|
||||
if (flight.landed) {
|
||||
@@ -178,7 +182,7 @@ export default class StartBoostOpening {
|
||||
node.convertToWorldSpaceAR(cc.v2(0, rocket ? -node.height : 0))));
|
||||
if (t === 1) this.land(flight);
|
||||
}
|
||||
return this.elapsed >= 0.25 && this.displayedTime === this.timeTarget &&
|
||||
return this.elapsed >= LAUNCH_CLOUD_SECONDS && this.displayedTime === this.timeTarget &&
|
||||
this.carriedEntries.every(entry => this.elapsed + ENTRY_HOLD_SECONDS >= entry.trail.life + entry.trail.lifeVar) &&
|
||||
this.flights.every(flight => flight.landed && flight.impactElapsed >= flight.impactSeconds);
|
||||
}
|
||||
@@ -257,7 +261,7 @@ export default class StartBoostOpening {
|
||||
node.y + node.height * node.scaleY / 2 - 8);
|
||||
}
|
||||
const from = cc.v2(node.x, node.y);
|
||||
const control = shot ? cc.v2((from.x + to.x) / 2, Math.max(from.y, to.y) + 600)
|
||||
const control = shot ? cc.v2((from.x + to.x) / 2, Math.max(from.y, to.y) + ROCKET_ARC_HEIGHT)
|
||||
// 沙漏交替绕左、绕右,后续沙漏使用更宽、不同高度的弧线,最后汇入时钟。
|
||||
: cc.v2((from.x + to.x) / 2 + (i % 2 === 0 ? -1 : 1) * (240 + Math.floor(i / 2) * 180),
|
||||
from.y + (to.y - from.y) * (0.4 + i * 0.12));
|
||||
@@ -280,7 +284,7 @@ export default class StartBoostOpening {
|
||||
rocketDistances.set(shot.origin, distances[distances.length - 1]);
|
||||
}
|
||||
this.flights.push({ node, shot, to, from, control, distances, trail, timeText,
|
||||
landed: false, impact: null, impactElapsed: 0, impactSeconds: 0.8 });
|
||||
landed: false, impact: null, impactElapsed: 0, impactSeconds: trail.life + trail.lifeVar });
|
||||
if (this.carriedEntries.some(entry => entry.node === node)) this.onUseCarried(shot ? "rocket" : "hourglass");
|
||||
}
|
||||
}
|
||||
@@ -304,7 +308,8 @@ export default class StartBoostOpening {
|
||||
this.root.addChild(flight.impact);
|
||||
flight.impact.setPosition(flight.to);
|
||||
const track = skeleton.setAnimation(0, "eff", false);
|
||||
flight.impactSeconds = Math.max(0.8, track.animation.duration);
|
||||
track.trackTime = Math.min(ROCKET_IMPACT_START_SECONDS, track.animation.duration);
|
||||
flight.impactSeconds = Math.max(flight.impactSeconds, track.animation.duration - track.trackTime);
|
||||
const shot = flight.shot;
|
||||
const id = this.map.mapBlocksWall[shot.x][shot.y].getComponent("MapBlock").block_Id;
|
||||
const block = this.map.blocks.find(node => node.uuid === id).getComponent("Block");
|
||||
@@ -327,10 +332,10 @@ export default class StartBoostOpening {
|
||||
const size = 64, pixels = new Uint8Array(size * size * 4);
|
||||
for (let y = 0; y < size; y++) for (let x = 0; x < size; x++) {
|
||||
const radius = Math.hypot(x + 0.5 - size / 2, y + 0.5 - size / 2) / (size / 2);
|
||||
const edge = Math.min(1, Math.max(0, (1 - radius) / 0.3));
|
||||
const softness = Math.max(0, 1 - radius * radius);
|
||||
const offset = (y * size + x) * 4;
|
||||
pixels[offset] = pixels[offset + 1] = pixels[offset + 2] = 255;
|
||||
pixels[offset + 3] = Math.round(255 * edge * edge * (3 - 2 * edge));
|
||||
pixels[offset + 3] = Math.round(160 * softness * softness);
|
||||
}
|
||||
this.cloudTexture = new cc.Texture2D();
|
||||
this.cloudTexture.initWithData(pixels, cc.Texture2D.PixelFormat.RGBA8888, size, size);
|
||||
@@ -356,13 +361,19 @@ export default class StartBoostOpening {
|
||||
}
|
||||
this.launchCloud.active = !(dispersing && progress === 1);
|
||||
if (!this.launchCloud.active) return;
|
||||
this.launchCloud.opacity = Math.round(255 * (dispersing ? 1 - progress : Math.min(1, progress * 2)));
|
||||
this.launchCloud.opacity = Math.round(255 * (dispersing ? 1 : Math.min(1, progress * 2)));
|
||||
this.launchCloud.children.forEach(cloud => cloud.children.forEach((puff, i) => {
|
||||
const radius = i === 0 ? 0 : i <= 6 ? 55 : 110;
|
||||
const layer = i === 0 ? 0 : i <= 6 ? 1 : 2;
|
||||
const radius = layer * 55;
|
||||
const angle = i <= 6 ? (i - 1) * Math.PI / 3 : (i - 7) * Math.PI / 6;
|
||||
const spread = dispersing ? 1 + progress * 0.15 : 0.6 + progress * 0.4;
|
||||
// 外层先散,内层稍后散;同层也略微错开,避免整团一起消失。
|
||||
const delay = (2 - layer) * 0.1 + i % 3 * 0.025;
|
||||
const phase = dispersing ? Math.min(1, Math.max(0, (progress - delay) / (0.8 - layer * 0.1))) : 0;
|
||||
const fade = phase * phase * (3 - 2 * phase);
|
||||
puff.opacity = Math.round((155 - layer * 20 - i % 3 * 9) * (1 - fade));
|
||||
const spread = dispersing ? 1 + fade * (0.07 + layer * 0.04) : 0.6 + progress * 0.4;
|
||||
puff.setPosition(Math.cos(angle) * radius * spread, Math.sin(angle) * radius * spread);
|
||||
puff.setScale((2.5 + i % 3 * 0.05) * (dispersing ? 1 + progress * 0.1 : 0.5 + progress * 0.5));
|
||||
puff.setScale((2.5 + i % 3 * 0.05) * (dispersing ? 1 + fade * 0.1 : 0.5 + progress * 0.5));
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@ export default class ThreeWinStreak {
|
||||
|
||||
/** 无参数先恢复本地;登录后传服务器数据,旧账号缺失字段从零开始。 */
|
||||
static restore(serverData?: { threeWinStreak?: number }, forced = false) {
|
||||
if (cc.fx.GameConfig.forceThreeWinStreak) {
|
||||
cc.fx.GameConfig.GM_INFO.threeWinStreak = 3;
|
||||
return;
|
||||
}
|
||||
const storage = cc.fx.StorageMessage;
|
||||
if (serverData && forced) {
|
||||
storage.setStorage("threeWinStreakPending", false);
|
||||
@@ -37,6 +41,7 @@ export default class ThreeWinStreak {
|
||||
begin() {
|
||||
if (!this.enabled || this.started || this.settled) return;
|
||||
this.started = true;
|
||||
if (cc.fx.GameConfig.forceThreeWinStreak) return;
|
||||
cc.fx.StorageMessage.setStorage("threeWinStreakPending", true);
|
||||
}
|
||||
|
||||
@@ -52,6 +57,10 @@ export default class ThreeWinStreak {
|
||||
|
||||
private finish(value: number) {
|
||||
this.settled = true;
|
||||
if (cc.fx.GameConfig.forceThreeWinStreak) {
|
||||
cc.fx.GameConfig.GM_INFO.threeWinStreak = 3;
|
||||
return;
|
||||
}
|
||||
const count = ThreeWinStreak.count(value);
|
||||
const storage = cc.fx.StorageMessage;
|
||||
cc.fx.GameConfig.GM_INFO.threeWinStreak = count;
|
||||
|
||||
@@ -32,6 +32,7 @@ export default class ThreeWinsPanel extends cc.Component {
|
||||
private callbacks: ThreeWinsPanelCallbacks = null;
|
||||
private selected: ThreeWinsSelection = { hourglass: false, rocket: false };
|
||||
private bound = false;
|
||||
private entryScale: cc.Vec2 = null;
|
||||
|
||||
init(atlas: cc.SpriteAtlas, data: ThreeWinsPanelData, callbacks: ThreeWinsPanelCallbacks) {
|
||||
this.atlas = atlas;
|
||||
@@ -44,6 +45,19 @@ export default class ThreeWinsPanel extends cc.Component {
|
||||
this.bound = true;
|
||||
}
|
||||
this.refresh(data);
|
||||
this.entryScale = cc.v2(this.node.scaleX, this.node.scaleY);
|
||||
this.node.setScale(0);
|
||||
}
|
||||
|
||||
playEntry() {
|
||||
if (!this.entryScale) return;
|
||||
const scale = this.entryScale;
|
||||
this.entryScale = null;
|
||||
cc.tween(this.node)
|
||||
.to(0.28, { scaleX: scale.x * 1.06, scaleY: scale.y * 1.06 }, { easing: "cubicOut" })
|
||||
.to(0.10, { scaleX: scale.x * 0.97, scaleY: scale.y * 0.97 }, { easing: "sineInOut" })
|
||||
.to(0.12, { scaleX: scale.x, scaleY: scale.y }, { easing: "sineOut" })
|
||||
.start();
|
||||
}
|
||||
|
||||
refresh(data: ThreeWinsPanelData) {
|
||||
@@ -64,6 +78,17 @@ export default class ThreeWinsPanel extends cc.Component {
|
||||
this.renderProp("rocket");
|
||||
}
|
||||
|
||||
refreshInventory(data: ThreeWinsPanelData) {
|
||||
const previous = this.data;
|
||||
this.data = data;
|
||||
if (!previous || previous.hourglassAmount !== data.hourglassAmount || previous.infiniteHourglass !== data.infiniteHourglass) {
|
||||
this.renderProp("hourglass");
|
||||
}
|
||||
if (!previous || previous.rocketAmount !== data.rocketAmount || previous.infiniteRocket !== data.infiniteRocket) {
|
||||
this.renderProp("rocket");
|
||||
}
|
||||
}
|
||||
|
||||
setSelected(prop: ThreeWinsProp, selected: boolean) {
|
||||
this.selected[prop] = selected;
|
||||
this.renderProp(prop);
|
||||
@@ -83,29 +108,24 @@ export default class ThreeWinsPanel extends cc.Component {
|
||||
|
||||
private renderProp(prop: ThreeWinsProp) {
|
||||
const node = this.node.getChildByName(prop);
|
||||
const selected = this.selected[prop];
|
||||
node.getChildByName("add").active = !selected;
|
||||
node.getChildByName("select").active = selected;
|
||||
|
||||
let amount = node.getChildByName("amount");
|
||||
if (!amount) {
|
||||
amount = new cc.Node("amount");
|
||||
amount.parent = node;
|
||||
amount.y = -140;
|
||||
}
|
||||
const count = prop === "hourglass" ? this.data.hourglassAmount : this.data.rocketAmount;
|
||||
const infinite = prop === "hourglass" ? this.data.infiniteHourglass : this.data.infiniteRocket;
|
||||
if (!selected && infinite) {
|
||||
const available = count > 0 || !!infinite;
|
||||
if (!available) this.selected[prop] = false;
|
||||
const selected = this.selected[prop];
|
||||
node.getChildByName("add").active = !available;
|
||||
node.getChildByName("select").active = selected;
|
||||
const remaining = node.getChildByName("remaining");
|
||||
remaining.active = available && !selected;
|
||||
|
||||
const amount = remaining.getChildByName("number");
|
||||
if (infinite) {
|
||||
this.clearNumber(amount);
|
||||
this.addCountSymbol(amount, "∞", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const count = selected ? 1 : prop === "hourglass" ? this.data.hourglassAmount : this.data.rocketAmount;
|
||||
this.renderNumber(amount, count, "prop_", 30);
|
||||
if (selected) {
|
||||
for (const digit of amount.children) digit.x += 13;
|
||||
this.addCountSymbol(amount, "+", -17);
|
||||
}
|
||||
}
|
||||
|
||||
private renderNumber(target: cc.Node, value: number, prefix: string, spacing: number, right = false) {
|
||||
|
||||
@@ -444,6 +444,9 @@ export class GameConfig {
|
||||
// 临时老彩虹测试开关(默认关闭):开启后强制 C、立即解锁连胜、始终十连胜。
|
||||
static forceOldRainbowWinStreakC = false;
|
||||
|
||||
// 临时测试:本地始终保持三连胜,不写入真实存档;false 恢复正常规则。
|
||||
static forceThreeWinStreak = false;
|
||||
|
||||
static isStartBoostersUnlocked(): boolean {
|
||||
return this.GM_INFO.level + 1 >= 25 && !(this.GM_INFO.otherLevel > 0);
|
||||
}
|
||||
@@ -826,7 +829,7 @@ export class GameConfig {
|
||||
popPassCheck: false, // 弹窗通行证
|
||||
passCheckActivate: false,
|
||||
winStreak: (this.forceOldRainbowWinStreakC || this.forceRainbowWinStreakB) ? 10 : 0, //测试模式默认十连胜
|
||||
threeWinStreak: 0,
|
||||
threeWinStreak: this.forceThreeWinStreak ? 3 : 0,
|
||||
tasks: { levelPass: { value: 0, target: 0, state: 0 }, share: { value: 0, target: 0, state: 0 }, useEnergy: { value: 0, target: 0, state: 0 }, useProp: { value: 0, target: 0, state: 0 } },
|
||||
addLevel: 0, //每日过关数
|
||||
address: "", //用户城市信息
|
||||
|
||||
Reference in New Issue
Block a user