Skip to content

Commit

Permalink
feat(jsbattle-docs): add walkthroughs
Browse files Browse the repository at this point in the history
  • Loading branch information
jamro committed Jan 9, 2020
1 parent a02cae5 commit eb21a06
Show file tree
Hide file tree
Showing 15 changed files with 459 additions and 148 deletions.
7 changes: 5 additions & 2 deletions packages/jsbattle-docs/build/md2html.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ function processMd(txt) {
function processHtml(txt, level, sidebarContent) {
sidebarContent = sidebarContent.replace(/(\[[^\]]*\]\()([^\)]*\.)md\)/gi, '$1' + ('../'.repeat(level)) + '$2html)');
let htmlContent = converter.makeHtml(sidebarContent);
let css = '../'.repeat(level) + 'style.css';
let root = '../'.repeat(level);
txt = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JsBattle Docs</title>
<link rel="stylesheet" href="${css}" type="text/css">
<link rel="stylesheet" href="${root}style.css" type="text/css">
<link rel="stylesheet" href="${root}highlight.css">
<script src="${root}highlight.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body>
<div id="side">
Expand Down
7 changes: 7 additions & 0 deletions packages/jsbattle-docs/docs/_sidebar.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
- [Shooting](./algorithms/shooting.md)
- [Aiming](./algorithms/aiming.md)
- [Movement](./algorithms/movement.md)
- [**Walkthroughs**](./walkthroughs/README.md)
- [Challenge #1](./walkthroughs/challenge01.md)
- [Challenge #2](./walkthroughs/challenge02.md)
- [Challenge #3](./walkthroughs/challenge03.md)
- [Challenge #4](./walkthroughs/challenge04.md)
- [Challenge #5](./walkthroughs/challenge05.md)
- [Challenge #6](./walkthroughs/challenge06.md)
- [**Development Guide**](./dev_guide/README.md)
- [Architecture](./dev_guide/architecture/README.md)
- [Infrastructure](./dev_guide/architecture/infrastructure.md)
Expand Down
64 changes: 0 additions & 64 deletions packages/jsbattle-docs/docs/algorithms/aiming.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,67 +199,3 @@ When your radar spot an enemy, `state.radar.enemy` will contain all its, data in
let radarAngleDiff = Math.deg.normalize(radarAngle - state.radar.angle);
control.RADAR_TURN = 0.3 * radarAngleDiff;
```


### Keep the proper distance to the target
To control the distance, you must turn your tank to the direction of the target. In this way, you can easily be farther or closer by going back and forth. It is quite similar to pointing the gun or radar to the target, but this time we will be moving the whole tank:

```javascript
let targetAngle = Math.deg.atan2(state.radar.enemy.y - state.y, state.radar.enemy.x - state.x);
let bodyAngleDiff = Math.deg.normalize(targetAngle - state.angle);
control.TURN = 0.5 * bodyAngleDiff;
```
Notice that it should not impact any of code that rotates gun or radar since in all of those cases calculations consider rotation of tank's body (`state.angle`).

Radar beam has a range of `300` (you can check it in [Constants and Formulas Section](../manual/consts.md) ). Let's assume that a safe distance that avoids losing the target is half of that, so `150`. The following code will ensure that the tank tries to keep that distance

```javascript
let targetDistance = Math.distance(state.x, state.y, state.radar.enemy.x, state.radar.enemy.y);
let distanceDiff = targetDistance - 150;
control.THROTTLE = distanceDiff/100;
```

### Put everything together

At the end the code should look like this:

```javascript
let enemy = state.radar.enemy;

if(!enemy) {
control.RADAR_TURN = 1;
} else {
control.RADAR_TURN = 0;

// predict position of target
let bulletSpeed = 4;
let distance = Math.distance(state.x, state.y, enemy.x, enemy.y)
let bulletTime = distance / bulletSpeed;
let targetX = enemy.x + bulletTime * enemy.speed * Math.cos(Math.deg2rad(enemy.angle));
let targetY = enemy.y + bulletTime * enemy.speed * Math.sin(Math.deg2rad(enemy.angle));

let targetAngle = Math.deg.atan2(targetY - state.y, targetX - state.x);
let enemyAngle = Math.deg.atan2(enemy.y - state.y, enemy.x - state.x);

// keep enemy in the radar beam
let radarAngle = Math.deg.normalize(enemyAngle - state.angle);
let radarAngleDiff = Math.deg.normalize(radarAngle - state.radar.angle);
control.RADAR_TURN = 0.3 * radarAngleDiff;

// keep proper enemy distance
let bodyAngleDiff = Math.deg.normalize(enemyAngle - state.angle);
control.TURN = 0.5 * bodyAngleDiff;
let targetDistance = Math.distance(state.x, state.y, enemy.x, enemy.y);
let distanceDiff = targetDistance - 150;
control.THROTTLE = distanceDiff/100;

// aim and shoot
let gunAngle = Math.deg.normalize(targetAngle - state.angle);
let angleDiff = Math.deg.normalize(gunAngle - state.gun.angle);
control.GUN_TURN = 0.3 * angleDiff;
if(Math.abs(angleDiff) < 1) {
control.SHOOT = 0.1;
}

}
```
17 changes: 17 additions & 0 deletions packages/jsbattle-docs/docs/algorithms/movement.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,23 @@ tank.loop(function(state, control) {
control.TURN = 0;
}
});
```

## Follow the target
To control the distance between your tank and the enemy, you must turn your tank to the direction of the target (step #1). In this way, you can easily be farther or closer by going back and forth (step #2).

```javascript
// Step #1
let targetAngle = Math.deg.atan2(state.radar.enemy.y - state.y, state.radar.enemy.x - state.x);
let bodyAngleDiff = Math.deg.normalize(targetAngle - state.angle);
control.TURN = 0.5 * bodyAngleDiff;
```

Radar beam has a range of `300` (you can check it in [Constants and Formulas Section](../manual/consts.md) ). Let's assume that a safe distance that avoids losing the target is half of that, so `150`. The following code will ensure that the tank tries to keep that distance:

```javascript
// Step #2
let targetDistance = Math.distance(state.x, state.y, state.radar.enemy.x, state.radar.enemy.y);
let distanceDiff = targetDistance - 150;
control.THROTTLE = distanceDiff/100;
```
80 changes: 0 additions & 80 deletions packages/jsbattle-docs/docs/algorithms/shooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,83 +6,3 @@ As described in [Battle Anatomy Section](../manual/battle_anatomy.md), you can d
Amount of damage that can be dealt over the same amount of time is not constant. Formulas required to calculate that can be found in [Constants and Formulas Section](../manual/consts.md).

Using most powerful shots (`control.SHOOT=1`) can be 25% more efficient than firing weaker bullets at the maximum rate of fire (`control.SHOOT=0.1`). However, this calculation is right only under an assumption of 100% accuracy. When shooting a moving target that is hard to hit, it may be better to use a hail of bullets and increase the probability that at least some of them will hit the target.

## Predict the position of the target
It takes time for a bullet to reach the target so shooting a long distance, moving target could be difficult. The enemy may be in a different place when the bullet reaches it. In such case, it may be worth to predict the new position of the target. Most of the calculations will be based on a simple, physic formula for speed:

```
speed = distance / time
```

what also can be written as:
```
distance = speed * time
time = distance / speed
```

Let's split that problem into a few steps:

### Predict the time when the bullet will reach the target
The accurate formula may be complicated in this case. The time needed to reach the target depends on the distance, and the distance is changing when the target is moving. However, for this particular case let's assume that the distance between your tank and the enemy will not change. Of course, it is incorrect and does not match the reality but it will make all calculations much simpler. The error introduced by this wrong assumption should be still small enough that we will hit the target.

Assume that we know the following:
- position of your tank (`state.x`, `state.y`)
- position of the enemy (`state.radar.enemy.x`, `state.radar.enemy.y`)
- speed of the bullet (`4`)

First of all, we need to calculate the distance between your tank and the enemy. It can be easily achieved using [Extended Math Object](../manual/extended_math.md):

```javascript
let bulletDistance = Math.distance(state.x, state.y, state.radar.enemy.x, state.radar.enemy.y);
```
Now the time required for the bullet to hit the target can be calculated using formula `time = distance / speed`:

```javascript
let dt = bulletDistance / 4;
```

### Predict position of target after time `dt`
Assume that we know:
- the current position of the enemy (`state.radar.enemy.x`, `state.radar.enemy.y`)
- the current rotation of the enemy (`state.radar.enemy.angle`)
- the current speed of the enemy (`state.radar.enemy.speed`)
- the time that the bullet needs to hit the target (`dt`)

And we need to find coordinates of the target after time `dt`:
- `targetX`
- `targetY`

At first, we need to calculate the distance travelled over time `dt`:
```
let enemyDistance = state.radar.enemy.speed * dt;
```

knowing the distance, the new position can be calculated using sine and cosine functions (as explained in [Geometry Algorithms](./geometry.md)):

```
let enemyAngle = Math.deg2rad(state.radar.enemy.angle);
let targetX = state.radar.enemy.x + Math.cos(enemyAngle) * enemyDistance;
let targetY = state.radar.enemy.y + Math.sin(enemyAngle) * enemyDistance;
```

### Calculate angle where the gun should be pointed
A similar case was explained in [Geometry Algorithms](./geometry.md):

```javascript
let targetAngle = Math.deg.atan2(targetY - state.y, targetX - state.x);
```

### Put everything together

```javascript
let bulletDistance = Math.distance(state.x, state.y, state.radar.enemy.x, state.radar.enemy.y);
let dt = bulletDistance / 4;

let enemyDistance = state.radar.enemy.speed * dt;
let enemyAngle = Math.deg2rad(state.radar.enemy.angle);

let targetX = state.radar.enemy.x + Math.cos(enemyAngle) * enemyDistance;
let targetY = state.radar.enemy.y + Math.sin(enemyAngle) * enemyDistance;

let targetAngle = Math.deg.atan2(targetY - state.y, targetX - state.x);
```
10 changes: 10 additions & 0 deletions packages/jsbattle-docs/docs/walkthroughs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Challenge Walkthroughs

This section is contains solution of all JsBattle Challenges. If you got stuck, you can check the solution here. Try to not use it too much since it will take all the fun away from you.

- [Challenge #1](./challenge01.md)
- [Challenge #2](./challenge02.md)
- [Challenge #3](./challenge03.md)
- [Challenge #4](./challenge04.md)
- [Challenge #5](./challenge05.md)
- [Challenge #6](./challenge06.md)
16 changes: 16 additions & 0 deletions packages/jsbattle-docs/docs/walkthroughs/challenge01.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Challenge #1 Walkthrough

```javascript
importScripts('lib/tank.js');

tank.init(function(settings, info) {
// initialize tank here
});

tank.loop(function(state, control) {
// Change control object to start shooting.
// The loop() function is called at each simulation
// step resulting in continuous fire.
control.SHOOT = 1;
});
```
24 changes: 24 additions & 0 deletions packages/jsbattle-docs/docs/walkthroughs/challenge02.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Challenge #2 Walkthrough

```javascript
importScripts('lib/tank.js');

tank.init(function(settings, info) {
// initialize tank here
});

tank.loop(function(state, control) {
// calculate desired direction of the gun.
// Take into account rotation of the tank
const targetAngle = 45
const gunAngle = Math.deg.normalize(targetAngle - state.angle);

// point the gun at the target.
const turnSpeed = 0.1;
const angleDiff = Math.deg.normalize(gunAngle - state.gun.angle);
control.GUN_TURN = turnSpeed * angleDiff;

// keep shooting
control.SHOOT = 1;
});
```
36 changes: 36 additions & 0 deletions packages/jsbattle-docs/docs/walkthroughs/challenge03.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Challenge #3 Walkthrough

```javascript
importScripts('lib/tank.js');

tank.init(function(settings, info) {
// initialize tank here
});

tank.loop(function(state, control) {
let enemy = state.radar.enemy;
// Keep scannig until you find the enemy
if(!enemy) {
control.RADAR_TURN = 1;
} else {
control.RADAR_TURN = 0;
}

// Aim at the target when found
if(enemy) {
// Calculate desired direction of the gun.
// If you need additional explanation on math operations
// read the docs: Algorithms / Geometry Basics
const targetAngle = Math.deg.atan2(enemy.y - state.y, enemy.x - state.x);
const gunAngle = Math.deg.normalize(targetAngle - state.angle);

// point the gun at the target
const turnSpeed = 0.1;
const angleDiff = Math.deg.normalize(gunAngle - state.gun.angle);
control.GUN_TURN = turnSpeed * angleDiff;

// keep shooting
control.SHOOT = 1;
}
});
```
57 changes: 57 additions & 0 deletions packages/jsbattle-docs/docs/walkthroughs/challenge04.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Challenge #4 Walkthrough

```javascript
importScripts('lib/tank.js');

// SHOOT ENEMY ---------------------------------------------------------------------------------
function shootEnemy(state, control) {
let enemy = state.radar.enemy;
if(!enemy) {
return;
}

// predict position of moving target
let bulletSpeed = 4;
let distance = Math.distance(state.x, state.y, enemy.x, enemy.y)
let bulletTime = distance / bulletSpeed;
let targetX = enemy.x + bulletTime * enemy.speed * Math.cos(Math.deg2rad(enemy.angle));
let targetY = enemy.y + bulletTime * enemy.speed * Math.sin(Math.deg2rad(enemy.angle));

// calculate desired direction of the gun
let targetAngle = Math.deg.atan2(targetY - state.y, targetX - state.x);
let gunAngle = Math.deg.normalize(targetAngle - state.angle);

// point the gun at the target
let angleDiff = Math.deg.normalize(gunAngle - state.gun.angle);
control.GUN_TURN = 0.3 * angleDiff;

// shoot when aiming at target
if(Math.abs(angleDiff) < 1) {
control.SHOOT = 0.5;
}
}

// SCAN ENEMY ---------------------------------------------------------------------------------
function scanEnemy(state, control) {
if(!state.radar.enemy) {
// scan around for the enemy
control.RADAR_TURN = 1;
} else {
//keep the enemy in the middle of radar beam
let targetAngle = Math.deg.atan2(state.radar.enemy.y - state.y, state.radar.enemy.x - state.x);
let radarAngle = Math.deg.normalize(targetAngle - state.angle);
let angleDiff = Math.deg.normalize(radarAngle - state.radar.angle);
control.RADAR_TURN = angleDiff;
}
}

// -------------------------------------------------------------------------------------------
tank.init(function(settings, info) {
// initialize tank here
});

tank.loop(function(state, control) {
scanEnemy(state, control);
shootEnemy(state, control);
});
```
Loading

0 comments on commit eb21a06

Please sign in to comment.