創作內容

1 GP

11/10~5/3,仿臥龍吟,只仿了戰鬥系統且沒仿完

作者:李兒諳│2023-11-10 16:48:01│巴幣:2│人氣:302
5/4(六),明天實況
會先處理模擬宇宙祝福相關文件
再來是嘗試啟動記錄所選擇的祝福
明天之後這篇實況文會解除置頂
改成新的實況文置頂

下星期六大概是不實況了,可能要陪家人去大賣場一趟
(題外話,如果我放假的是星期天,大概就是星期天去
就算不去,也不見得方便用電腦
所以通常實況在週末大概都僅在星期六)
星穹鐵道私服的資料格式不好懂
程式檔.java還算比較好懂些
改了後重新編譯也確實有效果
但具體到遊戲細節的
大部份都是個JSON檔,然後對應個奇怪的數字
不知道是不是有加密處理過這樣
(不過應該不是純粹加密,因為是純數字,連英文都沒有)
所以就放棄改善私服的計劃了
自己仿可能還比較快一些

所以我也不太清楚私服要怎麼換角色模組
本來打的算盤是更改劇情文字檔或者是模擬宇宙的祝福跟描述這樣
但手頭有的私服有沒有劇情還不知道
私服的模擬宇宙也很難玩
不能選事件,不能重置祝福,敵人陣容蠻固定的

此外還有部份原因是實況私服可能會對自己有不利影響
所以之後還是放棄實況星穹鐵道修改私服好了

思考了一陣子後,這個月不回花蓮了!!
本來是想回花蓮帶家人去散步
雖然散步的地方蠻空曠的,應該是還可以
而且其實回花蓮時間那麼久,散步頂多一天花半個小時吧
怕還沒搖完,所以就算了

隔這麼久實況是因為正好沒什麼假日
然後我上個月時就已經決定這個月有兩天要回花蓮

4/6實況結束,有產出文章
4/3,完成手邊全帳號主線,但活動都還沒肝
我應該4/7以前能忙完2.1版本上半
下次程式實況可能要4月中旬,最近要忙著解星穹鐵道、原神活動
此外最近比較忙得原因是,臥龍吟也是一次玩很多帳號的關係
突然得知3/23(六) 13:00~15:00
因為早上要掃墓,很可能就不實況了

3/15,星穹鐵道2.0版本今天大概是忙完了
下次實況3/23(六) 13:00~15:00
3/9暫停實況一次,玩遊戲太忙了
下次研究如何用MMD模型進行遊戲是3/9(六) 13:00~15:00
3/2實況產出晚些再新增文章
對我而言3D比較燒腦,所以這次實況到14點多就提早結束了
不過MMD動作要怎麼判斷已經完成一循環了我目前還沒頭緒
下次實況可能也不會很順利

2/15,實況,景元能跳MMD舞蹈了,主要卡點是
沒有把標籤視窗按出來的話,就算有安裝Add-ons
也是看不到MMD標籤的
雖然我不清楚MMD模型有沒有更直接的動作方式
像是骨骼在幾幀時位移那樣的簡潔動畫
但至少可以用很麻煩的.vmd檔來讓角色動起來
雖然我使用了現成的.vmd之後
其實渲染是會卡在第二幀到第三幀渲不出來的
還不清楚是常態現象或者是特例

2/12,實況,將webGPU的範例畫個紅色三角形的那個
修改了下shader(因為用webGPU,格式是WGSL)
改天會再新增一篇文章特別講Shader(中譯是著色器)
因為在碰之前我自己也不是很清楚是什麼因此一直沒講
成功畫出平行四邊形
不過用的方法是樸素的兩個三角形
也就是在不修改primitive: {
      topology: 'triangle-list',
    },
的狀態下完成
看了下知乎描述
WGSL的拓樸似乎有以下種類
enum GPUPrimitiveTopology {
  "point-list",
  "line-list",
  "line-strip",
  "triangle-list",
  "triangle-strip"
};
enum這個是類似C語言的語法
雖然這邊是webGPU在Javascript的定義的樣子
具體的不同可以測試一下
其中point-list是只畫點,由於點很小
所以測試的時候可能會以為測試失敗
要看仔細點
triangle-strip跟line-strip比較難測試
(就完成的圖片看不太出差異)
這改天再研究

2/12 13:00~15:00,繼續研究webgpu載入3D模型
呼,版本更新後,AI繪圖能用的安裝順序是這篇
巨匠電腦意外的不錯
我舊有能順利跑的sygil-webui
其實我也不確定我舊有能跑的是不是那個
但之前的readme文件是導向到那github頁面
在執行時因為先跑更新,然後死在檔案依賴性上
就像是SessionInfo載入失敗
ffebm.dll什麼的關聯失敗
還跑出很神奇的錯誤 Window 127跟Window 126
第一次看到那種錯誤
CUDA、miniconda、pytorch、pytorchaudio、pytorchvideo......等
安裝又再跑了好幾次
在指定的Python版本中執行
還是不行
就想說從頭來過
從頭來過還是比較順利的

不過不知道是不是下載的模型訓練集好像是比較粗略的版本
有空再換個模型(.ckpt)試試看好了
感覺這次跑出來的圖結果比較不理想
本來以為這麼久沒更新
一些比較新的動漫人物關鍵字會補上
但試了幾個似乎沒有能較近期的名字對上動漫人物的
嗯...那它們沒事更新做什麼啦!!
我這次完後也許幾個月想到後又不能跑了也說不定
呀,今天就先這樣吧
有的沒的弄完後也18:41了
還要忙著衝戰鬥次數跟今天完整的模擬宇宙還有兩次左右沒打

下次實況在很久之後,我2/12是回台北了
但會不會實況還在考慮
2/5實況已結束,太久沒用AI繪圖,導致需要版本更新
但版本更新遇上了些麻煩
這次實況主要是在找3D模型相關的資料
是有找到Stanford Dragon這類供教育使用的模型
但Stanford Dragon好像沒有設定骨骼
所以載入後可能沒辦法動起來
現在的webgpu範例,還沒看到模型能動起來的(雖然我也只找到一個)
three.js是有載入MMD模型且能動得起來
只是能的話我想學webgpu就是了
今天相當於沒什麼進度

