大貓共和國

Meow

GLUT+Code::Blocks+Mingw環境設定

GLUT….不介紹了,反正就是OpenGL的一些Toolkit,讓programmer避免處理low level的視窗控制。

其實我滿推薦寫程式的人不要「只」用微軟的IDE。之前看到某位網友抱怨,他們學校沒有正版的VC教育版,老師還要求要用VC寫作業。多推廣一下免費開源的IDE不是很好嗎?



Code::Blocks+Mingw的安裝可以參考這篇,如果不是要跑OGRE的話,直接去官網下載區抓安裝包應該比較簡單 (with Mingw compiler的)。

原本的GLUT Windows Binary和Mingw似乎不太相容,請抓GLUT for Mingw32,隨便解壓到一個目錄(我放在Mingw下),就可以了。

預備動作就這麼簡單 (不過我灌時試GLUT library試了一陣子,才發現要抓Mingw版的) ,進到Code::Block,New project -> GLUT project -> 到GLUT’s location時輸入你安裝GLUT的位置。

這樣開好專案後會出現template的範例程式,compile&run看看…
C:\codeblock\GLUTMingw32\include\GL\glut.h:45: error: redeclaration of C++ built-in type `short'
疑…不知道怎麼回事的error,但我們見招拆招一下
方法一: 修改範例程式,再include之前加上# define _WCHAR_T_DEFINED
方法二: 修改glyt.h第45行,將typedef unsigned short wchar_t;這行給註解掉

兩者任做一項,這樣就可以run囉…

TJS特訓99解說篇

上一篇忘了說,我的架構主要是參考這篇TJS實作教學的

先講一下類別的設計:

  • MovingObject:所有戰場上會移動的物件,Player及Enemy的父類別
  • Player:玩家自機,畫面上那個藍點
  • Enemy:敵機,不停撞過來的那些小紅點
  • GameMaster:管理整個遊戲的迴圈與邏輯
  • GameWindow:遊戲視窗
GameWindow類別
作用其實很簡單
  • 建立一個視窗,設定大小為400x400。
  • 建立一個Layer,該視窗的主要圖層。
  • 然後建立一個GameMaster物件,就這樣。接下來遊戲的進行都交給GameMaster控制。
GameMaster類別
  • 建立fore(前景)圖層,所有遊戲的物件都畫在這個圖層上。
  • 建立玩家物件及99個敵人物件,敵人物件用一個陣列(Array)存放。
  • 建立一個Timer,每25ms呼叫一次 (理想狀態下40fps),負責玩家、敵機的移動、碰撞判定。
MovingObject類別
  • 之前說過這個範例不要想用到圖檔,所以我們使用正方形來表示自機與子彈。size是邊長,color是顏色
  • 繼承Layer物件,建構時將自己放在fore這個圖層上
Enemy類別
  • 建構時指定顏色(子彈是紅色)及邊長。
  • init函式負責初始化敵機 (在畫面的邊緣出現,向畫面內非)
  • check_bound函式負責檢查敵機是否出界了,如果是的話,呼叫init來重置敵機。
  • update函式負責敵機的移動
Player類別
  • 建構時指定顏色(藍色)
  • update函式負責移動,使用System.getKeyState()來判斷方向鍵是否已被按下。
我就不一行一行的講解程式碼了,有興趣的話可以留言討論。



延伸練習:這只是個小小範例,我的code有滿多問題的,如果你想練習的話…
  1. 我忘了寫Player出界的判定,請補上
  2. 碰撞判定的公式其實是不對的,你發現了嗎?請修正
  3. Frame穩速的機制是否有比使用Timer還要好的方式呢?
  4. 敵機移動的速度目都只是整數,請修改init函式讓敵機的移動速度不要那麼規律。
  5. 找找看還有沒有其他bug吧 :)

吉里吉里TJS特訓99

特訓99是數年前在巴哈姆特kuso版看到的一個遊戲,規則很簡單:「閃避畫面上的99顆子彈,看你可以撐幾秒」自從看到了這個遊戲之後,每到一個可以寫遊戲的環境,我都把他當hello, world來寫了,幫助熟悉整個程式環境。(印像中寫過C++/DirectDraw, J2SE, J2ME on 手機, VisualBasic, Ruby/RPG Maker XP還有什麼忘了)

剛剛把試著用吉里吉里的TJS寫了一下,心得…喵的文件有夠不完整,要到處翻來翻趣,有的地方乾脆去template裡直接看他怎麼寫的比較快。寫出來就這樣囉:


不停的閃子彈閃到死吧 XD

  • 其實code寫的很差,我只是一直翻文件然後找出一個能寫出來的方法而已。很多地方應該可以再修正的。碰撞判定的公式其實也是錯的,可是我懶得改了,可以跑就好了啦,只是做個小範例而已 @@
  • 為了簡化範例,被擊中game over時就直接跳出遊戲了 (好我懶得做game over畫面了 XD)
  • 為了簡化範例所以沒有貼圖,都是用方塊表示。這樣只需要把程式複置貼上就可以跑囉


把以下程式複置貼到startup.tjs (原本的程式清掉) 即可

class MovingObject extends Layer{
var master;
var size;
var color;

function MovingObject(gm, window, parent) {
super.Layer(window, parent);
master = gm;
visible = true;
setSize(size, size);
fillRect(0, 0, size, size, color);
}
}

class Enemy extends MovingObject {
var vx, vy;
function Enemy(gm, window, parent) {
size = 6;
color = 0xffff0000;
super.MovingObject(gm, window, parent);
init();
}
function init() {
var side = Math.floor(Math.random()4);
switch (side) {
case 0:
top = 0;
left = Math.floor(Math.random()
400);
vx = Math.floor(Math.random()5)-2;
vy = Math.floor(Math.random()
2)+1;
break;
case 1:
top = 400;
left = Math.floor(Math.random()400);
vx = Math.floor(Math.random()
5)-2;
vy = -Math.floor(Math.random()2)-1;
break;
case 2:
left = 0;
top = Math.floor(Math.random()
400);
vy = Math.floor(Math.random()5)-2;
vx = Math.floor(Math.random()
2)+1;
break;
default:
left = 400;
top = Math.floor(Math.random()400);
vy = Math.floor(Math.random()
5)-2;
vx = -Math.floor(Math.random()*2)-1;
break;
}
}
function check_bound() {
if (top>-5&&top<405&&top>-5&&top<405)
return;
init();
}
function update() {
top += vy;
left += vx;
check_bound();
}
}

class Player extends MovingObject {
function Player(gm, window, parent) {
size = 10;
color = 0xff0000ff;
super.MovingObject(gm, window, parent);
top = left = 200;
}
function update() {
var speed = 2;
if (System.getKeyState(VK_DOWN))
top += speed;
if (System.getKeyState(VK_UP))
top -= speed;
if (System.getKeyState(VK_LEFT))
left -= speed;
if (System.getKeyState(VK_RIGHT))
left += speed;
}
}

class GameMaster {
var window;
var parent;
var fore;

var player;
var enemies;

var timer1;

function GameMaster(win, par) {
window = win;
parent = par;

fore = new Layer(win, par);

with (fore) {
.visible = true;
.setSize(400, 400);
}

timer1 = new Timer(onTimer1, "");
timer1.interval = 25;
timer1.enabled = true;

player = new Player(this, window, fore);

enemies = [];
for (var i=0; i<99; ++i) {
enemies.add(new Enemy(this, window, fore));
}

}
function onTimer1() {
player.update();
for (var i=0; i<enemies.count; ++i) {
var e = enemies[i];
e.update();
if (Math.abs(e.top-player.top)<10&&Math.abs(e.left-player.left)<10)
window.close();
}
}

}

class GameWindow extends Window {
var master;

function GameWindow() {

super.Window();

add(new Layer(this, null));
primaryLayer.setSize(400, 400);
setInnerSize(400, 400);

caption = "特訓99";
visible = true;

master = new GameMaster(this, primaryLayer);
}
function finalize() {
super.finalize();
}
function action(ev) { }
}
var win = new GameWindow();


解說篇….下次再說吧 XD

初探Shattered Ruby(4) - 結論

前四篇對於Shattered Ruby似乎是貶多於褒,但其實我覺得這東西還是滿有趣的。有很多implement的功能是這裡沒提到的,大家可以詳閱WikiRDoc。其實他們已經做了很多了….

說實話,我沒看過一個工具建構以3D介面為基楚的遊戲那麼容易的,這應該是他最大的優點吧。要是目前這個專案還有人持續在maintain,那我應該毫不考慮的繼續玩下去。

Shattered Ruby中的設計流程其實很高階,我們可以看到Tutorial幾乎都是用DSL的方式在寫作。但根據抽象滲漏法則,當專案被擴大的時候不知道會不會遇到麻煩…

好啦,Shattered Ruby就寫到這囉,我應該短期之內不會再碰他了。有什麼意見的話也歡迎提出來吧 :)

初探Shattered Ruby(3) - 回到舊版本玩Example

我們可以看到Shattered Ruby Wiki首頁上有好幾個Tutorial&Example,但除了第一個之外,其他都不能在最新的版本上跑。如果我們要快速的玩玩看Example的話(不想去改code),可能回到舊版本是比較快的選擇。

我們以俄羅斯方塊為例吧….先把他解壓到某個地方,然後我們開始裝0.3.3版的Shattered Ruby

首先為了避免混淆,我們先將舊版本的ShatteredRuby全都反安裝。執行

C:\temp\mygame>gem uninstall shattered*

Select RubyGem to uninstall:
1. shattered-0.4.0.1
2. shattered_ogre-0.4-windows
3. shattered_pack-0.4.0.1
4. shattered_support-0.4.0.1
5. All versions
> 5
Successfully uninstalled shattered version 0.4.0.1
Successfully uninstalled shattered_ogre version 0.4
Successfully uninstalled shattered_pack version 0.4.0.1
Successfully uninstalled shattered_support version 0.4.0.1


然後再安裝0.3.3版的ShatteredRuby,可能又需要一些時間,因為另一個revision的DLL必需重新下載一次,安裝方式如下:

C:\temp\mygame>gem install -y shattered -v 0.3.3
Bulk updating Gem source index for: http://gems.rubyforge.org
Bulk updating Gem source index for: http://gems.rubyforge.org
Select which gem to install for your platform (i386-mswin32)
1. shattered_ogre 0.4 (windows)
2. shattered_ogre 0.3.3 (windows)
3. Cancel installation
> 2
Bulk updating Gem source index for: http://gems.rubyforge.org
Bulk updating Gem source index for: http://gems.rubyforge.org
Successfully installed shattered-0.3.3
Successfully installed shattered_ogre-0.3.3-windows
Successfully installed shattered_pack-0.4.0.1
Successfully installed shattered_support-0.4.0.1
下略

這樣就裝好了….但我們執行tetris時卻會發生錯誤….經過一連串的試誤,我發現在gemspec中這樣定義:shattered 0.3.3版需要shattered_pack及shattered_support0.3.3「以上」的版本。但事實上是不相容的。所以我們必需手動移除,再灌正確的版本。 (如果你熟希gems的話,你可以一開始就灌正確的版本,這樣比較快)

執行這四行吧:

gem uni shattered_support -i
gem uni shattered_pack -i
gem i shattered_support -v 0.3.3
gem i shattered_pack -v 0.3.3


事情還沒結束,還要上wiki的補丁。見A Confession這段。 (我試過了,上面手動灌0.3.3版和這個補丁兩者都是必需的,缺一不可,當初gemspec沒寫好的關係 Orz)

再跑一次tetris的script/runner



好啦….終於成功了….真累….