You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JS/HTML/CSS战斗游戏攻击按钮仅单次点击生效问题求助

问题

开发玩家对战敌人的简易战斗游戏,玩家拥有4个攻击按钮,点击按钮后生成随机数判定攻击先手,再生成随机数确定伤害值并累加到HP进度条中。但目前按钮仅首次点击能触发伤害计算,后续点击完全无效。

逻辑说明:

  • attackOrder():负责判定攻击先手
  • start():启动攻击流程
  • enemyAttack():生成敌人伤害

附完整代码:

HTML

<!DOCTYPE html>
<html>
<!-- Head -->
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Mon Fight!</title>
    <link rel="stylesheet" href="style.css">
    <style>
        body {
          background-image: url('battleBackground.png');
          background-repeat: no-repeat;
          background-position: 50% 1%;
        }
        </style>
        
  </head>
<!-- Body -->
<body> 
    <div class="container">
<!-- moves -->        
        <div class="actions">
            <button id = "attackMove1" class="userMove">Quick Attack</button>
            <button id = "attackMove2" class="userMove">Water Gun</button>
        </div>
        <div class="actions">
            <button id = "attackMove3" class="userMove">Lick</button>
            <button id = "attackMove4" class="userMove">Pound</button>
        </div>
<!-- user character -->
        <div class="userCharacter">
            <img class="userSprite" src="https://www.pokencyclopedia.info/sprites/3ds/ani-b_6/3a-b__656__xy.gif" style = "position: absolute; left: 30%; top:50%">
            <progress id = "userHP" value="0" max="100"></progress>
        </div>       
<!-- enemy character-->        
        <div class="monsterCharacter">
            <img class="enemySprite" src="https://pa1.aminoapps.com/6202/8b1a1344c2f3c1e5d8251d998f8e9b63e193c81f_hq.gif" style = "position: absolute; left: 58%; top:27%">
            <progress id = "monsterHP" value="0" max="100"></progress>
        </div>
    </div>  
    <script src="script.js"></script>      
</body>
</html>

CSS

body {
    background-color: #449C6A;
  }
  
progress {
    width: 300px;
    height : 25px;
    border: 2px solid #FFE5B4;
    
 }
 progress::-webkit-progress-bar {
    background-color: green;
 }
 progress::-webkit-progress-value {
    background-color: red;
 }

 body{
    overflow:hidden;
 }

 .container{
    width: 95%;
    height: 100vh;
    margin: auto;
    display: flex;
    align-items: end;
    justify-content: center;
        /*Delete after done*/
    border: 1px solid black;
 }

 .actions{
    width: 370px;
    margin: 0;
    border-radius: 2px;
    padding: 15px 15px 20px 20px;
    align-items: end;
    justify-content: center;
    position: static;
        /*Delete after done*/
    border: 1px solid black;
  }


.userMove{
    width: 95%;
    height: 40px;
    border-radius: 2px;
    border: none;
    border-radius: 2rem;
    margin-top: 3px;
    margin-bottom: 15px;
    background: white(0, 0, 0);
}

.userMove:hover{background-color: rgba(255, 255, 255, 0.514);}

#userHP{
    position:fixed;
    top:72%;
    left:26.5%;
  
}
#monsterHP{
    position:fixed;
    top:50%;
    left:57%;
  
}

img.userSprite{
    width: 9%;
    height: auto;
}

img.enemySprite{
    width: 13%;
    height: auto;
  }

JavaScript

var userDamage, monsterDamage = 0;
var move = 0;
var priority;
var randomNum = 0;
var someoneIsAlive = true;

    attackMove1.addEventListener("click", function(e){
        attackOrder();
        move = 1;

    });
    attackMove2.addEventListener("click", function(e){
        attackOrder();
        move = 2;

    });
    attackMove3.addEventListener("click", function(e){
        attackOrder();
        move = 3;

    });
    attackMove4.addEventListener("click", function(e){
        attackOrder();
        move = 4;
    });
    


function attackOrder(){
    let froakieSpeed = Math.floor((Math.random()* 62));
    let goomySpeed = Math.floor((Math.random()* 55));
    if (froakieSpeed > goomySpeed)
       {
        priority = "froakie";
       } 
    else {
        priority = "goomy"
        if (move = 1){priority = "froakie"};
    }
    start();
}
    
function start(){
        if (priority = "froakie"){
            userAttack();
            enemyAttack();
        } else {
            enemyAttack();
            userAttack();
        }   
}
var poisonDamage;
/*
Quick Attack (unconditionally attacks first), 
Watergun, 
Lick (afflicts poison), 
Pound  
*/
function userAttack(){
    randomNum = Math.floor((Math.random() * 6));
    switch(randomNum){
        case 0:
            userDamage = 1;
            break;
        case 1:
            userDamage = 10;
            break;
        case 2:
            userDamage = 10;
            break;
        case 3:
            userDamage = 15;
            break;
        case 4:
            userDamage = 15;
            break;
        case 5:
            userDamage = 20;
            break;
        case 6:
            userDamage = 40;
            break;        
    }
    if (move = 3){
        poisonStatus();   
    } 

    if (poisonStatus = true){
        userDamage += 5;
    }
    let monsterHP = document.getElementById("monsterHP")
    monsterHP.value += userDamage;
    if (monsterHP.value >= 100){
        alert("You Win!");
    }
}

