JAVA GAME2D 游戏设计的答辨讲稿

1. 单机游戏直接【开始】   就行了
2. 联机游戏 A 方游戏玩家建立游戏服务器端等待另一方加入游戏后才可 以开始游戏 B 方通过 A 方的 IP 加入 A 方创建的游戏,加入成功后 B 方能看 到加入成功的提示 B 方加入成功后 A 方看到 B 方已经加入了游戏,此时 A 方可以【开始】游戏,这样 A B 方就能同步地玩游戏了

v 游戏用例图
v 整个游戏要实现的功能

类图 ( 聚合关系 )

类图 ( 继承实现关系 )

设计要点
v 实现两机互连
v 矩阵 à 游戏界面
v 方块移动和变形算法
v 键盘控制
v 游戏同步
v 游戏网络协议
v 菜单控制
实现两机互连
v MyServer 类:继承的 Thread 类,在线程的 Run ()方法里面建 ServerSocket 进行监听,这样做的目的是在没有客户连接请 求时可以做其它的事情.负责接受客户端请求的套接字,然后 获得按受到的套接字的输入流和输出流.输入流的读取交给了 ReadThread 线程. ReadThread 线程取得输入流中的数据再让 网络接口(自定义的接口,主要负责解析数据类型)去解析数 据.

MyClient 类:负责与服务器连接,指定 IP ,指定端口,同样要在连接成功之后,获得 Socket 的输入流和输出流.输入流的读取交给了 ReadThread 线程. ReadThread 线程取得输入流中的数据再让网络接口(自定义的接口,主要负责解析数据类型)去解析数据.
矩阵 --> 游戏界面
v private int[ ][ ] m_nField 10 20
v Java 动画技术里经常会使用到双缓冲。双缓冲技术是一种很有效的避免闪烁的方 法。它的特点是:不是直接在屏幕上画图,而是对内存里的一个虚拟的图片进行操 作,当复杂的画图过程结束后,直接将内存里的这张图,贴到屏幕上就行了。这样 做的好处在于对屏幕操作的时间缩短,这样对图像的闪烁感就会减少。
v 双缓冲的实现分两步:
v ①首先建立一个 Image 对象
v Image img=createImage(width,height);
v Java Image 类是一个虚类,不能直接创建出一个新的对象,不过可用 Java 里的 createImage(int w,int h) 创建出宽为 w 高为 h 的图片图像。
v ②获取 Image 对象的 Graphics 对象,通过这个对象就可以在 Image 对象上画需要的图 形。
v Graphics g=img.getGraphics();
v g 上画图就相当于在 Image 上画图。
v ③画好图后,将 img 对象直接贴到游戏界面上
v public void paint(Graphics gg)
v {
v  gg.draw(img,0,0,this);
v }

 

0
1
2
3
4
5
6
7
8
9
0










1










2










3










4










5










6










7
m_nField[20][10]
8
9










10










11










12










13










14










15










16










17










18










19





































方块的定义
v 在游戏里操纵的是一个个方块,应该编写一个类来封装这 些方块。
v 方块类的设计:
v 一个方块有三个属性 :X 坐标, Y 坐标和颜色
v int m_nColumn;
v int m_nRow;
int m_nColor;
对于方块类还有一些方法:
v 判断两个方块是不是相等
public boolean IsEqual(Square s)
v 判断这个方块是不是还在游戏的可玩的区域里
public boolean InBounds (int colMax, int rowMax)
v 方块组的构成
形状索引
0
1
2
3
4
5
6
形状




























1
0
2
3

 


 


 


2

 


 


1

 


2

 


1
0
2
2
0
1

 


 


 


0
3

 


 


3

 


0

 


3
0

 


 


3
3

 


 





























颜色索引
1
2
3
4
5
6
7
颜色描述
红色
桔黄色
绿色
兰色
品红色
粉红色
青色

方块组移动和变形算法
v 方块组的移动算法,从一个方块组移动到另一个方块组,如果可以移 动,则返回真,并且修改 m_nField[][] 的值 , 不可以返回假
v public boolean moveSquares(Square from[],Square to[])
v {
v /** 判断是否能移动 */
v outerlable:
v for (int i = 0; i < to.length; i++)
v {
v /** 如果不在可玩区域,则返回假 */
v if (to[i].InBounds(m_nCols,m_nRows+4) == false)
v return false;
v if (m_nField[to[i].m_nColumn][to[i].m_nRow] != 0)
v {
v for (int j = 0; j < from.length; j++)
v if (to[i].IsEqual(from[j]))
v continue outerlable;
v return false;
v }
v }
v /** 移动到 to 的位置,清除 from 位置 */
v for (int i = 0; i < from.length; i++)
v if (from[i].InBounds(m_nCols,m_nRows+4))
v m_nField[from[i].m_nColumn][from[i].m_nRow] = 0;
v for (int i = 0; i < to.length; i++)
v m_nField[to[i].m_nColumn][to[i].m_nRow] = to[i].m_nColor;
v this.playMusic("dead.wav");// 移动一次播放一次移动的声音
v return true;
v }
v From 定义为没有移动之前的那个方块组, to 定义为要移到的方块组。

v 定理:对于两个非零的向量 a,b, 如果 a ž b=0, 那么 a b ;反之如果 a b ,那么 a ž b=0
v 问题:已经向量 a=(X,Y) 要使 |b|=|a| ,且 b a, 求向量  b?
v 解:设向量 b(X1,Y1)
X2+Y2= X12+Y12
X*X1+Y*Y1=0
v 解出方程组的解为 x1=-y,y1=x; 或者 x1=y,y1=-x.
v 如果要实现方块的逆时针方向转动 取第一种解 : x1=-y,y1=x1203 逆时
v 0,1,2,3 表示 m_curPiece [0], m_curPiece [1], m_curPiece [2],
    m_curPiece [3]
v 根据求解得出的公式
m_curPiece [0] 的坐标为相对坐标原点,依次求出 m_curPiece [1],
m_curPiece [2], m_curPiece [3] 的相对于 m_curPiece [0] 的坐标
int dx = m_curPiece[i].m_nColumn - m_curPiece[0].m_nColumn;
int dy = m_curPiece[i].m_nRow - m_curPiece[0].m_nRow;
v 那么 m_curPiece[i] 逆时针旋转 90 度后的相对于 m_curPiece[0] 坐标为
v (-dy,dx) 那么 m_curPiece[i] 绝对坐标为
v (m_curPiece[0].m_nColumn-dy, m_curPiece[0].m_nRow+dx)
v m_curPiece[i] 旋转 90 度后的的新方块为
v Square(m_curPiece[0].m_nColumn-dy,
v m_curPiece[0].m_nRow+dx,
v m_curPiece[i].m_nColor)
v 如果不旋转 左右移动则相应加或减去移动的步长
v newpos[i] = new Square(m_curPiece[i].m_nColumn + nDx,
v                        m_curPiece[i].m_nRow + nDy,
v                        m_curPiece[i].m_nColor)



