📄 sporen.jc
字号:
//------------------------------------------------------------------------------
// sporen.jc
//------------------------------------------------------------------------------
//
// An applet for the ScriptApp application, based on my life simulation
// algorithm "Sporen".
// To run this script, simply drag it onto the ScriptApp's icon.
//
//------------------------------------------------------------------------------
import stdlib;
import Screen;
import RectLayer;
//------------------------------------------------------------------------------
// forward declarations
//------------------------------------------------------------------------------
class World;
class Spore;
class Color;
//------------------------------------------------------------------------------
// class SporeApplet
//------------------------------------------------------------------------------
class SporeApplet : interface Applet
{
method SporeApplet (Screen&);
method OnOpen ();
method OnClose ();
method OnClick (long button, long x, long y);
method OnKey (long key);
method Idle ();
method Init ();
Screen& m_Screen;
World& m_World;
long m_Inited;
long m_Timer;
}
//------------------------------------------------------------------------------
// class World
//------------------------------------------------------------------------------
// The World is a two dimensional array where the Spores live.
// This class uses the built-in array to create a two-dimensional array.
class World
{
method World (long width, long height);
method long Life ();
method PlaceSpore (long x, long y, Spore& s );
method RemoveSpore (long x, long y);
method const Spore& GetSpore (long x, long y);
method Wrap (long& x, long& y);
long dimX;
long dimY;
long updateY;
array& matrix;
}
//------------------------------------------------------------------------------
// class Spore
//------------------------------------------------------------------------------
// A spore has a fixed life-cycle: It gets born into a cell, eats one or more of it's neighbors,
// reproduces itself to into a free cell next to it, and eventually dies.
class Spore
{
method Spore (const Color& c, long s);
method Spore (const Spore& dad);
method Life ();
method SpinToXY (long& x, long& y);
long energy; // decreases continually, if 0, it dies
long x; // position in matrix
long y; // position in matrix
Color color; // color of the spore
long shape; // "family" of the spore
long spin; // direction of the spore
}
//------------------------------------------------------------------------------
// class Cell
//------------------------------------------------------------------------------
// A simple data class that stores a reference to a Spore and a RectLayer, which
// is used to display the cell on the screen.
class Cell
{
method Cell (long x, long y);
method Update ();
var& spore;
RectLayer& layer;
}
//------------------------------------------------------------------------------
// class Color
//------------------------------------------------------------------------------
// Simple data class that stores an RGB value.
class Color
{
long r, g, b;
method Color(long red, long green, long blue) { r = red; g = green; b = blue; }
}
//------------------------------------------------------------------------------
// global variables and constants
//------------------------------------------------------------------------------
const long kEnergyDec = 1; // defines how fast spore grows old (and dies)
const long kEatBonus = 49; // how much energy eating brings
const long kReproCost = 1; // how much energy reproduction costs
const long kEatLevel = 36; // level at which spore starts to eat
const long kReproLevel = 71; // level at which spore starts to reproduce
const long kCellSize = 8; // width and height of a cell in pixel
const long kUpdateTime = 50; // update interval in msec
const long kUpdateRowsPerIdle = 60; // update 60 rows at once
const Color& kBackColor = new Color(0, 0, 0);
//------------------------------------------------------------------------------
// global reference to our applet
//------------------------------------------------------------------------------
// This allows us to store a reference to our applet as a global variable.
// Several classes need access to our applet, and this is the most convenient
// way to do it.
var& g_Applet = null; // Only type 'var' allows us to do this...
//------------------------------------------------------------------------------
// function CreateApplet
//------------------------------------------------------------------------------
// The Application calls this function to create our applet.
// We need to implement this function and return an instance of our applet.
function Applet& CreateApplet(Screen& screen)
{
g_Applet = new SporeApplet( screen );
return g_Applet;
}
//------------------------------------------------------------------------------
// class SporeApplet
//------------------------------------------------------------------------------
// constructor
method SporeApplet::SporeApplet(Screen& screen)
{
// store reference to screen
m_Screen = screen;
// set fixed size
m_Screen.FixedSize( 640, 480 );
// set background color
m_Screen.BackColor( kBackColor.r, kBackColor.g, kBackColor.b );
// init members
m_Inited = false;
m_Timer = 0;
// allocate a world
m_World = new World( 80, 60 );
// init random generator
stdlib::RandInit();
}
//------------------------------------------------------------------------------
// OnOpen
//------------------------------------------------------------------------------
//
method SporeApplet::OnOpen()
{
// add all Cell layers to our Screen object
for( long y = 0; y < m_World.dimY; y++ )
{
for( long x = 0; x < m_World.dimX; x++ )
{
Cell& cell = m_World.matrix[y][x];
m_Screen.AddLayer( cell.layer );
}
}
}
//------------------------------------------------------------------------------
// OnClose
//------------------------------------------------------------------------------
//
method SporeApplet::OnClose()
{
m_Screen.RemoveAllLayers();
}
//------------------------------------------------------------------------------
// OnClick
//------------------------------------------------------------------------------
//
method SporeApplet::OnClick(long button, long x, long y)
{
}
//------------------------------------------------------------------------------
// OnKey
//------------------------------------------------------------------------------
//
method SporeApplet::OnKey(long key)
{
}
//------------------------------------------------------------------------------
// Idle
//------------------------------------------------------------------------------
//
method SporeApplet::Idle()
{
if( not m_Inited )
{
Init();
}
m_World.Life();
if( m_Timer < stdlib::GetTicks() )
{
m_Timer = stdlib::GetTicks() + kUpdateTime;
m_Screen.Redraw();
}
}
//------------------------------------------------------------------------------
// Init
//------------------------------------------------------------------------------
//
method SporeApplet::Init()
{
// create some colors
Color blue = new Color( 64, 64,255);
Color red = new Color(255, 64,64 );
Color green = new Color( 64,255,64 );
Color yello = new Color(255,255,64 );
// place four spores of different colors and shape as start population
m_World.PlaceSpore( 39, 29, new Spore(blue, 1) );
m_World.PlaceSpore( 40, 29, new Spore(red, 2) );
m_World.PlaceSpore( 39, 30, new Spore(green, 3) );
m_World.PlaceSpore( 40, 30, new Spore(yello, 4) );
m_Inited = true;
}
//------------------------------------------------------------------------------
// class World
//------------------------------------------------------------------------------
// Implementation
method World::World(long width, long height)
{
dimX = width;
dimY = height;
updateY = 0;
matrix = new array[height];
for( long y = 0; y < height; y++ )
{
matrix[y] = new array[width];
for( long x = 0; x < width; x++ )
{
matrix[y][x] = new Cell(x, y);
}
}
}
//------------------------------------------------------------------------------
// Life
//------------------------------------------------------------------------------
// Call Life() of all Spores in this world
method long World::Life()
{
long allDead = true;
long y = updateY;
updateY += kUpdateRowsPerIdle;
if( updateY > dimY )
updateY = dimY;
for( ; y < updateY; y++ )
{
for( long x = 0; x < dimX; x++ )
{
Cell& cell = matrix[y][x];
Spore& spore = cell.spore;
if( spore != null )
{
spore.Life();
cell.Update();
allDead = false;
}
}
}
if( updateY == dimY )
updateY = 0;
return allDead;
}
//------------------------------------------------------------------------------
// PlaceSpore
//------------------------------------------------------------------------------
// Place a Spore in the world
method World::PlaceSpore(long x, long y, Spore& s)
{
Cell& cell = matrix[y][x];
Color& c = s.color;
cell.layer.SetColor( c.r, c.g, c.b );
cell.layer.Show();
cell.spore = s;
s.x = x;
s.y = y;
}
//------------------------------------------------------------------------------
// RemoveSpore
//------------------------------------------------------------------------------
// Remove a Spore from the world
method World::RemoveSpore(long x, long y)
{
Cell& cell = matrix[y][x];
cell.layer.Hide();
cell.spore = null;
}
//------------------------------------------------------------------------------
// GetSpore
//------------------------------------------------------------------------------
// Check if a cell contains a Spore and return it
method const Spore& World::GetSpore(long x, long y)
{
Cell& cell = matrix[y][x];
return cell.spore;
}
//------------------------------------------------------------------------------
// Wrap
//------------------------------------------------------------------------------
// Wrap around coords
method World::Wrap(long& x, long& y)
{
if( x < 0 )
x += dimX;
else if( x >= dimX )
x -= dimX;
if( y < 0 )
y += dimY;
else if( y >= dimY )
y -= dimY;
}
//------------------------------------------------------------------------------
// class Cell
//------------------------------------------------------------------------------
// Constructor
method Cell::Cell(long x, long y)
{
spore = null;
layer = new RectLayer();
layer.ResizeTo( kCellSize - 1, kCellSize - 1 );
layer.MoveTo( x * kCellSize, y * kCellSize );
}
//------------------------------------------------------------------------------
// Update
//------------------------------------------------------------------------------
//
method Cell::Update()
{
Spore& s = spore;
if( s != null )
{
long e = s.energy;
Color& c = s.color;
long r = c.r * e / 100;
long g = c.g * e / 100;
long b = c.b * e / 100;
layer.SetColor(r, g, b);
}
}
//------------------------------------------------------------------------------
// class Spore
//------------------------------------------------------------------------------
// Constructor
method Spore::Spore(const Color& c, long s)
{
energy = 100;
x = 0;
y = 0;
color = c;
shape = s;
spin = stdlib::Rand(0, 7);
}
//------------------------------------------------------------------------------
// class Spore
//------------------------------------------------------------------------------
// copy constructor
method Spore::Spore(const Spore& dad)
{
energy = dad.energy * 81 / 100;
x = 0;
y = 0;
color = dad.color;
shape = dad.shape;
spin = dad.spin;
}
//------------------------------------------------------------------------------
// Life
//------------------------------------------------------------------------------
// Simulate the Spores life
method Spore::Life()
{
long sporX = 0;
long sporY = 0;
World& world = g_Applet.SporeApplet::m_World;
energy -= kEnergyDec;
if( energy <= 0 )
{
// spore is dead, remove from world
world.RemoveSpore( x, y );
return;
}
if( energy < kEatLevel )
{
// peek around to find something to eat...
SpinToXY(sporX, sporY);
world.Wrap(sporX, sporY);
// get the spore from the cell
const Spore& enemy = world.GetSpore(sporX, sporY);
// only eat if it's from other family
if( enemy != null )
{
// found a meal?
if( enemy.shape != shape )
{
// yum!
world.RemoveSpore( sporX, sporY );
energy += kEatBonus;
if( energy > 100 )
energy = 100;
}
}
}
else if( energy >= kReproLevel )
{
// peek around to find a free place
SpinToXY(sporX, sporY);
world.Wrap(sporX, sporY);
// found a spot?
if( world.GetSpore(sporX, sporY) == null )
{
// place kid in cell
world.PlaceSpore( sporX, sporY, new Spore(this) ); // kid inherits from us
energy -= kReproCost;
if( energy < 0 )
energy = 0;
}
}
if( ++spin > 7 )
spin = 0;
}
//------------------------------------------------------------------------------
// SpinToXY
//------------------------------------------------------------------------------
// Computes cell coords from the spin index
method Spore::SpinToXY(long& nx, long& ny)
{
long s = spin;
if( s >= 4 )
s++;
nx = x + s % 3 - 1;
ny = y + s / 3 - 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -