★★★最終課題について★★★


▽SI-27,341062H,桜井健一
▼▼▼使用した画像▼▼▼

▼▼▼ゲームの説明▼▼▼

とりあえず、上にゲームの概略図を。学校では体験版しか動きません。
▼▼▼説明用ゲームソース▼▼▼

/** ************************************************************************
□/home/g340162/java/Kadai1216/S_Demo10.java
□名前:桜井健一
□学籍番号:341062H
□全体の説明:3Dシューティングに見える?ゲーム。
□ゲームの説明:
  マウスのクリックのみを使って“スフィア”をうち、その点数で競うゲーム。
 レベルセレクトには3種類用意したが、速いほうが臨場感が出るかも。それな
 りのものができたと思う。
□javaの説明:
  いくつかのクラスからなるが、詳細は個々で述べる。本当は3Dっぽいレース
 ゲームを作りたかったので、ViewPointクラスにはa,b,cという視界方向のべクト
 ル用パラメータなどが残っている。また、効率性を追求する時間がなかったの
 で、メモリの消費が激しいらしく、家のPCでしか動かない。加えて、遊べはす
 るものの、実行すると、意味不明なエラーが出る。さらなる改良の余地は多分に
 あるが、期限に間に合わないのでこの状態で提出する。
************************************************************************** */

/** *** 各種インポート **** */
import java.awt.*;
import java.awt.event.*;
import java.util.*;

/** ******************* Screens クラスの説明 *******************************
□全体の説明:
   画面上の座標用クラス。ViewPointから視界方向1mにあるスクリーンにPoint3D
  を投影する。コンストラクタは直接座標を入れる場合と2種用意した。
□変数の説明:画面上の座標に対応。
□メソッドの説明:Screensクラス2点の画面上の距離を返すメソッドdistance。
************************************************************************** */
class Screens{
    public int x,y;
    public Screens(int x,int y){
	this.x=x;
	this.y=y;
    }
    public Screens(ViewPoint vp,Point3D p){
	double j,k;
	j=((p.z-vp.z)/((p.x-vp.x)*vp.a+(p.y-vp.y)*vp.b+(p.z-vp.z)*vp.c)-vp.c)/(1-vp.c*vp.c);
	k=((p.x-vp.x)/((p.x-vp.x)*vp.a+(p.y-vp.y)*vp.b+(p.z-vp.z)*vp.c)-vp.a+j*vp.a*vp.c)/vp.b;
	x=300+(int)(k*Math.sqrt(vp.a*vp.a+vp.b*vp.b)*150);
	y=300-(int)(j*Math.sqrt(vp.a*vp.a+vp.b*vp.b)*150);
    }
    public int distance(Screens s){
	return (int)Math.sqrt((s.x-x)*(s.x-x)+(s.y-y)*(s.y-y));
    }
}

/** ******************* Point3D クラスの説明 *******************************
□全体の説明:仮想空間上の座標用クラス。
□変数の説明:仮想空間(3次元)の座標に対応。
□メソッドの説明:仮想空間上での距離を返すメソッドdistance。
************************************************************************** */
class Point3D{
    public double x,y,z;
    public Point3D(){
	this(0.0,0.0,0.0);
    }
    public Point3D(double x,double y,double z){
	this.x=x;
	this.y=y;
	this.z=z;
    }
    public double distance(Point3D p){
	double d;
	d=Math.sqrt((p.x-x)*(p.x-x)+(p.y-y)*(p.y-y)+(p.z-z)*(p.z-z));
	return d;
    }
    public double distance(ViewPoint vp){
	double d;
	d=Math.sqrt((vp.x-x)*(vp.x-x)+(vp.y-y)*(vp.y-y)+(vp.z-z)*(vp.z-z));
	return d;
    }
}

/** ******************* ViewPoint クラスの説明 *******************************
□全体の説明:仮想空間上の視点用クラス。
□変数の説明:仮想空間(3次元)の座標と視界方向のベクトルに対応。
□メソッドの説明:なし。
************************************************************************** */
class ViewPoint extends Point3D{
    public double a,b,c;
    public ViewPoint(double x,double y,double z,double a,double b,double c){
	this.x=x;
	this.y=y;
	this.z=z;
	this.a=a/Math.sqrt(a*a+b*b+c*c);
	this.b=b/Math.sqrt(a*a+b*b+c*c);
	this.c=c/Math.sqrt(a*a+b*b+c*c);
    }
    public ViewPoint(Point3D p,double a,double b,double c){
	this(p.x,p.y,p.z,a,b,c);
    }
    public ViewPoint(double x,double y,double z){
	this(x,y,z,0.0,1.0,0.0);
    }
    public ViewPoint(Point3D p){
	this(p.x,p.y,p.z,0.0,1.0,0.0);
    }
}

