JS基础知识——创建角色扮演游戏

code with freecodecamp。

script 元素用于将 JavaScript 加载到 HTML 文件中。
<script src="./script.js"></script>

访问 JavaScript 中的属性的方法:

1、使用点符号。下面是一个用点表示法将按钮的 onclick 属性设置为函数引用的例子。

示例代码
button.onclick = myFunction;

在这个例子中,button 是按钮元素,而 myFunction 是对函数的引用。 当按钮被点击时,myFunction 将被调用。

2、括号表示法([])。 如果你尝试访问的对象的属性名称中包含空格,则需要使用括号表示法。

arduino 复制代码
const spaceObj = {
  "Space Name": "Kirk",
};

spaceObj["Space Name"]; // "Kirk"

index.html:

复制代码
<html lang="en">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="./styles.css">
    <title>RPG - Dragon Repeller</title>
  </head>
  <body>
    <div id="game">
      <div id="stats">
        <span class="stat">XP: <strong><span id="xpText">0</span></strong></span>
        <span class="stat">Health: <strong><span id="healthText">100</span></strong></span>
        <span class="stat">Gold: <strong><span id="goldText">50</span></strong></span>
      </div>
      <div id="controls">
        <button id="button1">Go to store</button>
        <button id="button2">Go to cave</button>
        <button id="button3">Fight dragon</button>
      </div>
      <div id="monsterStats">
        <span class="stat">Monster Name: <strong><span id="monsterName"></span></strong></span>
        <span class="stat">Health: <strong><span id="monsterHealth"></span></strong></span>
      </div>
      <div id="text">
        Welcome to Dragon Repeller. You must defeat the dragon that is preventing people from leaving the town. You are in the town square. Where do you want to go? Use the buttons above.
      </div>
    </div>
    <script src="./script.js"></script>
  </body>
</html>

script 元素不应该放在 head 中

当浏览器加载HTML文档时,它会从上到下逐行解析文档。当遇到<script>元素时,浏览器会立即停止HTML解析,下载并执行该脚本,然后才继续解析文档的其余部分。(最佳实践:放在body末尾)

  1. 渲染阻塞(白屏时间延长) 脚本在head中 → 必须先加载执行脚本 → 然后渲染页面内容 脚本在body末尾 → 先渲染页面内容 → 然后加载执行脚本
  2. DOM访问时机问题 放在head中的脚本运行时,body中的元素尚未解析和创建 尝试访问尚未存在的DOM元素会导致JavaScript错误
  3. 性能与用户体验 用户需要等待更长时间才能看到页面内容 对于慢速网络连接,这个问题更加明显 影响页面加载速度和SEO排名

styles.css

body 复制代码
  background-color: #0a0a23;
}

#text {
  background-color: #0a0a23;
  color: #ffffff;
  padding: 10px;
}

#game {
  max-width: 500px;
  max-height: 400px;
  background-color: #ffffff;
  color: #ffffff;
  margin: 30px auto 0px;
  padding: 10px;
}

#controls,
#stats {
  border: 1px solid #0a0a23;
  padding: 5px;
  color: #0a0a23;
}

#monsterStats {
  display: none;
  border: 1px solid #0a0a23;
  padding: 5px;
  color: #ffffff;
  background-color: #c70d0d;
}

.stat {
  padding-right: 10px;
}

button {
  cursor: pointer;
  color: #0a0a23;
  background-color: #feac32;
  background-image: linear-gradient(#fecc4c, #ffac33);
  border: 3px solid #feac32;
}

script.js

javascript 复制代码
let xp = 0;
let health = 100;
let gold = 50;
let currentWeapon = 0;
let fighting;
let monsterHealth;
let inventory = ["stick"];//数组封装

/*JavaScript 使用文档对象模型(又称 DOM)与 HTML 交互。 DOM 是一个代表 HTML 的对象树。可以使用 document 对象来访问 HTML,其代表你的整个HTML文档。
在HTML中找到特定元素的一个方法是使用 querySelector() 函数。 
querySelector() 方法需要一个 CSS 选择器作为参数,并返回与该选择器匹配的第一个元素。 例如,要在 HTML 中找到 <h1> 元素,
示例代码:
let h1 = document.querySelector("h1");
请注意, h1 是一个字符串,它匹配你将要使用的 CSS 选择器。*/

const button1 = document.querySelector('#button1');
const button2 = document.querySelector("#button2");
const button3 = document.querySelector("#button3");
const text = document.querySelector("#text");
const xpText = document.querySelector("#xpText");
const healthText = document.querySelector("#healthText");
const goldText = document.querySelector("#goldText");
const monsterStats = document.querySelector("#monsterStats");
const monsterName = document.querySelector("#monsterName");
const monsterHealthText = document.querySelector("#monsterHealth");
const weapons = [
  { name: 'stick', power: 5 },
  { name: 'dagger', power: 30 },
  { name: 'claw hammer', power: 50 },
  { name: 'sword', power: 100 }
];
const monsters = [
  {
    name: "slime",
    level: 2,
    health: 15
  },
  {
    name: "fanged beast",
    level: 8,
    health: 60
  },
  {
    name: "dragon",
    level: 20,
    health: 300
  }
]
const locations = [
  {
    name: "town square",
    "button text": ["Go to store", "Go to cave", "Fight dragon"],
    "button functions": [goStore, goCave, fightDragon],
    text: "You are in the town square. You see a sign that says \"Store\"."
  },
  {
    name: "store",
    "button text": ["Buy 10 health (10 gold)", "Buy weapon (30 gold)", "Go to town square"],
    "button functions": [buyHealth, buyWeapon, goTown],
    text: "You enter the store."
  },
  {
    name: "cave",
    "button text": ["Fight slime", "Fight fanged beast", "Go to town square"],
    "button functions": [fightSlime, fightBeast, goTown],
    text: "You enter the cave. You see some monsters."
  },
  {
    name: "fight",
    "button text": ["Attack", "Dodge", "Run"],
    "button functions": [attack, dodge, goTown],
    text: "You are fighting a monster."
  },{
    name: "kill monster",//如果对象的属性名称(键)中包含空格,则需要在名称周围使用单引号或双引号。
    "button text": ["Go to town square", "Go to town square", "Go to town square"],
    "button functions": [goTown, goTown, easterEgg],
    //字符串中包含引号:1、双引号为单引号 ',然后在 "string" 周围加上双引号。2、转义引号
    text: 'The monster screams "Arg!" as it dies. You gain experience points and find gold.'
  },
 {
    name: "lose",
    "button text": ["REPLAY?", "REPLAY?", "REPLAY?"],
    "button functions": [restart, restart, restart],
    text: "You die. &#x2620;"
  },
  { 
    name: "win", 
    "button text": ["REPLAY?", "REPLAY?", "REPLAY?"], 
    "button functions": [restart, restart, restart], 
    text: "You defeat the dragon! YOU WIN THE GAME! &#x1F389;" 
  },
  {
    name: "easter egg",
    "button text": ["2", "8", "Go to town square?"],
    "button functions": [pickTwo, pickEight, goTown],
    text: "You find a secret game. Pick a number above. Ten numbers will be randomly chosen between 0 and 10. If the number you choose matches one of the random numbers, you win!"
  }
];

// initialize buttons
button1.onclick = goStore;
button2.onclick = goCave;
button3.onclick = fightDragon;

function update(location) {
//style 属性用于访问元素的内联样式,display 属性用于设置元素的可见性。
  monsterStats.style.display = "none";
  button1.innerText = location["button text"][0];
  button2.innerText = location["button text"][1];
  button3.innerText = location["button text"][2];
  button1.onclick = location["button functions"][0];
  button2.onclick = location["button functions"][1];
  button3.onclick = location["button functions"][2];
  //innerHTML 属性允许你使用 JavaScript 访问或修改 HTML 元素内的内容。
  text.innerHTML = location.text;
}

function goTown() {
  update(locations[0]);
}

function goStore() {
  update(locations[1]);
}

function goCave() {
  update(locations[2]);
}

function buyHealth() {
  if (gold >= 10) {
    gold -= 10;
    health += 10;
    goldText.innerText = gold;
    healthText.innerText = health;
  } else {
    text.innerText = "You do not have enough gold to buy health.";
  }
}

function buyWeapon() {
  if (currentWeapon < weapons.length - 1) {
    if (gold >= 30) {
      gold -= 30;
      currentWeapon++;
      goldText.innerText = gold;
      let newWeapon = weapons[currentWeapon].name;
      text.innerText = "You now have a " + newWeapon + ".";
      inventory.push(newWeapon);
      text.innerText += " In your inventory you have: " + inventory;
    } else {
      text.innerText = "You do not have enough gold to buy a weapon.";
    }
  } else {
    text.innerText = "You already have the most powerful weapon!";
    button2.innerText = "Sell weapon for 15 gold";
    button2.onclick = sellWeapon;
  }
}

function sellWeapon() {
  if (inventory.length > 1) {
    gold += 15;
    goldText.innerText = gold;
    let currentWeapon = inventory.shift();
    text.innerText = "You sold a " + currentWeapon + ".";
    text.innerText += " In your inventory you have: " + inventory;
  } else {
    text.innerText = "Don't sell your only weapon!";
  }
}

function fightSlime() {
  fighting = 0;
  goFight();
}

function fightBeast() {
  fighting = 1;
  goFight();
}

function fightDragon() {
  fighting = 2;
  goFight();
}

/*innerText 属性控制 HTML 元素中显示的文本。
示例代码
<p id="info">Demo content</p> 
示例代码
const info = document.querySelector("#info"); 
info.innerText = "Hello World"; 
上面的例子会将 p 元素的文本从 Demo content 更改为 Hello World。
*/
function goFight() {
  update(locations[3]);
  monsterHealth = monsters[fighting].health;
  monsterStats.style.display = "block";
  monsterName.innerText = monsters[fighting].name;
  monsterHealthText.innerText = monsterHealth;
}

function attack() {
  text.innerText = "The " + monsters[fighting].name + " attacks.";
  text.innerText += " You attack it with your " + weapons[currentWeapon].name + ".";
  health -= getMonsterAttackValue(monsters[fighting].level);
  //JavaScript 中的 Math 对象包含数学常量和函数的静态属性和方法。
  //Math.random(),它生成一个从 0(含)到 1(不含)的随机数。
  //Math.floor(),它将给定的数字向下舍入为最接近的整数。
  if (isMonsterHit()) {
    monsterHealth -= weapons[currentWeapon].power + Math.floor(Math.random() * xp) + 1;    
  } else {
    text.innerText += " You miss.";
  }
  healthText.innerText = health;
  monsterHealthText.innerText = monsterHealth;
  if (health <= 0) {
    lose();
  } else if (monsterHealth <= 0) {
    if (fighting === 2) {
      winGame();
    } else {
      defeatMonster();
    }
  }
  if (Math.random() <= .1 && inventory.length !== 1) {
    text.innerText += " Your " + inventory.pop() + " breaks.";
    currentWeapon--;
  }
}

function getMonsterAttackValue(level) {
  const hit = (level * 5) - (Math.floor(Math.random() * xp));
  console.log(hit);
  //三元运算符是一个条件运算符,可以用作单行 if-else 语句。 语法是:condition ? expressionIfTrue : expressionIfFalse。
  return hit > 0 ? hit : 0;
}
/*逻辑 OR 运算符 ||:如果第一个值是真值,则逻辑或运算符将使用第一个值 - 即除 NaN、null、undefined、0、-0、0n、"" 和 false 之外的任何值。 否则,它将使用第二个值。*/

function isMonsterHit() {
  return Math.random() > .2 || health < 20;
}

function dodge() {
  text.innerText = "You dodge the attack from the " + monsters[fighting].name;
}

function defeatMonster() {
  gold += Math.floor(monsters[fighting].level * 6.7);
  xp += monsters[fighting].level;
  goldText.innerText = gold;
  xpText.innerText = xp;
  update(locations[4]);
}

function lose() {
  update(locations[5]);
}

function winGame() {
  update(locations[6]);
}

function restart() {
  xp = 0;
  health = 100;
  gold = 50;
  currentWeapon = 0;
  inventory = ["stick"];
  goldText.innerText = gold;
  healthText.innerText = health;
  xpText.innerText = xp;
  goTown();
}

function easterEgg() {
  update(locations[7]);
}

function pickTwo() {
  pick(2);
}

function pickEight() {
  pick(8);
}

function pick(guess) {
  const numbers = [];
  while (numbers.length < 10) {
    numbers.push(Math.floor(Math.random() * 11));
  }
  text.innerText = "You picked " + guess + ". Here are the random numbers:\n";
  //for 循环由三个以分号分隔的表达式声明:for (a; b; c),其中 a 是初始化表达式,b 是条件,c 是最终表达式。
  for (let i = 0; i < 10; i++) {
    text.innerText += numbers[i] + "\n";
  }
  //.includes() 方法确定数组是否包含元素,并将返回 true 或 false。
  if (numbers.includes(guess)) {
    text.innerText += "Right! You win 20 gold!";
    gold += 20;
    goldText.innerText = gold;
  } else {
    text.innerText += "Wrong! You lose 10 health!";
    health -= 10;
    healthText.innerText = health;
    if (health <= 0) {
      lose();
    }
  }
}
相关推荐
傻梦兽2 小时前
用 scheduler.yield() 让你的网页应用飞起来⚡
前端·javascript
然我2 小时前
搞定异步任务依赖:Promise.all 与拓扑排序的妙用
前端·javascript·算法
Focusbe2 小时前
为什么 “大前端” 需要 “微前端”?
前端·后端·架构
usagisah2 小时前
为 CSS-IN-JS 正个名,被潮流抛弃并不代表无用,与原子类相比仍有一战之力
前端·javascript·css
阿笑带你学前端2 小时前
Flutter应用自动更新系统:生产环境的挑战与解决方案
前端·flutter
不一样的少年_2 小时前
老板催:官网打不开!我用这套流程 6 分钟搞定
前端·程序员·浏览器
徐小夕2 小时前
支持1000+用户同时在线的AI多人协同文档JitWord,深度剖析
前端·vue.js·算法
小公主3 小时前
面试必问:跨域问题的原理与解决方案
前端
Cache技术分享3 小时前
194. Java 异常 - Java 异常处理之多重捕获
前端·后端