Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // 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)
- }
Add Comment
Please, Sign In to add comment