오픈 소스 모험: 에피소드 57: BATTLETECH 무기 앱 확장

앱을 개선할 시간입니다. 이 에피소드의 주요 기능은 다음과 같습니다.
  • 안정성 손상 표시
  • 안정성 손상 및 최소 범위를
  • 형식으로 포함
  • 무기 유형 표시
  • 간접 화재 표시기 표시 - 🚀 이모티콘 포함
  • 디스플레이 약간 정리

  • Slider.svelte



    구성 요소에 추가 속성step을 추가했습니다. Svelte에서 속성을 선택 사항으로 표시하려면 속성이 undefined 인 경우에도 기본값을 지정해야 합니다. 이렇게 하지 않으면 경고만 표시됩니다.

    <script>
    export let label, min, max, value, format, step = undefined
    let id = Math.random().toString(36).slice(2)
    </script>
    
    <label for={id}>{label}:</label>
    <input type="range" {min} {max} {step} bind:value id={id} />
    <span>{format(value)}</span>
    


    Form.svelte



    양식에는 이제 3개의 추가 슬라이더가 있으며 슬라이더와 열 보상을 위해 step를 사용합니다.

    이제 이 기능이 있으므로 0-100 슬라이더를 0.01 단계의 0-1 범위로 전환하고 싶을 수 있습니다. 지금은 두 가지가 혼합되어 있습니다.

    <script>
    import Slider from "./Slider.svelte"
    
    export let ammoRounds
    export let heatPercentage
    export let doubleHeatSinksPercentage
    export let rangeAtLeast
    export let damageValue
    export let stabDamageValue
    </script>
    
    <form>
      <Slider label="Ammo for how many rounds" bind:value={ammoRounds} min={1} max={30} format={(v) => `${v}`}/>
      <Slider label="Heat to compensate for" bind:value={heatPercentage} min={0} max={100} step={5} format={(v) => `${v}%`}/>
      <Slider label="How many double heat sinks" bind:value={doubleHeatSinksPercentage} min={0} max={100} format={(v) => `${v}%`}/>
      <Slider label="Normal damage value" bind:value={damageValue} min={0} max={1} step={0.01} format={(v) => `${v}`}/>
      <Slider label="Stability damage value" bind:value={stabDamageValue} min={0} max={1} step={0.01} format={(v) => `${v}`}/>
      <Slider label="Range at least" bind:value={rangeAtLeast} min={90} max={720} step={30} format={(v) => `${v}m`}/>
    </form>
    
    <style>
    form {
      display: grid;
      grid-template-columns: auto auto auto;
      margin-bottom: 1em;
    }
    </style>
    


    App.svelte



    모든 추가 기능이 실제로 코드를 너무 복잡하게 만들지는 않았지만 어느 시점에서 리팩토링을 원할 수 있습니다.

    소수점 이하 두 자리로 반올림 기능을 Row 구성 요소로 옮겼습니다. 여기서 그렇게 하면 약간의 반올림 문제가 발생하고 SRM2/SRM4/SRM6은 너무 많은 반올림으로 인해 값이 약간 다릅니다.

    <script>
    import {sortBy} from "lodash"
    import data from "./data.json"
    import Form from "./Form.svelte"
    import Headers from "./Headers.svelte"
    import Row from "./Row.svelte"
    
    let ammoRounds = 10
    let heatPercentage = 80
    let doubleHeatSinksPercentage = 0
    let rangeAtLeast = 90
    let damageValue = 1.0
    let stabDamageValue = 0.5
    
    $: heatSinkingPerTon = 3.0 + 3.0 * doubleHeatSinksPercentage / 100
    $: costPerHeat = (heatPercentage / 100) / heatSinkingPerTon
    
    let sortedData
    $: {
      for (let row of data) {
        row.value = row.shots * (row.baseDamage * damageValue + row.baseStabDamage * stabDamageValue)
        row.ammoWeight = ammoRounds * row.ammoTonnagePerShot
        row.cost = row.tonnage + row.ammoWeight + row.heat * costPerHeat
        row.ratio = row.value / row.cost
        row.id = Math.random().toString(36).slice(2)
      }
      sortedData = sortBy(data, [(x) => -x.ratio, (x) => x.name])
    }
    </script>
    
    <h1>BATTLETECH Weapons Data</h1>
    
    <Form bind:ammoRounds bind:heatPercentage bind:doubleHeatSinksPercentage bind:rangeAtLeast bind:damageValue bind:stabDamageValue />
    
    <table>
      <Headers />
      {#each sortedData as row (row.id)}
        {#if row.maxRange >= rangeAtLeast}
          <Row data={row} />
        {/if}
      {/each}
    </table>
    
    <style>
    :global(body) {
      margin: 0;
      min-height: 100vh;
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    table :global(tr):nth-child(even) {
      background-color: #f2f2f2;
    }
    table :global(tr):nth-child(odd) {
      background-color: #e0e0e0;
    }
    </style>
    


    헤더.svelte



    이것에 대해 너무 흥미로운 것은 없습니다.

    <tr>
      <th>Name</th>
      <th>Bonus</th>
      <th>Type</th>
      <th>Damage</th>
      <th>Stab Damage</th>
      <th>Heat</th>
      <th>Weight</th>
      <th>Ammo Weight</th>
      <th>Range</th>
      <th>Value</th>
      <th>Cost</th>
      <th>Ratio</th>
    </tr>
    


    행.svelte



    여기에 더 많은 기능이 있습니다. 아마도 typeSymbol는 데이터 익스포터로 옮겨야 할 것 같은데, 게임 파일에서 지원 무기가 AntiPersonnel로 표시되는 것을 몰랐습니다.

    가독성을 높이기 위해 0개의 필드를 비우고 있지만 MG++의 가중치 필드는 비우지 않습니다.

    <script>
    export let data
    
    let round100 = (v) => Math.round(v * 100) / 100
    
    let {baseName, bonus, category, baseStabDamage, heat, shots, baseDamage, tonnage, maxRange, value, cost, ratio, ammoWeight, indirectFire} = data
    let damage, stabDamage
    if (shots == 1) {
      damage = baseDamage
      stabDamage = baseStabDamage
    } else {
      damage = `${shots}x${baseDamage}`
      stabDamage = `${shots}x${baseStabDamage}`
    }
    if (heat == 0) {
      heat = ""
    }
    if (baseStabDamage == 0) {
      stabDamage = ""
    }
    if (ammoWeight == 0) {
      ammoWeight = ""
    }
    let typeSymbol = (category == "AntiPersonnel") ? "S" : category.substring(0, 1)
    </script>
    
    <tr>
      <td>{baseName}</td>
      <td>{bonus}</td>
      <td>{typeSymbol}</td>
      <td>{damage}</td>
      <td>{stabDamage}</td>
      <td>{heat}</td>
      <td>{tonnage}</td>
      <td>{round100(ammoWeight)}</td>
      <td>
        {maxRange}m
        {#if indirectFire}
          🚀
        {/if}
      </td>
      <td>{round100(value)}</td>
      <td>{round100(cost)}</td>
      <td>{round100(ratio)}</td>
    </tr>
    


    지금까지의 이야기



    All the code is on GitHub .

    저는 이것을 GitHub Pagesyou can see it here에 배포했습니다.

    다음에 온다



    앱은 꽤 괜찮은 것 같아서 다음화에서는 다른 것으로 넘어가도록 하겠습니다.

    좋은 웹페이지 즐겨찾기