RUSSIA RECT 全过程开发 开发讲师:龙博强
RUSSIA RECT 从什么地方入手
RUSSIA RECT 从什么地方入手 涉及的类
RUSSIA RECT 从什么地方入手 涉及的类 每个类中的方法
RUSSIA RECT 游戏的启动类 Main_MIDlet.class 紧接着我们最容易联系到的就是与显示相关的画板类
RUSSIA RECT 游戏的显示画板 GamePanel.class
void paint(Graphics g) RUSSIA RECT 游戏的显示画板 GamePanel.class void paint(Graphics g)
RUSSIA RECT 方块 Shape.class 既然是俄罗斯方块,那自然是要有方块的对象 那么方块类中都应该有什么方法呢?当然是应该存在方块移动
RUSSIA RECT 方块 Shape.class void moveDown()
void moveDown() void moveLeft() RUSSIA RECT 方块 Shape.class void moveDown() void moveLeft()
void moveDown() void moveLeft() void moveRight() RUSSIA RECT 方块 Shape.class void moveDown() void moveLeft() void moveRight() 方块有下,左,右的移动,而它是无法向上移动的,但是方块是有旋转的,所以向上键就应该承担旋转的功能
void moveDown() void moveLeft() void moveRight() RUSSIA RECT 方块 Shape.class void moveDown() void moveLeft() void moveRight() void rotate() 那么还需要什么方法呢? 是不是还需要将自己绘制出来呢?
RUSSIA RECT 方块 Shape.class void moveDown() void moveLeft() void moveRight() void rotate() void paint(Graphics g) 为什么不在GamePanle里绘制方块呢? 因为在绘制方块时,是需要知道方块的坐标等等相关信息的,那这些信息当然是在方块类自身中最容易得到。所以,绘制方块应该属于自己的功能。
RUSSIA RECT 方块 Shape.class void moveDown() void moveLeft() void moveRight() void rotate() void paint(Graphics g) 自动定时下移 不去动任务按键,方块仍然能够自动向下移动
RUSSIA RECT 图形工厂 ShapeFactory.class 在开发到一定规模时,往往需要将类与类之间的关系分融合理才能有效联系,方块类只是用于实现方块的逻辑与绘制的,并不实现自身生产方块的能力。这时我们定制一个图形工厂用于生产方块。
RUSSIA RECT 图形工厂 ShapeFactory.class Shape getShape() 方块落地后,就会成为障碍物,那么此时,我们就需要再创造一个类,名为Ground.class
RUSSIA RECT 障碍物类 Ground.class 这个类拥有什么方法呢? 它应该能够接收落地的方块,使它能够成为障碍的一部分
void accept(Shape shape) RUSSIA RECT 障碍物类 Ground.class void accept(Shape shape) 同样,它应该能够将自己显示出来
RUSSIA RECT 障碍物类 Ground.class void accept(Shape shape) void paint(Graphics g)
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel Shape Ground 这四个类应该说是平级关系,而它们之间又是如何沟通和联系呢? 首先我们看 GamePanel是用于绘制的总司令部 Ground
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel Shape 显示 Ground 那么图形工厂类是用来创造方块的 Ground
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel 生产 Shape 显示 Ground 游戏过程中是要有用户按键的交互的 Ground
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel 生产 Shape 显示 Ground 处理按键事件 而且会有组织整体游戏的逻辑构架 Ground
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel 生产 Shape 显示 Ground 处理按键事件 处理逻辑事件 显示 还要分配绘制,以供界面显示 Ground
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel 生产 Shape 显示 Ground 处理按键事件 处理逻辑事件 显示 用户按键会直接控制方块的状态及位置 Ground 指配绘制
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel 生产 Shape 显示 Ground 处理按键事件 处理逻辑事件 显示 逻辑事件分管各个类之间的交互 Ground 指配绘制
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel 生产 Shape 显示 Ground 处理按键事件 处理逻辑事件 显示 Ground 指配绘制
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel 生产 Shape 显示 Ground 处理按键事件 处理逻辑事件 显示 Ground 指配绘制
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel 生产 Shape 显示 Ground 处理按键事件 处理逻辑事件 显示 指配绘制将所有需要显示的模块进行统一,然后指配显示类进行实现 Ground 指配绘制
RUSSIA RECT 类之间的关系 ShapeFactory GamePanel 生产 Shape 显示 Ground 处理按键事件 处理逻辑事件 显示 那么如此一来,我们就将最重要的中央管理类烘托出台 Ground 指配绘制
RUSSIA RECT 类之间的关系 Controller ShapeFactory GamePanel 生产 Shape 显示 处理按键事件 生产 Shape 处理逻辑事件 显示 Ground 指配绘制
RUSSIA RECT 不要和陌生人说话 图形定时下落,每下落一次后都需要生新显示 图形移动和变形后,也需要重新显示 而Shape类又不能直接操控Controller来通知GamePanle,怎么办呢? 那么我们就需要一种特殊的媒介来建立之间的联系
RUSSIA RECT 通过接口实现间接联系 Controller ShapeFactory GamePanel 生产 Shape 显示 处理按键事件 生产 Shape 处理逻辑事件 显示 通过这个接口连接Shape与Controller的关系 Ground 指配绘制 ShapeListener
RUSSIA RECT 通过接口实现间接联系 Controller ShapeFactory GamePanel 生产 Shape 显示 处理按键事件 生产 Shape 处理逻辑事件 显示 Ground 指配绘制 ShapeListener
RUSSIA RECT 项目启动 启动Eclipse,创造项目
RUSSIA RECT 项目启动 将所有涉及的类写出
RUSSIA RECT 项目启动 编写各类中的方法框架(Main_MIDlet.class)
RUSSIA RECT 项目启动 编写各类中的方法框架(Controller.class)
RUSSIA RECT 项目启动 编写各类中的方法框架(GamePanel.class)
RUSSIA RECT 项目启动 编写各类中的方法框架(Shape.class)
RUSSIA RECT 项目启动 编写各类中的方法框架(ShapeFactory.class)
RUSSIA RECT 项目启动 编写各类中的方法框架(Ground.class)
RUSSIA RECT 项目启动 编写各类中的方法框架(Ground.class)
RUSSIA RECT 项目启动 实现方块自动向下移动功能框架 1.内部类 2.继承线程接口 3.编写run()
RUSSIA RECT 项目启动 在GamePanel类中编写 方法 属性 完善paint()方法 public void display(Graphics g, Shape shape, Ground ground){} private Shape shape; private Ground ground;
RUSSIA RECT 项目启动 GamePanel.java
RUSSIA RECT 项目启动 在Controller中 加入属性
RUSSIA RECT 项目启动 在Controller中 构造方法实例化
RUSSIA RECT 项目启动 在Controller中 按键方法完善 上、下、 左、右 并与绘制连接
RUSSIA RECT 项目启动 在Controller中 继承接口ShapeListener实现方法并与绘制连接
public void addListener(ShapeListener listener) RUSSIA RECT 项目启动 在Shape中 增加方法,为实现下落移动绘制使用接口监听与 主控制类进行耦合 并增加属性,接收监听对象 在线程中加入方块下落绘制方法 编写Shape构造方法并启动线程 public void addListener(ShapeListener listener)
RUSSIA RECT 项目启动 Shape.java
RUSSIA RECT 项目启动 为实现Shape下落绘制显示,已经将Shape加入 监听能力,那么就需要修改图形工厂(ShapeFactory),让其Shape getShape()方法接收ShapeListener对象。
RUSSIA RECT 项目启动 现在就让我们回到控制台类(Controller),编写newGame()方法并生成一个Shape。 ?
RUSSIA RECT 项目启动 现在就让我们回到控制台类(Controller),编写newGame()方法并生成一个Shape。 ^.^
RUSSIA RECT 项目启动 框架搭建完毕 开始测试
RUSSIA RECT 项目启动 如何表示图形方块与障碍物
RUSSIA RECT 项目启动 可以用一个4×4的矩形方阵表示图形,并且具有多种形态
RUSSIA RECT 项目启动 可以用一个4×4的矩形方阵表示图形,并且具有多种形态 为什么要用4×4的矩形方阵?
RUSSIA RECT 项目启动 可以用一个4×4的矩形方阵表示图形,并且具有多种形态
RUSSIA RECT 项目启动 可以用一个4×4的矩形方阵表示图形,并且具有多种形态
RUSSIA RECT 项目启动 可以用一个4×4的矩形方阵表示图形,并且具有多种形态
RUSSIA RECT 项目启动 可以用一个4×4的矩形方阵表示图形,并且具有多种形态
RUSSIA RECT 项目启动 将图形与代码进行结合
RUSSIA RECT 项目启动 将图形与代码进行结合
RUSSIA RECT 项目启动 将图形与代码进行结合
RUSSIA RECT 项目启动 Shape类中应存有自身 状态并设置相应设置 方法 形态并设置相应设置
RUSSIA RECT 项目启动 方法的形态是由ShapeFactory决定的
RUSSIA RECT 项目启动 方法的形态是由ShapeFactory决定的 决定方块种类
RUSSIA RECT 项目启动 方法的形态是由ShapeFactory决定的 决定方块种类
RUSSIA RECT 项目启动 方法的形态是由ShapeFactory决定的 决定方块种类 决定当前方块形态
RUSSIA RECT 项目启动 方法的形态是由ShapeFactory决定的 决定方块种类 决定当前方块形态
RUSSIA RECT 项目启动 方法的形态是由ShapeFactory决定的 决定方块种类 决定当前方块形态 决定当前方块形态具体信息
RUSSIA RECT 项目启动 方法的形态是由ShapeFactory决定的 决定方块种类 决定当前方块形态 决定当前方块形态具体信息
RUSSIA RECT 项目启动 在ShapeFactory->getShape()中 随机获取方块形态 设置方块形态 设置方块状态
RUSSIA RECT 项目启动 方块自身会向下移动,那么我们应该让方块身身保存位置信息
RUSSIA RECT 项目启动 方块自身会向下移动,那么我们应该让方块身身保存位置信息 用left代表方块与左边界的距离
RUSSIA RECT 项目启动 方块自身会向下移动,那么我们应该让方块身身保存位置信息 用left代表方块与左边界的距离 用top代表方块与上边界的距离
RUSSIA RECT 项目启动 方块自身会向下移动,那么我们应该让方块身身保存位置信息 用left代表方块与左边界的距离 用top代表方块与上边界的距离 图形移动就是改变left与top的值
RUSSIA RECT 项目启动 图形的绝对坐标与相对坐标
RUSSIA RECT 项目启动 编写Shape对应代码
RUSSIA RECT 项目启动 绘制方块。 主要思路是:将方阵中为1的地方画上矩形。
RUSSIA RECT 项目启动 绘制方块。 主要思路是:将方阵中为1的地方画上矩形。 图形中的格子在显示区域中的位置 X坐标: left + 格子的x相对坐标 Y坐标: top + 格子的y相对坐标 (相对坐标是格子在方阵中的坐标)
RUSSIA RECT 项目启动 图形绝对坐标和相对坐标。
RUSSIA RECT 项目启动 绘制格子的要素
RUSSIA RECT 项目启动 计算绘制格子 left
RUSSIA RECT 项目启动 编写绘制格子 循环一个矩阵 每个方块矩阵 是由4*4组成的
RUSSIA RECT 项目启动 判断矩阵中的格子是否需要绘制
RUSSIA RECT 项目启动 组合
RUSSIA RECT 项目启动 边界检测与障碍物生成 按键以后方块是否一定能移动或改变呢? 答案是:不一定
RUSSIA RECT 项目启动 边界检测与障碍物生成
RUSSIA RECT 项目启动 边界检测与障碍物生成 定义一个常量代表一行容纳的最大格子数 定义一个常量代表一列容纳的最大格子数
RUSSIA RECT 项目启动 边界检测与障碍物生成 在Shape中加入四个常量 在Shape中加入返回left,top信息方法
RUSSIA RECT 项目启动 在Ground类中 编写”是否能够 移动”方法 需要: 方块, 方块下一步要 做的状态
RUSSIA RECT 项目启动 在Shape中编写”获取是否有效方块方法”
RUSSIA RECT 项目启动 继承在Ground 类中完善isMoveable
RUSSIA RECT 项目启动 在Contorller中将isMoveable方法合理的安插进去 控制按键
RUSSIA RECT 项目启动 在Contorller中将isMoveable方法合理的安插进去 自动下落问题未被解决 解决方案:让方块线程停止 疑问: 方块线程在Shape类中,判断方块无法下落方法在Ground类中,两个类无法沟通,如何解决?
RUSSIA RECT 项目启动 在Contorller中将isMoveable方法合理的安插进去 自动下落问题未被解决 解决方案:让方块线程停止,方块生命结束 疑问: 方块线程在Shape类中,判断方块无法下落方法在Ground类中,两个类无法沟通,如何解决? 通过Controller,通过ShapeListener接口
RUSSIA RECT 项目启动 接口ShapeListener添加方法
RUSSIA RECT 项目启动 Controller类实现父类接口方法 ? ?
RUSSIA RECT 项目启动 Shape类实现方块线程控制
RUSSIA RECT 项目启动 多线程访问同一方法时,会出现数据异常问题
RUSSIA RECT 项目启动 多线程访问同一方法时,会出现数据异常问题 解决方案:
RUSSIA RECT 项目启动 多线程访问同一方法时,会出现数据异常问题 解决方案 互斥锁:保证共享数据操作的完整性。
RUSSIA RECT 项目启动 多线程访问同一方法时,会出现数据异常问题 解决方案 互斥锁:保证共享数据操作的完整性。 互斥锁标记:保证在任一时刻,只能有一个线程执 行该对象锁住的代码。
RUSSIA RECT 项目启动 多线程访问同一方法时,会出现数据异常问题 解决方案 互斥锁:保证共享数据操作的完整性。 互斥锁标记:保证在任一时刻,只能有一个线程执 行该对象锁住的代码。 Synchronized:关键字,用于标示出以某对象为”互斥锁”的代码或用于声明方法,表示整个方法为同步。
RUSSIA RECT 项目启动 我们的程序中哪个方法需要被同步呢?
RUSSIA RECT 项目启动 我们的程序中哪个方法需要被同步呢?
RUSSIA RECT 项目启动 我们的程序中哪个方法需要被同步呢?
RUSSIA RECT 项目启动 方块能否继续下落,由isShapeMoveable()决定 方块若不能继续下落需要做哪些事情?
RUSSIA RECT 项目启动 方块能否继续下落,由isShapeMoveable()决定 方块若不能继续下落需要做哪些事情? 1.将方块变为障碍物
RUSSIA RECT 项目启动 方块能否继续下落,由isShapeMoveable()决定 方块若不能继续下落需要做哪些事情? 1.将方块变为障碍物 2.生成新的方块
RUSSIA RECT 项目启动 方块能否继续下落,由isShapeMoveable()决定 方块若不能继续下落需要做哪些事情? 1.将方块变为障碍物 2.生成新的方块
RUSSIA RECT 项目启动 方块能否继续下落,由isShapeMoveable()决定 方块若不能继续下落需要做哪些事情? 1.将方块变为障碍物 2.生成新的方块
RUSSIA RECT 项目启动 方块能否继续下落,由isShapeMoveable()决定 方块若不能继续下落需要做哪些事情? 1.将方块变为障碍物 2.生成新的方块
RUSSIA RECT 项目启动 开始编写Ground中的accept()方法。 疑问:如何存储障碍物?
RUSSIA RECT 项目启动 开始编写Ground中的accept()方法。 疑问:如何存储障碍物? 分析:用一个和显示区域相对应的 二维数组 保 存障碍物的位置信息。
RUSSIA RECT 项目启动 开始编写Ground中的accept()方法。 疑问:如何存储障碍物? 分析:用一个和显示区域相对应的 二维数组 保 存障碍物的位置信息。 方案:数组中用1代表障碍物,0代表无障碍物。
RUSSIA RECT 项目启动 Ground.java 构造存入障碍物空间
RUSSIA RECT 项目启动 Ground.java 解决产生障碍物问题
RUSSIA RECT 项目启动 Ground.java 解决障碍物绘制问题
RUSSIA RECT 项目启动 Ground.java 解决方块碰到障碍物问题
RUSSIA RECT 项目启动 消行 分析:当一行中没有空白, 证明这一行是满行。
RUSSIA RECT 项目启动 消行 分析:当一行中没有 空白,证明这一行是满 行。
RUSSIA RECT 项目启动 消行 分析:当一行中没有 空白,证明这一行是满 行。 判断是否有满行 真正删除一行
RUSSIA RECT 项目启动 真正删除一行 从被删行以上所有行依次向下覆盖 最终,顶行一定是空行
RUSSIA RECT 项目启动 我们应该把它加到哪里? deleteFullLine()
RUSSIA RECT 项目启动 何时需要判断是否消行呢? 在产生障碍物时才有机会构成消行因素
RUSSIA RECT 项目启动 判断游戏是否结束 如果有的障碍物超出了上边界(容器满了),就是游戏结束
RUSSIA RECT 项目启动 判断游戏是否结束 如果有的障碍物超出了上边界(容器满了),就是游戏结束 如果第一行有障碍物,就是游戏结束
RUSSIA RECT 项目启动 判断游戏是否结束 因为是根据障碍物进行判断,所以要在在Ground中
RUSSIA RECT 项目启动 判断游戏是否结束 那又在何时调用isFull()方法呢?
RUSSIA RECT 项目启动 判断游戏是否结束 那又在何时调用isFull()方法呢?
RUSSIA RECT 项目启动 判断游戏是否结束 那又在何时调用isFull()方法呢? 如果一直产生新的图形,游戏就一直不会结束 所以要找到产生新图形的位置
RUSSIA RECT 项目启动 判断游戏是否结束 那又在何时调用isFull()方法呢? 如果一直产生新的图形,游戏就一直不会结束 所以要找到产生新图形的位置
RUSSIA RECT 项目启动 判断游戏是否结束 完善isShapemoveable方法
RUSSIA RECT 项目启动 完善游戏 用户控制方块下落也同样需要进行游戏结束判断
RUSSIA RECT 项目启动 出现BUG
RUSSIA RECT 项目启动 分析BUG 用户按下键,调用isShapeMoveable(A)当前A方块下移 A方块移动至底 =====同一时刻===== A方块线程每1秒调用一次listener.isShapeMoveable(Shape.this) Shape.this就是A 此时因为用户按下致使A方块已经变为障碍物,产生B方块 但A方块线程仍然未完毕,此时调用listener.isShapeMoveable(Shape.this) isShapeMoveable()会判断传来的Shape.this(A)已经是障碍物了 然后将this.shape作为障碍物处理,而此时的this.shape却是B
RUSSIA RECT 项目启动 解决BUG
RUSSIA RECT 项目启动 出现BUG 怎么没消掉??!!
RUSSIA RECT 项目启动 分析BUG 主要原因是由于Ground类中的判断满行。 比如y = =15,第15行满行了,则将15行消掉并且y— 而原先的14行也是满行,可将15行消掉后,原14行变为15行 而此时y == 14,已略过15行
RUSSIA RECT 项目启动 解决BUG
RUSSIA RECT 项目启动 向ShapeFactory.java中添加各种方块
RUSSIA RECT 项目结束向龙懂致敬