function enemyAttack(){
        randomNum = Math.floor((Math.random() * 6));
    switch(randomNum){
        case 0:
            monsterDamage = 1;
            break;
        case 1:
            monsterDamage = 10;
            break;
        case 2:
            monsterDamage = 10;
            break;
        case 3:
            monsterDamage = 15;
            break;
        case 4:
            monsterDamage = 15;
            break;
        case 5:
            monsterDamage = 20;
            break;
        case 6:
            monsterDamage = 40;
            break; 

    }
    let userHP = document.getElementById("userHP")
    userHP.value += monsterDamage;

    if (userHP.value >= 100){
        alert("You Lose! :(");
    }
}

var poisonBreak;
function poisonStatus(){
    poisonBreak = Math.floor((Math.random() * 2 ));
    if (poisonBreak = 2){
        poisonDamage = false;
    } else {
        poisonDamage = true;
    }   
}

userDamage, monsterDamage = 0;
randomNum = 0;
move = 0;

问题原因与修复方案

核心错误点

  1. 赋值运算符替代比较运算符:代码中大量使用=(赋值)而非===(严格比较),导致逻辑判断完全失效,比如if (priority = "froakie")会直接将priority设为"froakie",而非判断是否相等。
  2. 按钮点击逻辑顺序错误:点击按钮时先调用attackOrder()再设置move,导致attackOrder()中无法获取当前点击的技能类型,先手判定逻辑出错。
  3. 进度条值类型问题:progress元素的value是字符串类型,直接用+=会触发字符串拼接而非数值累加,比如"0"+10变成"010",后续>=100的判断永远为真,触发alert后用户误以为按钮失效。
  4. 变量初始化冗余:代码末尾重复初始化变量,覆盖了当前战斗状态,导致后续逻辑混乱。

修复后的JavaScript代码

var userDamage = 0, monsterDamage = 0;
var move = 0;
var priority;
var randomNum = 0;
var someoneIsAlive = true;
var poisonDamage = false; // 初始化毒状态为false

// 调整点击顺序:先设置当前技能,再执行攻击逻辑
attackMove1.addEventListener("click", function(e){
    move = 1;
    attackOrder();
});
attackMove2.addEventListener("click", function(e){
    move = 2;
    attackOrder();
});
attackMove3.addEventListener("click", function(e){
    move = 3;
    attackOrder();
});
attackMove4.addEventListener("click", function(e){
    move = 4;
    attackOrder();
});

function attackOrder(){
    let froakieSpeed = Math.floor(Math.random() * 62);
    let goomySpeed = Math.floor(Math.random() * 55);
    // Quick Attack无条件先手,或玩家速度更高时先手
    if (move === 1 || froakieSpeed > goomySpeed) {
        priority = "froakie";
    } else {
        priority = "goomy";
    }
    start();
}

function start(){
    if (priority === "froakie"){
        userAttack();
        // 敌人攻击前先判断是否已战败
        if (parseInt(document.getElementById("monsterHP").value) < 100) {
            enemyAttack();
        }
    } else {
        enemyAttack();
        // 玩家攻击前先判断是否已战败
        if (parseInt(document.getElementById("userHP").value) < 100) {
            userAttack();
        }
    }
}

function userAttack(){
    randomNum = Math.floor(Math.random() * 7); // 生成0-6的随机数,需乘7
    switch(randomNum){
        case 0:
            userDamage = 1;
            break;
        case 1:
        case 2:
            userDamage = 10;
            break;
        case 3:
        case 4:
            userDamage = 15;
            break;
        case 5:
            userDamage = 20;
            break;
        case 6:
            userDamage = 40;
            break;        
    }
    // Lick技能触发毒状态判断
    if (move === 3){
        poisonStatus();
    } 

    // 毒状态生效时追加伤害
    if (poisonDamage){
        userDamage += 5;
    }
    let monsterHP = document.getElementById("monsterHP");
    // 转换为数值后累加,避免字符串拼接
    monsterHP.value = parseInt(monsterHP.value) + userDamage;
    if (monsterHP.value >= 100){
        alert("You Win!");
        // 获胜后禁用所有攻击按钮
        document.querySelectorAll('.userMove').forEach(btn => btn.disabled = true);
    }
}

function enemyAttack(){
    randomNum = Math.floor(Math.random() * 7);
    switch(randomNum){
        case 0:
            monsterDamage = 1;
            break;
        case 1:
        case 2:
            monsterDamage = 10;
            break;
        case 3:
        case 4:
            monsterDamage = 15;
            break;
        case 5:
            monsterDamage = 20;
            break;
        case 6:
            monsterDamage = 40;
            break; 
    }
    let userHP = document.getElementById("userHP");
    userHP.value = parseInt(userHP.value) + monsterDamage;
    if (userHP.value >= 100){
        alert("You Lose! :(");
        // 战败后禁用所有攻击按钮
        document.querySelectorAll('.userMove').forEach(btn => btn.disabled = true);
    }
}

function poisonStatus(){
    // 生成0或1的随机数,50%概率触发毒状态
    poisonBreak = Math.floor(Math.random() * 2);
    poisonDamage = poisonBreak !== 0;
}

额外优化

  • 简化了switch语句的重复分支,提升代码可读性
  • 增加了战败/获胜后禁用按钮的逻辑,避免无效重复点击
  • 修复了Quick Attack的先手逻辑(原代码中该技能的先手判断位置错误)
  • 初始化poisonDamage为false,避免未定义状态导致的逻辑异常

内容的提问来源于stack exchange,提问作者Potato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 13:24:50