Skip to content

Commit f3036e5

Browse files
coder-pmMarcin Polak
authored andcommitted
Refactored tank move handler to perform step predict while receiving keyboard event (this should remove glitch with blinking tank rotation)
1 parent c4f8818 commit f3036e5

File tree

2 files changed

+67
-45
lines changed

2 files changed

+67
-45
lines changed

src/game/handlers/TankMoveHandler.ts

Lines changed: 50 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,59 +20,70 @@ export const TANK_MOVE_HANDLER = (tank: TankModel, world: World, isStuck: boolea
2020
isStuck: isStuck
2121
};
2222
if (activeKey) {
23-
let x = move.location.x;
24-
let y = move.location.y;
25-
let r = move.rotation;
26-
let initialDirection = r;
27-
let correctionAxis = 'x';
28-
switch (activeKey) {
29-
case 'ArrowUp':
30-
y -= TANK_MOVE_STEP;
31-
r = 0;
32-
break;
33-
case 'ArrowRight':
34-
x += TANK_MOVE_STEP;
35-
r = 90;
36-
correctionAxis = 'y';
37-
break;
38-
case 'ArrowDown':
39-
y += TANK_MOVE_STEP;
40-
r = 180;
41-
break;
42-
case 'ArrowLeft':
43-
x -= TANK_MOVE_STEP;
44-
r = 270;
45-
correctionAxis = 'y';
46-
break;
47-
default:
48-
}
49-
50-
// move correction (stick to grid)
51-
if (initialDirection !== r) {
52-
if (correctionAxis === 'x') {
53-
x = 3 + (Math.round(x / OBSTACLE_WIDTH) * OBSTACLE_WIDTH);
54-
} else {
55-
y = 3 + (Math.round(y / OBSTACLE_HEIGHT) * OBSTACLE_HEIGHT);
56-
}
57-
}
23+
// perform step
24+
const predict = TANK_STEP_HANDLER(move, activeKey);
5825

5926
// intersection check
6027
if (world.isIntersecting(
61-
Object.assign({}, tank, {location: {x: x, y: y}}),
28+
Object.assign({}, tank, {location: predict.location}),
6229
Collision.BLOCK_MOVE
6330
).length === 0) {
64-
move.location = {x: x, y: y};
65-
move.rotation = r;
31+
move = predict;
6632
move.isStuck = false;
6733
world.updateObject(tank.id, move.location);
6834
} else {
6935
move.isStuck = true;
7036
// just rotate in case of intersection
7137
// but prevent rotation of stucked AI as it looks like glitch
7238
if (tank.actor !== TankActor.AI || !move.isStuck) {
73-
move.rotation = r;
39+
move.rotation = predict.rotation;
7440
}
7541
}
7642
}
7743
return move;
44+
};
45+
46+
/**
47+
* Tank step handler.
48+
*
49+
* @param move - tank move
50+
* @param activeKey - active key
51+
* @param step - step to perform
52+
*/
53+
export const TANK_STEP_HANDLER = (move: TankMove, activeKey: string, step: number = TANK_MOVE_STEP) => {
54+
let x = move.location.x;
55+
let y = move.location.y;
56+
let r = move.rotation;
57+
let initialDirection = r;
58+
let correctionAxis = 'x';
59+
switch (activeKey) {
60+
case 'ArrowUp':
61+
y -= step;
62+
r = 0;
63+
break;
64+
case 'ArrowRight':
65+
x += step;
66+
r = 90;
67+
correctionAxis = 'y';
68+
break;
69+
case 'ArrowDown':
70+
y += step;
71+
r = 180;
72+
break;
73+
case 'ArrowLeft':
74+
x -= step;
75+
r = 270;
76+
correctionAxis = 'y';
77+
break;
78+
default:
79+
}
80+
// move correction (stick to grid)
81+
if (initialDirection !== r) {
82+
if (correctionAxis === 'x') {
83+
x = 3 + (Math.round(x / OBSTACLE_WIDTH) * OBSTACLE_WIDTH);
84+
} else {
85+
y = 3 + (Math.round(y / OBSTACLE_HEIGHT) * OBSTACLE_HEIGHT);
86+
}
87+
}
88+
return Object.assign({}, move, {location: {x: x, y: y}, rotation: r});
7889
};

src/server/classes/Game/Game.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {TankActor} from "../../../game/enums/TankActor";
1010
import ObstacleModel from "../../../game/models/components/ObstacleModel";
1111
import {Collision} from "../../../game/enums/Collision";
1212
import {ObstacleType} from "../../../game/enums/ObstacleType";
13-
import {TANK_MOVE_HANDLER} from "../../../game/handlers/TankMoveHandler";
13+
import {TANK_MOVE_HANDLER, TANK_STEP_HANDLER} from "../../../game/handlers/TankMoveHandler";
1414
import MissileModel from "../../../game/models/components/MissileModel";
1515
import {MISSILE_MOVE_HANDLER} from "../../../game/handlers/MissileMoveHandler";
1616
import Structure from "../../../game/models/Structure";
@@ -110,16 +110,27 @@ export default class Game {
110110
socket.on(NetworkPacket.TANK_EVENT_KEYBOARD, (packet: TankEventKeyboardPacket) => {
111111
// tank might be destroyed in meantime
112112
if (typeof this.tanks[clientId] === 'object') {
113-
this.clients[clientId].activeKey = packet.key;
113+
let location = this.tanks[clientId].location;
114114
const distance = Math.sqrt(
115-
Math.pow(packet.location.x - this.tanks[clientId].location.x, 2) +
116-
Math.pow(packet.location.y - this.tanks[clientId].location.y, 2)
115+
Math.pow(packet.location.x - location.x, 2) +
116+
Math.pow(packet.location.y - location.y, 2)
117117
);
118118
// fix location due to latency and micro differences in server game loop
119119
if (distance > 10) {
120-
this.tanks[clientId].location = packet.location;
121-
this.world.updateObject(clientId, packet.location);
120+
location = packet.location;
122121
}
122+
// fix rotation (we should take in account new key)
123+
const predict = TANK_STEP_HANDLER({
124+
location: location,
125+
rotation: this.tanks[clientId].rotation,
126+
isStuck: false
127+
}, packet.key, 0);
128+
// update state
129+
this.tanks[clientId].location = predict.location;
130+
this.tanks[clientId].rotation = predict.rotation;
131+
this.world.updateObject(clientId, predict.location);
132+
this.clients[clientId].activeKey = packet.key;
133+
// broadcast update
123134
this.io.emit(NetworkPacket.TANK_EVENT_KEYBOARD, {
124135
tankId: clientId,
125136
key: packet.key,

0 commit comments

Comments
 (0)