javascript - 如何限制圆圈在一个范围内的移动?

标签 javascript reactjs algorithm

我正在创建一个游戏,其中会有一张 map 和一些 svg 圆圈(代表单位/部队),上面有一些计数。单位随鼠标位置移动。还有一个代表范围的圆圈。

我有两个需求

  • 当单位被移动时,它不应该越过它的范围
  • 如果鼠标超出范围,那么我希望单位在鼠标方向的范围圆的圆周上。下面是解释第二点的图片。

enter image description here

有两个问题

  • 如果我快速移动设备,它就会移出范围圈。
  • 如果单位移出圆圈,它就不会再移动了。

下面是片段。我已经尽可能多地解释了评论。问题最重要的部分是onMouseMove<Board />

//helper functions

//to get the difference b/w two array.(Absoulute difference)
const getAbsDist= (arr1,arr2) => arr1.map((x,i) => Math.abs(x - arr2[i]))
//to get diagonal distance coverered from vertical and horizontal distance covered
const getDiaDist = (x,y) => Math.sqrt((x*x) + (y*y)); 
const clone = (obj) => JSON.parse(JSON.stringify(obj)); //to clone object

class UnitBox extends React.Component {
  state = {};
  render() {
    const {
      x, //current vertical postion
      y, //current horizontal position
      count, 
      range, 
      moving, //determines whether a range circle will appear or not
      onMouseDown,
      index,
      //position from which we started moving unit
      _x, 
      _y
    } = this.props;
    return (
      <g className="ub">
        <g
          onMouseDown={() => onMouseDown(index)}
          transform={"translate(" + x + ',' + y + ')'}
        >
          <text id="one" selectable="false">{count}</text>
          <circle r="15" />

          <use xlinkHref="#one" />
        </g>
        {moving && (
          <circle r={range} cx={_x} cy={_y} className="range" />
        )}
      </g>
    );
  }
}

class Board extends React.Component {
  state = {
    movingUnit: -1,
    unitBoxes: [
      { moving: false, count: 10, x: 200, y: 100, range: 50 }
    ]
  };
  onMouseDownUnit = unitIndex => {
    const state = clone(this.state),
    unit = state.unitBoxes[unitIndex];
    state.movingUnit = unitIndex;
    unit.moving = true;
    //'_x' and '_y' are the cords from where we click mouse it repesents the initial position
    [unit._x, unit._y] = [unit.x, unit.y]; 
    this.setState(state);
  };
  onMouseUp = e => {
    const state = clone(this.state);
    const unit = state.unitBoxes[this.state.movingUnit];
    state.movingUnit = -1;
    if (unit) unit.moving = false;
    this.setState(state);
  };
  onMouseMove = e => {
    
    let { movingUnit, unitBoxes } = this.state;
    if (movingUnit === -1) return;
    const { clientX, clientY } = e;
    const unit = unitBoxes[movingUnit];
    const { x, y,_x, _y, range} = unit;
    //get the difference b/w initial positon and final position and last final position and get diagonal distance from that.
    let dist = getDiaDist(...getAbsDist([x, y], [_x, _y]));
    
    //if distance covered is less than range than move the object.
    if(dist < range){ 
      unit.x = parseInt(clientX);
      unit.y = parseInt(clientY);
    }
    this.setState({ movingUnit, unitBoxes });
  };
  render() {
    const { unitBoxes } = this.state;
    return (
      <svg
        height="1000px"
        width="1000px"
        onMouseMove={this.onMouseMove}
        onMouseUp={this.onMouseUp}
        style={{ backgroundColor: "orange" }}
      >
        {unitBoxes.map((x, i) => (
          <UnitBox
            onMouseDown={this.onMouseDownUnit}
            {...x}
            index={i}
            key={i}
          />
        ))}
      </svg>
    );
  }
}

ReactDOM.render(<Board/>,document.getElementById('root'))
.ub text {
    text-anchor: middle;
    alignment-baseline: central;
    font-family: sans-serif;
    font-weight: bold;
    font-size: 16px;
    fill: #454545;
}
.ub{
    cursor: pointer;
}
.ub circle {
    stroke: #707070;
    fill: #cacaca;
    stroke-width: 2px;
}
.ub .range{
    fill:green;
    fill-opacity: 0.3;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

最佳答案

您用移动单元的最后更新位置测量当前距离实际位置dist,但当鼠标超出有效范围时位置不会更新。改为使用鼠标指针的当前位置:

  let dist = getDiaDist(...getAbsDist([clientX, clientY], [_x, _y]));

此更改将使单位保持在其范围内,但当鼠标移出范围时它不会更新其位置。为此,通过将单位“夹紧”到鼠标指针方向的范围来处理距离大于范围的情况:

  if (dist < range) { 
      unit.x = clientX;
      unit.y = clientY;
  } else {
      let xx = clientX;
      let yy = clientY;
      let cc = range / dist;

      unit.x = _x + (xx - _x) * cc;
      unit.y = _y + (yy - _y) * cc;
  }

关于javascript - 如何限制圆圈在一个范围内的移动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56179770/

相关文章:

node.js - React 元标签不适用于 Facebook

algorithm - 为每个人分配一组文章供阅读,同时优先考虑某些分组

arrays - 如何在这个游戏中最大化总和?

c - 简单字符串匹配期间比较的字符数

javascript - 如何检测移动到 Mobile Safari 中的新选项卡

javascript - 如何在 Babel 中将 * 导出为命名空间?

javascript - 删除未使用的 Javascript base.js (Youtube iframe api)

javascript - 如何阻止网站在 iframe 中加载?

reactjs - Redux 表单 - 将当前输入值作为字符串返回 onChange

reactjs - 影响 Material UI 控件的 Tab 键顺序