目 录
1. 摘要.................................................................................................................................... 1
2. 概述.................................................................................................................................... 2
2.1课程设计目的............................................................................................................ 2
2.2课程设计内容和要求................................................................................................ 3
3. 系统需求分析...................................................................................................................... 3
3.1 系统目标................................................................................................................... 3
3.2 主体功能................................................................................................................... 3
4.系统总体设计................................................................................................................... 3
4.1 系统的功能模块划分............................................................................................... 3
5.主要工作原理和关键技术介绍....................................................................................... 4
5.1 魔方旋转原理技术介绍........................................................................................... 4
5.2关键问题解决思路.................................................................................................... 5
5.2.1 三维魔方的描述问题的解决方法................................................................... 5
5.2.2 魔方整体旋转问题的解决办法....................................................................... 5
6 .代码调试.......................................................................................................................... 6
7.总结............................................................................................................................... 18
参考文献............................................................................................................................. 19
网页魔方块游戏
1. 摘要
随着科技发展和社会进步,尤其是计算机大范围的普及,计算机应用逐渐由大规模计算的海量数据处理转向大规模的事物处理和对工作流的管理,这就产生一台式计算机为核心的管理系统。
在80年代成为一种流行的游戏,在中国把这游戏叫魔方块游戏。真正的魔方块总是让人不停地钻研,人们通过旋转魔方,开发自己的思想,可是有时候买一个魔方还是一件很麻烦的事情,很多人有自己的电脑,他们有时候也想能否在电脑上就能体验一下玩魔方的感觉。很多人都有自己的电脑,他们有时候也想能否在电脑上就能体验一下玩魔方的感觉。
《Java高级程序设计》课程设计是计算机科学与技术专业的主要时实践性教学环节。解决具有一定规模的,具有实际意义的应用题,实现理论课所要求掌握的java解决实际问题。提高进行工程设计的基本技能及分析,解决实际问题的能力,为毕业设计和以后的工程实践打下良好的基础。解决具有一定规模的,具有实际意义的应用题,实现理论课所要求掌握的java解决实际问题。
2. 概述
2.1课程设计目的
1.真实的魔方总是让人不停地钻研,人们通过旋转魔方,开发自己的思维,可是有时候买一个魔方还是一件很麻烦的事情,很多人都有自己的电脑,他们有时候也想能否在电脑上就能体验一下玩魔方的感觉。
2.知道魔方的发明和流行历史。
3.知道魔方的流行玩法。
4.知道三阶魔方的结构。
5.提高学生科技论文写作能力,规范完成课程设计报告。
2.2课程设计内容和要求
魔方,Rublik’s Cube又叫魔术方块,也称鲁比克方块。是匈牙利布达佩斯建筑学院厄尔诺.鲁比克教授在1974年发明的。
1.三阶魔方核心是一个轴,并由26个小正方体组成。包括中心方块6个,固定不动,只一面有颜色。边角方块8个(3面有色)(角块)可移动 。边缘方块12个(2面有色)(棱块)亦可转动。
2对魔方的应用也乐此不疲,数学与计算机方面,研究工作者以魔方为原型和工具,研究代数学,计算机图形图像,加密算法理论等等。
3.在电脑上最好能都简单的通过鼠标控制魔方游戏使其操作更简单。
4.当用户按要求排列好方块后,程序弹出对话框,提示用户成功的消息。
5.绘制三维仿真魔方:绘制一个六面体,是一个3*3*3形式的魔方。
6. 通过引进开发包DirectX基于C#,来实现绘制三维的仿真实的九宫格虚拟魔方,并且通过鼠标控制其整体的旋转,和各个层的旋转。
3.系统需求分析
3.1 系统目标
使用所学知识制作一个基于java的魔方游戏。
3.2 主体功能
这个程序定义了一些组件,工具栏按钮,文本区和菜单。魔板游戏程序设计通过绘制三维仿真魔方 等类来实现魔方游戏的整体功能。
4.系统总体设计
4.1 系统的功能模块划分
魔方游戏所用到的一些重要的类以及之间的组合关系如下图。
5.主要工作原理和关键技术介绍
5.1 魔方旋转原理技术介绍
魔方的旋转主要是通过算法记录旋转前各个小块的颜色,旋转后重新对其着色。对图形不停地进行渲染。
图 1-1 魔方块外面图
魔方6面正方体。核心是一个轴,并由26小正方体组成包括中心方块有6个,固定不动只有一面有颜色。边角方块8个可转动。
5.2关键问题解决思路
5.2.1 三维魔方的描述问题的解决方法
定义了一个Block类,用来表示一个小的六面体,以及它所在的位置的世界坐标,和给它的每个面着色的实现。
5.2.2 魔方整体旋转问题的解决办法
通过鼠标点击拖动,控制魔方的整体旋转。
定义了一个鼠标监听函数,鼠标移动后,坐标的改变将引起视图显示的角度的变化,然后视觉上给人以不同的效果。
5.2.3魔方每一层旋转和打乱问题的解决方法
每一层的旋转,定义了一个旋转函数,每次指定旋转层,根据其中心块的表面颜色,来执行函数。旋转函数通过改变块的颜色,视觉上给人以旋转后的效果,即重新对魔方的部分要求被改变的小块进行着色。
5.3 魔方的打乱
魔方的打乱只是多次随机调用魔方的层旋转函数。
系统实现
6.代码调试
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import static java.awt.RenderingHints.*;
import javax.swing.Timer;
public class m extends Applet implements ActionListener,MouseListener,MouseMotionListener{
private int[][] xyz; //4个坐标构成的面
private double[] x,y,z; //原始点
private double[] x1,y1,z1; // 旋转后的点
private double[][] mxy={{1,0,0},{0,1,0},{0,0,1}}; //旋转矩阵
private int time=0;
private int[] colors={0x70e33e,0x65f0e4,0xf20f2f,0xffff00,0x454545,0xaaaaaa}; //六面色
private int 数量=4; //在此设置是(4*4)的魔方
private int 视距=800; //越大越远
private int 鼠标点=-1; //装的是点击后得到的方块在xyz里的索引
private int[] 鼠标点击={-1,-1}; //点击时的鼠标坐标
private int[] 鼠标移动={-1,-1};
private double[][] nou;//旋转矩阵
private double 段号;
private int 取轴;
private BufferedImage bi;
private Graphics2D big;
//定时器
public void actionPerformed(ActionEvent e){
if(time>0){
for(int i=0;i<数量*数量*6;i++){
if(get轴(i)){
for(int u=0;u<4;u++){
double[] hh={x[xyz[i][u]],y[xyz[i][u]],z[xyz[i][u]]};
double[] hjh=setMxy(hh,nou);
x[xyz[i][u]]=hjh[0];
y[xyz[i][u]]=hjh[1];
z[xyz[i][u]]=hjh[2];
}
}
}
time--;
}
repaint();
}
//Download by http://www.codefans.net
//初始化数据
public void init(){
double[] 临时点=new double[3];
int i1,i2,i3,i4;
int 直径=100;
int 边距=8;
int 中心点=((直径+边距)*数量-边距)/2;
x=new double[数量*数量*数量<<3];
y=new double[数量*数量*数量<<3];
z=new double[数量*数量*数量<<3];
x1=new double[数量*数量*数量<<3];
y1=new double[数量*数量*数量<<3];
z1=new double[数量*数量*数量<<3];
xyz=new int[数量*数量*数量<<1][4];
double[][] X轴矩阵={{1,0,0},{0,0,1},{0,-1,0}};
double[][] Y轴矩阵={{0,0,1},{0,1,0},{-1,0,0}};
for(i1=0;i1<数量;i1++){
i4=i1<<2;
x[i4+3]=x[i4]=i1*(直径+边距)-中心点;
x[i4+1]=x[i4+2]=x[i4]+直径;
y[i4+1]=y[i4]=中心点;
y[i4+2]=y[i4+3]=y[i4]-直径;
z[i4]=z[i4+1]=z[i4+2]=z[i4+3]=中心点;
}
for(i2=1;i2<数量;i2++){
for(i1=0;i1<数量*4;i1++){
x[i2*数量*4+i1]=x[i1];
z[i2*数量*4+i1]=z[i1];
y[i2*数量*4+i1]=y[i1]-i2*(直径+边距);
}
}
for(i2=0;i2<3;i2++){
for(i1=0;i1<数量*数量*4;i1++){
临时点[0]=x[i2*数量*数量*4+i1];
临时点[1]=y[i2*数量*数量*4+i1];
临时点[2]=z[i2*数量*数量*4+i1];
临时点=setMxy(临时点,X轴矩阵);
x[(i2+1)*数量*数量*4+i1]=临时点[0];
y[(i2+1)*数量*数量*4+i1]=临时点[1];
z[(i2+1)*数量*数量*4+i1]=临时点[2];
}
}
for(i1=0;i1<数量*数量*4;i1++){
临时点[0]=x[i1];
临时点[1]=y[i1];
临时点[2]=z[i1];
double[] sy=setMxy(临时点,Y轴矩阵);
x[数量*数量*16+i1]=sy[0];
y[数量*数量*16+i1]=sy[1];
z[数量*数量*16+i1]=sy[2];
double[][] kj=getMxy(getMxy(Y轴矩阵,Y轴矩阵),Y轴矩阵);
sy=setMxy(临时点,kj);
x[数量*数量*20+i1]=sy[0];
y[数量*数量*20+i1]=sy[1];
z[数量*数量*20+i1]=sy[2];
}
for(i1=0;i1<数量*数量*6;i1++){
for(i2=0;i2<4;i2++){
xyz[i1][i2]=i1*4+i2;
}
}
addMouseMotionListener(this);
addMouseListener(this);
Timer t=new Timer(40,this);
setBackground(new Color(0x00ff00));
bi= new BufferedImage(800, 600, BufferedImage.TYPE_INT_RGB);
big = bi.createGraphics();
t.start();
}
//生成图像
public void paint(Graphics g){
int i,u,o;
Graphics2D g2=(Graphics2D)g;
big.setColor(new Color(0x000000));
big.fillRect(0,0,800,600);
double[] xx1=new double[3];
for(i=0;i<数量*数量*24;i++){
xx1[0]=x[i];
xx1[1]=y[i];
xx1[2]=z[i];
xx1=setMxy(xx1,mxy);
x1[i]=xx1[0];
y1[i]=xx1[1];
z1[i]=xx1[2];
}
for(i=0;i<数量*数量*6;i++){
int[] lx1=new int[4];
int[] ly1=new int[4];
int[] lz1=new int[4];
for(u=0;u<4;u++){
lz1[u]=(int)(z1[xyz[i][u]])-视距;
lx1[u]=(int)(x1[xyz[i][u]])*400/-lz1[u]+400;
ly1[u]=(int)(y1[xyz[i][u]])*400/-lz1[u]+300;
}
big.setColor(new Color(colors[i/数量/数量]));
if(getabc(lx1[0],ly1[0],lx1[1],ly1[1],lx1[3],ly1[3])){big.fillPolygon(lx1,ly1,4);}
}
g2.drawImage(bi,0,0,null);
}
public boolean get轴(int i){
if(取轴==0){
return ((x[xyz[i][0]]>段号-2 && x[xyz[i][0]]<段号+2)||(x[xyz[i][1]]>段号-2 && x[xyz[i][1]]<段号+2) || (x[xyz[i][2]]>段号-2 && x[xyz[i][2]]<段号+2));
}else if(取轴==1){
return ((y[xyz[i][0]]>段号-2 && y[xyz[i][0]]<段号+2) || (y[xyz[i][1]]>段号-2 && y[xyz[i][1]]<段号+2) || (y[xyz[i][2]]>段号-2 && y[xyz[i][2]]<段号+2));
}else{
return ((z[xyz[i][0]]>段号-2 && z[xyz[i][0]]<段号+2) || (z[xyz[i][1]]>段号-2 && z[xyz[i][1]]<段号+2) || (z[xyz[i][2]]>段号-2 && z[xyz[i][2]]<段号+2));
}
}
//坐标旋转
public double[] setMxy(double[] l,double[][] m){
double xx2[]={0,0,0};
for(int u=0;u<3;u++){
for(int o=0;o<3;o++){
xx2[u]+=l[o]*m[o][u];
}
}
return xx2;
}
//矩阵乘法
public double[][] getMxy(double[][] xx,double[][] yy){
int i=0,u=0,o=0;
double xx1[][]={{0,0,0},{0,0,0},{0,0,0}};
for(i=0;i<3;i++){
for(u=0;u<3;u++){
for(o=0;o<3;o++){
xx1[i][u]+=xx[i][o]*yy[o][u];
}
}
}
return xx1;
}
//判断是否是顺时针方向排列
public boolean getabc(double ax,double ay,double bx,double by,double cx,double cy){
double cax=cx-ax;
double cay=cy-ay;
double bcx=bx-cx;
double bcy=by-cy;
return cax*bcy>cay*bcx;
}
public void mouseClicked(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
//鼠标按下时的动作
public void mousePressed(MouseEvent e){
if(e.getButton()==1){
鼠标点=getf(e.getX(),e.getY());
鼠标点击[0]=e.getX();
鼠标点击[1]=e.getY();
}else if(e.getButton()==3){
鼠标移动[0]=e.getX();
鼠标移动[1]=e.getY();
}
}
public double 取点(int n,double[] o){
double li=o[xyz[n][0]];
if(li>0){
for(int i=1;i<4;i++){li=(li>o[xyz[n][i]])?li:o[xyz[n][i]];}
}else{
for(int i=1;i<4;i++){li=(li<o[xyz[n][i]])?li:o[xyz[n][i]];}
}
return li;
}
//鼠标放开时的动作
public void mouseReleased(MouseEvent e){
if(e.getButton()==1 && time==0 && 鼠标点!=-1){
double[] 点=new double[2];
鼠标点击[0]=e.getX()-鼠标点击[0];
鼠标点击[1]=e.getY()-鼠标点击[1];
if(Math.abs(鼠标点击[0])>Math.abs(鼠标点击[1])){鼠标点击[1]=0;}else{鼠标点击[0]=0;}
double cos1=Math.cos(2*Math.PI/180);
double sin1=Math.sin(2*Math.PI/180);
if( (z[xyz[鼠标点][0]]>z[xyz[鼠标点][2]]-10 &&z[xyz[鼠标点][0]]<z[xyz[鼠标点][1]]+10) && (z[xyz[鼠标点][1]]>z[xyz[鼠标点][2]]-10 &&z[xyz[鼠标点][1]]<z[xyz[鼠标点][2]]+10) ){
double hu=Math.atan2(mxy[0][1],mxy[0][0]);
点[0]=鼠标点击[0]*Math.cos(hu)+鼠标点击[1]*Math.sin(hu);
点[1]=鼠标点击[1]*Math.cos(hu)-鼠标点击[0]*Math.sin(hu);
if(Math.abs(点[0])>Math.abs(点[1])){
int l=(点[0]>0)?-1:1;
if(z[xyz[鼠标点][0]]<0){l*=-1;}
double[][] anou={{cos1,0,sin1*l},{0,1,0},{-sin1*l,0,cos1}};nou=anou;
段号=取点(鼠标点,y);
取轴=1;
}else{
int l=(点[1]>0)?-1:1;
double[][] anou={{1,0,0},{0,cos1,sin1*l},{0,-sin1*l,cos1}};nou=anou;
段号=取点(鼠标点,x);
取轴=0;
}
}else if( (x[xyz[鼠标点][0]]>x[xyz[鼠标点][2]]-10 &&x[xyz[鼠标点][0]]<x[xyz[鼠标点][1]]+10) && (x[xyz[鼠标点][1]]>x[xyz[鼠标点][2]]-10 &&x[xyz[鼠标点][1]]<x[xyz[鼠标点][2]]+10) ){
double hu=Math.atan2(mxy[2][1],mxy[2][0]);
点[0]=鼠标点击[0]*Math.cos(hu)+鼠标点击[1]*Math.sin(hu);
点[1]=鼠标点击[1]*Math.cos(hu)-鼠标点击[0]*Math.sin(hu);
if(Math.abs(点[0])>Math.abs(点[1])){
int l=(点[0]>0)?-1:1;
if(x[xyz[鼠标点][0]]>0){l*=-1;}
double[][] anou={{cos1,0,sin1*l},{0,1,0},{-sin1*l,0,cos1}};nou=anou;
段号=取点(鼠标点,y);
取轴=1;
}else{
int l=(点[1]>0)?-1:1;
double[][] anou={{cos1,sin1*l,0},{-sin1*l,cos1,0},{0,0,1}};nou=anou;
段号=取点(鼠标点,z);
取轴=2;
}
}else{
double hu=Math.atan2(mxy[0][1],mxy[0][0]);
点[0]=鼠标点击[0]*Math.cos(hu)+鼠标点击[1]*Math.sin(hu);
点[1]=鼠标点击[1]*Math.cos(hu)-鼠标点击[0]*Math.sin(hu);
if(Math.abs(点[0])>Math.abs(点[1])){
int l=(点[1]>0)?-1:1;
System.out.println(y[xyz[鼠标点][0]]);
if(y[xyz[鼠标点][0]]<0){l*=-1;}
double[][] anou={{cos1,sin1*l,0},{-sin1*l,cos1,0},{0,0,1}};nou=anou;
段号=取点(鼠标点,z);
取轴=2;
}
Else
{
int l=(点[1]>0)?-1:1;
double[][] anou={{1,0,0},{0,cos1,sin1*l},{0,-sin1*l,cos1}};nou=anou;
段号=取点(鼠标点,x);
取轴=0;
}
}
time=45;
//System.out.println(hu*180/Math.PI);
鼠标点=-1;
}
鼠标移动[0]=鼠标移动[1]=-1;
}
//鼠标按下移动时的动作
public void mouseDragged(MouseEvent e)
{
if(鼠标移动[0]!=-1&&鼠标移动[1]!=-1)
{
double oix=(鼠标移动[0]-e.getX())*Math.PI/720;
double oiy=(鼠标移动[1]-e.getY())*Math.PI/720;
double[][] fff={{1,0,0},{0,1,0},{0,0,1}};
fff[0][0]=fff[2][2]=Math.cos(oix);
fff[0][2]=Math.sin(oix);
fff[2][0]=-fff[0][2];
double[][] fff1={{1,0,0},{0,1,0},{0,0,1}};
fff1[1][1]=fff1[2][2]=Math.cos(oiy);
fff1[1][2]=Math.sin(oiy);
fff1[2][1]=-fff1[1][2];
mxy=getMxy(mxy,fff);
mxy=getMxy(mxy,fff1);
鼠标移动[0]=e.getX();
鼠标移动[1]=e.getY();
}
}
public void mouseMoved(MouseEvent e)
{}
//判断鼠标点是在哪个方块上
public int getf(int xx,int yy){
boolean[] t1=new boolean[4];
double x4,y4,z4,x5,y5,z5;
for(int i=0;i<数量*数量*6;i++)
{
for(int j=0;j<4;j++)
{
int l=(j==3)?0:j+1;
z4=z1[xyz[i][j]]-视距;
x4=x1[xyz[i][j]]*400/-z4+400;
y4=y1[xyz[i][j]]*400/-z4+300;
z5=z1[xyz[i][l]]-视距;
x5=x1[xyz[i][l]]*400/-z5+400;
y5=y1[xyz[i][l]]*400/-z5+300;
t1[j]=getabc(x4,y4,x5,y5,xx,yy);
}
if(t1[0]&&t1[1]&&t1[2]&&t1[3])
{
return i;
}
}
return -1;
}
}
图 1-2 魔方块后面旋转运行
旋转的方块是通过滑动覆带让小球一直撞击反弹,将所有的方块撞碎即可过关,速度要快。固定一个角块,剩下三个角块同时旋转一个方向。每个角块虽然会出现8个位置,但是只有3种方向。移动的坐标来研究3种方向的变换,不妨让视线穿过角块的顶点和魔方的中心,这个时候角块的三条边呈现Y字形,我把视线所在的直线叫做“旋转轴”。
图 1-3 魔方块前面旋转运行图
游戏的玩法很简单,屏幕中的魔方有不同的颜色的方块组成,我们的目的是寻找连成横排或竖排的3个相同颜色方块进行消除。如果方块上有相同颜色的宝石,那么就可以一并消除。消除了屏幕中的所有宝石可以获得分数加成,并且会刷新新一轮的宝石。
具体操作方便,第一次开始游戏也会有贴心的教程指引,上下左右滑动屏幕,就可以让魔方对应地转向了,而点击屏幕下方的按钮也可以让魔方180度转向。当找到了连成一排的同颜色方块,轻轻点击屏幕即可消除方块。在限定时间内消除获得一定的分数,即可解锁下一关。
一款魔方益智小游戏,玩魔方已经不再是一个单纯的智力游戏。
我们可以用原子操作的思想来证明魔方不能单独翻转一个棱块,也不能单独交换两个同类块。在魔方的转动过程中,有一些属性是保持不变的。我们假设魔方每个面是纯白的,没有图案,还原时白色面对着。
魔方游戏玩法,无非就是立体旋转扭动与三点一线。而本作就是结合两者后,变换除了崭新玩法。点选方块,与邻近方块替换位置,在魔方六个平方中,寻找三点同色连成一线,实现旋转,连线,消除的无限循环。
7.总结
此次课程设计,主要历时一个月,但其从前期的确定指导老师,到选题,然后根据老师的指导,进行前期准备则不止一个月。本人通过图书馆,网络等各种途径查询我此次所做课题的国内外研究情况,礼品魔方几乎没有过实现,各种魔方游戏倒是有不少,不过其实现方式都是依靠。
经过这次课设计,我在查阅资料的同时几乎熟悉了如今软件行业,各种工具,语言的特点,他们的开发特点,
遗憾的是这个项目还有功能没有实现。不过对于以后的研究方向有了一定的规则。
还有就是得感谢陈纪龙老师给了这么一个选题,让我涉及到了以前几乎不了解的图形开发。相信对于我以后的发展会带来无尽的帮助,还有就是得感谢老师,给予的指导,才有可能个人完成这样一个项目。
参考文献
[1]《java 程序设计书》;
[2]Microsoft. 《visual s# 程序设计教程》;