Created
August 5, 2017 18:52
-
-
Save Johnicholas/c759a4bdee8ecd15bcc9041c56ff3eaf to your computer and use it in GitHub Desktop.
Example of simple AI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// utility functions | |
function dist(a, b) { | |
let dx = a.x - b.x; | |
let dy = a.y - b.y; | |
return Math.sqrt(dx * dx + dy * dy); | |
} | |
// GLOBALS GLOBALS GLOBALS | |
var canvas = document.getElementById("myCanvas"); | |
var ctx = canvas.getContext("2d"); | |
var keys = []; | |
let ENEMY_SPEED = 150; // pixels per second | |
let PLAYER_SPEED = 150; // pixels per second | |
// the enemy's reaction speed in ms | |
let REACTION_TIME = 50; | |
// the enemy's averag dwell time while browsing, in ms | |
let BROWSING_DWELL = 500; | |
var player = { x: 0, y: 0 }; | |
var enemy = { x: 100, y: 100 }; | |
var target = { x: 100, y: 100 }; | |
var nest = { x: canvas.width * 0.8, y: canvas.height * 0.2 }; | |
// update the player's position, 8-way movement at PLAYER_SPEED | |
function update_player(dt) { | |
var distance = (PLAYER_SPEED / 1000) * dt; | |
let dx = 0 | |
let dy = 0 | |
if (keys[39] || keys[68]) { | |
dx += distance; | |
} | |
if (keys[37] || keys[65]) { | |
dx -= distance; | |
} | |
if (keys[38] || keys[87]) { | |
dy -= distance; | |
} | |
if (keys[40] || keys[83]) { | |
dy += distance; | |
} | |
player.x += dx; | |
player.y += dy; | |
} | |
// update the target's position | |
function update_target(dt) { | |
if (Math.random() < (dt / REACTION_TIME)) { | |
if (dist(player, enemy) > 200) { | |
enemy.text = 'player far'; | |
if (Math.random() < (dt / BROWSING_DWELL)) { | |
target.x = Math.random() * canvas.width; | |
target.y = Math.random() * canvas.height; | |
} | |
for (var i = 0; i < 100; i++) { | |
if (dist(enemy, target) < 200 && dist(target, nest) < 200) { | |
break; | |
} | |
target.x = Math.random() * canvas.width; | |
target.y = Math.random() * canvas.height; | |
} | |
} else { | |
enemy.text = 'player near'; | |
// player is near, flee to somewhere further away from player | |
for (var i = 0; i < 100; i++) { | |
if (dist(player, target) > 200 && dist(player, target) > dist(enemy, target)) { | |
// acceptable | |
break; | |
} | |
target.x = Math.random() * canvas.width; | |
target.y = Math.random() * canvas.height; | |
} | |
} | |
} | |
} | |
// update the enemy's position, 8-way movement toward target at ENEMY_SPEED | |
function update_enemy(dt) { | |
// update the enemy's position, 8-way movement at ENEMY_SPEED | |
var distance = (ENEMY_SPEED / 1000) * dt; | |
if (Math.abs(enemy.x - target.x) < distance) { | |
enemy.x = target.x; | |
} else { | |
enemy.x += distance * Math.sign(target.x - enemy.x); | |
} | |
if (Math.abs(enemy.y - target.y) < distance) { | |
enemy.y = target.y; | |
} else { | |
enemy.y += distance * Math.sign(target.y - enemy.y); | |
} | |
} | |
function update(dt) { | |
update_player(dt); | |
update_target(dt); | |
update_enemy(dt); | |
} | |
function draw() { | |
// clear the canvas to black | |
ctx.beginPath(); | |
ctx.rect(0, 0, canvas.width, canvas.height); | |
ctx.fillStyle = "black"; | |
ctx.fill(); | |
// draw the player (a blue rectangle) | |
ctx.beginPath(); | |
ctx.rect(player.x, player.y, 50, 50); | |
ctx.fillStyle = "blue"; | |
ctx.fill(); | |
// draw the enemy's nest | |
ctx.beginPath(); | |
ctx.rect(nest.x, nest.y, 50, 50); | |
ctx.fillStyle = "green"; | |
ctx.fill(); | |
// draw the enemy (a red rectangle) | |
ctx.beginPath(); | |
ctx.rect(enemy.x, enemy.y, 50, 50); | |
ctx.fillStyle = "red" | |
ctx.fill(); | |
// draw the enemy's mind state as text | |
if (enemy.text) { | |
ctx.font = "30px Arial"; | |
ctx.fillStyle = "white"; | |
ctx.fillText(enemy.text, enemy.x, enemy.y + 50); | |
} | |
} | |
// at the top level, the game state sees these events | |
// the game starts (start playing the attract mode / splash) | |
// the player starts playing | |
// the player finishes a play session, win or lose | |
var previous_timestamp = null; | |
function frame(timestamp) { | |
if (previous_timestamp) { | |
let dt = (timestamp - previous_timestamp); | |
update(dt); | |
} | |
previous_timestamp = timestamp; | |
draw(); | |
requestAnimationFrame(frame); | |
}; | |
requestAnimationFrame(frame); | |
document.body.addEventListener("keydown", function (e) { | |
if (e.keyCode == 39 | |
|| e.keyCode == 68 | |
|| e.keyCode == 37 | |
|| e.keyCode == 65 | |
|| e.keyCode == 38 | |
|| e.keyCode == 87 | |
|| e.keyCode == 40 | |
|| e.keyCode == 83 | |
|| e.keyCode == 32) { | |
e.preventDefault(); | |
keys[e.keyCode] = true; | |
//if (e.keyCode == 32) { | |
// currentState.action(); | |
//} | |
} | |
}); | |
document.body.addEventListener("keyup", function (e) { | |
keys[e.keyCode] = false; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment