![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702640/pasted-from-clipboard.png)
Games always change
Liad YosefÂ
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702595/liad2.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702610/Picture1.png)
Liad Yosef
Client Architect @ Duda
Pixels and Robots
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702535/bUntitled.png)
![](https://media1.giphy.com/media/s239QJIh56sRW/giphy.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702528/aUntitled.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702564/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790743/pasted-from-clipboard.png)
Village of Boredom
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789507/pngegg__3_.png)
Chapter 1
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789524/pngegg__5_.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789524/pngegg__5_.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790743/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702005/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702010/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702010/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702010/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790743/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702026/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702027/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790776/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790778/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790783/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7699627/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7699633/pasted-from-clipboard.png)
![](https://24.media.tumblr.com/59d89903250e13782a11b972c6dca9ef/tumblr_mw590mV4yB1rmin5no1_400.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790908/pasted-from-clipboard.png)
Pit of Despair
Chapter 1a
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702032/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702037/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790918/pasted-from-clipboard.png)
Valley of Pixels
Chapter 2
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790980/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790982/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790981/pasted-from-clipboard.png)
<body>
...
<canvas></canvas>
...
</body>
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790995/pasted-from-clipboard.png)
Game Graphics
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791522/pasted-from-clipboard.png)
<body>
...
<canvas></canvas>
...
</body>
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790995/pasted-from-clipboard.png)
Game Graphics
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
<body>
...
<canvas></canvas>
...
</body>
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790995/pasted-from-clipboard.png)
Game Graphics
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
// later - draw on canvas
context.fillStyle = "#201A23";
context.fillRect(0, 0, 1220, 400);
context.fillStyle = "#8DAA9D";
context.beginPath();
context.rect(square.x, square.y, square.width, square.height);
context.fill();
Game Elements
const player = {
x: 30,
y: 90,
running: false,
health: 5
}
const enemy = {
x: 10,
y: 60,
velocity: 0.5
}
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791038/aAsset_2_4x.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791039/frAsset_1_4x.png)
Game Controls
const keys = {};
window.addEventListener("keydown", onKeyDown);
window.addEventListener("keyup", onKeyUp);
const onKeyDown = (event) => registerKey(event.keyCode, true);
const onKeyUp = (event) => registerKey(event.keyCode, false);
function registerKey(keyCode, isPressed) {
switch(keyCode) {
case 37:
keys.left = isPressed;
case 38:
keys.up = isPressed;
case 39:
keys.right = isPressed;
case 40:
keys.down = isPressed;
}
}
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791049/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791050/Untitled.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791058/d84187p-b757eb5c-910f-4b8f-847f-8902d090e651.gif)
Game Logic
if(keys.left) {
batman.velocityX = 0.5;
}
if(keys.down) {
batman.velocityY = 0.5;
}
batman.x += batman.velcoityX;
batman.y += batman.velocityY;
if(batman.y >= screenHeight) {
batman.y = screenHeight;
}
if(batman.x === superman.x) {
batman.lives -= 1;
}
if(player.x === heart.x) {
batman.lives += 1;
}
if(martha) {
break;
}
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791084/dribbble_2.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791086/pasted-from-clipboard.png)
Game Loop
function loop() {
// magic here
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791094/DirtyBonyLeafbird-size_restricted.gif)
Game Loop
function loop() {
// update according to input
if(keys.left) {
batman.velocityX = 0.5;
}
batman.x += batman.velcoityX;
...
// run game logic (collisions, etc.)
if(batman.x === superman.x) {
batman.lives -= 1;
}
if(player.x === heart.x) {
batman.lives += 1;
}
...
// draw on canvas
context.fillStyle = "#8DAA9D";
context.rect(square.x, square.y, square.width, square.height);
context.fill();
...
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791090/Tails_finalsmash-3-2.gif)
Sprites
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791099/pngegg6.png)
Pixel Art
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/1697570/Reporter_makes_little_boy_cry_when_asks_if_he_ll_miss_mom.gif)
Game Engines to The Rescue!
![](https://media1.tenor.com/images/d85d112b35eea84b6a2426b4032547d9/tenor.gif?itemid=5366345)
Meadow of Efficiency
Chapter 3
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791103/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791104/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791105/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791106/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791148/pasted-from-clipboard.png)
bitmelo.com
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791115/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791116/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791117/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791118/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791119/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791120/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7699740/pasted-from-clipboard.png)
npx create-react-app 2d-game
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7699753/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7699757/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791128/pasted-from-clipboard.png)
// initialize engine
import projectData from "./projectData.json";
const engine = new window.bitmelo.Engine();
engine.addProjectData(projectData);
// game logic
export function init() {
engine.start();
}
<head>
<script src="%PUBLIC_URL%/bitmelo.js"></script>
...
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791124/pasted-from-clipboard.png)
index.html
game.js
import * as game from './game/game.js';
function GameWrapper() {
useEffect(() => {
game.init();
}, [])
return <div className='main'>
<div id='bitmelo-container'></div>
...
</div>
}
GameWrapper.jsx
engine.onUpdate = () => {
scr.drawMap(0, 0, -1, -1, 0, 0, 0);
drawTargets();
updatePlayer();
scr.drawText("React Summit 2020!", 50, 90);
};
function drawTargets() {
targets.forEach((target) => {
if (!target.wasGrabbed) {
scr.drawTile(
61,
target.x - 8,
target.y - 8,
0
);
}
});
}
function updatePlayer() {
let newX = player.x;
let isWalking = false;
if (inp.left.pressed) {
newX -= player.speed;
isWalking = true;
player.flip = 1;
}
...
const distance = Math.sqrt(dX*dX + dY*dY);
// player has grabbed a target
if (distance <= 12) {
target.wasGrabbed = true;
}
...
// draw the player
let frameGID = 1;
if (player.isWalking) {
if (player.framesSinceWalkStart % 16 < 8) {
frameGID = frameGID + 1;
} else {
frameGID = frameGID + 2;
}
}
}
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790967/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791509/gmAsset_3_4x.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790967/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791509/gmAsset_3_4x.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790940/pasted-from-clipboard.png)
Mountain of Wisdom
Chapter 4
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791583/starcraft.gif)
AI playing Games
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791595/sky_and_cloud_3bis.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791605/T4bt.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791586/mario.gif)
Coding the rules
Inferring rules from data
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791637/learning_gif.gif)
![](https://thumbs.gfycat.com/PhysicalComplicatedBaiji-size_restricted.gif)
if(player.x > enemy.x) {
if (player.health > 5) {
movePlayerRight();
} else {
movePlayerLeft();
}
}
if (player.y > enemy.y) {
if (player.health > 5) {
movePlayerUp();
} else {
movePlayerDown();
}
}
const inputs = [
[input1, result1],
[input2, result2],
[input3, result3],
...
];
model.train(inputs);
const newResult = model.predict(newInput);
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791648/pasted-from-clipboard.png)
In games, we don't have all the inputs
Reinforcement Learning!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791662/reinforce.png)
Reinforcement Learning!
Agent
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
Environment
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791050/Untitled.png)
Action
State
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
x: 30
y: 60
enemies: 2
lives: 3
coins: 4
Reinforcement Learning!
Agent
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
State
Environment
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
x: 30
y: 60
enemies: 2
lives: 3
coins: 4
Reward
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791718/pasted-from-clipboard.png)
Reinforcement Learning!
Agent
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
State
Environment
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
x: 30
y: 60
enemies: 2
lives: 3
coins: 4
Reinforcement Learning!
Agent
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
New State
Environment
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
x: 30
y: 60
enemies: 2
lives: 3
coins: 5
How good is this action?
+
Immediate Reward
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791718/pasted-from-clipboard.png)
Expected rewards from new state
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791727/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791728/pngfind.com-8-bit-bowser-png-3883447.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791729/pasted-from-clipboard.png)
Value Table
UP | DOWN | LEFT | RIGHT | |
---|---|---|---|---|
State 1 (x: 20, y: 30) | 12 | 5 | 15 | 4 |
State 2 (x: 10, y: 10) | 11 | 8 | 9 | 3 |
State 3 (x: 10, y: 20) | 8 | 7 | 9 | 10 |
... | ... | ... | ... | ... |
Reward: 2
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
Value Table
UP | DOWN | LEFT | RIGHT | |
---|---|---|---|---|
State 1 (x: 20, y: 30) | 12 | 5 | 15 | 4 |
State 2 (x: 10, y: 10) | 11 | 8 | 9 | 3 |
State 3 (x: 10, y: 20) | 8 | 7 | 9 | 10 |
... | ... | ... | ... | ... |
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
Value Table
UP | DOWN | LEFT | RIGHT | |
---|---|---|---|---|
State 1 (x: 20, y: 30) | 12 | 5 | 15 | 4 |
State 2 (x: 10, y: 10) | 12 | 8 | 9 | 3 |
State 3 (x: 10, y: 20) | 8 | 7 | 9 | 10 |
... | ... | ... | ... | ... |
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791684/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791813/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791814/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791817/pasted-from-clipboard.png)
Value Table
FLAP | NOTHING | |
---|---|---|
Distance1, Height1 | 12 | 5 |
Distance2, Height2 | 12 | 8 |
Distance3, Height3 | 8 | 7 |
... | ... | ... |
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791829/pasted-from-clipboard.png)
Value Network
Feeding Frames
Exploration
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7792153/pasted-from-clipboard.png)
Exploration
Cool, but.
Cool, but.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791883/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791886/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7792159/unnamed.gif)
https://github.com/aaronhma/awesome-tensorflow-js
https://www.metacar-project.com/
Cool, but.
Cool, but.
https://openai.com/blog/gym-retro/
// create an environment object
var env = {};
env.getNumStates = function() { return 8; }
env.getMaxNumActions = function() { return 4; }
// create the DQN agent
var spec = { alpha: 0.01 } // see full options on DQN page
agent = new RL.DQNAgent(env, spec);
setInterval(function(){ // start the learning loop
var action = agent.act(s); // s is an array of length 8
//... execute action in environment and get the reward
agent.learn(reward); // the agent improves its Q,policy,model, etc. reward is a float
}, 0);
https://github.com/karpathy/reinforcejs
export function fireAction(key, wait = 0) {
fireWindowEvent(key, true);
setTimeout(async () => {
fireWindowEvent(key, false);
}, wait);
}
export function getActor() {
return [player.x, player.y];
}
export function getTarget() {
return [target.x, target.y];
}
game.js
env.getNumStates = () => 4;
env.getMaxNumActions = () => 4;
agent = new RL.DQNAgent(env, spec);
[actor, target] = [getActor(), getTarget()];
const distance_before = getDistance(actor, target);
const action = agent.act([actor.x, actor.y, target.x, target.y]);
const actions = {
0: () => fireAction("ArrowRight"),
1: () => fireAction("ArrowLeft"),
2: () => fireAction("ArrowUp"),
3: () => fireAction("ArrowDown")
}
actions[action]();
[actor, target] = [getActor(), getTarget()];
const distance_after = getDistance(actor, target);
let reward =
actorInEdge
? -(distance_after / 300)
: (distance_before - distance_after) / (distance_before);
agent.learn(reward);
ai.js
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791983/pasted-from-clipboard.png)
const saved = agent.toJSON();
...
agent.fromJSON(saved);
![](https://reactiongifs.me/wp-content/uploads/2020/08/Whoa-Parks-and-Recreation.gif)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/4457093/3ohs86qwN8WkQ4O5A4.gif)
We have AI!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790967/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791509/gmAsset_3_4x.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790967/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791509/gmAsset_3_4x.png)
River of Opportunities
Chapter 5
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7792013/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7792020/bitmelo2.png)
Let's explore!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7792021/bml3.png)
Let's explore!
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7792021/bml3.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7792026/2p.png)
let inputs = [actor.x, actor.y, target.x, target.y, target.direction]
ai.js
let reward = (distance_before - distance_after) / (distance_before);
ai.js
let reward = - (distance_before - distance_after) / (distance_before);
let reward = (-1 * gettingCloserToMorty) + gettingCloserToTarget
ai.js
Village of Boredom
Chapter 1
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789507/pngegg__3_.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789524/pngegg__5_.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789524/pngegg__5_.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7789525/mario.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790918/pasted-from-clipboard.png)
Valley of Pixels
Chapter 2
River of Opportunities
Chapter 5
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7792013/pasted-from-clipboard.png)
Chapter 3
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7791103/pasted-from-clipboard.png)
Meadow of Efficiency
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790908/pasted-from-clipboard.png)
Pit of Despair
Chapter 1a
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7790940/pasted-from-clipboard.png)
Chapter 4
Mountain of Wisdom
![](https://media1.giphy.com/media/41A9eaqZf6iS4/giphy.gif)
![](https://thumbs.gfycat.com/FlickeringDisastrousAnkole-size_restricted.gif)
Just do it.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702640/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7792101/pixel.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7792101/pixel.png)
![](https://i.giphy.com/5wWf7GW1AzV6pF3MaVW.gif)
You're awesome!
![](https://media.tenor.com/images/d2cdbc9a64857acdfa4b1b4385a57073/tenor.gif)
QUESTIONS?
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7350845/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/233297/images/7702661/pasted-from-clipboard.png)
@liadyosef
https://github.com/liady/rl-games
https://rl-games-ai.netlify.app/
Games & AI
By Liad Yosef
Games & AI
Build games for your AI to play.
- 3,039