Advertisement
Masterchoc

Untitled

Dec 21st, 2017
2,693
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. Maths      = require './core/Maths'
  2. IKinematic = require './core/IKinematic'
  3. Vec2       = require './core/Vec2'
  4. Color      = require './core/Color'
  5. Bullet     = require './bullet'
  6.  
  7. class Agent
  8.     constructor: (x = 0, y = 0, dna) ->
  9.         @acceleration    = new Vec2()
  10.         @velocity        = new Vec2 Maths.randRange(-3, 3), Maths.randRange(-3, 3)
  11.         @angle           = @velocity.getAngle() + Math.PI * 0.5
  12.         @position        = new Vec2 x, y
  13.         @radius          = 8
  14.         @maxSpeed        = 3
  15.         @maxForce        = 0.2
  16.         @health          = 1
  17.         @maxHealth       = 1
  18.         @tail            = null
  19.         @tailPhase       = 0
  20.         @tailSegments    = 16+
  21.         @tailSegLength   = 6
  22.         @team            = null
  23.         @color           = new Color 0, 0, 220, 1
  24.         @bullets         = []
  25.         @targetNutrition = null
  26.         @targetEnemy     = null
  27.         @shooting        = false
  28.         @aiming          = false
  29.         @seeking         = false
  30.  
  31.         @maxShootDistance = 200
  32.         @closestTargetEnemy = Infinity
  33.         @closestTargetNutrition = Infinity
  34.  
  35.         if dna instanceof Array
  36.             @dna = []
  37.             for i in [0 .. dna.length]
  38.                 if Math.random() < 0.1
  39.                     if i < 3
  40.                         @dna[i] = dna[i] + Maths.randRange -0.2, 0.2
  41.                     else if i == 3
  42.                         v =  dna[i] + Maths.randRange -10, 10
  43.                         rSq = @radius * @radius
  44.                         v = rSq if v < rSq
  45.                         @dna[i] = v
  46.                     else if i == 4
  47.                         min = Math.PI / 16
  48.                         max = Math.PI / 2
  49.                         v =  dna[i] + Maths.randRange min, max
  50.                         v = min if v < min
  51.                         @dna[i] = v
  52.                 else
  53.                     @dna[i] = dna[i]
  54.         else
  55.             max = 3
  56.             # 0: Attraction / repulsion to food
  57.             # 1: Attraction / repulsion to poison
  58.             # 2: Attraction / repulsion to enemy
  59.             # 3: Line of sight radius
  60.             # 4: Line of sight angle
  61.  
  62.             @dna = [
  63.                 Maths.randRange(-max, max),
  64.                 Maths.randRange(-max, max),
  65.                 Maths.randRange(-max, max),
  66.                 Maths.randRange(@radius * @radius, @radius * @radius + @radius * @radius),
  67.                 Maths.randRange(Math.PI / 16, Math.PI / 2)
  68.             ]
  69.         @
  70.  
  71.     isDead : -> @health <= 0
  72.  
  73.     reproduce: ->
  74.         if Math.random() < 0.001
  75.             agent = new Agent @position.x, @position.y, @dna
  76.             agent.team = @team
  77.             agent.color = @color
  78.             agent.createTail()
  79.             return agent
  80.         else
  81.             return null
  82.  
  83.     createTail: ->
  84.         @tail = new IKinematic @position
  85.         @tail.addNode(@tailSegLength, @color) for i in [1 .. @tailSegments]
  86.  
  87.     shoot: (target) ->
  88.         bullet = new Bullet this, @color
  89.         bullet.position.setX @position.x
  90.         bullet.position.setY @position.y
  91.         bullet.velocity.setLength Maths.randRange(4, 8)
  92.         bullet.velocity.setAngle target.position.subtract(@position).getAngle()
  93.         @bullets.push bullet
  94.  
  95.         setTimeout =>
  96.             @aiming = false
  97.         , 1100
  98.  
  99.     attack: (enemies) ->
  100.         @aim enemies
  101.  
  102.     aim: (list) ->
  103.         @targetEnemy = null
  104.         @closestTargetEnemy = Infinity
  105.  
  106.         for enemy, i in list by -1
  107.             dist = enemy.position.distance @position
  108.  
  109.             if dist < @dna[3] and dist < @closestTargetEnemy
  110.                 @closestTargetEnemy = dist
  111.                 @targetEnemy = enemy
  112.  
  113.         if @targetEnemy != null && !@aiming
  114.             if @isInSight @targetEnemy.position
  115.                 @aiming = true
  116.                 seek = @seek @targetEnemy
  117.                 seek.multiply @dna[2]
  118.                 seek.limit @maxForce
  119.                 @applyForce seek
  120.                 @shoot @targetEnemy
  121.  
  122.     eat: (list, index) ->
  123.         @targetNutrition = null
  124.         @closestTargetNutrition = Infinity
  125.  
  126.         for item, i in list by -1
  127.             dist = item.position.distance @position
  128.  
  129.             if dist < @dna[3] and dist < @closestTargetNutrition
  130.                 @closestTargetNutrition = dist
  131.                 @targetNutrition = item
  132.  
  133.                 if dist < 9
  134.                     @health += item.nutrition
  135.                     list.splice i, 1
  136.  
  137.         if @targetNutrition != null
  138.             if @isInSight @targetNutrition.position
  139.                 seek = @seek @targetNutrition, index
  140.                 seek.multiply @dna[index]
  141.                 seek.limit @maxForce
  142.                 @applyForce seek
  143.  
  144.     followFlowField: (flowField) ->
  145.         x = Math.floor @position.x / flowField.scale
  146.         y = Math.floor @position.y / flowField.scale
  147.         i = x + y * flowField.cols
  148.         force = flowField.field[i]
  149.         @applyForce force.limit(@maxForce) if typeof force != 'undefined'
  150.  
  151.     draw: (ctx) ->
  152.         if window.toggleTails
  153.             @tail.draw ctx if @tail isnt null
  154.  
  155.         ctx.save()
  156.         @drawAimLine ctx
  157.         ctx.translate @position.x, @position.y
  158.  
  159.  
  160.         @angle = @velocity.getAngle() + Math.PI * 0.5
  161.  
  162.         ctx.rotate @angle
  163.         @drawLineOfSight ctx
  164.  
  165.         @debug ctx
  166.         @drawHealthBar ctx
  167.  
  168.         @drawShape ctx
  169.  
  170.         ctx.restore()
  171.  
  172.     drawShape: (ctx) ->
  173.         ctx.beginPath()
  174.         ctx.ellipse 0, 0, @radius, @radius * 2, 0, 0, 2 * Math.PI
  175.         ctx.closePath();
  176.         gradient = ctx.createRadialGradient 0, 0, @radius * 1.5, 0, -@radius * 1.5, @radius / 3
  177.         c = Color.FromHex @color
  178.         c.r += 60
  179.         c.g += 60
  180.         c.b += 60
  181.         gradient.addColorStop 1, c.toStr()
  182.         gradient.addColorStop 0, @color
  183.         ctx.fillStyle = gradient
  184.         ctx.fill()
  185.  
  186.     drawAimLine: (ctx) ->
  187.         if @targetEnemy && window.toggleAimLines
  188.             p = @targetEnemy.position.clone()
  189.             ctx.beginPath()
  190.             ctx.moveTo @position.x, @position.y
  191.             ctx.lineTo p.x, p.y
  192.             ctx.closePath()
  193.             color = Color.FromHex @color
  194.             ctx.lineWidth = 2
  195.             ctx.strokeStyle = "rgba(#{color.r}, #{color.g}, #{color.b}, 1)"
  196.             ctx.stroke()
  197.  
  198.     isInSight: (target) ->
  199.         delta = target.subtract(@position)
  200.         angle = delta.getAngle()
  201.         baseAngle = @angle - (Math.PI * 0.5)
  202.         los1Angle = baseAngle - (@dna[4] * 0.5)
  203.         los2Angle = baseAngle + (@dna[4] * 0.5)
  204.  
  205.         if angle >= los1Angle && angle <= los2Angle
  206.             return true
  207.         else
  208.             @color = @team.color
  209.             return false
  210.  
  211.     drawLineOfSight: (ctx) ->
  212.         if window.toggleSightLines
  213.             los1 = new Vec2()
  214.             los2 = new Vec2()
  215.             baseAngle = @angle - (Math.PI * 0.5)
  216.             los1Angle = baseAngle - (@dna[4] * 0.5)
  217.             los2Angle = baseAngle + (@dna[4] * 0.5)
  218.  
  219.             ctx.save()
  220.             ctx.lineWidth = 0
  221.             ctx.rotate -@angle
  222.             gradient = ctx.createRadialGradient 0, 0, @dna[3] / 3, 0, 0, @dna[3]
  223.             c = Color.FromHex @color
  224.             c.a = 0.3
  225.             gradient.addColorStop 1, 'rgba(255,255,255,0.0)'
  226.             gradient.addColorStop 0, c.toStr()
  227.             los1.setLength @dna[3]
  228.             los2.setLength @dna[3]
  229.             los1.setAngle los1Angle
  230.             ctx.beginPath()
  231.             ctx.moveTo 0, 0
  232.             ctx.lineTo los1.x, los1.y
  233.  
  234.             ctx.arc 0, 0,  @dna[3], los1Angle, los2Angle
  235.  
  236.             los2.setAngle los2Angle
  237.             ctx.moveTo 0, 0
  238.             ctx.lineTo los2.x, los2.y
  239.             ctx.fillStyle = gradient
  240.             ctx.fill()
  241.  
  242.             ctx.restore()
  243.  
  244.     drawHealthBar: (ctx) ->
  245.         if window.toggleHealthBar
  246.             ctx.save()
  247.             ctx.rotate -@angle
  248.             ctx.rect -@radius * 4, 40, @radius * 8, 4
  249.             ctx.strokeStyle = "rgba(0,0,0,0.3)";
  250.             ctx.lineWidth = 2
  251.             ctx.stroke()
  252.             percent = @health / @maxHealth
  253.             green = new Color 0, 255, 0, 1
  254.             red = new Color 255, 0, 0, 1
  255.             ctx.fillStyle = red.blend(green, @health).toStr()
  256.             ctx.fillRect -@radius * 4, 40, (@radius * 8) * percent, 4
  257.             ctx.restore()
  258.  
  259.     debug: (ctx) ->
  260.         if window.toggleFoodAttraction is true
  261.             lineFood = new Vec2()
  262.             lineFood.setLength @dna[0] * 60
  263.             lineFood.setAngle -Math.PI * 0.5
  264.  
  265.             ctx.beginPath()
  266.             ctx.moveTo 0, 0
  267.             ctx.lineTo lineFood.x, lineFood.y
  268.             ctx.closePath()
  269.             ctx.strokeStyle = 'rgba(0, 255, 0, 1)'
  270.             ctx.lineWidth = 1
  271.             ctx.stroke()
  272.  
  273.  
  274.         if window.togglePoisonAttraction is true
  275.             linePoison = new Vec2()
  276.             linePoison.setLength @dna[1] * 60
  277.             linePoison.setAngle Math.PI * 0.5
  278.  
  279.             ctx.beginPath()
  280.             ctx.moveTo 0, 0
  281.             ctx.lineTo linePoison.x, linePoison.y
  282.             ctx.closePath()
  283.             ctx.strokeStyle = 'rgba(255, 0, 0, 1)'
  284.             ctx.lineWidth = 1
  285.             ctx.stroke()
  286.  
  287.     update: ->
  288.         if @tail isnt null
  289.             @tail.update()
  290.  
  291.         @velocity.add @acceleration
  292.         @velocity.limit @maxSpeed
  293.         @position.add @velocity
  294.         @acceleration.multiplyBy 0
  295.         @health -= 0.0015
  296.         @health = @maxHealth if @health > @maxHealth
  297.         @health = 0 if @health < 0
  298.  
  299.     applyForce: (force) ->
  300.         @acceleration.add force
  301.  
  302.     seek: (target) ->
  303.         @seeking = true
  304.         focus = target.position.subtract @position
  305.         focus.setLength @maxSpeed
  306.         focus.subtract @velocity
  307.  
  308.     boundaries: ->
  309.         dist = 10
  310.         focus = null
  311.  
  312.         if @position.x  < dist
  313.             focus = new Vec2 @maxSpeed, @velocity.y
  314.         else if @position.x + dist > window.canvasWidth - dist
  315.             focus = new Vec2 -@maxSpeed, @velocity.y
  316.  
  317.         if @position.y  < dist
  318.             focus = new Vec2 @velocity.x, @maxSpeed
  319.         else if @position.y + dist > window.canvasHeight - dist
  320.             focus = new Vec2 @velocity.x, -@maxSpeed
  321.  
  322.         if focus isnt null
  323.             focus.setLength @maxSpeed
  324.             steer = focus.subtract @velocity
  325.             steer.limit @maxForce
  326.             @applyForce steer
  327.  
  328. if typeof module != 'undefined'
  329.     module.exports = Agent
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement