覺得自己能做到和不能做到,其實只在一念之間。開始寫就距離完成不遠了。
今天的勵志小語送給自己,
其實在鐵人賽開始前,
小的也是一直擔心,
不曉得自己能不能辦到自己訂的目標,
但一旦開始了其實離終點就會越來越近,
其實就算那天只踏出一小步也算是踏出去了。
Day30 後的標題小的就不再做改變了,
畢竟鐵人賽完賽後剩下的就是小的自己的挑戰了。
昨天進度到顯示各角色的招式清單,
但是還沒把選擇做出來,
所以現在先把招式下面的箭頭做出來吧!
這邊我一樣先在 html 寫靜態資料,
再調整 CSS,再改到 JavaScript 做動態顯示。
html:
<div class="skill_menu">
<div class="magiccost_show">
5/<span class="total_magic">240</span>
</div>
<ul class="skill_list">
<li value="0">
<div class="skill_name active">風咒</div>
<div class="flag">▲</div>
</li>
<li value="1">
<div class="skill_name">雷咒</div>
<div class="flag">▲</div>
</li>
<li value="2">
<div class="skill_name">炎咒</div>
<div class="flag">▲</div>
</li>
<li value="3">
<div class="skill_name">風咒</div>
<div class="flag">▲</div>
</li>
<li value="4">
<div class="skill_name">雷咒</div>
<div class="flag">▲</div>
</li>
<li value="5">
<div class="skill_name">炎咒</div>
<div class="flag">▲</div>
</li>
</ul>
</div>
CSS:
.skill_list{
display: flex;
flex-wrap: wrap;
padding: 0 60px;
padding-top: 40px;
li{
position: relative;
display: flex;
flex-direction: column;
align-items: center;
width: 31.33333%;
margin: 20px 1%;
.skill_name{
color: #c2b6a5;
font-size: 44px;
font-family: "新細明體";
font-weight: bold;
text-shadow: 4px 4px #000000; // 文字陰影效果 (X偏移 Y偏移 顏色)
text-align: center;
&.active{
animation-iteration-count: infinite; // 定義動畫重複的次數。你可以用 infinite 來讓動畫永遠重複播放。
animation-direction: alternate; // 定義是否動畫播放完畢後將會反向播放。
// alternate:正反轉輪流播放,奇數次為 0% 到 100%,偶數次為 100% 到 0%,若動畫播放次數只有一次就只會正常播放。
animation-name: skillnameBlink; // 定義關鍵影格 @keyframes 的名字。
animation-duration: 0.3s; // 定義動畫完成一次週期的時間。
}
}
.flag{
display: none;
position: absolute;
bottom: -10px;
color: #ffffff;
font-size: 24px;
}
}
}
@keyframes skillnameBlink{
from {color: #c2b6a5;}
to {color: #d3aa66;}
}
再來 JavaScript 的部份是,
在顯示招式(skillShow)時,在 li 埋 value(為該角色招式的第幾個),
方便之後比對 currentSkill 與 li value。
而現在選到的招式要做箭頭及閃爍顯示(setSkillActiveClass),
這邊比對 .skill_list li value 及 currentSkill,
一致的話表示為所選的招式,
就要在招式名字加上閃爍樣式(.active),
且箭頭(.flag) 要顯示出來;
反之則招式名字移除閃爍樣式(.active),
且箭頭(.flag) 要隱藏起來。
function skillShow(){
console.log("顯示招式");
currentSkill = 0; // 顯示招式預設第1個顯示為現在所選
let skillHTMLStr = "";
skillHTMLStr = `<div class="magiccost_show">
${roleStatus[currentActor].Moves[currentSkill].Cost}/<span class="total_magic">
${roleStatus[currentActor].MagicPoint[0]}</span>
</div>`;
skillHTMLStr += `<ul class="skill_list">`;
for ( let i=0; i<roleStatus[currentActor].Moves.length; i++ ){
skillHTMLStr += `<li value="${i}">
<div class="skill_name">${roleStatus[currentActor].Moves[i].MoveName}</div>
<div class="flag">▲</div>
</li>`;
}
skillHTMLStr += `</ul>`;
skillMenuFlagElement.innerHTML = skillHTMLStr;
setSkillActiveClass(); // 現在選到的招式要做箭頭及閃爍顯示
window.addEventListener("keydown", skillSelect);
}
function skillSelect(event){
console.log("選擇招式");
switch(event.keyCode){
case 27: // ESC鍵
skillMenuFlagElement.style = "display:none";
window.removeEventListener("keydown", skillSelect); // 移除招式選擇的監聽
window.addEventListener("keydown", optionSelect); // 回到原本動作選擇的監聽
break;
case 37: // 左鍵
if ( currentSkill > 0 ){
currentSkill -= 1;
}
setSkillActiveClass(); // 現在選到的招式要做箭頭及閃爍顯示
break;
case 39: // 右鍵
if ( currentSkill < roleStatus[currentActor].Moves.length-1 ){
currentSkill += 1;
}
setSkillActiveClass(); // 現在選到的招式要做箭頭及閃爍顯示
break;
default:
console.log("default");
break;
}
}
function setSkillActiveClass(){
const skillMagicCostElement = document.querySelector(".skill_menu .magiccost_show");
const skillListOptionElement = document.querySelectorAll(".skill_list li");
for ( let i=0; i<skillListOptionElement.length; i++){
// skillListOptionElement[i].childNodes[1] 為招式名字
// skillListOptionElement[i].childNodes[3].style 為箭頭
if ( skillListOptionElement[i].value === currentSkill ){
skillListOptionElement[i].childNodes[1].setAttribute("class","skill_name active");
skillListOptionElement[i].childNodes[3].style = "display:block";
} else{
skillListOptionElement[i].childNodes[1].setAttribute("class","skill_name");
skillListOptionElement[i].childNodes[3].style = "display:none";
}
}
// 更新現在選擇招式所消耗法力
let skillMagicCostHTMLStr = "";
skillMagicCostHTMLStr = `
${roleStatus[currentActor].Moves[currentSkill].Cost}/<span class="total_magic">
${roleStatus[currentActor].MagicPoint[0]}</span>
`;
skillMagicCostElement.innerHTML = skillMagicCostHTMLStr;
}
讓我們看一下目前效果:
非常好,接下來就是要將選擇招式存下來,
然後依據這個進行攻擊。
function skillSelect(event){
console.log("選擇招式");
switch(event.keyCode){
... 前略 ...
case 13: // ENTER鍵
roleStatus[currentActor].Action.SkillSelection = currentSkill;
currentActor ++;
skillMenuFlagElement.style = "display:none";
window.removeEventListener("keydown", skillSelect); // 移除招式選擇的監聽
roleActionSelect();
break;
default:
console.log("default");
break;
}
}
function roleActionExecute(){
console.log(`${new Date()}`);
console.log(`開始執行動作,現在輪到 ${roleStatus[currentActor].Name}`);
console.log(`${roleStatus[currentActor].Name} 選擇的動作是 ${roleStatus[currentActor].Action.OptionSelection}`);
if ( currentActor < 2 ){
let attackQty;
switch(roleStatus[currentActor].Action.OptionSelection){
case "attack": // 動作為攻擊
attackQty = roleStatus[currentActor].AttackPower - roleStatus[2].DefensePower;
break;
case "skill": // 動作為招式
let skillSelection = roleStatus[currentActor].Action.SkillSelection;
attackQty = roleStatus[currentActor].Moves[skillSelection].Cost*roleStatus[currentActor].MagicAttackPower*0.5 - roleStatus[2].DefensePower;
// 法力消耗
roleStatus[currentActor].MagicPoint[0] -= roleStatus[currentActor].Moves[skillSelection].Cost;
break;
default:
console.log("default");
break;
}
attackQty = parseInt(attackQty);
roleStatus[2].HealthPoint[0] -= attackQty;
monsterBloodMinusElement.textContent = `-${attackQty}`;
console.log(`現在 ${roleStatus[2].Name} 的血量為 ${roleStatus[2].HealthPoint[0]}`);
// 重讀角色血量&法力
roleStatusRefresh();
... 後略 ...
}
然後因為有多個地方用到重讀角色血量跟法力,
所以我將重讀角色血量跟法力弄成函數,
方便重複呼叫。
function roleStatusRefresh(){
// 李逍遙 HP MP 顯示
boyStatusElement.innerHTML = `<p class="HP">${roleStatus[0].HealthPoint[0]}/${roleStatus[0].HealthPoint[1]}</p>`;
boyStatusElement.innerHTML += `<p class="MP">${roleStatus[0].MagicPoint[0]}/${roleStatus[0].MagicPoint[1]}</p>`;
// 趙靈兒 HP MP 顯示
girlStatusElement.innerHTML = `<p class="HP">${roleStatus[1].HealthPoint[0]}/${roleStatus[1].HealthPoint[1]}</p>`;
girlStatusElement.innerHTML += `<p class="MP">${roleStatus[1].MagicPoint[0]}/${roleStatus[1].MagicPoint[1]}</p>`;
}
好,讓我們看看目前成果吧!
李逍遙選擇御劍術:
李逍遙御劍術攻擊,法力有消耗:
趙靈兒選擇炎咒:
趙靈兒炎咒攻擊,法力有消耗:
耶!本日打完收工!
其實今天動工中間遇到很多小 bug,
但覺得再把它記錄上來會很亂,
就自己默默解掉了XD
例如第二回合攻擊完,
怪的血條反而會恢復全滿,
這是因為我沒有考量到怪被砍完可能血量會小於 0,
width: -10% => 這樣寬度顯示就會有問題,
所以這邊要增加如果 monsterBloodWidth <=0 要設為 0 的判斷。
// 怪的血條寬度設定
let monsterBloodWidth = (roleStatus[2].HealthPoint[0]/roleStatus[2].HealthPoint[1])*100;
if ( monsterBloodWidth <=0 ) monsterBloodWidth = 0; // 避免monsterBloodWidth為負值時會有問題
monsterBloodElement.style = `width: ${monsterBloodWidth}%`;
Code 越寫越多,
感覺該來整理一下了orz
還有 SCSS,
很多地方該改用變數管理了。
明天進度就來弄戰鬥勝利的畫面跟音效好了XD