v /**
v  * 移动方块
v  *@param nDx 左右移动,向左为 -1 向右为 1 不左右为 0
v  *@param nDy 上下移动,向下为 -1 不上下为 0
v  *@param bRotate 是否转动 true 为转动
v  */
v  public synchronized boolean moveCurPiece(
v int nDx,
v int nDy,
v boolean bRotate)
v {
v Square newpos[] = new Square[4];
v for (int i = 0; i < 4; i++)
v {
v   if (bRotate) // 变形
v {
v    int dx = m_curPiece[i].m_nColumn - m_curPiece[0].m_nColumn;
v    int dy = m_curPiece[i].m_nRow - m_curPiece[0].m_nRow;
v    newpos[i] = new Square(m_curPiece[0].m_nColumn - dy,
v                           m_curPiece[0].m_nRow + dx,
v                           m_curPiece[i].m_nColor);
v    }
v    else // 复制要移动到的位置
v   {
v      newpos[i] = new Square(m_curPiece[i].m_nColumn + nDx,
v                             m_curPiece[i].m_nRow + nDy,
v                             m_curPiece[i].m_nColor);
v   }
v  }
v  if (moveSquares(m_curPiece, newpos) == false)
v // 不能移到指定位置返回 false
v  return false;
v  m_curPiece = newpos; // 能移返回 true
v  return true;
v  }
键盘控制
v 给游戏添加键盘侦听器
v 侦听器 KeyHandler 实现接口 KeyListener
v 重写 KeyListener 中的 keyPressed 这个方法 ( 包含字母 键和非字母键 )
v 左移 m_tTetrics.moveCurPiece( -1, 0, false)
v 右移 m_tTetrics.moveCurPiece( 1, 0, false)
v 变形 m_tTetrics.moveCurPiece( 0, 0, true)
v 下降
v while (m_tTetrics.moveCurPiece(0, -1, false));
游戏同步
v 要想实现游戏的同步①保证游戏双方所需要的方块形状出现的 次序一样②游戏双方实时地进行游戏区域数据的交互
v 实现方法 :
v ①游戏双方都有自己存放方块形状的缓冲区
v 有了缓冲区当然就要有生产和消费 , 生产者有游戏服务器端去做 , 生产的方块添加到自己缓冲区并同时发送给客户端 , 客户端端收 到后再添加到自己的缓冲区
v ②一方的方块组每移动一步就要把自己的区域信息发送给另一 , 另一方收到后 , 再更新对方的游戏区域矩阵 m_nRivalField[][] 数据 , m_nRivalField[][] 里数据变了 , 画出的图形也就变了
v PieceBuffer 是一个具有互斥功能的环状缓冲区,用于 存放生产者生产出的游戏所需要的方块组索引值
v 方块组索引值加 1 后就是画图所用的颜色索引值 , 一值 两用

v PieceBuffer 是一个具有互斥功能的环状缓冲区,用于 存放生产者生产出的游戏所需要的方块组索引值
v 方块组索引值加 1 后就是画图所用的颜色索引值 , 一值 两用
游戏网络协议
v 这样游戏的服务器端和客户端就能在连接成功之后相 互通信了.既然能够通信,那么双方之间通信的数据 到底是属于哪些数据?是游戏的状态数据,还是组织 游戏的动作命令,或者是双方聊天的内容?这就需要 事先归定发送的数据是属于什么数据,从协议的角度 出发,在数据内容头部加一个数据类型的报头,这样 另一方在收到数据时,只要剥取数据的头部,然后根 据头部的内容来判断数据类型,然后再决定怎样对待 这类型的数据.
v 在网络接口里定义了这些网络协议报文头常量
v     public final int STARTGAME=11;     /** 开始游戏 */
v     public final int PAUSEGAME=12;     /** 暂停游戏 */
v     public final int ENDGAME=13;      /** 结束游戏 */
v     public final int EXITGAME=14;      /** 退出程序 */
v     public final int GAMEDATA=21;      /** 游戏数据 */   
v     public final int GAMEOVER=22;      /** 游戏结束 */  
v     public final int GAMEREMOVELINE=23;/** 游戏消行 */
v     public final int GAMESCORE=24;      /** 游戏分数 */
v     public final int GAMEPIECE=25;      /** 游戏的 Piece*/
v     public final int TALK=31;         /** 聊天内容 */
v    整个数据是一个字符串
v 字符串前 2 位是数据类型
v 如:" 31 表示该条数据是聊天内容
v 字符串第3位是一个分隔符冒号 隔开数据类型和数据内容
v 从第四位开始为数据内容
v :str=”31 : 你好!
3
1
你好!
v 1位 2位 3位  4位~N位

菜单控制

菜单结构一览
主菜单项
子菜单项
描述
游戏
jMenuGame
开始 jMenuStartGame
暂停 jMenuPauseGame
结束 jMenuEndGame
关闭 jMenuExit
开始游戏
暂停游戏
结束游戏
退出程序
设置
jMenuSet
设置级别 jMenuGameLevel
创建游戏 jMenuCreateGame
加入游戏 jMenuAddGame
退出游戏 jMenuExitGame
创建 server 端等待 client 来连接
作为 client 端去连接 server
断开网络连接
关于
jMenuHelp
关于 jMenuSeeAbout
记录 jMenuSeeRecord
关于制作
查看记录分数
创建游戏时序图


开始游戏时序图



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值