●姿を決めましょう。
setFigure() で姿を渡します。
setFigureのコードのところにサンプルを書いてますが、
姿は『文字列』でも『ポリゴン』でも『gifファイル』でもOKです。
●動作を変えましょう。
behavior() の中で特異な行動と、変身や死を設定しています。
オヤジッチやヘビッチに変身させてみてもいいでしょう。
糞でなくて、泡を出してもいいでしょう。
------------------ hazama3.java ----------------------
import java.awt.*;
import java.applet.*;
import java.util.*;
/********************************************************************
クラス階層
Energy…エネルギーの定数を与える
WaterStatus…水の状態の定数を与える
Spread…広さ。WidthとHeigitからなる。Dimensionの別バージョン
Direction…方向
Aquarium…水槽の中身の管理
hazama3…アプレット
Shape…姿。String, Image, Polygonなどを統一的に扱う。
Place…配置の定数を与える
Anima…動くもの
Creature…生き物
KoMedaka…子めだか。
Medaka…めだか。
CrazyDance…狂舞めだか。
Meal…食べ物
Plant…水草
Drops…落ちるもの。糞、死体など。
Muck…糞
StatusMonitor…状態表示盤。
ConsoleBox…操作盤。
Leftがいろいろ出てきたので、(表示の配列と向きと)
Leftの意味が分かるように、変数のクラスを作ってみた。
水草を餌として食べてみた。
食べた分だけ背を低くしようと思ったが、
オブジェクトの配置も変えなきゃいけなくなるので、形を変えることにした。
一番上から食べて欲しいので食べるところに黄色のマークをした。
めだかはお腹が空くとマークに向かって走るが、水草の領域と接したら食べる。
marginの扱いがいやらしい†ので、
hazama3とAquariumを完全に分離したかったんだけど、
なぜか表示しなくなってしまう…
# いやらしい†:ブラウザが決めるStatusMenu,ConsoleBoxの大きさに依存。
********************************************************************/
//一部ステータス判定に使うので、グローバルに定義してみた。
class Energy{ // エネルギーの定数を与える
static final int ToLive = 1; //これより下になったら死ぬ。
static final int Full = 800; //めだかの満タンエネルギー量
static final int Emergency = 50; //めだかがもう動けない。水草を諦めて餌を食う。
static final int Hunger = 350; //水草に向かって動き始める。
static final int Birth = 400; //これ以上あれば子供を産める。
}
class WaterStatus{ //水の状態の定数を与える
static final int CrazyClean = 0; //成人の時にこれ以下なら狂舞状態(CrazyDance)になる
static final int AlarmChild = 10; //警告。状態表示を変える
static final int KillChild = 13; //子供が死ぬ
static final int AlarmCrazy = 23; //警告。狂舞の色が七変化
static final int KillCrazy = 25; //狂舞が死ぬ
static final int KillAll =100; //みんな死ぬ
}
class Spread { //広さ //Dimensionにはresizeが無いから…
int width; //幅
int height; //高さ
Spread(int w, int h){
width=w;
height=h;
}
Spread(Dimension d){ //コピー
width=d.width;
height=d.height;
}
void resize(int w, int h){ //サイズ変更
width=w;
height=h;
}
void resize(Rectangle r){ //サイズ変更
width=r.width;
height=r.height;
}
}
class Direction { //動く方向
// 各ビットが[up][down][right][left]の意味。
static final int Stop = 0; //移動方向の要素
static final int Left = 1; //移動方向の要素
static final int Right = 2; //移動方向の要素
static final int Up = 4; //移動方向の要素
static final int Down = 8; //移動方向の要素
int val = Stop;
public Direction(){
random();
}
public Direction(int newval){
//newvalは、(Direction.Up+Direction.Left)などとする。
val = newval;
}
void set(int newval){
val = newval;
}
void set(int dx, int dy){ //dx, dyから、向きを決める
val=0;
if (dx<0){ val += Left; }
if (dx>0){ val += Right; }
if (dy<0){ val += Up; }
if (dy>0){ val += Down; }
}
//向きを設定する。相殺されないように逆向き成分をなくす。
void setLeft(){ val = (val & ~Right)|Left; }
void setRight(){ val = (val & ~Left)|Right; }
void setUp(){ val = (val & ~Down)|Up; }
void setDown(){ val = (val & ~Up)|Down; }
//ランダムな方向をつくる。
void random(){ val = (int)(Math.random() * 16); } // 0〜15の乱数
//方向に各成分が含まれているか検査
boolean isLeft(){ return (val & Left)!=0; }
boolean isRight(){ return (val & Right)!=0; }
boolean isUp(){ return (val & Up)!=0; }
boolean isDown(){ return (val & Down)!=0; }
}
class Dirtiness{ //水槽の汚れ。
int val = 0;
Panel applet;
Dirtiness(Panel w){ val=0; applet=w; }
void clean(){ //掃除
val = 0;
}
public void pollution(int dirty){ //汚す
val += dirty;
}
public int getLevel(){ //汚れ度合い
return val * 100 / (1+applet.size().width) ; //画面幅に反比例させる
}
}
class Food { //餌の状況
// 餌の実現方法にはいくつか考えられるが、
// 水草は具体的な餌。この餌は「水槽」の属性としての抽象的な餌。
protected int val; //餌の量。
Dirtiness dirtiness; //汚れ管理オブジェクト
Food(Dirtiness d){ val=0; dirtiness=d; }
void clean(){ //掃除
val=0;
}
void feed(int count){ //供給
val += count;
dirtiness.pollution(5); //餌で水が汚れる
}
int eat(int count){ //消費
if (val < count){
count = val;
}
val -= count;
return count;
}
}
class Aquarium extends Applet { //水槽の中身の管理
int time = 0; //時間
Spread margin = new Spread(5,45); //表示のマージン
//水槽の中身の管理
Vector animas = new Vector(); //動くもの
Vector droppers = new Vector(); //落ちるもの
Vector creatures = new Vector(); //生物 … めだか、子めだか、顔
Vector canEat = new Vector(); //食べ物 … 水草
Vector cleanMe = new Vector(); //姿を消したいもの
// オブジェクトは Graphics を持ってない。
// cleanMe に登録すれば、clean(Graphics)が呼ばれる。
Dirtiness dirtiness; //水槽の汚れ。
Food food; //属性としての抽象的な餌
public Aquarium(){
super();
dirtiness = new Dirtiness(this); //水槽の汚れ。
food = new Food(dirtiness); //属性としての抽象的な餌
}
void clean(){ //掃除
dirtiness.clean();
food.clean(); //掃除すると、投入した餌もなくなる
}
void pollution(int dirty){ //汚す
dirtiness.pollution(dirty);
}
public void run(){ //スレッドの処理内容
++time;
for(Enumeration e = animas.elements();
e.hasMoreElements(); ){
//動く物として登録されているものを動かす。
((Anima)(e.nextElement())).move();
}
for(Enumeration e = canEat.elements();
e.hasMoreElements(); ){
//食べ物として登録されているものを動かす。
((Anima)(e.nextElement())).move();
}
for(Enumeration e = droppers.elements();
e.hasMoreElements(); ){
//落下物として登録されているものを動かす。
((Anima)(e.nextElement())).move();
}
for(Enumeration e = creatures.elements();
e.hasMoreElements(); ){
//生物として登録されているものを動かす。
((Anima)(e.nextElement())).move();
}
//生き物は生き物。食べ物は食べ物として管理して、
//それぞれのオブジェクトを1つのVectorにだけ登録したからこうなった。
//「めだか」は「動くもの」と「生物」との両方に登録するのがいいのかも。
}
public void paint(Graphics g){
for(Enumeration e = cleanMe.elements();
e.hasMoreElements(); ){
//消えたがっているものを消す。
Anima a = (Anima)(e.nextElement());
a.clean(g);
cleanMe.removeElement(a);
}
for(Enumeration e = animas.elements();
e.hasMoreElements(); ){
//動く物として登録されているものを表示する
((Anima)(e.nextElement())).draw(g);
}
for(Enumeration e = canEat.elements();
e.hasMoreElements(); ){
//食べ物として登録されているものを表示する
((Anima)(e.nextElement())).draw(g);
}
for(Enumeration e = droppers.elements();
e.hasMoreElements(); ){
//落下物として登録されているものを表示する
((Anima)(e.nextElement())).draw(g);
}
for(Enumeration e = creatures.elements();
e.hasMoreElements(); ){
//生物として登録されているものを表示する
((Anima)(e.nextElement())).draw(g);
}
}
}
class Shape {
//メダカや水草の姿として イメージ/文字列/ポリゴン を統一的に扱う。
int type=0; //内包するデータ形式
static final int String=1; //typeに設定する値
String string;
static final int Image=2; //typeに設定する値
Image image;
static final int Polygon=4; //typeに設定する値
Polygon polygon; //基準点を(0,0)とするポリゴン。移動はこのクラスでやる。
Point offset = new Point(0,0); //領域と座標のズレ
Spread size = new Spread(0,0); //領域のサイズ
Shape(String val){ type += String; string = val; }
Shape(Polygon val){ type += Polygon; polygon = val; }
Shape(Image val){ type += Image; image = val; }
Shape(Applet applet, String file){ //gifファイル名による初期化
type += Image;
image = applet.getImage(applet.getDocumentBase(),file);
}
//複数のデータ形式を備える場合の形の追加。
void addShape(String val){ type += String; string = val; offset.y=10; }
void addShape(Image val){ type += Image; image = val; }
void addShape(Polygon val){ type += Polygon; polygon = val; }
//サイズ指定。外枠を決めるだけであって、中身の変形は伴わない。:-)
// privateが良いかも。
void resize(Spread nsize){ resize(nsize.width, nsize.height); }
void resize(int w, int h){ size.width = w; size.height = h; }
void resize(Graphics g, Applet applet){
if ((size.width !=0) && (size.height != 0)){ return; }
if ((type & Polygon) != 0){
Rectangle r = polygon.getBoundingBox();
offset.x = (-1)*r.x;
offset.y = (-1)*r.y;
size.resize(r);
}else if ((type & Image) != 0){
if(size.width == 0){ size.width = image.getWidth(applet); }
if(size.height == 0){ size.height = image.getHeight(applet); }
}else if ((type & String) != 0){
if((size.height==0)&&(size.width==0)){
//緊急避難(;_;)
//linux版ではFontMetricsを取れないので、
// 文字のサイズを「固定。一文字は6x10」と決めうちしている。
size.height = 10;
size.width = 6*string.length();
offset.y = size.height;
}
if((size.height==0)&&(size.width==0)){
//Windows版ではうまく動くが、linux版ではFontMetricsを取れない。
size.height=g.getFontMetrics().getHeight();
size.width = g.getFontMetrics().stringWidth(string);
offset.y = size.height;
}
}
}
void resize(){
if ((size.width !=0) && (size.height != 0)){ return; }
if ((type & Polygon) != 0){
Rectangle r = polygon.getBoundingBox();
offset.x = (-1)*r.x;
offset.y = (-1)*r.y;
size.width = r.width;
size.height = r.height;
}
}
//移動後/死亡後/変身後に姿を消す。
void clean(Graphics g, Point box, Applet applet){
// 移動した後、消す時に、Shape.clean() を使っている。
// イメージの時の処理を特別扱いしたくなかったので、冗長ですが、
// 背景色で描いた後、その大きさのfillRectで消すようにしています。
resize(g, applet);
g.setColor(applet.getBackground());
g.setColor(Color.blue);
this.draw(g,box,applet);
g.drawRect(box.x, box.y, size.width, size.height);//枠を消す
g.fillRect(box.x, box.y, size.width, size.height);//中身を消す
}
//姿を描く。
void draw(Graphics g, Point box, Applet applet){
resize(g, applet);
if ((type & Polygon) != 0){
int xp[] = new int[polygon.npoints];
int yp[] = new int[polygon.npoints];
for (int i=0; i")}};
setShape(myStr);
place(Place.any);
}
protected void transfer(Anima ref){ //乗り移る
box.move(ref.box.x, ref.box.y);
this.mode = 0;
this.time = 0;
direction = ref.direction;
lastFig = ref.lastFig;
last.move(ref.last.x, ref.last.y);
}
void place(int pos){ //再配置する。
// 水草は接地したいが、イソギンチャク など水底に置くものを考えると、
// 接地配置は水草の仕事ではないと思ったので、作った。
// Animaのサブクラスで「水底/壁面の物」クラスを作るのが良いかも。
if (pos == Place.any){
setPositionRate(Math.random(), Math.random());
return;
}
if (pos == Place.bottom){
setPositionRate(Math.random(), Math.random());
box.y = aquarium.size().height - aquarium.margin.height
- lastFig.size.height;
return;
}
}
void setPositionRate(double dx, double dy){
//全体に対する割合で配置する。
box.x = (int)((aquarium.size().width - aquarium.margin.width*2
- lastFig.size.width) * dx)
+ aquarium.margin.width - lastFig.offset.x;
box.y = (int)((aquarium.size().height - aquarium.margin.height*2
- lastFig.size.height) * dy)
+ aquarium.margin.height- lastFig.offset.y ;
}
public void changeColor(){ //ランダムカラーを与える
int red = (int)(Math.random()*256); //random.nextInt()%128 + 128;
int green = (int)(Math.random()*256);
int blue = (int)(Math.random()*256);
color = new Color(red, green, blue);
}
protected Shape getShape(){ //姿を取り出す。
if (direction.isLeft()){ // Rightビットを取り出す
return(figure[mode%figure.length][0]);
}else{
return(figure[mode%figure.length][1]);
}
}
public void setShape(Shape fig[][]){ //姿を決める。
// 姿を混ぜることもできる。
// Shape myStr[][] = {
// {new Shape("<-"), new Shape("->")},
// {new Shape("<-"), new Shape("->")},
// {new Shape(new Polygon(xpL,yp,meal)),
// new Shape(new Polygon(xpR,yp,meal))},
// {new Shape(applet, "medakaL.gif"),
// new Shape(applet, "medakaR.gif")}
// };
// setShape(myStr);
figure = fig;
lastFig=getShape();
}
public void draw(Graphics g){ //表示
lastFig.clean(g, last, applet); //前の姿を消して
lastFig=getShape(); //新しい姿に変更して
last.move(box.x, box.y); //今の位置に移動して、
g.setColor(color); //自分の色を設定して
lastFig.draw(g, last, applet); //表示する
}
void clean(Graphics g){ //表示を消す
lastFig.clean(g, last, applet);
}
public void move(){ //動作
time++;
habit(); //固有の動作
changePosition(); //移動
}
protected void habit(){}
protected void changePosition(){ //移動
int dx=0, dy=0;
// Up/Down, Left/Rightの両方立っていれば相殺されて0
if (direction.isLeft()){
dx -= (int)(Math.random() * speed.x) +1;
}
if (direction.isRight()){
dx += (int)(Math.random() * speed.x) +1;
}
if(direction.isUp()){
dy -= (int)(Math.random() * speed.y) +1;
}
if(direction.isDown()){
dy += (int)(Math.random() * speed.y) +1;
}
energy -= Math.abs(dx) + Math.abs(dy);
direction.set(dx, dy);
box.x += dx;
box.y += dy;
}
}
class Creature extends Anima { //生き物
protected int frequencyOfChangeDirection = 20;//方向を変える頻度
public Creature(Anima ref){ super(ref); construct(); }
public Creature(Applet apl, Aquarium aquarium)
{ super(apl, aquarium); construct(); }
private void construct(){
//コンストラクタに共通の部分をまとめた。
//まとめることで{super(...); construct(...);}の形に統一できた。
//privateにしないと、サブクラスからコンストラクタを呼び出した時に
//コンストラクタからのconstruct()呼び出しが、
//サブクラスのconstruct()になってしまうので要注意。
aquarium.creatures.addElement(this);
}
public void Destroy(){ //オブジェクトの削除。
//削除時の処理の一貫性を保つために導入。
//Vectorに繋がったままでは消したつもりでも消えないから…
//サブクラスのDestroy()はスーパクラスのDestroy()を呼ぶ。
aquarium.cleanMe.addElement(this);
aquarium.creatures.removeElement(this);
}
public void move(){
time++;
if((time % frequencyOfChangeDirection) == 0){
direction.random();
}
wallCheck();
habit();
changePosition();
}
protected void wallCheck(){ //壁に当たったかの判定
if(box.x + aquarium.margin.width + lastFig.size.width
> aquarium.size().width ){ //右端に来た時
direction.set(Direction.Left); //左に進む
}
if(box.x < aquarium.margin.width){ //左端に来た時
direction.set(Direction.Right); //右に進む
}
if(box.y < aquarium.margin.height + lastFig.size.height){ //上端に来た時
if(box.x < aquarium.size().width/2){ //左寄りの時は右下へ
direction.set(Direction.Down + Direction.Right);
}
else{ //右寄りの時は左下へ
direction.set(Direction.Down + Direction.Left);
}
}
if(box.y + lastFig.size.height + aquarium.margin.height
> aquarium.size().height ){ //下端に来た時
if(box.x < aquarium.size().width/2){ //左寄りの時は右上へ
direction.set(Direction.Up + Direction.Right);
}
else{ //右寄りの時は左上へ
direction.set(Direction.Up + Direction.Left);
}
}
}
}
class Meal extends Anima { //食べもの
int meal; //食べられる量
int factor=300; //食べた時のエネルギー変換係数(1粒で300m :-)
Meal(Applet applet, Aquarium aquarium){
super(applet,aquarium);
aquarium.canEat.addElement(this);
}
int eat(int count){
if (meal * factor < count){
count = meal * factor;
}
meal -= count/factor+1;
reShape();
if(meal<=0){
aquarium.cleanMe.addElement(this);
aquarium.canEat.removeElement(this);
}
return count;
}
// 食われて形が変わるなら、形を変える。
void reShape(){}
//食いつく座標を得る。
Point getPoint(){ return new Point(box.x, box.y); }
}
//==============================================================
class Plant extends Meal { //水草
// ただの水草を止めて、食糧になってもらった。
// meal エネルギー量
// ystep 水草の最小単位
// meal*ystep 水草の背丈
int ystep=2; //水草の一節
int orgMeal; //mealの初期値
int width=10; //水草の芯からの幅 = 全体の幅の半分
public Plant(Applet applet, Aquarium aquarium)
{ super(applet, aquarium); construct(); }
private void construct(){
color = Color.green;
//食べられる量を高さで表す。
// 小さ過ぎるのはイヤだから1/4(0.25)の高さは確保。
meal=(int)((aquarium.size().height-aquarium.margin.height*2)/ystep*0.25 +
(aquarium.size().height-aquarium.margin.height*2)/ystep*0.7
* Math.random());
orgMeal = meal;
//姿を作る
int xpL[]=new int[meal];//左向き … 実はユラユラするだけで向きは無い。
int xpR[]=new int[meal];//右向き
int yp[] =new int[meal];
xpL[0] = 0; //一番底は芯にのせる
xpR[0] = 0;
yp[0] = 0;
for (int i=1; imeal; k--){
//食べ終ったところは芯しか残ってない。
if (k<=0) break;
figure[i][j].polygon.xpoints[k] = 0;
}
}
}
}
int eat(int count){
int ret = super.eat(count);
lastFig.resize();
return ret;
}
protected void changePosition(){} //水草は移動しない。
protected void habit(){
//5回に1回ユラユラする。
if (time%10 == 5) direction.random();
}
}
//-------------------------------------------------------------
class MyMedaka extends Creature { //私のめだか
public MyMedaka(Anima ref)
{ super(ref); construct(); transfer(ref); }
public MyMedaka(Applet applet, Aquarium aquarium, double dx, double dy)
{ super(applet, aquarium); construct(); setPositionRate(dx, dy); }
public MyMedaka(Applet applet, Aquarium aquarium)
{ super(applet, aquarium); construct(); }
private void construct(){
frequencyOfChangeDirection = 11;
speed = new Point(3,1);
Shape myFig[][] = {
// { new Shape(applet, "myL.gif"), new Shape(applet, "myR.gif") },
{ new Shape("<==="), new Shape("===>") }
};
setShape(myFig);
}
protected void habit(){
if ((time%83) == 0 ){ //糞をする
new Muck(applet, aquarium, this);
}
if (time > 500){ //めだかになる。
new Medaka(this);
Destroy();
}
}
}
class KoMedaka extends Creature { //めだかっ子 :-)
public KoMedaka(Anima ref)
{ super(ref); construct(); transfer(ref); }
public KoMedaka(Applet applet, Aquarium aquarium, double dx, double dy)
{ super(applet, aquarium); construct(); setPositionRate(dx, dy); }
public KoMedaka(Applet applet, Aquarium aquarium)
{ super(applet, aquarium); construct(); }
private void construct(){
frequencyOfChangeDirection = 11;
speed = new Point(3,1);
Shape myStr[][] = {{new Shape(":--"), new Shape("--:")}};
// Shape myImg[][] = {
// {new Shape(applet, "medakaSLC.gif"),
// new Shape(applet, "medakaSRC.gif")}
// };
setShape(myStr);
}
protected void habit(){
if ((time%83) == 0 ){ //糞をする
new Muck(applet, aquarium, this);
}
if (time > 290){ changeColor(); }
if (time > 300){
if ((aquarium.dirtiness.getLevel() == WaterStatus.CrazyClean)
&& (Math.random() < 0.5)){//50%の確立で
//きれい過ぎて喜んで踊り出す。
new CrazyDance(this);
Destroy();
}else if ((aquarium.dirtiness.getLevel() > WaterStatus.KillChild)
&& (Math.random() < 0.2)){//20%の確立で死ぬ。
//汚れていれば死ぬ。
color=Color.red;
Shape dieFig[][] = {{new Shape(".--"), new Shape("--.")}};
new Drops(this, dieFig);
Destroy();
}else{
//成長する。
new Medaka(this);
Destroy();
}
}
}
}
class Medaka extends Creature { //口パクめだか
public Medaka(Anima ref) { super(ref); construct(); transfer(ref); }
public Medaka(Applet applet, Aquarium aquarium, double dx, double dy)
{ super(applet, aquarium); construct(); setPositionRate(dx, dy); }
public Medaka(Applet applet, Aquarium aquarium)
{ super(applet, aquarium); construct(); }
private void construct(){
energy = Energy.Full;
Shape myStr[][] = {
{ new Shape("=^)))><"), new Shape("><(((^=")},
{ new Shape(">^)))><"), new Shape("><(((^<")}
};
setShape(myStr);
/*----------------
Shape myImg[][] = {
{new Shape(applet,"medakaLC.gif"),
new Shape(applet,"medakaRC.gif")}
};
setShape(myImg);
----------------*/
/*----------------
int xsetLO[] = {0,2,3,2,2,2,8,9,9,8,2,2,0,2,0};
int xsetLC[] = {0,2,3,2,2,2,8,9,9,8,2,2,0,0,0};
int xsetRO[] = {0,-2,-3,-2,-2,-2,-8,-9,-9,-8,-2,-2,0,-2,0};
int xsetRC[] = {0,-2,-3,-2,-2,-2,-8,-9,-9,-8,-2,-2,0, 0,0};
int yset[] = {1,0,1,1,0,0,1,0,3,2,3,3,2,1,1};
Shape myPoly[][] = {
{ new Shape(new Polygon(xsetLO, yset, yset.length)),
new Shape(new Polygon(xsetRO, yset, yset.length))},
{ new Shape(new Polygon(xsetLC, yset, yset.length)),
new Shape(new Polygon(xsetRC, yset, yset.length))}
};
setShape(myPoly);
----------------*/
}
private void die(){ //死体の形を統一したくて…
Shape dieFig[][] = {{new Shape(">.|++++<"), new Shape(">++++|.<")}};
new Drops(this, dieFig);
Destroy();
}
protected void habit(){
mode=0; //普通は口を閉じてる。
color=Color.white;
if ( energy < Energy.Hunger ){
mode=1; //腹減ったら口開ける。
color=Color.red; //色を赤にする。
Meal meal = null;
if(!aquarium.canEat.isEmpty()){
//食べ物があるなら
meal = (Meal)(aquarium.canEat.firstElement());
//一番近い食べ物を探す
// 距離=Δx + Δy …何距離っていうんだっけ。
Meal m;
for(Enumeration e = aquarium.canEat.elements();
e.hasMoreElements(); ){
m = ((Meal)(e.nextElement()));
if ( (Math.abs(box.x - m.getPoint().x) +
Math.abs(box.y - m.getPoint().y))
<(Math.abs(box.x - meal.getPoint().x) +
Math.abs(box.y - meal.getPoint().y))){
meal = m;
}
}
}
if (meal != null){ //目指す食べ物がある
//自分を囲む四角の領域を求めて、
Rectangle I = new Rectangle(this.box);
I.resize(this.lastFig.size.width,this.lastFig.size.height);
//相手を囲む四角の領域を求めて、
Rectangle you = new Rectangle(meal.box);
you.resize(meal.lastFig.size.width,meal.lastFig.size.height);
if(I.intersects(you)){ //四角が交わっていたら、
energy += meal.eat(Energy.Full - energy); //水草を食う
meal = null;
}else{ //交わってなかったら、
//食べ物の食いつくポイントの方に移動する。
if(I.x > meal.getPoint().x){ direction.setLeft(); }
if(I.x < meal.getPoint().x){ direction.setRight(); }
if(I.y > meal.getPoint().y){ direction.setUp(); }
if(I.y < meal.getPoint().y){ direction.setDown(); }
}
}
}
if ( energy < Energy.Emergency ){
//飢餓して死にそうになったら、
mode=1; //腹減ったら口開ける
color=Color.red;
energy += aquarium.food.eat(Energy.Full - energy); //餌を食う
}
if ( energy < Energy.ToLive ){ die(); } //エネルギー切れで死ぬ
if (( time % 133 ) == 0 ){ //糞をする
new Muck(applet, aquarium, this);
}
if (( time % 500 ) == 0 ){ //子を産む
if (energy > Energy.Birth){ //エネルギーがあれば子を産む
if (aquarium.creatures.size() *10 / aquarium.size().width < 1){
new KoMedaka(this);
}else{ //エネルギーがなければ飢えて発狂して顔に変身する。
new CrazyDance(this);
Destroy();
}
}
}
}
}
class CrazyDance extends Creature { // 踊り狂うめだか
public CrazyDance(Anima ref) { super(ref); construct(); transfer(ref); }
public CrazyDance(Applet applet, Aquarium aquarium, double dx, double dy)
{ super(applet, aquarium); construct(); setPositionRate(dx, dy); }
public CrazyDance(Applet applet, Aquarium aquarium)
{ super(applet, aquarium); construct(); }
private void construct(){
frequencyOfChangeDirection = 27;
//バックスラッシュはエスケープしなきゃ…
Shape myfigure[][] = {
{ new Shape("\\\\(^^ ) "), new Shape( " ( ^^)//") }, //おどり
{ new Shape( " ( ^^)//"), new Shape("\\\\(^^ ) ") },
{ new Shape("\\\\(^^ ) "), new Shape( " ( ^^)//") },
{ new Shape( " ( ^^)//"), new Shape("\\\\(^^ ) ") },
{ new Shape( " \\(^-^)/ "), new Shape( " \\(^_^)/ ") },
{ new Shape( " (^-^) "), new Shape( " (^_^) ") }, //おじぎ
{ new Shape( " (_ _) "), new Shape( " (_ _) ") },
{ new Shape( " (^_^) "), new Shape( " (^_^) ") }
};
setShape(myfigure);
}
protected void habit(){
mode++; //姿を順々に変えていく。
if (aquarium.dirtiness.getLevel() > WaterStatus.AlarmCrazy){ changeColor(); }
if ((aquarium.dirtiness.getLevel() > WaterStatus.KillCrazy)
&& (Math.random() < 0.3)){//30%の確立で死ぬ。
Shape dieFig[][] = {
{new Shape(" (;_;) "), new Shape(" (;_;) ")},
};
new Drops(this,dieFig);
Destroy();
}
if (time > 500){ //時間がたてばフィーバーは終り。めだかに変身。
new Medaka(this);
Destroy();
}
}
}
//-------------------------------------------------------------
class Drops extends Anima { //ただ落ちて、落ちたらそれで終りのもの。
public Drops(Anima ref) { super(ref); construct(); transfer(ref); }
public Drops(Anima ref, Shape fig[][])
{ super(ref); construct(); transfer(ref); setShape(fig); }
public Drops(Applet applet, Aquarium aquarium)
{ super(applet, aquarium); construct(); }
private void construct(){
color=Color.gray;
speed = new Point(0,8);
aquarium.droppers.addElement(this);
}
protected void habit(){
direction.set(Direction.Down); //落ちるだけ。
if(aquarium.size().height <
aquarium.margin.height + lastFig.size.height + box.y ){
//底についた
aquarium.droppers.removeElement(this); //管理から外す。
}
}
}
class Muck extends Drops { //糞
public Muck(Applet applet, Aquarium aquarium, Creature owner) {
super(applet, aquarium);
aquarium.dirtiness.pollution(1); //水槽を汚す。
//糞をする者のまんなかあたりから出てくる。
this.box.move(owner.box.x+owner.lastFig.size.width/2,
owner.box.y);
Shape myfigure[][] = {{new Shape("*"), new Shape("*")}};
setShape(myfigure);
}
}
//==============================================================
class StatusMonitor extends Panel{ //状態表示パネル
Aquarium aquarium;
Label status; //メダカの状態を表示するためのラベル変数
Label level;
Label count;
Label food;
public StatusMonitor(Aquarium a){
super();
aquarium = a;
setLayout(new FlowLayout(FlowLayout.CENTER));
add(status = new Label(" All Green (^-^) ")); // 状態メッセージ
add(food = new Label("F: 00000")); // 水槽の属性の食糧
add(level = new Label("L: 00")); // 汚れのレベル
add(count = new Label("C: 000/000")); // 動物/植物
}
public void labelChange(){ //ラベルの表示文字をある時間毎に書き換える
if( aquarium.dirtiness.getLevel() > WaterStatus.AlarmChild ){
status.setText("(;_;) Clean up!");
}else if((aquarium.canEat.size()==0)&&
(aquarium.food.val < aquarium.creatures.size()*Energy.Emergency)){
status.setText("(-.-) Hungry!");
}else {
status.setText("(^-^) All Green ");
}
food.setText("F: "+aquarium.food.val);
level.setText("L: "+aquarium.dirtiness.getLevel());
count.setText("C: "+aquarium.creatures.size()+"/"+aquarium.canEat.size());
}
}
class ConsoleBox extends Panel{ //操作ボタンパネル
hazama3 applet;
Aquarium aquarium;
Button foodButton; //餌ボタン
Button cleanButton; //掃除ボタン
Button medakaButton; //めだか追加ボタン
Button komedakaButton;//子めだか追加ボタン
Button mymedakaButton;//子めだか追加ボタン
Button plantButton; //植物追加
public ConsoleBox(hazama3 ap, Aquarium aqua){
super();
applet = ap;
aquarium = aqua;
setLayout(new FlowLayout(FlowLayout.CENTER));
add(cleanButton = new Button("CLEAN")); //掃除ボタン
add(plantButton = new Button("plant add")); //植物追加
add(foodButton = new Button("FOOD ")); //餌ボタン
add(mymedakaButton = new Button("MyMedaka")); //私のメダカ
add(komedakaButton = new Button("Komedaka")); //子メダカ
add(medakaButton = new Button("medaka")); //メダカ
}
public boolean action(Event v, Object o){ //ボタンのイベント処理
if (v.target == foodButton){
aquarium.food.feed(5000); //管理情報で餌を入れる。
} else if (v.target == cleanButton){
applet.flush(); //画面をきれいにする。
aquarium.clean(); //汚れをきれいにする。
} else if (v.target == medakaButton){
new Medaka(applet, aquarium); // めだか
} else if (v.target == mymedakaButton){
new MyMedaka(applet, aquarium); // めだか
} else if (v.target == komedakaButton){
new KoMedaka(applet, aquarium); // 子めだか
} else if (v.target == plantButton){
new Plant(applet, aquarium); // 水草
}
return true;
}
}
public class hazama3 extends Aquarium implements Runnable{
Thread m_Thread; //スレッド変数
Aquarium aquarium;
StatusMonitor monitor;
ConsoleBox console;
Image offScreen; //ちらつき防止のためのImageオブジェクト作成
Graphics offGraphics; //ちらつき防止のためのGraphicsオブジェクト作成
public void init() {
setLayout(new BorderLayout());
aquarium = this;
// 本当はこんなしたい add("Center", aquareum = new Aquareum(this));
add("South", monitor = new StatusMonitor(aquarium));
add("North", console = new ConsoleBox(this, aquarium));
//中身
//描画用領域を生成
offScreen=createImage(size().width, size().height);
//offScreenに描くためのGraphicsオブジェクト
offGraphics=offScreen.getGraphics();
}
public void run(){ //スレッドの処理内容
while (true){ //ずっと繰り返す
super.run();
monitor.labelChange();
repaint();
pause();
}
}
public void paint(Graphics g){
//描画用領域offScreenに対して描画を行う
super.paint(offGraphics);
//画面へと転送する
g.drawImage(offScreen, 0, 0, this);
}
public void flush(){ //表示をきれいにする。
Graphics g = offGraphics;
//バックグランドを書き直して、画面をきれいにする。
g.setColor(getBackground());
//水
g.setColor(Color.blue);
g.fillRect(0, 0, size().width, size().height);
//地面
g.setColor(new Color(200,200,0));
g.fillRect(0, size().height-margin.height, size().width, margin.height);
}
public void update(Graphics g){
paint(g);
}
protected void pause(){
try{
Thread.sleep(200);
}catch (InterruptedException e){}
}
public void start(){
flush();
if (m_Thread == null){
m_Thread = new Thread(this);
m_Thread.start(); //スレッドを実行させる
}
}
public void stop(){
if (m_Thread != null){
m_Thread.stop(); //スレッドを止める
m_Thread =null;
}
}
}
// EOF