作者PsMonkey (痞子军团团长)
看板java
标题[GWT] 对战吧~踩地雷!
时间Mon Aug 23 15:52:04 2010
网页版:
http://pt2club.blogspot.com/2010/08/gwt.html
上一次教完如何写一个生命游戏(好久以前啊 [远目])
这次的题目同样是阵列系的踩地雷
不过,如果单机自己玩也太无聊了点
所以呢... 这次的目标是「对抗电脑版的踩地雷」!
这个题目有点大,让我们一步一步慢慢来......
首先是先弄出一个 MineGM 的物件
来负责创造地雷世界、运作规则逻辑
所以 MineGM 必须要有这些 field
public static final int UNKNOW = -1;
private int x;
private int y;
private int total; //总共几个地雷
private int remainder; //剩下几个地雷
private boolean[][] answer; //地雷分布图
private int[][] map; //玩家看到的地图
private int[] playerHit = new int[2]; //分别踩了几个
一开始就用乱数把 answer 准备好
至於 map 的内容一开始都是 UNKNOWN,表示还不知道是啥状况
map 当中还可能出现:
0~8:九宫格内出现的地雷数
9:玩家踩到的地雷
-9:电脑踩到的地雷
而 MineGM 还需要有一个 public 的 method「shoot()」
负责接受玩家的输入、然後回报是否命中
public boolean shoot(int hitX, int hitY, boolean who){
map[hitX][hitY] = count(hitX, hitY);
//踩到空地的连锁反应
if(map[hitX][hitY]==0){
for(int i=-1; i<2; i++){
if(hitX+i==x || hitX+i<0){continue;}
for(int j=-1; j<2; j++){
if(hitY+j==y || hitY+j<0){continue;}
if(map[hitX+i][hitY+j] != -1){
continue;
}else{
shoot(hitX+i, hitY+j, who);
}
}
}
}
//不同人踩到地雷要给不同值
if(map[hitX][hitY]==9){
remainder--;
if(who){
playerHit[0]++;
}else{
map[hitX][hitY]=-9;
playerHit[1]++;
}
}
return Math.abs(map[hitX][hitY])==9;
}
count() 就是计算周围九宫格有几个地雷,然後设定到对应的 map 上
另外,因为我采取「answer 的周围多一格空地」的作法
所以「踩到空地的连锁反应」那段的回圈可以比较好看一点
虽然已经有 MineGM 建立、维护地雷世界了
但是,我们还是需要另外一个 GameInfo 来包装给玩家的资讯
不然如果玩家 or 电脑直接拿 MineGM 的 answer 来作弊怎麽办? Orz
所以在 MineGM 当中弄了一个 static method 来转换成 GameInfo
public static GameInfo toGameInfo(MineGM server) {
GameInfo result = new GameInfo();
result.setMap(server.getMap());
result.setRemainder(server.remainder);
result.setTotal(server.total);
result.setPlayerHit(server.playerHit);
return result;
}
至於其他的细节就留给大家慢慢写了......
接下来处理 UI 的部份
这次使用 GWT 2.0 的 UiBinder 来处理排版
使用方法可以看官方文件或痞子版的中文翻译
预计的游戏画面是长这样:
http://tinyurl.com/296b2mz
上方是数据区
左右两侧是双方的名字与分数,包了一个 PlayerInfo 来处理
其实很简单,刚好适合拿来了解 UiBinder
PlayerInfo.ui.xml:
<!DOCTYPE ui:UiBinder SYSTEM "
http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:style>
.title{
padding-left: 5px;
}
</ui:style>
<g:FlowPanel>
<g:InlineLabel ui:field="title" styleName="{style.title}" />
<g:InlineLabel ui:field="hitCount" />
</g:FlowPanel>
</ui:UiBinder>
PlayerInfo.java:
public class PlayerInfo extends Composite {
private static PlayerInfoUiBinder uiBinder =
GWT.create(PlayerInfoUiBinder.class);
interface PlayerInfoUiBinder extends
UiBinder<Widget, PlayerInfo> {}
@UiField Label title;
@UiField Label hitCount;
public PlayerInfo() {
initWidget(uiBinder.createAndBindUi(this));
setHitCount(0);
}
public void setHitCount(int i) {
hitCount.setText(""+i);
}
public void setName(String name){
title.setText(name+":");
}
}
中间是还剩下多少地雷,用一个 Label 解决
下方的地雷区则是用 FlexTable 处理
这些东西都放在 MineMain 这个 class 当中
所以 MineMain.ui.xml 会长成这样:
<!DOCTYPE ui:UiBinder SYSTEM "
http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui"
xmlns:m="urn:import:org.psmonkey.product.client.mine">
<ui:style>
.playerInfo{
width: 480px;
}
.cpu{
width: 220px;
background-color: red;
}
.player{
width: 220px;
background-color: #64A0C8;
}
.remainder{
width: 40px;
color: white;
background-color: gray;
text-align: center;
}
</ui:style>
<g:VerticalPanel>
<g:HorizontalPanel styleName="{style.playerInfo}">
<m:PlayerInfo ui:field="cpu" styleName="{style.cpu}" />
<g:Label ui:field="remainder" styleName="{style.remainder}" />
<m:PlayerInfo ui:field="player" styleName="{style.player}" />
</g:HorizontalPanel>
<g:FlexTable ui:field="map"></g:FlexTable>
</g:VerticalPanel>
</ui:UiBinder>
很懒惰地用 VerticalPanel 跟 HorizontalPanel 解决 XD
接下来,就要处理跟 web server 之间的沟通了! [待续]
--
钱锺书:
说出来的话
http://www.psmonkey.org
比不上不说出来的话
Java 版 cookcomic 版
只影射着说不出来的话
and more......
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 219.70.214.149