★★★最終課題について★★★
▽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();
}
}
コンパイル用ゲームソース
体験版ゲームソース