將改進混亂時鐘的網頁版
Re: 將改進混亂時鐘的網頁版
這個函式是否未有用到?檢查程式中還有哪些需要修改的地方。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將改進混亂時鐘的網頁版
開始遊戲時,時針也應該從-90度通過動畫轉到90度。
代码: 全选
沒問題!為了解決這兩個需求,我們需要修改**指針動畫的更新邏輯**(確保使用我們前面寫好的 `updateTransform` 來保留其他變形),以及**修改開始遊戲的方法**來加入動畫效果。
以下是需要修改的程式碼片段,請替換您類別中對應的方法:
### 1. 修正指針更新邏輯(保留其他 Transform)
將 `updatePointersRealtime` 與靜態的 `updatePointers` 修改為使用 `updateTransform`,這樣就能確保原有的 `translate` 或 `scale` 不會被覆蓋掉。
```javascript
// 實時改變時針與分針屬性(動畫用)
updatePointersRealtime(duration) {
const hourHand = this.doc.querySelector('#path900');
const minHand = this.doc.querySelector('#path1029');
// 如果沒有初始紀錄,時針預設為 -90,分針預設為 0
const startHour = this.currentHourRotation !== undefined ? this.currentHourRotation : -90;
const startMin = this.currentMinRotation !== undefined ? this.currentMinRotation : 0;
return this.animateAttribute(duration, (p) => {
const h = startHour + (this.hourRotation - startHour) * p;
const m = startMin + (this.minuteRotation - startMin) * p;
// 使用 updateTransform 僅修改 rotate,保留其他變形屬性
if (hourHand) this.updateTransform(hourHand, 'rotate', h);
if (minHand) this.updateTransform(minHand, 'rotate', m);
if (p === 1) {
this.currentHourRotation = this.hourRotation;
this.currentMinRotation = this.minuteRotation;
}
});
}
// 靜態改變時針與分針屬性(非動畫用)
updatePointers() {
const hourHand = this.doc.querySelector('#path900');
const minHand = this.doc.querySelector('#path1029');
if (hourHand) {
hourHand.setAttribute('transform-origin', '0 0');
this.updateTransform(hourHand, 'rotate', this.hourRotation);
}
if (minHand) {
minHand.setAttribute('transform-origin', '0 0');
this.updateTransform(minHand, 'rotate', this.minuteRotation);
}
// 同步紀錄當前角度,以供後續動畫計算起點
this.currentHourRotation = this.hourRotation;
this.currentMinRotation = this.minuteRotation;
}
```
### 2. 修改開始遊戲方法(加入動畫)
將 `startGame` 修改為異步函數(`async`),並在改變目標角度後呼叫 `updatePointersRealtime` 執行 1 秒的動畫。
```javascript
async startGame() {
this.state = 'playing';
this.turn = 1; // 乙方先手
this.initialPlayer = 1;
this.btnStart.style.display = 'none';
this.btnRandom.style.display = 'none';
this.setNormalMessage('遊戲開始,輪到乙方');
// 時針從 -90 轉到 90
this.hourRotation = 90;
// 確保遊戲開始時執行 1 秒的指針動畫
this.isAnimating = true;
await this.updatePointersRealtime(1000);
this.isAnimating = false;
}
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將改進混亂時鐘的網頁版
Unexpected value rotate(NaN) scale(1.2) translate(-6.17,-54.816) parsing transform attribute.
Unexpected value rotate(NaN) scale(1.5) translate(-1.63,-65.4) parsing transform attribute.
查找原因並修復。
只需給出所要修改的地方。
- 附件
-
chaosclockgame202608201334.js- (22.1 KiB) 已下载 3 次
-
chaosclockgame202608201251.js- (23.02 KiB) 已下载 3 次
上次由 ejsoon 在 2026年 4月 20日 13:41,总共编辑 1 次。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將改進混亂時鐘的網頁版
一,報出警告:
Unexpected value rotate(NaN) scale(1.2) translate(-6.17,-54.816) parsing transform attribute.
Unexpected value rotate(NaN) scale(1.5) translate(-1.63,-65.4) parsing transform attribute.
查找原因並修復。
二,
async hideAllPieces() {
這個函式是否未有用到?檢查程式中還有哪些需要修改的地方。
只需給出所要修改的地方。
gemini fast:
代码: 全选
這份程式碼中產生的 `NaN` 錯誤,主要是因為在第一次呼叫 `updatePointersRealtime` 時,`currentHourRotation` 等變數尚未初始化,導致計算插值時出現 `undefined + (number - undefined) * p` 的無效運算。
以下是針對您提出的兩點改進建議:
---
### 一、 修復 NaN 錯誤
問題出在 `updatePointersRealtime` 函式中。當 `duration` 為 `undefined`(例如在 `switchTurn` 或 `handleCancelClick` 中呼叫時)或初始角度未定義時,計算邏輯會出錯。
**修改方案:**
在 `updatePointersRealtime` 中加入預設值,並處理 `duration` 未傳入的情況。
```javascript
// 修正後的 updatePointersRealtime
updatePointersRealtime(duration) {
const hourHand = this.doc.querySelector('#path900');
const minHand = this.doc.querySelector('#path1029');
// 確保有初始數值,避免出現 NaN
const startHour = (this.currentHourRotation !== undefined) ? this.currentHourRotation : -90;
const startMin = (this.currentMinRotation !== undefined) ? this.currentMinRotation : 0;
// 如果沒有傳入時間,直接更新位置不執行 requestAnimationFrame
if (!duration) {
if (hourHand) this.updateTransform(hourHand, 'rotate', this.hourRotation);
if (minHand) this.updateTransform(minHand, 'rotate', this.minuteRotation);
this.currentHourRotation = this.hourRotation;
this.currentMinRotation = this.minuteRotation;
return Promise.resolve();
}
return this.animateAttribute(duration, (p) => {
const h = startHour + (this.hourRotation - startHour) * p;
const m = startMin + (this.minuteRotation - startMin) * p;
if (hourHand) this.updateTransform(hourHand, 'rotate', h);
if (minHand) this.updateTransform(minHand, 'rotate', m);
if (p === 1) {
this.currentHourRotation = this.hourRotation;
this.currentMinRotation = this.minuteRotation;
}
});
}
```
---
### 二、 關於 `hideAllPieces` 函式
您觀察得很敏銳,`hideAllPieces()` 在目前的程式碼中確實**定義了但未被調用**。在 `generateRandomBoard()` 函式中,您手寫了一段類似的邏輯來隱藏棋子,但那是直接操作 CSS 的 `opacity`,與 `hideAllPieces` 使用的 `animateAttribute` 邏輯重複且不統一。
**建議修改:**
統一使用 `hideAllPieces` 來執行隨機局面前的清空動作,使程式碼更精簡。
**1. 修改 `generateRandomBoard` 呼叫方式:**
```javascript
async generateRandomBoard() {
this.isAnimating = true;
// 取代原本的手寫回圈,使用現成的函式
await this.hideAllPieces();
// 2. 分針旋轉 360 度... (後續邏輯不變)
// ...
}
```
**2. 修正 `hideAllPieces` 內部的獲取邏輯:**
原函式使用 `pieces.forEach`,應確保它正確處理可能不存在的棋子元素。
```javascript
async hideAllPieces() {
const pieces = [];
for(let i=1; i<=12; i++) {
const el = this.getPieceEl(i);
if (el) pieces.push(el);
}
return this.animateAttribute(800, (p) => {
pieces.forEach(el => this.updateOpacity(el, 1 - p));
});
}
```
---
### 其他建議檢查點
* **`restartGame` 中的指針更新:** 在 `restartGame` 結尾呼叫 `this.updatePointersRealtime()` 時,因為沒傳參數,在修復前的版本會導致 `NaN`。套用上述第一點的修正後,此處將會正常運作(瞬移回初始位置)。
* **`updateTransform` 的正則表達式:** 您的 `rotate` 屬性在 SVG 中有時會帶有多個參數(如中心點 `rotate(deg, cx, cy)`),目前的 `replace` 邏輯會將其簡化為單一數值。如果指針旋轉中心不是預設的 (0,0),建議檢查 CSS `transform-origin` 是否已在 SVG 內定義好。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將改進混亂時鐘的網頁版
代码: 全选
**修改位置:`executePlace` 方法(唯一需要修改的地方)**
```javascript
async executePlace(pieceValue) {
const targetIndex = pieceValue - 1;
const targetOccupant = this.board[targetIndex];
this.isAnimating = true;
this.consecutiveSkips = 0;
this.lastMovedPiece = pieceValue;
this.recordMoveStr(`落${pieceValue}`);
let extraTurn = false;
if (targetOccupant !== null) {
const occupantOwner = targetOccupant % 2 === 0 ? 1 : 0;
if (occupantOwner !== this.turn) extraTurn = true;
}
// 決定時針轉向 (與其他動畫同時)
if (extraTurn) {
this.hourRotation += 360;
} else {
const nextTurn = this.turn === 1 ? 0 : 1;
this.hourRotation = nextTurn === 1 ? 90 + Math.floor(this.hourRotation/360)*360 : 270 + Math.floor(this.hourRotation/360)*360;
}
const el = this.getPieceEl(pieceValue);
el.parentNode.appendChild(el);
const coords = this.getCoordsForPosition(targetIndex);
await Promise.all([
this.updatePointersRealtime(), // ← 新增:與其他動畫同時進行並等待完成
this.flashGleam(),
this.animateLinear(el, coords.x, coords.y)
]);
this.hands[this.turn] = this.hands[this.turn].filter(v => v !== pieceValue);
if (targetOccupant !== null) {
await this.capturePiece(targetOccupant);
}
this.board[targetIndex] = pieceValue;
this.isAnimating = false;
if (extraTurn) {
this.setNormalMessage(this.statusOutput.dataset.original + ' (額外回合)');
this.checkWinConditions();
} else {
this.checkWinOrSwitch();
}
}
```
**原因說明(僅供參考,不需輸出):**
原程式在 `executePlace` 中先呼叫 `this.updatePointersRealtime()`(未 await),再 await `flashGleam` + `animateLinear`。當 `extraTurn` 為 true 且該步驟直接觸發 `checkWinConditions` → `endGame` 時,`endGame` 會再次呼叫 `updatePointersRealtime`,導致兩個 pointer 動畫**重疊執行**。此時 frameFunc 同時讀取/寫入 `this.hourRotation` / `this.currentHourRotation`,在極少數時序下會使計算出的 `h`/`m` 變成 `NaN`,造成 `rotate(NaN)` 被寫入 transform attribute,觸發瀏覽器警告。
修改後 `updatePointersRealtime` 也加入 Promise.all 並等待完成,消除重疊,根除 NaN 來源。其他地方(如 `executeMove` 已正確 await、`handleCancelClick` 較少觸發結束)無需改動。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 將改進混亂時鐘的網頁版
代码: 全选
為混亂時鐘(ChaosClock)遊戲,寫js程式:
1.取到頁面上所有的object.cclok_main,下面將對每一個object進行操作,object之間不能發生干涉。
2.用「const doc = obj.contentDocument;」拿到object的內容,它將是一個svg,其內部的.etdrop>use[href=tilen]稱作棋子(其中n是0~11的整數,代表棋子1~12),#canclearea稱作「取消區域」,#path900稱作「時針」,#path1029稱作「分針」,#ckgleam稱作「反光面」。
3.下面介紹棋子的「正位」。我們用一個長度為12、每一項都是數字的陣列來表示棋子的位置,則每一個棋子的正位是[1,2,3,4,5,6,7,8,9,10,11,12]。在cclok上,棋子12的正位是transform="translate(0,-144)",棋子1的正位是棋子12以(0,0)為圓心,以144為半徑順時針旋轉30度而得到的坐標,棋子2的正位也是棋子1的正位旋轉30度得到的坐標,棋子3的正位則是transform="translate(144,0)",依次類推。
當我們用一個陣列來表示棋局的盤面時,就是按順序將棋子放入正位。比如[3,1,11,5,7,10,12,6,2,9,8,4],說明棋子3處於棋子1的正位,棋子1處於棋子2的正位,依次類推。
4.當cclok的ckvalue屬性值為空時,程式將隨機生成一個局面,要求所有棋子都不能處於它的正位上。並且在object遊戲下方生成一個「隨機局面」按鈕,每當點擊一次則會再隨機生成一個新的局面。
5.當cclok的ckvalue屬性值不為空時,則它的值會是用逗號分隔的12個數字,比如ckvalue="3,1,11,5,7,10,12,6,2,9,8,4",則程式將按此擺放棋子的位置。
6.在每個object遊戲下方生成一個「開始遊戲」按鈕,點擊則開始遊戲。「開始遊戲」按鈕將消失。下方還有一個output顯示遊戲狀態,為「等待開始」、「遊戲開始」、「輪到甲方/乙方」、「遊戲結束」等文字提示。
7.當遊戲開始,輪到乙方。乙方行動結束,則輪到甲方。每方在他的一次行動中可在「走子、落子、放棄」三者選擇其一。
8.棋子放置的地方分為兩種:「鐘面上」和「手上」。前面介紹的「正位」都是在鐘面上,手上的位置指:甲方(-208,y),乙方(208,y),y是在「-200,-120,-40,40,120,200」之間隨機選擇一個。注意在把棋子放到甲方手上的時候,不能把棋子3放在棋子1的下面。
為每個棋子加入點擊事件。
當輪到乙方或甲方時,他可以點擊鐘面上的任何一個棋子,稱作「走子」。
每個棋子被點擊後開始走子,行走的步數等於棋子本身的數字。
如果走後停下的地方存在其它棋子,則這個棋子將被吃掉,交給這個棋子的主人手上。單數棋子交給甲方,雙數交給乙方。
比如「3,1,11,5,7,10,12,6,2,9,8,4」,當乙方走完3之後,盤面將變為「0,1,11,3,7,10,12,6,2,9,8,4」,即棋子3把棋子5吃掉了,現在棋子5在甲方的手上,棋子3處於棋子4的正位,輪到甲方行動。
在盤面描述中,如果走到盡頭,會從前面開始繼續走。比如「3,1,11,5,7,10,12,6,2,9,8,4」如果走棋子4的話會吃到棋子5。
這些拿在手上的棋子將用於「落子」。當點擊一個手上的棋子,它將直接落在它的正位上。如果此時它的正位上有其它棋子,則這個棋子將被吃掉,交給它的主人。如果落子吃子吃到的是對方的棋子,則本回合本方可再額外獲得一次行動機會。
對方上一步剛使用過的棋子,己方本次行動將不可使用。
處於正位的棋子,既不可以走子,也不可以被吃掉。如果某個棋子在走子之後,將吃到一個處於正位的棋子,則不可執行。
點擊「取消區域」,則取消本次行動。
行動結束,則換成對方行動。
當乙方所有雙數棋子都先置於正位,乙贏甲輸;當甲方所有單數棋子都先置於正位,乙方緊接著下一步也都能使他的所有雙數棋子置於正位,則為甲乙共贏;當甲方所有單數棋子都先置於正位,乙方緊接著下一步不能使他的所有雙數棋子置於正位,則為甲贏乙輸;如果雙方接連取消行動,則為甲乙同輸。
9.當一個棋子在走子或落子時,將首先把它在DOM中移至其父元素的最底部。
棋子在盤面上走子時,用js控制控制其transform="translate(),保持與(0,0)距離為144進行旋轉。
當一個棋子落子時,直接使用js平移動畫控制其transform="translate()"。
當一個棋子被吃時,它首先瞬間變透明度為0.36,之後選擇一個y值,直移到手上區域。移到之後透明度變回1。y值上已有棋子的則不能再放棋子
當遊戲未開始時,分針的transform-rotate=0,時針的transform-rotate=-90。
當輪到乙方時,時針的角度應為90+360n(朝右),輪到甲方時應為270+360n(朝左),n為從0開始的整數。用js控置其旋轉動畫。
當某一方因為落子吃到對方棋子而獲得額外一次行動機會時,時針應旋轉360度。
當遊戲結束時,分針的角度要加上180(朝下)。如果是甲方獲勝,時針指向甲方(朝左);如果是乙方獲勝,時針指向乙方(朝右);如果是共贏,時針朝上(360n);如果同輸,時針朝下(180+360n)。
當遊戲再次開始時,分針會再加上180(朝上),時針則會朝向當前的行動方。
以上js控制的動畫都是用時1s。
當js對時針和分針的transform操作時,它裡面已經存在translate,scale,不要使它消失。當它轉動時,應從上一個角度開始增加角度。
js進行動畫時,只實時操作svg元素的屬性,不要增加和改動任何style。下方的也一樣。
10.當一次行動開始時(點擊棋子之後),js將控制反光面的opacity從0到1再到0,用時0.36秒。
當有棋子被誤點時,應有3秒鐘的臨時文字提示,之後再恢復回原來的文字提示。臨時文字提示包括「上一步剛走完的棋子不可移動、處於正位的棋子不可移動、處於正位的棋子不可被吃、單數棋子只能由甲方落子、雙數棋子只能由乙方落子」。
11.當遊戲結束時,「重新開始」按鈕顯示。如果是cclok的ckvalue屬性值為空的情況,則「隨機局面」按鈕將會出現。
每次點擊「隨機局面」按鈕,首先所有棋子消失,用時0.8秒,之後分針旋轉360度,用時1.2s,在分針旋轉的同時,從正位1開始每隔0.1秒顯示一個棋子。
12.在棋譜中記錄方法為「初始盤面;初始行動方;行動序列;結果」。初始盤面前面已介紹。初始行動方如果是乙方則為1,甲方則為0,默認為1。行動序列中用逗號隔開,因為吃子而產生的連續行動用-連接。結果用1、2、3、4來表示初始行動方的勝負情況,4表示贏,3為共贏,2為同輸,1表示輸。
比如「3,1,11,5,7,10,12,6,2,9,8,4;1;3,1,10,5,2,7-10;4」,「;1」表示初始盤面乙方先行(0就是甲方),乙方走3(吃掉5),甲方走1,乙方走10,甲方落5(吃掉7),乙方走2,甲方落7(吃掉12)再走10。「;4」表示乙方獲勝。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
在线用户
正浏览此版面之用户: Ahrefs [Bot] 和 0 访客