/** ******************* Sphere クラスの説明 *******************************
□全体の説明:スフィア用クラス。
□変数の説明:
  SPHERE1など:種類を示す定数
  size:仮想空間上での大きさ
  kind:種類を示す変数
  appear:画面上に現れているかを示す真偽値
  p:仮想空間上の座標
  image:kindに対応した画像ファイル
□メソッドの説明:
  マウスのクリックした座標にスフィアがあるかどうかを返すjudgeと、画面上
 でのサイズを返すscreensize。
************************************************************************** */
class Sphere{
    public static final int SPHERE1=1,SPHERE2=3,SPHERE3=5,SPHERES=20,SPHEREB=(-2);
    public double size;
    public int kind;
    public boolean appear;
    public Point3D p;
    public Image image;
    public Sphere(double x,double y,double z,double size,int kind){
	p=new Point3D(x,y,z);
	this.size=size;
	appear=false;
	this.kind=kind;
	switch(kind){
	    case SPHERE1:image=Toolkit.getDefaultToolkit().getImage("sphere1.png");break;
	    case SPHERE2:image=Toolkit.getDefaultToolkit().getImage("sphere2.png");break;
	    case SPHERE3:image=Toolkit.getDefaultToolkit().getImage("sphere3.png");break;
	    case SPHERES:image=Toolkit.getDefaultToolkit().getImage("sphereS.png");break;
	    case SPHEREB:image=Toolkit.getDefaultToolkit().getImage("sphereB.png");break;
	}
    }
    public boolean judge(ViewPoint vp,int mx,int my){
	if(appear){
	    Screens s=new Screens(vp,p);
	    boolean j=(((s.x-mx)*(s.x-mx)+(s.y-my)*(s.y-my))<=(screensize(vp)*screensize(vp)));
	    return j;
	}
	else return false;
    }
    public int screensize(ViewPoint vp){
	double j,k;
	j=(vp.x-p.x);k=(p.y-vp.y);
	Screens sc1=new Screens(vp,new Point3D(p.x+size*k/Math.sqrt(j*j+k*k),p.y+size*j/Math.sqrt(j*j+k*k),p.z));
	Screens sc2=new Screens(vp,p);
	return sc2.distance(sc1);
    }
}

/** ******************* MyFrame クラスの説明 *******************************
□全体の説明:
    Frameクラスを継承し、Runnable,MouseListenerインターフェイスを実装して
 いる。コンストラクタで空間上のコース、スフィアを配置したため、膨大な長さ
 になっている。各所のtryやSystem.ou.printlnはこのプログラム作成時のエラー
 解消用に作ったものの名残で、消す時間がなかったもの。また、OPENINGなどは
 実際に最後まで作ろうと思っていたオープニング関係のもの。
□変数の説明:
  TITLEなど:状態切り替えよう定数。
  c:現在の視点のいる位置のpoints換算。
  score:現在の点数。
  scene:現在の状態。
  v1など:速さ。
  r:道のり。
  t:時間。
  vp:視点。
  points:コースの仮想空間上の座標を入れた配列。
  sample:pointsから10(40)個を画面上に投影したもの。
  spV:スフィアを収めたベクトル。
  readyなど:画像ファイル。
□メソッドの説明:各所にて述べる。
************************************************************************** */
class MyFrame extends Frame implements Runnable,MouseListener{
    private final int TITLE=0,MAIN=1,SCORE=2,OPENING=3,QUIT=4;
    public int c=0,score=0,scene=OPENING;
    public double v1=80.0,v2=50.0,v3=100.0,r=0.0,t=0.0;
    public ViewPoint vp;
    public Point3D[][] points=new Point3D[411][4];
    public Screens[][] sample=new Screens[10][4];
    public Vector spV=new Vector();
    Image ready,go,goal;

    //コンストラクタ
    public MyFrame(){
	super();
	try{
	    vp=new ViewPoint(new Point3D());

	    //ここからひたすらコース設定
	    for(int i=0;i<101;i++){
       		points[i][0]=new Point3D(4.0,i*10,2.0);
       		points[i][1]=new Point3D(4.0,i*10,-2.0);
       		points[i][2]=new Point3D(-4.0,i*10,-2.0);
       		points[i][3]=new Point3D(-4.0,i*10,2.0);
	    }
//-----------------長いので省略------------------------------
	}
	catch(Exception e){
	    System.out.println(e);
	}

	//イメージ読み込み
	ready=Toolkit.getDefaultToolkit().getImage("ready.png");
	go=Toolkit.getDefaultToolkit().getImage("go.png");
	goal=Toolkit.getDefaultToolkit().getImage("goal.png");

	//スフィア設定
	for(int i=0;i<5;i++){Sphere sp=new Sphere(4.0-2.0*i,500.0+i*80.0,2.0-i,3.0,Sphere.SPHERE1);spV.addElement(sp);}
//-----------------長いので省略------------------------------
	

	//ウィンドウ関連
	setSize(600,600);
	setVisible(true);
	addMouseListener(this);
    }

  //スレッド実行時。sceneにより各メソッドへ分岐
    public void run(){
	while(scene!=QUIT){
	    switch(scene){
		case OPENING:opening();
		case TITLE:title();break;
		case MAIN:System.out.println("start");game();break;
		case SCORE:scoretable();
	    }
	}
	System.exit(0);
    }

  //本当は作り込みたかった各メソッド
    public void opening(){scene=TITLE;}
    public void title(){repaint();}
    public void scoretable(){repaint();}

    //ゲームの中核
    public void game(){
	while(true){
	    try{Thread.sleep(20);}
	    catch(Exception e){}
	    t+=20.0;

	    //視点設定
	    if((t-1)<(1000.0*(1000.0/v1)))vp=new ViewPoint(0.0,v1*t/1000.0,0.0);
	//-----------------長いので省略------------------------------
   
	    else break;

	    //道のり設定
	    if(t>(1000*(1000/v1)) & t<=(1000*(1000/v1+100/v2)))r+=v2*0.02;
	    else if(t>(1000*(3500/v1+100/v2)) & t<=(1000*(3500/v1+100/v2+300/v3)))r+=v3*0.02;
	    else r+=v1*0.02;

	    //コースの表示設定用各変数の設定
	    c=(int)Math.ceil((r+1)*0.1);
	    try{
		for(int i=0;i<10;i++){
		    for(int k=0;k<4;k++)sample[i][k]=new Screens(vp,points[i+c][k]);
		}
	    }
	    catch(ArrayIndexOutOfBoundsException e){}

	    //スフィアの削除
	    int size=spV.size();
	    for(int i=size-1;i>=0;i--){
		Sphere sp1=(Sphere)spV.elementAt(i);
		if(sp1.screensize(vp)>=(int)sp1.size*150){spV.removeElementAt(i);System.out.println("?");}
	    }

	    repaint();
	}
	scene=SCORE;
    }


    //ダブルバッファリング
    Image offScreenImage;
    Graphics offScreenGraphics;
    public void update(Graphics g){
	if(offScreenImage==null){
	    offScreenImage=createImage(600,600); 
	    offScreenGraphics=offScreenImage.getGraphics();
	}
	paint(offScreenGraphics);
	g.drawImage(offScreenImage,0,0,this);
    }

    //描画全般
    public void paint(Graphics g){
	switch(scene){
	    case OPENING:

	    //タイトル画面
	    case TITLE:
        	g.setColor(Color.black);
        	g.fillRect(0,0,600,600);
        	g.setColor(Color.white);
		g.setFont(new Font("Arial",Font.BOLD,35));
		FontMetrics fm=getFontMetrics(g.getFont());
		g.drawString("SHOOTING GAME!",(600-fm.stringWidth("SHOOTING GAME!"))/2,250);
		g.setFont(new Font("Arial",Font.BOLD,28));
		fm=getFontMetrics(g.getFont());
		g.drawString("EASY",(600-fm.stringWidth("EASY"))/2,360);
		g.drawString("NORMAL",(600-fm.stringWidth("NORMAL"))/2,400);
		g.drawString("HARD",(600-fm.stringWidth("HARD"))/2,440);
		g.setFont(new Font("Arial",Font.BOLD,12));
		fm=getFontMetrics(g.getFont());
		g.drawString("produced by 341062H",(600-fm.stringWidth("produced by 341062H"))/2,520);
		break;

	    //スコア表示画面
	    case SCORE:
        	g.setColor(Color.black);
        	g.fillRect(0,0,600,600);
        	g.setColor(Color.white);
	  	g.setFont(new Font("Arial",Font.BOLD,35));
		fm=getFontMetrics(g.getFont());
		g.drawString("YOUR SCORE:"+score,(600-fm.stringWidth("YOUR SCORE:"+score))/2,250);
		g.setFont(new Font("Arial",Font.BOLD,28));
		fm=getFontMetrics(g.getFont());
		g.drawString("NEW GAME",(600-fm.stringWidth("NEW GAME"))/2,400);
		g.drawString("QUIT",(600-fm.stringWidth("QUIT"))/2,440);
		break;

	    //ゲーム自体の表示画面
	    case MAIN:
        	g.setColor(Color.white);
        	g.fillRect(0,0,600,600);
		for(int i=0;i<10;i++){
		    int[] x=new int[4],y=new int[4];
		    for(int k=0;k<4;k++){
			x[k]=sample[i][k].x;
			y[k]=sample[i][k].y;
		    }
		    g.setColor(Color.black);
		    g.drawPolygon(x,y,4);
		}
		int size=spV.size();
		for(int i=size-1;i>=0;i--){
		    Sphere sp2=(Sphere)spV.elementAt(i);
		    if(sp2.screensize(vp)>5){
			sp2.appear=true;
			Screens sc=new Screens(vp,sp2.p);
			g.drawImage(sp2.image,sc.x-sp2.screensize(vp),sc.y-sp2.screensize(vp),2*sp2.screensize(vp),2*sp2.screensize(vp),this);
		    }
		}
		if(t>500&t<=1500)g.drawImage(ready,200,220,this);
		else if(t>1600&t<=2400)g.drawImage(go,200,220,this);
		if(r>3900)g.drawImage(goal,200,220,this);
	}
    }

  //マウスイベント
    public void mousePressed(MouseEvent e){
	int mx=e.getX(),my=e.getY();System.out.println(mx+":"+my);
	FontMetrics fm=getFontMetrics(new Font("Arial",Font.BOLD,28));
	if(scene==TITLE){
	    if((my<360&my>360-fm.getHeight())&(mx>(600-fm.stringWidth("EASY"))/2&mx<(600+fm.stringWidth("EASY"))/2)){
		v1=50.0;
		v2=40.0;
		v3=80.0;System.out.println(v1+":"+v2+":"+v3);scene=MAIN;
	    }
	    else if((my<400&my>400-fm.getHeight())&(mx>(600-fm.stringWidth("NORMAL"))/2&mx<(600+fm.stringWidth("NORMAL"))/2)){
		v1=80.0;
		v2=50.0;
		v3=100.0;System.out.println(v1+":"+v2+":"+v3);scene=MAIN;
	    }
	    else if((my<440&my>440-fm.getHeight())&(mx>(600-fm.stringWidth("HARD"))/2&mx<(600+fm.stringWidth("HARD"))/2)){
		v1=100.0;
		v2=80.0;
		v3=120.0;System.out.println(v1+":"+v2+":"+v3);scene=MAIN;
	    }
	}
	else if(scene==MAIN){
	    int size=spV.size();
	    int k=0;
	    for(int i=size-1;i>=0;i--){
		Sphere sp3=(Sphere)spV.elementAt(i);
		if(sp3.judge(vp,mx,my)){
		    spV.removeElementAt(i);
		    score+=sp3.kind*100;k++;
		}
	    }
	    if(k==0)score-=10;
	}
	else if(scene==SCORE){
	    if((my<440&my>440-fm.getHeight())&(mx>(600-fm.stringWidth("QUIT"))/2&mx<(600+fm.stringWidth("QUIT"))/2)){
		scene=QUIT;
	    }

	}
    }

  //いらないものも描いておく
    public void mouseReleased(MouseEvent e){}
    public void mouseClicked(MouseEvent e){}
    public void mouseEntered(MouseEvent e){}
    public void mouseExited(MouseEvent e){}

  //ここから起動
    public static void main(String args[]){
	MyFrame frame=new MyFrame();
	Thread th=new Thread(frame);
	th.start();
    }
}


コンパイル用ゲームソース

体験版ゲームソース