【问题标题】:Calculate move cost based on speed and distance根据速度和距离计算移动成本
【发布时间】:2017-06-26 20:14:15
【问题描述】:

我正在开发画布迷你游戏,我想构建一个函数来计算将你的船从 A 点移动到 B 点的成本。

我需要两件事:

  • 发货前的总成本
  • 每个移动滴答的成本(服务器循环滴答)

每次移动船(每次服务器循环滴答声)都会收取费用,因此总数必须与服务器为到达那里所做的所有滴答声的总和相匹配。

我有一个简单的服务器循环来移动船:

setInterval(function() {
    ship.move();
}, 10);

现在是简化的船代码:

var rad = (p1, p2) => Math.atan2(p2.y - p1.y, p2.x - p1.x),
    distance = (p1, p2) => Math.sqrt( (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) );

var ship = function() {

    this.x; // current ship x
    this.y; // current ship y
    this.destination; // destination object
    this.total_distance; // total distance before dispatch
    this.remaining_distance; // remaining distance before arrival
    this.speed = 0.5; // ship speed modifier

    this.set_travel = function(target) {
        this.destination = target;
        this.total_distance = distance( { x: this.x, y: this.y }, { x: this.destination.x, y: this.destination.y } );
    };

    this.move = function() {
        this.remaining_distance = distance( { x: this.x, y: this.y }, { x: this.destination.x, y: this.destination.y } );

        var _rad = rad( { x: this.x, y: this.y }, { x: this.destination.x, y: this.destination.y } );

        this.x += Math.cos(rad) * this.speed;
        this.y += Math.sin(rad) * this.speed;
    };

};

现在我们可以引入燃料成本并像这样添加到上面的代码中:

var ship = function() {

    ...
    this.total_fuel_cost; // total fuel cost that player will consume during entire travel

    this.set_travel = function(target) {
        ...
        this.total_fuel_cost = ?
    };

    this.move = function() {
        ...
        player.fuel -= ? // fuel cost every tick that must match total after arrival
    };

};

也许有人可以帮助解决这个问题。也许假设每 1 距离花费 x 燃料可能是一个好方法,但我不知道是否可以这样做。

----- 编辑

当船被创建时,它以这种方式被实例化:

objects.push(new ship())

正如我在我的问题中解释的那样,如果总数不够,拒绝飞行是不可接受的,只要有燃料,船就必须走

【问题讨论】:

    标签: javascript math


    【解决方案1】:

    我使用提供的设置组装了一个小演示:

    • move() 循环间隔 10 毫秒
    • 飞行中消耗的燃料
    • 整个旅程消耗的燃料必须与开始时假定的消耗相等

    逻辑解释:

    您的逻辑中真正需要的唯一变量是船速。

    您的代码如下所示:

    this.move = function() {
        this.remaining_distance = distance( { x: this.x, y: this.y }, { x: this.destination.x, y: this.destination.y } );
    
        var _rad = rad( { x: this.x, y: this.y }, { x: this.destination.x, y: this.destination.y } );
    
        this.x += Math.cos(rad) * this.speed;
        this.y += Math.sin(rad) * this.speed;
    
        player.fuel -= this.speed;
    };
    

    假设玩家有1000 燃料,你需要飞行距离845。如果我们假设1 distance === 1 fuel,我们预计在旅程结束时您应该还剩下155 燃料。此外,不管你飞得快(比如2)还是慢(比如0.5),油耗应该是一样的,因为你飞得更快会消耗更多的油。上面的代码正是这样做的。

    演示链接: https://jsfiddle.net/7khvxkaa/1/

    可以调整燃料成本以处理较小的数字,例如,如果假设1 distance === 0.01 燃料您最终将在整个1000 距离旅程中消耗10 燃料。考虑到上述情况,这是唯一需要进行的更改:

    player.fuel -= this.speed / 100;
    

    还请记住,演示仅用于调试目的以验证概念证明,在您有更多变量(例如移动目的地或船舶加速/减速)的实际环境中,可能难以预测总燃料消耗,但逻辑将仍然按预期工作。

    【讨论】:

      【解决方案2】:

      我认为您最需要一个关于 OOP 的解释。

      你的功能船不是一个对象;它是一个类的(构造函数)。
      (嗯,这就是其他语言的称呼。)

      要制作一个对象,请执行以下操作:

      var myship = new ship();
      

      这是一个例子;有点像你的游戏。但我的主要观点是让您了解如何使用对象。如您所见,属性 myship.fuel 跟踪燃料;如果一次旅行需要的燃料比它多,它会拒绝移动。

      您可以自己处理的计算。看看“我有什么属性?” “我需要什么?”,...

      <script>
      // constructor 
      function Ship(elementId) {
        // properties
        this.elm = document.getElementById(elementId);
        this.x = 0;                      // current ship x
        this.y = 0;                      // current ship y
        this.fuel = 300;
        this.fuelprice = 0.2;            // moving 1 pixel costs 0.2 fuel 
        this.destination = {x:0, y:0};   // destination object
      
        // static function, doesn't interact with any property, just takes parameters ans returns something
        this.distance = function(p1, p2) {
          return Math.sqrt( (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) ); // Pythagoras
        }
        this.rad = function(p1, p2) {
          return Math.atan2(p2.y - p1.y, p2.x - p1.x);
        }
      
        // method.  this is a function bound to an object.  Whomever calls this function will be affected.
        // in this case myship will be moved, but there could be many boats in the game; many buttons that each move 1 boat, ...
        this.moveTo = function(to) {
          var from = {x: this.x, y: this.y};
          var totalDistance = this.distance(from, to);
          // see if there is enougn fuel
          var fuelNeeded = this.fuelprice * totalDistance;
          if(this.fuel >= fuelNeeded) {
            display(
              '<h3>This trip</h3>'+
              'total distance: ' + totalDistance + '<br/>'+
              'fuel at start: ' + this.fuel +'<br/>'+
              'fuel needed: ' + fuelNeeded +'<br/>'
            );
            this.moveStep(to, 10, 10);
            // 
            this.fuel -= fuelNeeded;
          }
          else {
            display(
              '<h3>Not enough fuel</h3>'+
              'fuel at start: ' + this.fuel +'<br/>'+
              'fuel needed: ' + fuelNeeded +'<br/>'
            );
          }
        }
      
        // function that calls itself, until stepsLeft = 0
        this.moveStep = function(to, steps, stepsLeft) {
          var self = this;  // within a setTimeout the "this" changes its meaning.  So I make a copy.
          var x = to.x + (this.x - to.x) * (stepsLeft / steps);
          var y = to.y + (this.y - to.y) * (stepsLeft / steps);
          if(stepsLeft > 0) {
            this.elm.style.left = x;
            this.elm.style.top = y;
            setTimeout(function() { self.moveStep(to, steps, stepsLeft - 1) }, 100);
          }
          else {
            // animation is finished, so the "to" situation becomes the new x and y
            this.x = to.x;
            this.y = to.y;
          }
        }
      }
      
      // function that uses the myship object
      function submitMove() {
        myship.moveTo({
          x: Number(document.getElementById('x').value), 
          y: Number(document.getElementById('y').value)
        });
      }
      
      // just to display messages to screen
      function display(message) {
        document.getElementById('display').innerHTML = message;
      }
      
      // now this is our object: myship
      var myship;
      
      // when the page is loaded we can make myship a Ship object
      window.onload = function() {
        myship = new Ship('boat');
      }
      
      </script>
      <style>
      #sea {
        position: relative;
        background: #2040f0;
        height: 500px;
        width: 500px;
      }
      #boat {
        position: absolute;
      }
      </style>
      <div id="sea">
        <img id="boat" src="http://icons.veryicon.com/32/Leisure/Summer%20Holiday/sailing%20boat.png" />
      </div>
      <hr/>
      <input id="x" placeholder="X" value="200">
      <input id="y" placeholder="X" value="40">
      <input type="button" value="GO" onclick="submitMove()">
      <div id="display"></display>
      

      【讨论】:

      • 您的结论有点仓促,这里没有人对 OOP 有任何问题,只需查看代码就可以明显看出,我的代码船中的某处是从我提供的构造函数实例化的。您的解决方案非常糟糕,我特别解释说,即使总量大于您当前的燃料状态,旅行也开始了,它只是不会到达终点,但必须即时进行计算。还使用 div 进行游戏?我认为您最需要解释在构建任何游戏时使用什么技术。
      • 这个答案根本不关注解决问题,这个答案的内容与提出的问题无关。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-30
      • 2014-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多