我正在创建一个游戏,其中会有一张 map 和一些 svg 圆圈(代表单位/部队),上面有一些计数。单位随鼠标位置移动。还有一个代表范围的圆圈。
我有两个需求
- 当单位被移动时,它不应该越过它的范围
- 如果鼠标超出范围,那么我希望单位在鼠标方向的范围圆的圆周上。下面是解释第二点的图片。
有两个问题
- 如果我快速移动设备,它就会移出范围圈。
- 如果单位移出圆圈,它就不会再移动了。
下面是片段。我已经尽可能多地解释了评论。问题最重要的部分是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/