Survival

by shuetsu
食物連鎖シミュレーション
・赤 ・・・ 肉食動物
・青 ・・・ 草食動物
・緑 ・・・ 植物

スライダーで増殖率を調整
♥2 | Line 423 | Modified 2011-09-14 15:19:46 | MIT License
play

ActionScript3 source code

/**
 * Copyright shuetsu ( http://wonderfl.net/user/shuetsu )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/kqS3c
 */

// forked from shuetsu's Survival
package {
    import flash.events.Event;
    import flash.geom.Point;
    import flash.media.Sound;
    import flash.display.Sprite;
    import com.bit101.components.Slider;
    
    [SWF(width=465, height=465, frameRate=60, backgroundColor=0xeeeeee)]
    public class Survival extends Sprite {
        public const PLANT_COUNT:int = 300;
        public const HERB_COUNT:int = 50;
        public const PRED_COUNT:int = 10;
        public const PLANT_MAX_COUNT:int = 500;
        public const HERB_MAX_COUNT:int = 500;
        public const PRED_MAX_COUNT:int = 500;
        
        public var plants:Array = new Array();
        public var herbivores:Array = new Array();
        public var predators:Array = new Array();
        private var plantRate:Slider;
        private var herbRate:Slider;
        private var predRate:Slider;

        public function Survival() {
            for (var i:int = 0; i < PLANT_COUNT; i++) {
                plants.push(new Plant(
                  this, 
                  new XY(Math.random() * 465, Math.random() * 465)));
            }
            
            for (i = 0; i < HERB_COUNT; i++) {
                herbivores.push(new Herbivore(
                  this,
                  new XY(Math.random() * 465, Math.random() * 465)));
            }
            
            for (i = 0; i < PRED_COUNT; i++) {
                predators.push(new Predator(
                  this,
                  new XY(Math.random() * 465, Math.random() * 465)));
            }
            plantRate = new Slider(Slider.HORIZONTAL, this, 2, 0);
            herbRate = new Slider(Slider.HORIZONTAL, this, 2, 10);
            predRate = new Slider(Slider.HORIZONTAL, this, 2, 20);
            plantRate.value = 50;
            herbRate.value = 50;
            predRate.value = 50;
            addEventListener(Event.ENTER_FRAME, onEnter);
        }
        
        public function onEnter(e:Event):void {
            plants = plants.filter(function(item:*, index:int, array:Array):Boolean {
                return item.life();
            })
            herbivores = herbivores.filter(function(item:*, index:int, array:Array):Boolean {
                return item.life(plants);
            })
            predators = predators.filter(function(item:*, index:int, array:Array):Boolean {
                return item.life(herbivores);
            })
            if (plants.length < PLANT_MAX_COUNT) {
                var newPlants:Array = new Array();
                for each(var plant:Plant in plants){
                    var newPlant:Plant = plant.multiply(toRate(plantRate.value)); 
                    if (newPlant != null){
                        newPlants.push(newPlant);
                    }
                }
                plants = plants.concat(newPlants);
            }
            
             if (herbivores.length < HERB_MAX_COUNT) {
                var newHerbivores:Array = new Array();
                for each(var herbivore:Herbivore in herbivores){
                    var newHerbivore:Herbivore = herbivore.multiply(toRate(herbRate.value));
                    if (newHerbivore != null){
                        newHerbivores.push(newHerbivore);
                    }
                }
                herbivores = herbivores.concat(newHerbivores);
            }
            
             if (predators.length < PRED_MAX_COUNT) {
                var newPredators:Array = new Array();
                for each(var predator:Predator in predators){
                    var newPredator:Predator = predator.multiply(toRate(predRate.value));
                    if (newPredator != null){
                        newPredators.push(newPredator);
                    }
                }
                predators = predators.concat(newPredators);
            }
            
           for each (herbivore in herbivores) {
               herbivore.move();
           }
           for each (predator in predators) {
               predator.move();
           }
           
           graphics.clear();
           graphics.beginFill(0x00ff00);
           graphics.drawRect(105, 0, plants.length * 360 / PLANT_MAX_COUNT, 10);
           graphics.endFill();
           graphics.beginFill(0x4040ff);
           graphics.drawRect(105, 10, herbivores.length * 360 / HERB_MAX_COUNT, 10);
           graphics.endFill();
           graphics.beginFill(0xff0000);
           graphics.drawRect(105, 20, predators.length * 360 / PRED_MAX_COUNT, 10);
           graphics.endFill();
        }
        
        private function toRate(v:int):Number{
            if (v >= 50){
                return (150 - v) / 100;
            }else{
                return (100 - v) / 50;
            }
        }
    }
    
}

