Last active
April 17, 2018 06:00
-
-
Save josephg/f1dcae6bdbd121cf94dcb0905bde6eb0 to your computer and use it in GitHub Desktop.
Behaviour trees with generators example 2
This file contains 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
// 2 entities, George and Phil will meet on this fateful night | |
const e1 = { | |
name: 'George', | |
health: 400, | |
target: null, | |
} | |
const e2 = { | |
name: 'Phil', | |
health: 400, | |
target: null, | |
} | |
e1.behave = agentBehaviour(e1) | |
e2.behave = agentBehaviour(e2) | |
function *patrol(e) { | |
console.log(e.name, 'patrolling for baddies...') | |
while(true) { | |
yield* wait(10) | |
console.log(e.name, 'continues to patrol') | |
} | |
} | |
function *attack(e, target) { | |
console.log(e.name, 'engages', target.name) | |
yield* iwhile(() => target.health > 0, function *() { | |
while (true) { | |
if (Math.random() < 0.5) { | |
// Cast fireball | |
console.log(e.name, 'charges a fireball at', target.name) | |
yield* wait(10) | |
const damage = 100 + (Math.random() * 10)|0 | |
target.health -= damage | |
console.log(`π₯ ${e.name}'s fireball hits ${target.name} for ${damage} damage, ${target.health} hp remaining`) | |
} else { | |
// Attack with sword | |
const damage = 10 + (Math.random() * 10)|0 | |
target.health -= damage | |
console.log(`βοΈ ${e.name}'s sword slices ${target.name} for ${damage} damage, ${target.health} hp remaining`) | |
yield* wait(3) | |
} | |
yield* wait(5) | |
} | |
}) | |
console.log(target.name, 'is dead!', e.name, 'cheers and hollers π') | |
e.target = null | |
//while(true) yield | |
} | |
function *agentBehaviour(e) { | |
yield* iwhile(() => e.health > 0, function *() { | |
while (true) { | |
// If we have no target, just patrol around. | |
yield* iwhile(() => e.target == null, patrol(e)) | |
// ... Ok we have a target now. Attack!! | |
yield* attack(e, e.target) | |
} | |
}) | |
console.log(e.name, 'is dead π»') | |
} | |
// *** Plumbing. | |
// The state is a stack of iterators. Each tick we'll take the top of the stack | |
// (the stack's last element) and iterate it. | |
// Run iterator so long as predicate remains true | |
function *iwhile(pred, iter) { | |
if (typeof iter === 'function') iter = iter() // Avoids some awkward syntax | |
while (true) { | |
if (!pred()) return | |
const {value, done} = iter.next() | |
if (done) return value // Wrap return value of iterator | |
else yield value | |
} | |
} | |
// Helper to wait X frames | |
function *wait(framecount) { | |
while(--framecount) yield // Each call to yield will wait 1 frame | |
} | |
// *** Actual runtime code | |
const timer = setInterval(tick, 100) | |
function updateEntity(e) { | |
if (e.dead) return | |
const {done} = e.behave.next() | |
if (done) { | |
console.log('Cleanup', e.name) | |
e.dead = true | |
} | |
} | |
let framecount = 0 | |
function tick() { | |
framecount++ | |
if (e1.target == null && framecount === 10) { | |
console.log('Oh no! They saw each other') | |
e1.target = e2 | |
e2.target = e1 | |
} | |
updateEntity(e1) | |
updateEntity(e2) | |
// Done! | |
if (e1.dead || e2.dead) clearInterval(timer) | |
} |
This file contains 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
$ node bt.js | |
George patrolling for baddies... | |
Phil patrolling for baddies... | |
Oh no! They saw each other | |
George engages Phil | |
βοΈ George's sword slices Phil for 19 damage, 981 hp remaining | |
Phil engages George | |
Phil charges a fireball at George | |
George charges a fireball at Phil | |
π₯ Phil's fireball hits George for 103 damage, 897 hp remaining | |
Phil charges a fireball at George | |
π₯ George's fireball hits Phil for 105 damage, 876 hp remaining | |
George charges a fireball at Phil | |
π₯ Phil's fireball hits George for 101 damage, 796 hp remaining | |
βοΈ Phil's sword slices George for 14 damage, 782 hp remaining | |
π₯ George's fireball hits Phil for 101 damage, 775 hp remaining | |
George charges a fireball at Phil | |
βοΈ Phil's sword slices George for 11 damage, 771 hp remaining | |
Phil charges a fireball at George | |
π₯ George's fireball hits Phil for 107 damage, 668 hp remaining | |
βοΈ George's sword slices Phil for 11 damage, 657 hp remaining | |
π₯ Phil's fireball hits George for 100 damage, 671 hp remaining | |
George charges a fireball at Phil | |
Phil charges a fireball at George | |
π₯ George's fireball hits Phil for 106 damage, 551 hp remaining | |
π₯ Phil's fireball hits George for 106 damage, 565 hp remaining | |
George charges a fireball at Phil | |
Phil charges a fireball at George | |
π₯ George's fireball hits Phil for 107 damage, 444 hp remaining | |
π₯ Phil's fireball hits George for 104 damage, 461 hp remaining | |
George charges a fireball at Phil | |
βοΈ Phil's sword slices George for 15 damage, 446 hp remaining | |
Phil charges a fireball at George | |
π₯ George's fireball hits Phil for 103 damage, 341 hp remaining | |
George charges a fireball at Phil | |
π₯ Phil's fireball hits George for 107 damage, 339 hp remaining | |
Phil charges a fireball at George | |
π₯ George's fireball hits Phil for 105 damage, 236 hp remaining | |
George charges a fireball at Phil | |
π₯ Phil's fireball hits George for 103 damage, 236 hp remaining | |
βοΈ Phil's sword slices George for 12 damage, 224 hp remaining | |
π₯ George's fireball hits Phil for 101 damage, 135 hp remaining | |
Phil charges a fireball at George | |
George charges a fireball at Phil | |
π₯ Phil's fireball hits George for 107 damage, 117 hp remaining | |
π₯ George's fireball hits Phil for 107 damage, 28 hp remaining | |
βοΈ Phil's sword slices George for 12 damage, 105 hp remaining | |
βοΈ George's sword slices Phil for 16 damage, 12 hp remaining | |
Phil charges a fireball at George | |
George charges a fireball at Phil | |
π₯ Phil's fireball hits George for 106 damage, -1 hp remaining | |
George is dead π» | |
Cleanup George | |
George is dead! Phil cheers and hollers π | |
Phil patrolling for baddies... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment