はじめに
BF6のPortalを触っていて気づいたことやメモを書いていきます。
この記事を見た人にあらかじめ書いておきますがVer.1.1.3時点でPortalを真面目に触ることはおすすめしません。動作しない関数やバグっている関数が多々あり気づきづらいです。また情報が乏しく仕様なのかバグなのかも判明しない点も多いので注意です。
Memo
日本語はNG、コメントにもNG。”→”などASCII以外の利用不可
Godotのidはユニークに。被っていると処理がおかしくなります。(置くだけのオブジェクトであれば-1のままで可)
OnGameModeStarted()が呼ばれる前にOngoingGlobal()が先に呼ばれる
OngoingGlobal()は毎フレームではなく毎チック(おそらく60/sぐらい?)ただチックはの速度は一定ではなく、処理依存です。例えば1秒かかる処理があると次のチックは1秒飛びます。
AIのスポーンポイントとPlayerのスポーンポイントは意味が違うので注意。Playerはシンプルにフィールドに出現するポイント、湧くポイントです。対してAIのスポーンポイントは生成される位置です。出現するポイント、湧くポイントとは少し違うので注意。AIのスポーンポイントには設定項目などがあります。
乗り物のアイコンは常にマップ上に表示され、敵の乗り物のアイコンを消すことはできない。
デプロイ画面で乗り物を選択しスポーンすることはできない。スポーンした後に乗り込むことになる
ローカルホスト時にチームを切り替えるとUI、スコアボードが壊れます。通常のホストであれば壊れないようです。
分隊の指定、割り当てなどの関数がない…取得はできるが指定する方法は無い。なので自動で割り当てられるか、直接操作し分隊を移動するしかないみたい…
ログ
ログはconsole.logを利用する。
例:QuickJS: console.log: Custom Conquest0.0.1 Game Mode Started
const VERSION = [0, 0, 1];
export function OnGameModeStarted() {
console.log("Custom Conquest ", VERSION[0], ".", VERSION[1], ".", VERSION[2], " Game Mode Started");
}
ログは
C:\Users\user名\AppData\Local\Temp\Battlefieldâ„¢ 6\PortalLog.tx
に生成される(ローカルホスト限定)
for文
mod.〇〇型の場合のループのさせかた
const players = mod.AllPlayers();
const playerCount = mod.CountOf(players);
for (let i = 0; i < playerCount; i++) {
const player = mod.ValueInArray(players, i);
console.log("Player ObjId:", mod.GetObjId(player));
}
OnTimeLimitReached
OnTimeLimitReached()は最初に呼ばれるだけで正しく動作しません。
OnPlayerEarnedKillAssist
OnPlayerEarnedKillAssist()は呼ばれません。
SetCapturePointCapturingTime
SetCapturePointCapturingTime()
SetCapturePointNeutralizationTime()
はうまく動作していません。OnGameModeStarted()内で同時に呼んでもうまく設定されず、デフォルトに戻ることもあります。どちらか片方のみを利用する事が可能のようですがそのような設定状態にすることはかなり少ないケースだと思います。下記コードでおそらく設定できます。ただ100%信用できるわけではない気がしています。(たまに抜ける?)
const CP_IDS = [100, 200, 300, 400, 500]; // CapturePoint の ObjId
const CP_CAPTURINGTIME = 45;
// OnGameModeStarted()で設定するのはSetCapturePointCapturingTime()かSetCapturePointNeutralizationTime()どちらか一方のみ同チックで同時に呼ばない
export function OnGameModeStarted() {
for (const cpId of CP_IDS) {
const cp = mod.GetCapturePoint(cpId);
// 拠点を中立から完全に占領するまでの時間(秒数)。
mod.SetCapturePointCapturingTime(cp, CP_CAPTURINGTIME)
}
}
// CapturePointを占領した時呼ばれる
export function OnCapturePointCaptured(eventCapturePoint: mod.CapturePoint) {
mod.SetCapturePointNeutralizationTime(eventCapturePoint, CP_CAPTURINGTIME);
}
// CapturePointを失った時に呼ばれる
export function OnCapturePointLost(eventCapturePoint: mod.CapturePoint) {
mod.SetCapturePointCapturingTime(eventCapturePoint, CP_CAPTURINGTIME)
}
// 前回progress
const gPrevProg = [0, 0, 0, 0, 0];
// 前回がCapturing方向だったか(1=Capturing / 0=Neutralizing)
const gWasCapturing = [1, 1, 1, 1, 1];
// 初回かどうか(初回は切替判定しない)
const gHasPrev = [0, 0, 0, 0, 0];
// おそらくこれでも設定できていないバグが存在する?未検証
export function TickCapturePoint(cp: mod.CapturePoint): void {
const prog = mod.GetCaptureProgress(cp);
// 0 or 1 は監視しない(海外コード踏襲)
if (prog === 0 || prog === 1) return;
const cpId = mod.GetObjId(cp);
const idx = GetCpIndexById(cpId);
if (idx < 0) return; // 管理対象外CP
// 初回だけは比較せず記録だけ(誤爆防止)
if (gHasPrev[idx] === 0) {
gHasPrev[idx] = 1;
gPrevProg[idx] = prog;
gWasCapturing[idx] = 1; // 初期はCapturing扱いでOK(好みで0でも)
return;
}
const prevProg = gPrevProg[idx];
const wasCapturing = gWasCapturing[idx];
console.log(":" + cpId);
if (prog < prevProg) {
// Neutralizing方向(減ってる)
if (wasCapturing === 1) {
mod.SetCapturePointNeutralizationTime(cp, CP_CAPTURINGTIME);
}
gWasCapturing[idx] = 0;
} else if (prog > prevProg) {
// Capturing方向(増えてる)
if (wasCapturing === 0) {
mod.SetCapturePointCapturingTime(cp, CP_CAPTURINGTIME);
}
gWasCapturing[idx] = 1;
} else {
// progが変化してない(停止/拮抗など)
// ここは「何もしない」が一番安全
}
gPrevProg[idx] = prog;
}
AISetUnspawnOnDead
AISetUnspawnOnDead()は機能していません。AIは強制的に一定時間後にゲームから除外されます。
SetPlayerMovementSpeedMultiplier
Playerの足の早さが遅くなるというよりは定期的に止まる…的な認識のほうが正しい。足は遅くならないでゴムバンド現象がおきるだけだと思います。ローカルホストと通常ホストで挙動が違うと思うので要確認
SpawnPlayerFromSpawnPoint
おそらく動作しない。スポーンモードを変更してもうまく動作しない。
EnableAllInputRestrictions
EnableAllInputRestrictions()は生きている時以外はエラーを吐く
const isAlive = mod.GetSoldierState(p, mod.SoldierStateBool.IsAlive);
1秒毎に処理を行う
let lastTime = 0; // 前チック時間
export function OngoingGlobal() {
const now = mod.GetMatchTimeElapsed();
if (lastTime === 0) { lastTime = now; return; }
const deltaTime = now - lastTime;
lastTime = now;
}
let gOneTickAcc = 0;
const ONETICK = 1.0;
// 1秒毎に定期処理を行う
function updateOneSeconds(dt: number) {
gOneTickAcc += dt;
if (gOneTickAcc < ONETICK) return;
gOneTickAcc -= ONETICK;
console.log(" ");
console.log("1 Seconds");
}
ランダム(mod.RandomReal)
指定された最小値と最大値(両端を含む)の間の乱数を返します。
※注意点は両端を含むことです
// 指定された最小値と最大値(両端を含む)の間の乱数を返します。
mod.RandomReal(0, 5)
例
2.2068114280700684
2.095896005630493
1.5900754928588867
0.10180890560150146
4.31406307220459
4.872622489929199
4.579616546630859
0.6429934501647949
2.09346342086792
点滅
let blinkTimer = 0;
let blinkOn = true;
function OnGameTickblink(deltaTime: number) {
blinkTimer += deltaTime;
if (blinkTimer >= 0.5) { // 0.5秒ごとに反転
blinkTimer = 0;
blinkOn = !blinkOn;
}
const alpha = blinkOn ? 1.0 : 0.2;
mod.SetUIWidgetBgAlpha(mod.FindUIWidgetWithName("blinkUI"),alpha);
}
let blinkAngle = 0;
let alphaSmooth = 0.3;
function clamp(v: number, lo: number, hi: number): number {
if (v < lo) return lo;
if (v > hi) return hi;
return v;
}
function OnGameTickblink(deltaTime: number) {
const dt = clamp(deltaTime, 0.0, 0.05);
const speed = 6.283185307179586; // 2π rad/sec
blinkAngle += speed * dt;
const s = mod.SineFromRadians(blinkAngle);
const target = 0.3 + 0.7 * (s * 0.5 + 0.5);
alphaSmooth += (target - alphaSmooth) * 0.2;
mod.SetUIWidgetBgAlpha(mod.FindUIWidgetWithName("blinkUI"),alphaSmooth);
}



コメント