const PRED_LIFE_MIN:int = 500;
const PRED_LIFE_MAX:int = 1000;
const PRED_FILL:int = 200;
const PRED_STARV:int = 100;
const PRED_MULTIPLY_INTERVAL_MIN:int = 200;
const PRED_MULTIPLY_INTERVAL_MAX:int = 400;
const HERB_LIFE_MIN:int = 400;
const HERB_LIFE_MAX:int = 800;
const HERB_FILL:int = 200;
const HERB_STARV:int = 150;
const HERB_MULTIPLY_INTERVAL_MIN:int = 200;
const HERB_MULTIPLY_INTERVAL_MAX:int = 350;
const PLANT_LIFE_MIN:int = 400;
const PLANT_LIFE_MAX:int = 700;
const PLANT_MULTIPLY_INTERVAL_MIN:int = 200;
const PLANT_MULTIPLY_INTERVAL_MAX:int = 400;

import flash.display.Sprite;
import flash.display.Shape;
import flash.display.Graphics;
import flash.filters.BlurFilter;

// xy
class XY {
    public var x:Number;
    public var y:Number;
    
    public function XY(x:Number, y:Number) {
        var _x:Number = x;
        var _y:Number = y;
        while (_x < 0){
            _x += 465;
        }
        while (_x > 465){
            _x -=465;
        }
        while (_y < 35){
            _y += 430;
        }
        while (_y > 465){
            _y -= 430;
        }
        this.x = _x;
        this.y = _y;
    }
    
    public function distance(xy:XY):Number {
        var dx:Number = x - xy.x;
        var dy:Number = y - xy.y;
        return Math.sqrt(dx * dx + dy * dy);
    }
    
    public function angle(xy:XY):Number {
        var dx:Number = x - xy.x;
        var dy:Number = y - xy.y;
        return Math.atan2(dy, dx);
    }
    
}

class Speed {
    public var angle:Number;
    public var speed:Number;
    
    public function Speed(angle:Number, speed:Number) {
        this.angle = angle;
        this.speed = speed;
    }
    
    public function move(xy:XY):XY {
        return new XY(xy.x + Math.cos(angle) * speed, xy.y + Math.sin(angle) * speed);
    }
    
    public static function normarizeAngle(r:Number):Number {
        var _r:Number = r;
        while (_r > Math.PI) {
            _r -= 2 * Math.PI;
        }
        while (_r < -Math.PI) {
            _r += 2 * Math.PI;
        }
        return _r;
    }
}


// 肉食動物
class Predator {
    public var multiplyInterval:int;
    public var pos:XY;
    public var speed:Speed;
    public var canvas:Sprite;
    public var count:int;
    public var countMax:Number;
    public var sprite:Sprite = new Sprite();
    public var fill:int = 0;
    public var target:Herbivore = null;
    public var eat:Boolean = false;
    
    public function Predator(canvas:Sprite, pos:XY):void {
        this.pos = pos;
        this.speed = new Speed(Math.random() * Math.PI * 2, Math.random() * 3 + 2);
        this.countMax = countMax;
        this.canvas = canvas;
        this.count = 0;
        this.countMax = Math.random() * (PRED_LIFE_MAX - PRED_LIFE_MIN) + PRED_LIFE_MIN;
        this.fill = Math.random() * PRED_FILL;
        this.multiplyInterval = Math.random() * (PRED_MULTIPLY_INTERVAL_MAX - PRED_MULTIPLY_INTERVAL_MIN) 
                                                 + PRED_MULTIPLY_INTERVAL_MIN;
        sprite.graphics.beginFill(0xff0000);
        sprite.graphics.lineTo(-5, -5);
        sprite.graphics.lineTo(10, 0);
        sprite.graphics.lineTo(-5, 5);
        sprite.graphics.endFill();
        canvas.addChild(sprite);
    }

    public function life(herbivores:Array):Boolean {
        count++;
        fill--;
        if (target == null && fill <= 0) {
            for each (var herbivore:Herbivore in herbivores) {
                if (pos.distance(herbivore.pos) < 50) {
                    target = herbivore;
                    break;
                }
            }
        }
        if (target != null && target.dead){
            target = null;
        }
        if(target != null) {
            if(pos.distance(target.pos) <= 10) {
                target.remove();
                herbivores.splice(herbivores.indexOf(target), 1);
                fill = PRED_FILL;
                eat = true;
            }
        }
        if (target != null){
            if (pos.distance(target.pos) > 400){
                target = null;
            }
        }
        if (target != null) {
            var r:Number = Speed.normarizeAngle(Speed.normarizeAngle(speed.angle) - pos.angle(target.pos));
            if(r > 0.1) { 
                speed.angle += 0.1;
            } else if (r < -0.1) {
                speed.angle -= 0.1;
            } else {
                speed.angle += r;
            }
        }
        pos = speed.move(pos);
        if (count >= countMax || fill < -PRED_STARV) {
            canvas.removeChild(sprite);
            return false;
        } else {
            return true;
        }
    }
    
    public function move():void {
        if (fill > 0){
            sprite.scaleX = 1 + fill / PRED_FILL;
            sprite.scaleY = 1 + fill / PRED_FILL;
        }else{
            sprite.scaleX = 1;
            sprite.scaleY = 1;
        }
        sprite.rotationZ = speed.angle * 180 / Math.PI;
        sprite.x = pos.x;
        sprite.y = pos.y;
    }
    
    public function multiply(rate:Number):Predator {
        var t:int = multiplyInterval * rate;
        if (fill > 0 && count % t == 0) {
            return new Predator(canvas,
                             new XY(pos.x + (Math.random() * 20 - 10),
                                    pos.y + (Math.random() * 20 - 10)));
        } else {
            return null;
        }
    }
}

// 草食動物
class Herbivore {
    public var multiplyInterval:int;
    public var pos:XY;
    public var speed:Speed;
    public var canvas:Sprite;
    public var count:int;
    public var countMax:Number;
    public var sprite:Sprite = new Sprite();
    public var fill:int = 0;
    public var target:Plant = null;
    public var eat:Boolean = false;
    public var dead:Boolean = false;
    
    public function Herbivore(canvas:Sprite, pos:XY):void {
        this.pos = pos;
        this.speed = new Speed(Math.random() * Math.PI * 2, Math.random() * 1 + 1);
        this.countMax = countMax;
        this.canvas = canvas;
        this.count = 0;
        this.countMax = Math.random() * (HERB_LIFE_MAX - HERB_LIFE_MIN) + HERB_LIFE_MIN;
        this.fill = Math.random() * HERB_FILL;
        this.multiplyInterval = Math.random() * (HERB_MULTIPLY_INTERVAL_MAX - HERB_MULTIPLY_INTERVAL_MIN) 
                                                 + HERB_MULTIPLY_INTERVAL_MIN;
        sprite.graphics.beginFill(0x4040ff);
        sprite.graphics.drawCircle(0,0,5);
        sprite.graphics.endFill();
        canvas.addChild(sprite);
    }

    public function life(plants:Array):Boolean {
        count++;
        fill--;
        if (target == null) {
            for each (var plant:Plant in plants) {
                if (pos.distance(plant.pos) < 50) {
                    target = plant;
                    break;
                }
            }
        }
        if (target != null && target.dead){
            target = null;
        }
        if(target != null && fill <= 0) {
            if(pos.distance(target.pos) <= 10) {
                target.remove();
                plants.splice(plants.indexOf(target), 1);
                fill = HERB_FILL;
                eat = true;
            }
        }
        if (target != null){
            if (pos.distance(target.pos) > 400){
                target = null;
            }
        }
        if (target != null) {
            var r:Number = Speed.normarizeAngle(Speed.normarizeAngle(speed.angle) - pos.angle(target.pos));
            if(r > 0.1) { 
                speed.angle += 0.1;
            } else if (r < -0.1) {
                speed.angle -= 0.1;
            } else {
                speed.angle += r;
            }
        }
        pos = speed.move(pos);
        if (count >= countMax || fill < -HERB_STARV) {
            remove();
            return false;
        } else {
            return true;
        }
    }
    
    public function move():void {
        if (fill > 0){
            sprite.scaleX = 1 + fill / HERB_FILL;
            sprite.scaleY = 1 + fill / HERB_FILL;
        }else{
            sprite.scaleX = 1;
            sprite.scaleY = 1;
        }
        sprite.x = pos.x;
        sprite.y = pos.y;
    }
    
    public function multiply(rate:Number):Herbivore {
        var t:int = multiplyInterval * rate;
        if (fill > 0 && count % t == 0) {
            return new Herbivore(canvas,
                             new XY(pos.x + (Math.random() * 20 - 10),
                                    pos.y + (Math.random() * 20 - 10)));
        } else {
            return null;
        }
    }
    
    public function remove():void{
        canvas.removeChild(sprite);
        dead = true;
    }
}

// 植物
class Plant {
    public var multiplyInterval:int;
    public var pos:XY;
    public var canvas:Sprite;
    public var count:int;
    public var countMax:Number;
    public var dead:Boolean = false;
    public var sprite:Sprite = new Sprite();
    
    public function Plant(canvas:Sprite, pos:XY):void {
        this.pos = pos;
        this.countMax = countMax;
        this.canvas = canvas;
        this.count = 0;
        this.countMax = Math.random() * (PLANT_LIFE_MAX - PLANT_LIFE_MIN) + PLANT_LIFE_MIN;
        this.multiplyInterval = Math.random() * (PLANT_MULTIPLY_INTERVAL_MAX - PLANT_MULTIPLY_INTERVAL_MIN) 
                                                 + PLANT_MULTIPLY_INTERVAL_MIN;
        sprite.graphics.beginFill(0x00ff00);
        sprite.graphics.drawRect(pos.x, pos.y, 10, 10);
        sprite.graphics.endFill();
        sprite.filters = [new BlurFilter()];
        canvas.addChild(sprite);
    }
    
    public function life():Boolean {
        count++;
        if (count >= countMax) {
            remove();
            return false;
        } else {
            return true;
        }
    }

    public function remove():void{
        canvas.removeChild(sprite);
        dead = true;
    }

    public function multiply(rate:Number):Plant {
        var t:int = multiplyInterval * rate;
        if (count % t == 0) {
            return new Plant(canvas,
                             new XY(pos.x + (Math.random() * 60 - 30),
                                    pos.y + (Math.random() * 60 - 30)));
        } else {
            return null;
        }
    }
}