2/2實況已提前結束,下次實況是2/5 13:00~15:00
2/2完成了一場戰鬥直到我方或敵方全數陣亡
但還沒進行些資料異動後的測試(例如調整一下血量跟攻防,讓我方先被敵方打死)
跟死亡動畫、攻擊特效、血條等還沒做
所以目前網頁上看起來就是 -100 -100這樣位置變個幾次後
畫面就不動了這樣
(我是可以簡單滴用彈出警告視窗來標明是誰勝利啦
不過我是想說以後會完善,就不急著做戰鬥結束時的畫面處理了)

1/28實況已結束
班表沒動的話,下次實況應該是2/2 星期五 13:00~15:00
其實我也不太確定
因為我下星期可能只休1天,也可能六日又會有休一天
但我記得我好像過年前只休兩天,似乎中間有隔幾天
(查了後,休2/2、2/5)
那我星期五以前可以把五個帳號下星期的事情都忙完嗎?
唔~但沒意外的話應該會挑下星期五(也就是下次放假啦)實況就是了

以後寫網頁檔不刻意挑時間全程實況
我最近都是一週挑一天假日13:00~15:00實況
沒放假就完全沒動這樣
之後會改一下,重心放在把寫好的網頁檔更新在小屋上面
至於實況寫網頁檔,就是有閒暇時才表演一下
(唔,我個人是覺得寫程式的實況非常難懂
通常要看別人刻意剪輯的解說影片才會比較有收獲)

嗯,那現在仿臥龍吟戰鬥系統缺什麼?
第一個比較重要的是,圖片載入時我們應該要做些顯示載入進度的呈現
第二個是角色攻擊動畫的添加
第三個與其它的等看這次實況結束能寫到哪邊再列出缺什麼

1/20實況產出
完整網頁檔依舊幾天後再補上

這次要用到載入的文字檔了
先新增一個 hit_order_1.txt
內容只有一行 1,4,7,2,5,8,3,6,9
這個意思是 位置站在1的 攻擊順序是
先打第一格,第一格沒有敵人再打第四格,第四格沒有敵人再打第七格這樣依此類推

敵我九宮格編號是這樣的
我方     敵方
741     147
852     258
963     369

唔,不過敵人的攻擊順序要怎麼儲存我還在想
我是在想要改文件檔名稱
分別載入our_hit_order_1.txt與enemy_hit_order_1.txt這樣

還是把敵方的九宮格位置編號+9,然後再載入hit_order_10.txt這樣
我覺得+9的做法比較死
如果哪天不是九宮格,需要比較大幅度的改動
但不管怎麼說,若哪天變成不是九宮格
我都至少要改18個檔案或者是直接新增對應格數的檔案數量

其實,唔,這麼點資料應該是可以不用檔案來存
畢竟載入18個文字檔也是有些繁瑣的
直接改為程式中來個18行攻擊順序寫入陣列似乎更為實際

我方的寫完之後發現敵人的好像不用存
如果是單純的仿臥龍吟,它們是對稱關係
所以存完我方的攻擊順序後
只要敵我的編號對調,就能套用同樣的攻擊順序

原先之所以會想說用文件檔來存的原因是
我是想說可能可以設計不同的關卡
那不同的關卡也許會用到各自特殊的攻擊順序
所以想說載入關卡時連帶載入他們的攻擊順序文件這樣
如果只是單純仿臥龍吟,基本上是沒有出現特例狀況的
(特例就是有些兵種是全體攻擊、直排攻擊、橫排攻擊)

1/12(五) 13:00~15:00這次實況的網頁檔我暫時不放出
打算另外開篇文章專門講放出的網頁檔
成果:
至於這次的實況結果大概是這樣的


戰鬥系統相當於還沒寫
只是大致上處理了傷害顯示的部份
實況是每幾秒就增加回合數,然後根據回合數是奇數還是偶數
用的是setInterval(函數,毫秒數)
把傷害值顯示在敵方還是我方身上
實際進入戰鬥系統後
會根據我方角色與敵方角色行動順序
來進行顯示微調
那時應該會根據角色行動與回合數
來使用setTimeout(函數,幾毫秒後執行該函數)取代之
跟要處理角色死亡的特效
我應該會用圖片逐漸變成白色的手法來解決
至於攻擊、受擊的話
我是會把圖片直接改成不同的表情用來表示正在攻擊跟被攻擊這樣

不過具體要怎麼寫
我還需要些時間思考!!
此外近期小屋有更新別的文章的計劃
所以可能到時候還是拖到下次實況時再想這樣吧!!
那這次實況大概就這樣!!

那現在的網頁檔講解文章新增預計是在下次放假 1/15時

---------------
1/6實況已經處理好圖片檔非同步載入
呃,其實還沒"完整"處理好,只是暫時夠用
正在著手處理九宮格戰鬥系統中

1/6產出網頁檔
檔案目錄底下需要有四個檔才能順利運作
1. "jquery-3.7.1.js (去jquery官網下載)
2. my_action_table.txt (沒有可能也沒關係,但有比較不會報錯,內容隨意,目前還沒用到)
3. cha_01_1.png
4. cha_02_1.png
目前圖檔格式是 100*96
雖然若用我透明檔處理的出來的圖檔會變成 160*90
不過最後只會用到左半邊就是了

滑鼠按一下之後,網頁應該要顯示的結果是
(上面兩張圖的順序可能會變
但底下第一回合那邊九宮格內的圖檔順序應該要
薔薇姬站在右上角
小雪站在右下角
如果多重新整理多按滑鼠幾次之後內容會變的話
代表目前的網頁有bug需要修正)

但今天的實況產出就這樣
還不會自動戰鬥
第一個是敵人還沒設定
第二個是我敵人的圖檔還沒處理好
目前只有寫好兩個圖檔的載入順序
如果是四個甚至是18個或以上的話我陣列要再改寫
其實我隱約覺得我目前的處理方式...
可能沒辦法同時載入太多張圖檔
但我現在網速變快了 300M
所以沒以前好測試!!
以前用傳統的image.onload()全部載入後再處理圖檔是肉眼可見的久
現在fetch我也不清楚有沒有快很多了
前些日子網速100M時是覺得fetch快很多

圖檔載入部份估計日後還要持續修正好一段時間

<!DOCTYPE html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<html lang="zh-Hant" type="text/html; charset=UTF-8">
<title>仿臥龍吟─圖片素材使用式姬系列</title>
<body>
<script src="jquery-3.7.1.js" type="application/javascript" ></script>
<div id="image-container"></div>
<canvas id="myCanvas" width="1600" height="900"></canvas>

<script type="application/javascript" charset="UTF-8">

