Added network interpolation and fix send rate for pointer
This commit is contained in:
parent
c6f9b29cc3
commit
eed47e644c
@ -23,9 +23,6 @@ function MapPointer({
|
||||
);
|
||||
const mapStageRef = useContext(MapStageContext);
|
||||
|
||||
// const [isBrushDown, setIsBrushDown] = useState(false);
|
||||
// const [brushPosition, setBrushPosition] = useState({ x: 0, y: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
if (!active) {
|
||||
return;
|
||||
@ -47,7 +44,7 @@ function MapPointer({
|
||||
}
|
||||
|
||||
function handleBrushUp() {
|
||||
onPointerMove && onPointerUp({ x: 0, y: 0 });
|
||||
onPointerMove && onPointerUp(getBrushPosition());
|
||||
}
|
||||
|
||||
interactionEmitter.on("dragStart", handleBrushDown);
|
||||
|
@ -1,4 +1,8 @@
|
||||
import { toRadians, roundTo as roundToNumber } from "./shared";
|
||||
import {
|
||||
toRadians,
|
||||
roundTo as roundToNumber,
|
||||
lerp as lerpNumber,
|
||||
} from "./shared";
|
||||
|
||||
export function lengthSquared(p) {
|
||||
return p.x * p.x + p.y * p.y;
|
||||
@ -238,3 +242,7 @@ export function distance(a, b, type) {
|
||||
return length(subtract(a, b));
|
||||
}
|
||||
}
|
||||
|
||||
export function lerp(a, b, alpha) {
|
||||
return { x: lerpNumber(a.x, b.x, alpha), y: lerpNumber(a.y, b.y, alpha) };
|
||||
}
|
||||
|
@ -1,14 +1,18 @@
|
||||
import React, { useState, useContext, useEffect } from "react";
|
||||
import React, { useState, useContext, useEffect, useRef } from "react";
|
||||
import { Group } from "react-konva";
|
||||
|
||||
import AuthContext from "../contexts/AuthContext";
|
||||
|
||||
import MapPointer from "../components/map/MapPointer";
|
||||
import { isEmpty } from "../helpers/shared";
|
||||
import { lerp } from "../helpers/vector2";
|
||||
|
||||
// Send pointer updates every 100ms
|
||||
const sendTickRate = 100;
|
||||
|
||||
function NetworkedMapPointer({ session, active, gridSize }) {
|
||||
const { userId } = useContext(AuthContext);
|
||||
const [pointerState, setPointerState] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
if (userId && !(userId in pointerState)) {
|
||||
setPointerState({
|
||||
@ -17,13 +21,28 @@ function NetworkedMapPointer({ session, active, gridSize }) {
|
||||
}
|
||||
}, [userId, pointerState]);
|
||||
|
||||
// Send pointer updates every sendTickRate to peers to save on bandwidth
|
||||
const ownPointerUpdateRef = useRef();
|
||||
useEffect(() => {
|
||||
function sendOwnPointerUpdates() {
|
||||
if (ownPointerUpdateRef.current) {
|
||||
session.send("pointer", ownPointerUpdateRef.current);
|
||||
ownPointerUpdateRef.current = null;
|
||||
}
|
||||
}
|
||||
const sendInterval = setInterval(sendOwnPointerUpdates, sendTickRate);
|
||||
|
||||
return () => {
|
||||
clearInterval(sendInterval);
|
||||
};
|
||||
}, [session]);
|
||||
|
||||
function updateOwnPointerState(position, visible) {
|
||||
const update = { [userId]: { position, visible, id: userId } };
|
||||
setPointerState((prev) => ({
|
||||
...prev,
|
||||
...update,
|
||||
[userId]: { position, visible, id: userId },
|
||||
}));
|
||||
session.send("pointer", update);
|
||||
ownPointerUpdateRef.current = { position, visible, id: userId };
|
||||
}
|
||||
|
||||
function handleOwnPointerDown(position) {
|
||||
@ -38,13 +57,31 @@ function NetworkedMapPointer({ session, active, gridSize }) {
|
||||
updateOwnPointerState(position, false);
|
||||
}
|
||||
|
||||
// Handle pointer data receive
|
||||
const syncedPointerStateRef = useRef({});
|
||||
useEffect(() => {
|
||||
function handlePeerData({ id, data }) {
|
||||
if (id === "pointer") {
|
||||
setPointerState((prev) => ({
|
||||
...prev,
|
||||
...data,
|
||||
}));
|
||||
// Setup an interpolation to the current pointer data when receiving a pointer event
|
||||
if (syncedPointerStateRef.current[data.id]) {
|
||||
const from = syncedPointerStateRef.current[data.id].to;
|
||||
syncedPointerStateRef.current[data.id] = {
|
||||
id: data.id,
|
||||
from: {
|
||||
...from,
|
||||
time: performance.now(),
|
||||
},
|
||||
to: {
|
||||
...data,
|
||||
time: performance.now() + sendTickRate,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
syncedPointerStateRef.current[data.id] = {
|
||||
from: null,
|
||||
to: { ...data, time: performance.now() + sendTickRate },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,6 +92,54 @@ function NetworkedMapPointer({ session, active, gridSize }) {
|
||||
};
|
||||
});
|
||||
|
||||
// Animate to the peer pointer positions
|
||||
useEffect(() => {
|
||||
let request = requestAnimationFrame(animate);
|
||||
|
||||
function animate(time) {
|
||||
request = requestAnimationFrame(animate);
|
||||
let interpolatedPointerState = {};
|
||||
for (let syncState of Object.values(syncedPointerStateRef.current)) {
|
||||
if (!syncState.from || !syncState.to) {
|
||||
continue;
|
||||
}
|
||||
const totalInterpTime = syncState.to.time - syncState.from.time;
|
||||
const currentInterpTime = time - syncState.from.time;
|
||||
const alpha = currentInterpTime / totalInterpTime;
|
||||
|
||||
if (alpha >= 0 && alpha <= 1) {
|
||||
interpolatedPointerState[syncState.id] = {
|
||||
id: syncState.to.id,
|
||||
visible: syncState.from.visible,
|
||||
position: lerp(
|
||||
syncState.from.position,
|
||||
syncState.to.position,
|
||||
alpha
|
||||
),
|
||||
};
|
||||
}
|
||||
if (alpha > 1 && !syncState.to.visible) {
|
||||
interpolatedPointerState[syncState.id] = {
|
||||
id: syncState.id,
|
||||
visible: syncState.to.visible,
|
||||
position: syncState.to.position,
|
||||
};
|
||||
delete syncedPointerStateRef.current[syncState.to.id];
|
||||
}
|
||||
}
|
||||
if (!isEmpty(interpolatedPointerState)) {
|
||||
setPointerState((prev) => ({
|
||||
...prev,
|
||||
...interpolatedPointerState,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
return () => {
|
||||
cancelAnimationFrame(request);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Group>
|
||||
{Object.values(pointerState).map((pointer) => (
|
||||
|
Loading…
Reference in New Issue
Block a user