tilemap.java
来自「mywork是rcp开发的很好的例子」· Java 代码 · 共 546 行 · 第 1/2 页
JAVA
546 行
/************************************************************
*
* Copyright (c) 2003 Chemi. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the MIT License
* which accompanies this distribution, and is available at
* http://www.opensource.org/licenses/mit-license.html
*
************************************************************/
package es.org.chemi.games.sokoban.ui;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.zip.ZipFile;
import net.sf.pim.game.util.DiamondMap;
import net.sf.pim.game.util.DiamondMap.IsoDirection;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import es.org.chemi.games.sokoban.SokobanPlugin;
import es.org.chemi.games.sokoban.actions.PauseAction;
import es.org.chemi.games.sokoban.events.TileMapKeyListener;
import es.org.chemi.games.sokoban.events.TileMapMouseListener;
import es.org.chemi.games.sokoban.util.Constants;
import es.org.chemi.games.sokoban.util.Preferences;
import es.org.chemi.games.util.Counter;
import es.org.chemi.games.util.Timer;
public class TileMap extends Composite
{
private ArrayList lines = new ArrayList();
private ArrayList holes = new ArrayList();
private ArrayList oldHoles = null;
Tile[][] tiles = null;
private Tile[][] oldTiles = null;
private Tile boyTile = null;
private Tile oldBoyTile = null;
private Preferences preferences = null;
private HashMap counters = null;
private Action undoAction = null;
private PauseAction pauseAction = null;
int width = 0;
int height = 0;
int deltaWidth = 0;
int deltaHeight = 0;
Image doubleBuffering = null;
boolean isNewLevel = true;
boolean isDemo =false;
private TileMapKeyListener keyListener = null;
private TileMapMouseListener mouseListner =null;
public TileMap(Composite parent, int style, Preferences preferences, HashMap counters)
{
super(parent,style);
this.preferences = preferences;
this.counters = counters;
this.keyListener=new TileMapKeyListener(this);
this.mouseListner=new TileMapMouseListener(this);
this.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent e)
{
SokobanPlugin.trace(this.getClass().getName(),"Refresh process of game field started."); //$NON-NLS-1$
// Doublebuffering.
GC tempGC = new GC(doubleBuffering);
tempGC.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WHITE));
if(isNewLevel){
tempGC.fillRectangle(0,0,doubleBuffering.getBounds().width,doubleBuffering.getBounds().height);
Image back = SokobanPlugin.getResourceManager().getImage(Constants.IMAGE_BACKGROUND);
tempGC.drawImage(back,0,0,back.getBounds().width,back.getBounds().height,0, 0,doubleBuffering.getBounds().width,doubleBuffering.getBounds().height);
}
for(int row=0; row<tiles.length; row++)
{
for(int column=0; column<tiles[0].length; column++)
{
if(tiles[row][column].isModified())
{
if(isNewLevel){
tiles[row][column].repaint(tempGC,deltaWidth,deltaHeight);
}else{
//考虑局部刷新,还要绘制周围受影响的Tile,设置剪切矩形
Point ptCenter=DiamondMap.tilePlotter(new Point(column,row),Constants.TILE_SIZE, Constants.TILE_SIZE/2,deltaWidth, deltaHeight);
//实际贴图图片高度目前没有固定,有48*48/48*32/48*38/48*24,取最大值减1
int rectWidth=Constants.TILE_SIZE-2,rectHeight=Constants.TILE_SIZE-2;
Rectangle rect=new Rectangle(ptCenter.x+1,ptCenter.y+1,rectWidth,rectHeight);
tempGC.setClipping(rect);
for(IsoDirection dir : IsoDirection.values()){
Point pt=DiamondMap.tileWalker(new Point(column,row),dir);
//防止越界,且WEST/EAST肯定不相交
if(pt.x >=0 && pt.y >= 0 && pt.x < width && pt.y < height && dir != IsoDirection.WEST && dir != IsoDirection.EAST)
tiles[pt.y][pt.x].repaint(tempGC,deltaWidth,deltaHeight);
}
tempGC.setClipping((Rectangle)null);
}
tiles[row][column].setModified(false);
}
}
}
if(isNewLevel){
isNewLevel = false;
}
tempGC.dispose();
e.gc.drawImage(doubleBuffering,0,0);
SokobanPlugin.trace(this.getClass().getName(),"Refresh process of game field finished."); //$NON-NLS-1$
}
});
this.addControlListener(new ControlAdapter()
{
public void controlResized(ControlEvent e)
{
resetDelta();
//Reset the double buffering image.
if(doubleBuffering != null)
doubleBuffering.dispose();
if(getSize().x != 0 && getSize().y != 0) // This line is needed to support Eclipse R2.0.x products
doubleBuffering = new Image(null,getSize().x,getSize().y);
//绘制背景
GC tempGC = new GC(doubleBuffering);
Image back = SokobanPlugin.getResourceManager().getImage(Constants.IMAGE_BACKGROUND);
tempGC.drawImage(back,0,0,back.getBounds().width,back.getBounds().height,0, 0,doubleBuffering.getBounds().width,doubleBuffering.getBounds().height);
tempGC.dispose();
//Force tile repaint.
if(tiles != null)
{
for(int row=0; row<height; row++)
{
for(int column=0; column<width; column++)
tiles[row][column].setModified(true);
}
}
}
});
}
public void loadMap() throws IOException
{
// Empty information from previous map.
lines.clear();
holes.clear();
width=0;
height=0;
// Read the map file.
ZipFile zf=new ZipFile(new File(FileLocator.getBundleFile(SokobanPlugin.getDefault().getBundle()),"levels/"+preferences.getMode()+".map"));
BufferedReader br = new BufferedReader(new InputStreamReader(zf.getInputStream(zf.getEntry(""+preferences.getLevel(preferences.getMode())+".sok"))));
while(true)
{
String line = br.readLine();
if(line == null)
{
br.close();
zf.close();
break;
}
if(!line.trim().isEmpty() && !line.startsWith("#Level") && !line.startsWith("#-") && line.compareTo(Constants.EMPTY_LINE) != 0) //$NON-NLS-1$
{
lines.add(line);
width = Math.max(width,line.length());
}
}
width += 2;
height = lines.size()+2;
tiles = new Tile[height][width];
parseLines();
resetCounters();
resetDelta();
fixMap();
resetWall();
}
/**
* 1.修正map中有些块没有初始化情况
* 2.将墙包围之外的floor置为false
* 3.去掉多余的墙
* 4.修订拐角刷新的bug
* 5.增加一圈外地板
* 为了简洁,每个处理都进行一次循环
*/
private void fixMap() {
//1修正map中有些块没有初始化情况
for(int row=0; row<tiles.length; row++)
{
for(int column=0; column<tiles[0].length; column++)
{
if(tiles[row][column] == null){
tiles[row][column]=new Tile(row,column);
tiles[row][column].setFloor(true);
}
}
}
//2.1将墙包围之外的floor置为false
for(int row=0; row<tiles.length; row++)
{
int cs=-1,ce=0;
for(int column=0; column<tiles[0].length; column++)
{
if(tiles[row][column].isWall()){
if(cs == -1) cs=column;
if(column > ce) ce=column;
}
}
for(int i=0;i<cs;i++)tiles[row][i].setFloor(false);
for(int i=ce;i<tiles[0].length;i++)tiles[row][i].setFloor(false);
}
//2.2颠倒行列
for(int column=0; column<tiles[0].length; column++)
{
int cs=-1,ce=0;
for(int row=0; row<tiles.length; row++)
{
if(tiles[row][column].isWall()){
if(cs == -1) cs=row;
if(row > ce) ce=row;
}
}
for(int i=0;i<cs;i++)tiles[i][column].setFloor(false);
for(int i=ce;i<tiles.length;i++)tiles[i][column].setFloor(false);
}
//3.去掉多余的墙
for(int row=0; row<tiles.length; row++)
{
for(int column=0; column<tiles[0].length; column++){
//多余的墙特征,其东南、东北、西南、西北均为墙或为空
Tile tile = tiles[row][column];
if(tile.isWall() &&
(neighborTile(tile, IsoDirection.SOUTH_EAST).isWall() ||neighborTile(tile, IsoDirection.SOUTH_EAST).isBlank())&&
(neighborTile(tile, IsoDirection.SOUTH_WEST).isWall() ||neighborTile(tile, IsoDirection.SOUTH_WEST).isBlank())&&
(neighborTile(tile, IsoDirection.NORTH_EAST).isWall() ||neighborTile(tile, IsoDirection.NORTH_EAST).isBlank())&&
(neighborTile(tile, IsoDirection.NORTH_WEST).isWall() ||neighborTile(tile, IsoDirection.NORTH_WEST).isBlank()))
tile.setWall(false);
}
}
//4.修订拐角刷新的bug,顺便美化拐角
for(int row=0; row<tiles.length; row++)
{
for(int column=0; column<tiles[0].length; column++){
//该块空白,其西南、东南为墙,其南为地板或小人
Tile tile = tiles[row][column];
if(tile.isBlank()){
//预防bug
if( neighborTile(tile, IsoDirection.SOUTH_WEST).isWall() && neighborTile(tile, IsoDirection.SOUTH_EAST).isWall() && (neighborTile(tile, IsoDirection.SOUTH).isFloor() || neighborTile(tile, IsoDirection.SOUTH).equals(boyTile)))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?