async function loadFileAndPrintToConsole(url) {
  try {
    const response = await fetch(url);
    const data = await response.text();
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

loadFileAndPrintToConsole('http://localhost/my_action_table.txt');

var c=document.getElementById("myCanvas");
var canvas_2 = document.createElement("canvas");
//canvas_2不顯示在網頁上,它用於處理非同步圖片載入順序
canvas_2.setAttribute("height",300);
canvas_2.setAttribute("width",300);
//var ctx=c.getContext("2d");
var ctx =c.getContext("2d", { willReadFrequently: true })
var ctx_2 =canvas_2.getContext("2d", { willReadFrequently: true })

ctx.fillStyle="#FFFFFF";

/*function Picture(file_name)
{
this.image=new Image();
this.image.id=file_name;
this.image.src=file_name;
}*/

var finish_num=0;

var board_width = 3;
var board_height = 3;

var board = [];

for(var i=0;i<board_width*board_height-1;i++)
{
board[i]=i;
}
board[board_width*board_height-1]=-1;


shuffle(board);

function re_draw()
{
ctx.fillRect(0,0,c.width,c.height);

for(var i=0;i<elements.length;i++)
{
ctx.drawImage(elements[i].image,i%3*elements[i].image.width,parseInt(i/3)*elements[i].image.height);
}
}

function shuffle(array) {
  var m = array.length, t, i;
  while (m) {
    i = Math.floor(Math.random() * m--);
    t = array[m];
    array[m] = array[i];
    array[i] = t;
  }
}

function click_region(id,left,top,width,height)
{
this.id=id;

var self=this;

this.left=left;
this.top=top;
this.width=width;
this.height=height;
$(c).on('handleClick', function(e, mouse) {
        if (self.left < mouse.x &&
            self.left + self.width > mouse.x &&
            self.top < mouse.y &&
            self.top + self.height > mouse.y) {
if((self.id-1) % board_width !=board_width-1 &&
board[self.id-1] == -1)
{
board[self.id-1] = board[self.id];
board[self.id] = -1;
//ws.send(board);
}
if(board[self.id-3] == -1)
{
board[self.id-3] = board[self.id];
board[self.id] = -1;
//ws.send(board);
}
if((self.id+1) % board_width != 0 &&
board[self.id+1] == -1)
{
board[self.id+1] = board[self.id];
board[self.id] = -1;
//ws.send(board);
}
if(board[self.id+3] == -1)
{
board[self.id+3] = board[self.id];
board[self.id] = -1;
//ws.send(board);
}
        }
    });
}


function my_unit(id,hp,atk,def,seat)
{
this.id=id;
var self=this;

this.hp=hp;
this.atk=atk;
this.def=def;
this.seat=seat;
}

var elements=[];
var img_count=0;

var battle_character=[];

const my_character_1 = new my_unit("薔薇姬",200,100,0,1);
const my_character_2 = new my_unit("小雪",200,100,0,3);

var loaded_flag=false;

var image_load_seq_map=[];


battle_character.push(my_character_1);
battle_character.push(my_character_2);

//elements.push(new Picture("cha_0"+ (i+1).toString() + "_1"+".png"));

//for (var i = 0; i < board_width*board_height; i++)
for (var i = 0; i < 2; i++)
{
fetch('http://localhost/cha_0'+ (i+1).toString() + '_1'+'.png',{
headers: {
      "content-type": "image/png; charset=UTF-8",
      "x-content-type":"nosniff",
      "cache-control":"no-cache",
    },})
  .then(res=>
{
return res.blob()
})
  .then((blob)=>{  

//以下這段特別感謝
//https://rapidapi.com/guides/fetch-images-with-fetch-api


const imageUrl = URL.createObjectURL(blob);
            const imageElement = document.createElement("img");
            imageElement.src = imageUrl;
            const container = document.getElementById("image-container");
            container.appendChild(imageElement);

    console.log(container.childNodes);

imageElement.onload = function(){
img_count++;
if (img_count==2)
{
ctx.clearRect(0,0,1,1);

var children = container.childNodes;

for (const node of children) {
console.log(node);
ctx_2.clearRect(0,0,1,1);

ctx_2.drawImage(node,0,0,imageElement.width,imageElement.height);

var imgData = ctx_2.getImageData(0,0,1,1);

switch(imgData.data[3])
{
case 253:
image_load_seq_map.push(node)//ctx.drawImage(node,0,0,imageElement.width,imageElement.height);
break;
case 254:
if(typeof image_load_seq_map !== 'undefined')
{
image_load_seq_map.push(node);
image_load_seq_map.reverse();
//目前方法只適用於就兩個圖檔需要載入
}
else
{
image_load_seq_map.push(node);
}
//ctx.drawImage(node,0,100,imageElement.width,imageElement.height);
break;
default:
console.log("我目前還不清楚為何會跳到這");
}
}

loaded_flag=true;
console.log(image_load_seq_map);
}

}



  });

//elements.push(new click_region(i,i%3*c.width/3,parseInt(i/3)*c.height/3,c.width/3,c.height/3));
}


var cell_width = 100;
var cell_height = 96;
$(c).on('click', function(e) {
var mouse= {
        x: e.pageX - c.offsetLeft,
        y: e.pageY - c.offsetTop
}
         
    //fire off synthetic event containing mouse coordinate info
    $(c).trigger('handleClick', [mouse]);
//re_draw();

//第一個九宮格
for(var i=0;i<3;i++)
{
for(var j=0;j<3;j++)
{
ctx.strokeStyle = "#009900";
        
ctx.moveTo(i*cell_width,j*cell_height);
ctx.lineTo((i+1)*cell_width,j*cell_height);
ctx.lineTo((i+1)*cell_width,(j+1)*cell_height);
ctx.lineTo(i*cell_width,(j+1)*cell_height);
ctx.lineTo(i*cell_width,j*cell_height);
ctx.stroke();
}
}

//第二個九宮格

for(var i=0;i<3;i++)
{
for(var j=0;j<3;j++)
{
ctx.strokeStyle = "#000099";
        
ctx.moveTo(i*cell_width+500,j*cell_height);
ctx.lineTo((i+1)*cell_width+500,j*cell_height);
ctx.lineTo((i+1)*cell_width+500,(j+1)*cell_height);
ctx.lineTo(i*cell_width+500,(j+1)*cell_height);
ctx.lineTo(i*cell_width+500,j*cell_height);
ctx.stroke();
//目前兩個九宮格是同個顏色,尚待修正
}
}
ctx.fillStyle="#000000";
ctx.font="40px 標楷體";
ctx.fillText("第一回合",320,30);

if(loaded_flag)
{
for(const n of battle_character)
{
switch(n.seat)
{
case 1:
console.log(n.id+"站在1");ctx.drawImage(image_load_seq_map[0],cell_width*2,cell_height*0,image_load_seq_map[0].width,image_load_seq_map[0].height);
break;
case 2:
break;
case 3:
ctx.drawImage(image_load_seq_map[1],cell_width*2,cell_height*2,image_load_seq_map[1].width,image_load_seq_map[1].height);
console.log(n.id+"站在3");
break;
case 4:
break;
case 5:
break;
case 6:
break;
case 7:
break;
case 8:
break;
case 9:
break;
default:
alert("角色戰鬥位置讀取出錯,error");

}
}
}
else
{
alert("圖片載入中,image loading");
}
});




</script>

</body>
</html>


1/1實況主要是在處理圖片檔載入,但還沒完成
所以這次的檔案就先不貼上來了
fetch的非同步載入真得很麻煩,雖然載入速度很快
下次實況寫網頁是1/6 13:00~15:00
下次要做的是完成圖片檔載入,關於修改透明度的
因為mousemove事件天生就有些缺陷在,要修改它很費神,我就先跳過了
先只挑幾個圖檔局部改透明度來處理
有需要我在開麥克風,不過我是想說我家可能有點吵

最近寫些async(非同步)網頁檔的話可能會遇到這個錯誤
Unchecked runtime.lastError: The message port closed before a response was received.
好像是在某次更新後
過往用到些非同步或者是要等圖檔、文字檔載入好後才能用的Javascript
需要更規範的寫法才能避免這報錯
不過它報錯的地方也很奇怪,顯示是<!DOCTYPE html> 第一行就報錯了
我找找看我哪些地方有用到非同步的,改寫看看能否解決這問題

誤會誤會,應該不是同步問題
而是現在html檔需要語言屬性,以方便正確的字體顯示
然後html應該必須要有<title>,設定title文字後,分頁就會顯示<title></title>中間的那段
(因為以前不寫也不會怎樣所以我就跳過)
跟些其它的問題這樣加起來有五個地方要修正

11/11,10:29更新,更新部份用不同字體顏色表示
Unchecked runtime.lastError: The message port closed before a response was received.
這錯誤是其它瀏覽器擴充功能導致的
把擴充功能停用或者是攔截runtime.error即可
應該是不太影響具體程式執行

然後把其它的viewport那些設定完後
如果你程式中有用到fetch跟var img = URL.createObjectURL(blob);這些的
可能會發現有兩個錯誤只會出現在重新整理的時候
Response should include 'x-content-type-options' header
找不到 cache-control header
這兩個錯誤僅是由cache讀取臨時產生的URL所引發的
好像是因為重新整理並不會把網頁內容全部重跑一次
所以本來在第一次完整執行時
有些http header會丟失些原來的設定
就算你已經把IIS或者是apache一類網頁伺服器的設定檔照著錯誤說明的設定完成
還是有可能導致兩個地方報錯
不管影不影響網頁具體執行
反正我嘗試了一早上後是修不好
所以這問題我就跳過了

雖然有報錯,但有時網頁能正常執行
不過就跟以前Visual C++一樣 scanf要改寫成scanf_s的樣子
就需要改成更規範、更安全的寫法才能避免
有看到個較簡易的取巧方式是寫 if(chrome.runtime.lastError){}
也就是另外處理的
但我在Edge也有遇到這問題,我想還是參考別篇的做法好了
目前在看這
promise新功能出來後我幾乎沒用過,有大概也是複製現有程式碼所以沒什麼印象
嗯...思考中
理論上來說我應該跳過這問題
直接寫戰鬥本體的程式碼才對
不然這問題處理下去我看明天大概是沒希望用好

哦,好像是現在讀取圖檔、.txt,.json跟一堆阿里不打的都是用fetch函數
我改改看看能不能讓網頁停止報執行時錯誤(runtime error)

改寫完後發現不是這個問題
不過改寫後,fetch的速度好像比傳統載入圖檔的快很多啊!!
但我目前只有fetch一個圖檔,多個圖檔還沒看會不會出問題

然後edge瀏覽器其實已經算很貼心了
有指出問題在哪跟怎麼修正
不過我一開始沒看到就是了
在圖中綠色框框處

--------------原文------------------------

就仿臥龍吟或神仙道一類的
這篇是承這篇10/15,進度稍微往前推進些,近期計劃與遊戲設計的第一道高牆跟第二道高牆 - y541258的創作 - 巴哈姆特 (gamer.com.tw)

明天希望要達成的目標是,寫死的狀況下
傷害都是固定-100點

敵我九宮格編號是這樣的
我方     敵方
741     147
852     258
963     369

那順利的話可以完成可拓展的情形
也就是我若把編號改成
4 3 2 1
8 7 6 5
12 11 10 9
16 15 14 13
或者是5*5,3*5各式各樣的

然後攻擊順序也不一定是只從對面數來第一個先打
這個我的想法是配個攻擊順序表來寫
算上次就想好的
看戰鬥系統是否還能順利運作

之所以會卡那麼久的原因是
攻擊動畫我沒做,但如果有做動畫的話
大致上有兩種做法
第一個是動畫做成分解圖,然後照一定時間依序播放
另一個是動畫做成分解圖,但每個動作配置的播放時間不一定相同

也就是說,做攻擊動畫就是依序播放圖片的意思
因此到時候改成程式碼時,這邊問題應該不大
大致上會像是for(var i=0;i<fix_step;i++){...}這樣

那我的第一組測試數據預計是這樣設置的

我方的九宮格
空 空 薔薇姬(血量200,傷害100)
空 空 空
空 空 小雪(血量200,傷害100)

敵方的九宮格
空 空 空
真祖(血量200,傷害100) 孫麗(血量200,傷害100) 空
空 空 空

若是這樣的話,誰先手誰就贏,按照打前排的攻擊順序的話
(唔,調攻擊順序後我還沒仔細算過先後手誰會贏)
但若仿臥龍吟的話,不管排法,只要敵我雙方數量相同,都是我打一下,敵人打一下的
不然我們換個說法
每個單位在別的單位這回合行動結束前,最多攻擊一次
(更正:
應該說是 一個單位一回合最多行動一次,行動0次的話就是在動之前先被消滅了
被控住的話就是 行動一次 但該次行動沒有造成傷害、技能、治療)

那基本上到明天結束之前只要完成這樣就好!!
程式用到的圖片可以去式姬大全 對話製作所那邊下載
但基本上就把用到的圖檔名稱改成自己要用的圖檔名稱即可

完成之後程式碼或者說網頁檔用到的文字內容會寫在這篇
那github因為舊帳號登入不了,新帳號我忘記我的帳密了
所以可能就不放github了

其實寫好之後,傷害跟血量是可以改的,預計用的方法是JSON
(JSON是一種資料格式,類似excel的.csv但寫法不同)
可以理解為用配表的方式
(配表其實跟寫死也很類似,只是寫死的話在傳統非網頁檔情形
改程式碼中的數值就要重新編譯過才能呈現預期結果
而配表的方式只要改文件檔中的文字或二進位資料,程式不用重新編譯就能運行結果
所以一個說寫死一個說沒寫死,只是程式運行到最後它會需要個確定的常數值
這部份表面上沒什麼,但根據實作方式不同有時影響還蠻大的
可以參考有些函數式程式語言,late binding(晚期繫結)的特性
讓它可以不用像命令式編程對某些特定情形下需要額外占用一大筆記憶體空間)

如果實作過程不順利,那我可能就不用JSON,直接寫死在程式碼中
(直接寫死在程式碼中的話,雖然感覺不太明智
但這麼做我印象中有個很直觀的好處
那就是我們在自己測試時
網頁檔就不用掛http服務器執行才看得到運行結果了
這原因是因為我若用JSON,引用的是jQuery現有的程式碼
但它的JSON相關程式碼好像依據網頁安全性原則
你不掛在http server上,會禁止網頁讀取所在目錄文件
我以前的印象中是這樣啦)

好,今天還有些時間,我就先處理動畫以外的畫面呈現部份好了
雖然上一篇已經將畫面顯示、傷害血量儲存的大部份程式碼處理好了
不過我上篇沒貼網頁檔具體內容就是了

------------------------------------------
想了想,先配個行動順序表,我打算用.txt或隨意自訂副檔名
用.txt的話Javascript應該有現成函數可用比較省事
戰鬥時就是根據行動順序表,檢查先手方是否有存活的單位
有存活的單位的話,根據攻擊順序表尋找敵方存活的單位
有的話行動(也就是執行播放動畫),並標記為已行動
沒有的話判定為先手方勝利
若我方沒存活的單位的話,判斷敵方是否有存活單位
有,我方戰敗
沒有,平手
戰鬥本體只有這樣

但等遊戲完整寫出來後
戰鬥結束後還要扣除玩家的一些資源
跟把關卡設定為已通過、關卡歷史最佳評分、戰報儲存與重播功能這些處理下
我今天跟明天的目標是先只完成戰鬥本體就好!!

然後每個關卡只要調整敵人數值,(攻、防、兵力、站位、武魂...)即可
那我方數值是根據其它養成系統來決定的
用到再去對應的JSON檔案讀取即可

以九宮格來說的話會用到敵我雙方的行動順序表、
我方九個單位的攻擊順序表、
和敵方九個單位的攻擊順序表

直接寫死的話就可以省掉很多表格
但我覺得先寫死可能會少掉後續很多可能產生的變化
所以就不先寫死
反奧卡姆剃刀原則,「沒有必要,不要亂砍程式碼」
(奧卡姆剃刀原則是:
兩個科學的理論如果都能表達同樣一件事情,我們應該選用表達較簡潔的為準
後來被簡化為
「如無必要,勿增實體」
聽起來很像是廢話,但實體那詞在哲學中是有很麻煩的解釋的
中文似乎沒有相近的概念
所以對於沒學過西洋哲學的人來說,感覺確實是廢話
因此一般人在理解奧卡姆剃刀原則時
是簡單理解為:能用一句話解釋的事情,不應該用更多話描述,"less is more")

程式碼理論上來說是越精簡越好
但問題是你不知道以後客戶會提出怎樣的需求
或者是我們也不管客戶了
如果自己以後想到什麼功能要加的時候,發現那段程式碼被自己精簡掉了
那就~

所以為了確保有新需求產生時能彈性變化
除非是運作在極端或已經確定的環境
(像是古早時期8bit還16bit不清楚的紅白機卡帶
還有編譯器會對程式一些用到的迴圈或沒用到的if敘述在背後做些微調
以增加運行速度或減少記憶體的使用)

不然程式碼不用在一開始的時候就先優化
「過早最佳化是萬惡之源」

嗯,那我先複習一下要網頁檔中要怎麼讀取.txt檔

第一階段程式執行結果
嗯,剛才巴哈忙碌中不能貼圖
現已補圖
那就先貼程式碼吧
用fetch執行速度是很快,但目前的寫法會有圖片順序不穩定的情形
因為fetch是非同步的函數
所以有時第一張載入的圖片不見得是第一張被顯示的圖片

非同步改同步有很多方法
但很多方法都會犧牲掉非同步的速度優勢
像是用遞迴,一個做完再做另一個
又或者是設定狀態,第一個狀態是已載入後再執行第二個
但這些會很可能會讓fetch函數的速度優越性降到跟以前圖檔載入一樣慢的地步
是還有其它的方法,可是我看不太懂,不太清楚有沒有大幅犧牲速度優勢

因此我想到的解決方案是
針對圖檔的透明度動手腳
我把順序第一個的圖檔,第一個像素透明度調整成254(也就是8bit最大正整數255-1)
然後順序第二個的圖檔,第一個像素透明度調整成253(也就是8bit最大正整數255-1)
使用fetch獲取圖檔時,獲得的不是圖檔本身,而是圖檔的二進位內容 blob區塊
因此似乎無法像古早圖檔載入直接針對圖檔名稱進行排序
所以我想要採用別的也就是上述的取巧方式
fetch在全部完成時,會執行.then()裡面的函數
應該是只要在.then的時候對所有圖檔進行排序就能順利滴將打亂的載入順序調回來

因此修改後的程式會分兩區塊
第一個區塊是針對原始圖檔進行第一個畫素的透明度修改
也有可能會獨立出來單獨做個檔案,就像以前仿《Dream Quest》那樣
第二個是載入圖檔後,根據各圖檔第一個像素的透明度進行圖檔正確載入順序的排序
(也許可以跳過圖檔,直接針對blob二進位資料的第一個像素進行操作)
嗯,明天不知道能否順利完成
今天先到這邊休息眼睛好了
要稍微複習下以前引用的javascript canvas操作的
現有putImageData()跟getImageData()那些函數

第一階段的網頁檔或說程式碼如下

<!DOCTYPE html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<html lang="zh-Hant" type="text/html; charset=UTF-8">
<title>仿臥龍吟─圖片素材使用式姬系列</title>
<body>
<script src="jquery-3.7.1.js" type="application/javascript" ></script>
<div id="image-container"></div>
<canvas id="myCanvas" width="640" height="480"></canvas>

<script type="application/javascript" charset="UTF-8">

async function loadFileAndPrintToConsole(url) {
  try {
    const response = await fetch(url);
    const data = await response.text();
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

loadFileAndPrintToConsole('http://localhost/my_action_table.txt');
//這段是載入文字檔,載入的是我方攻擊順序表
//但在後續程式中目前還沒作用
//現階段攻擊順序表大致上長得像
//7,4,1
//8,5,2
//9,6,3
//不一定要行列個數相等,但大概不能空號或變長度
//這部份還有待設計
//但若有要空掉的,我猜實務上應該還是用3*5類似這樣大小的長方形或正方形
//再設定個值當作空值,程式碰到空值時在做縷空的效果這樣

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");

ctx.fillStyle="#FFFFFF";

function Picture(file_name)
{
this.image=new Image();
this.image.id=file_name;
this.image.src=file_name;
}

var finish_num=0;

var board_width = 3;
var board_height = 3;

var board = [];

for(var i=0;i<board_width*board_height-1;i++)
{
board[i]=i;
}
board[board_width*board_height-1]=-1;


shuffle(board);

function re_draw()
{
ctx.fillRect(0,0,c.width,c.height);

for(var i=0;i<elements.length;i++)
{
ctx.drawImage(elements[i].image,i%3*elements[i].image.width,parseInt(i/3)*elements[i].image.height);
}
}

function shuffle(array) {
  var m = array.length, t, i;
  while (m) {
    i = Math.floor(Math.random() * m--);
    t = array[m];
    array[m] = array[i];
    array[i] = t;
  }
}

function click_region(id,left,top,width,height)
{
this.id=id;

var self=this;

this.left=left;
this.top=top;
this.width=width;
this.height=height;
$(c).on('handleClick', function(e, mouse) {
        if (self.left < mouse.x &&
            self.left + self.width > mouse.x &&
            self.top < mouse.y &&
            self.top + self.height > mouse.y) {
if((self.id-1) % board_width !=board_width-1 &&
board[self.id-1] == -1)
{
board[self.id-1] = board[self.id];
board[self.id] = -1;
//ws.send(board);
}
if(board[self.id-3] == -1)
{
board[self.id-3] = board[self.id];
board[self.id] = -1;
//ws.send(board);
}
if((self.id+1) % board_width != 0 &&
board[self.id+1] == -1)
{
board[self.id+1] = board[self.id];
board[self.id] = -1;
//ws.send(board);
}
if(board[self.id+3] == -1)
{
board[self.id+3] = board[self.id];
board[self.id] = -1;
//ws.send(board);
}
        }
    });
}


function my_unit(id,hp,atk,def,seat)
{
this.id=id;
var self=this;

this.hp=hp;
this.atk=atk;
this.def=def;
this.seat=seat;
}

var elements=[];

//for (var i = 0; i < board_width*board_height; i++)
for (var i = 0; i < 9; i++)
{

fetch('http://localhost/0107020101_'+ (i+1).toString() + '_small'+'.png',{
headers: {
      "content-type": "image/png; charset=UTF-8",
      "x-content-type":"nosniff",
      "cache-control":"no-cache",
    },})
  .then(res=>
{
return res.blob()
})
  .then((blob)=>{  

//以下這段特別感謝
//https://rapidapi.com/guides/fetch-images-with-fetch-api

const imageUrl = URL.createObjectURL(blob);
            const imageElement = document.createElement("img");
            imageElement.src = imageUrl;
            const container = document.getElementById("image-container");
            container.appendChild(imageElement);

  });

//elements.push(new Picture("0107020101_"+ (i+1).toString() + "_small"+".png"));

//elements.push(new click_region(i,i%3*c.width/3,parseInt(i/3)*c.height/3,c.width/3,c.height/3));
}
$(c).on('click', function(e) {
var mouse= {
        x: e.pageX - c.offsetLeft,
        y: e.pageY - c.offsetTop
}
         
    //fire off synthetic event containing mouse coordinate info
    $(c).trigger('handleClick', [mouse]);
//re_draw();
});

</script>

</body>
</html>

以下是用來切換圖片透明度的網頁檔
基本上是改以前仿Dream Quest的那篇
(此篇中圖檔名稱為0107020101_1_small.png
預計改良版為選擇檔案上傳來改透明度,好像是file loader什麼的吧
有些忘記)
這檔案如果圖檔小於寬160跟高90的話
可能下載圖片時會顯示 圖片正在載入中的那些文字
因為沒被圖檔資訊覆蓋掉那些畫素

<!DOCTYPE>
<meta charset="utf-8">
<html>
<head>
</head>
<body>
<div id="div_test"></div>
<canvas id="canvas" width="160" height="90" ></canvas>
<script>
var image_number=0;

function Picture(id,img)
{
this.id=id;
this.image = new Image();
this.image.src=img;
var self=this;
this.image.onload = function(){image_number++;}
}

var card_image = new Picture(0,"0107020101_1_small.png");
 
var timer_id = setInterval(check_load,1000);

var ctx = canvas.getContext("2d");

ctx.fillText("圖片載入中",10,10);

function check_load()
{
if(image_number == 1)
{
re_draw();
clearInterval(timer_id);
}
}


function re_draw()
{
ctx.clearRect(0,0,canvas.width,canvas.height);
//必須用clearRect,若用填色的方式,alpha值會被洗掉
ctx.drawImage(card_image.image,0,0,card_image.image.width,card_image.image.height);
//http://www.w3school.com.cn/html5/canvas_getimagedata.asp
var imgData = ctx.getImageData(0,0,card_image.image.width,card_image.image.height);
for (var i=0;i<4;i+=4)
{
imgData.data[i+3]=254;
//把透明度改成254
}
console.log(imgData.data[3]);
ctx.putImageData(imgData,0,0);
document.getElementById("div_test").innerHTML = "圖檔alpha值已轉換成254";
const link = document.createElement('a');
link.style.display = 'none';
link.href = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
link.download = 'test.png';

document.body.appendChild(link);
link.click();
link.remove();
}

</script>
</body>
</html>

以下是用來切換圖片透明度的網頁檔
可以自行選擇上傳檔案的
但目前只能更新0,0這位置畫素的透明度
而且固定更改為254
目前還不能同時載入多個圖檔進行操作

該網頁檔的使用方式


<!DOCTYPE>
<meta charset="utf-8">
<html>
<head>
</head>
<body>
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="image_uploads">Choose images to upload (PNG, JPG)</label>
    <input
      type="file"
      id="image_uploads"
      name="image_uploads"
      accept=".jpg, .jpeg, .png"
      multiple />
  </div>
  <div class="preview">
    <p>No files currently selected for upload</p>
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>
<div id="div_test"></div>
<canvas id="canvas" width="160" height="90" ></canvas>
<script>

//關於檔案上傳請參考
//https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

var image_number=0;

/*function Picture(id,img)
{
this.id=id;
this.image = new Image();
this.image.src=img;
var self=this;
this.image.onload = function(){image_number++;}
}*/

//var card_image = new Picture(0,"0107020101_1_small.png");
 

const input = document.querySelector("input");
const preview = document.querySelector(".preview");

var download_name;
var card_image;

input.style.opacity = 0;

input.addEventListener("change", updateImageDisplay);

function updateImageDisplay() {
  while (preview.firstChild) {
    preview.removeChild(preview.firstChild);
  }

  const curFiles = input.files;
  if (curFiles.length === 0) {
    const para = document.createElement("p");
    para.textContent = "沒有圖檔被選擇到";
    preview.appendChild(para);
  } else {
    const list = document.createElement("ol");
    preview.appendChild(list);

    for (const file of curFiles) {
      const listItem = document.createElement("li");
      const para = document.createElement("p");
      if (validFileType(file)) {
        para.textContent = `File name ${file.name}, file size ${returnFileSize(
          file.size,
        )}.`;
        const image = document.createElement("img");
        image.src = URL.createObjectURL(file);
card_image = image;
card_image.onload = function(){re_draw();}
        image.alt = image.title = file.name;

download_name = file.name;

        listItem.appendChild(image);
        listItem.appendChild(para);
      } else {
        para.textContent = `File name ${file.name}: Not a valid file type. Update your selection.`;
        listItem.appendChild(para);
      }

      list.appendChild(listItem);
    }
  }
}

// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
const fileTypes = [
  "image/apng",
  "image/bmp",
  "image/gif",
  "image/jpeg",
  "image/pjpeg",
  "image/png",
  "image/svg+xml",
  "image/tiff",
  "image/webp",
  "image/x-icon",
];

function validFileType(file) {
  return fileTypes.includes(file.type);
}

function returnFileSize(number) {
  if (number < 1024) {
    return `${number} bytes`;
  } else if (number >= 1024 && number < 1048576) {
    return `${(number / 1024).toFixed(1)} KB`;
  } else if (number >= 1048576) {
    return `${(number / 1048576).toFixed(1)} MB`;
  }
}

const button = document.querySelector("form button");
button.addEventListener("click", (e) => {
  e.preventDefault();
  const para = document.createElement("p");
  para.append("Image uploaded!");
  preview.replaceChildren(para);
});

var timer_id = setInterval(check_load,1000);

var ctx = canvas.getContext("2d");

ctx.fillText("圖片載入中",10,10);

function check_load()
{
if(image_number == 1)
{
re_draw();
clearInterval(timer_id);
}
}


function re_draw()
{
ctx.clearRect(0,0,canvas.width,canvas.height);
//必須用clearRect,若用填色的方式,alpha值會被洗掉
ctx.drawImage(card_image,0,0,card_image.width,card_image.height);
//http://www.w3school.com.cn/html5/canvas_getimagedata.asp
var imgData = ctx.getImageData(0,0,card_image.width,card_image.height);
for (var i=0;i<4;i+=4)
{
imgData.data[i+3]=254;
//把透明度改成254
}
console.log(imgData.data[3]);
ctx.putImageData(imgData,0,0);
document.getElementById("div_test").innerHTML = "圖檔alpha值已轉換成254";
const link = document.createElement('a');
link.style.display = 'none';
link.href = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
link.download = download_name+'.png';

document.body.appendChild(link);
link.click();
link.remove();
}
</script>
</body>
</html>

這修改透明度的網頁檔要改到什麼地步?
大致上就是有些類似小畫家那樣可自行選取範圍變更透明度即可
能的話就進階,能像Photoshop那樣的魔術棒(選取相似顏色當作選取範圍)功能

至於是否要允許多個檔案同時操作就看我修改得順不順利吧
如果要允許修改透明度的圖片範圍
大概會傾向於一次只改一張圖片

12/30實況產出網頁檔
是可以下載透明度修改的圖檔(那個改透明度看不出來,所以我現階段是填綠色)
但由於滑鼠位置似乎不太對
還在修正滑鼠拖曳過程中的圖片顯示選取範圍
因此我先把下載圖片相關的檔案程式碼先停用掉
要改的話在圖片 .onload那邊,把//re_draw()的註解符號//去掉後
再次存檔,重新整理網頁就能用了

滑鼠拖曳過程中是用白色代替,本來是用lighter效果
但由於白色是最亮的,lighter之後看起來就像是用白色填區塊

有兩個問題要修正(1/1時可能還修不好)
一個是滑鼠拖曳時的選取範圍顯示的位置感覺不太對
另一個是當我滑鼠點下去後,往左邊移時
也就是新的座標比點下去的座標還小時
顯示跟選取的問題還要修正

<!DOCTYPE>
<meta charset="utf-8">
<html>
<head>
</head>
<body>
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="image_uploads">Choose images to upload (PNG, JPG)</label>
    <input
      type="file"
      id="image_uploads"
      name="image_uploads"
      accept=".jpg, .jpeg, .png"
      multiple />
  </div>
  <div class="preview">
    <p>No files currently selected for upload</p>
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>
<div id="div_test"></div>
<canvas id="canvas" width="160" height="90" ></canvas>
左上角座標x<input type="text" id="c1x"></input>
左上角座標y<input type="text" id="c1y"></input>
<br>
右下角座標x<input type="text" id="c2x"></input>
右下角座標y<input type="text" id="c2y"></input>
<script>

//關於檔案上傳請參考
//https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file

var image_number=0;

/*function Picture(id,img)
{
this.id=id;
this.image = new Image();
this.image.src=img;
var self=this;
this.image.onload = function(){image_number++;}
}*/

//var card_image = new Picture(0,"0107020101_1_small.png");
 

const input = document.querySelector("input");
const preview = document.querySelector(".preview");

var download_name;
var card_image;

input.style.opacity = 0;

input.addEventListener("change", updateImageDisplay);

function updateImageDisplay() {
  while (preview.firstChild) {
    preview.removeChild(preview.firstChild);
  }

  const curFiles = input.files;
  if (curFiles.length === 0) {
    const para = document.createElement("p");
    para.textContent = "沒有圖檔被選擇到";
    preview.appendChild(para);
  } else {
    const list = document.createElement("ol");
    preview.appendChild(list);

    for (const file of curFiles) {
      const listItem = document.createElement("li");
      const para = document.createElement("p");
      if (validFileType(file)) {
        para.textContent = `File name ${file.name}, file size ${returnFileSize(
          file.size,
        )}.`;
        const image = document.createElement("img");
        image.src = URL.createObjectURL(file);
card_image = image;
card_image.onload = function(){//re_draw();
canvas.addEventListener("mousemove",select_graph_rect_ing,false);}
        image.alt = image.title = file.name;

download_name = file.name;

        listItem.appendChild(image);
        listItem.appendChild(para);
      } else {
        para.textContent = `File name ${file.name}: Not a valid file type. Update your selection.`;
        listItem.appendChild(para);
      }

      list.appendChild(listItem);
    }
  }
}

// https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Image_types
const fileTypes = [
  "image/apng",
  "image/bmp",
  "image/gif",
  "image/jpeg",
  "image/pjpeg",
  "image/png",
  "image/svg+xml",
  "image/tiff",
  "image/webp",
  "image/x-icon",
];

function validFileType(file) {
  return fileTypes.includes(file.type);
}

function returnFileSize(number) {
  if (number < 1024) {
    return `${number} bytes`;
  } else if (number >= 1024 && number < 1048576) {
    return `${(number / 1024).toFixed(1)} KB`;
  } else if (number >= 1048576) {
    return `${(number / 1048576).toFixed(1)} MB`;
  }
}

const button = document.querySelector("form button");
button.addEventListener("click", (e) => {
  e.preventDefault();
  const para = document.createElement("p");
  para.append("Image uploaded!");
  preview.replaceChildren(para);
});

var timer_id = setInterval(check_load,1000);

//var ctx = canvas.getContext("2d");
var ctx =canvas.getContext("2d", { willReadFrequently: true })

ctx.fillText("圖片載入中",10,10);

function check_load()
{
if(image_number == 1)
{
re_draw();
clearInterval(timer_id);
}
}

var target_rect_x1,target_rect_y1;
var target_rect_x2,target_rect_y2;
var tempX,tempY;

canvas.addEventListener("mousedown",select_graph_rect,false);
//canvas.addEventListener("mouseup",select_graph_rect_end,false);


function draw_rect(){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(card_image,0,0,card_image.width,card_image.height);
ctx.globalCompositeOperation = "lighter";
ctx.fillStyle = "#FFFFFF";
ctx.fillRect(target_rect_x1,target_rect_y1,tempX,tempY);
}

function re_draw()
{
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.drawImage(card_image,0,0,card_image.width,card_image.height);
/*
const temp_x1=document.getElementById("c1x");
const temp_y1=document.getElementById("c1y");
const temp_x2=document.getElementById("c2x");
const temp_y2=document.getElementById("c2y");
target_rect_x1 = temp_x1.value;
target_rect_y1 = temp_y1.value;
target_rect_x2 = temp_x2.value;
target_rect_y2 = temp_y2.value;

ctx.clearRect(0,0,canvas.width,canvas.height);
//必須用clearRect,若用填色的方式,alpha值會被洗掉
ctx.drawImage(card_image,0,0,card_image.width,card_image.height);
//http://www.w3school.com.cn/html5/canvas_getimagedata.asp
*/

//ctx.getImageData(0,0,card_image.width,card_image.height);
var imgData =ctx.getImageData(target_rect_x1,target_rect_y1,Math.abs(target_rect_x1-target_rect_x2),Math.abs(target_rect_y1-target_rect_y2));
//for (var i=0;i<4;i+=4) //這是只改第一個像素
//for (var i=0; i< target_rect_y2*Math.abs(target_rect_x1-target_rect_x2)*4 +target_rect_x2*4;i+=4)
for (var i=0; i< Math.abs(target_rect_x1-target_rect_x2)*Math.abs(target_rect_y1-target_rect_y2)*4;i+=4)
{
imgData.data[i+0]=0;
imgData.data[i+1]=255;
imgData.data[i+2]=0;
imgData.data[i+3]=255;
//把透明度改成255
}
ctx.putImageData(imgData,target_rect_x1,target_rect_y1);
document.getElementById("div_test").innerHTML = "圖檔alpha值已轉換成255";
const link = document.createElement('a');
link.style.display = 'none';
link.href = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
link.download = download_name+'.png';

document.body.appendChild(link);
link.click();
link.remove();
}

function select_graph_rect(e){

target_rect_x1=e.pageX- canvas.offsetLeft;
target_rect_y1=e.pageY- canvas.offsetTop;
//取得在canvas內的滑鼠座標
}

function select_graph_rect_end(e){
target_rect_x2=e.pageX- canvas.offsetLeft;
target_rect_y2=e.pageY- canvas.offsetTop;
re_draw();
}

function select_graph_rect_ing(e){
tempX=e.pageX- canvas.offsetLeft;
tempY=e.pageY- canvas.offsetTop;
draw_rect();
}
</script>
</body>
</html>
引用網址:https://home.gamer.com.tw/TrackBack.php?sn=5826946
All rights reserved. 版權所有,保留一切權利

相關創作

留言共 0 篇留言

我要留言提醒:您尚未登入,請先登入再留言

1喜歡★y541258 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:10/31,聊下近況,今... 後一篇:11/16,星穹鐵道─六...

追蹤私訊切換新版閱覽

作品資料夾

Lobster0627全體巴友
大家可以多多來我的YT頻道看看哦(*´∀`)~♥https://www.youtube.com/@lobstersandwich看更多我要大聲說昨天22:43


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】