宝探しゲーム
操作方法 / ルール
マウスのみで操作します。クリックすると少しダッシュします。
- プレイヤーは広いフィールドからアイテムを収集します。
- アイテムには1〜9の番号が振られており、1から順に取得していく必要があります。
- 9のアイテムを収集した時点でゲームクリアです。
こだわりポイント
- カメラを使ったフィールド表現
- まるでオープンワールドのようなゲームが作れます。
- 毎分変わるステージ
- ステージは毎分、起動ごとに変わります。
- 逆に同じ時間に起動すれば同じステージです。
- 友達との対戦などに使いましょう。
ゲーム企画の話
どうやってこのゲームを考えたかを共有。
- 広いフィールドで宝を複数探すゲームを思いつく
- しかし、ただ集めるだけでは運ゲーすぎて、プレイヤーのテクニックの幅がでない
- 上手い人と下手な人が生まれて欲しい。
- しかし、ただ集めるだけでは運ゲーすぎて、プレイヤーのテクニックの幅がでない
- 順番通りに集めるというルールを適用すれば、見かけた宝の場所を記憶しておく、というテクニックの幅が出る
- 順番通りというルールを説明書がなくてもわかってもらえるようにする必要がある。
- 宝に番号をつけることでルールをわかりやすくした。
- せっかくならプレイヤーには友達と対戦して欲しかったので、ステージ番号を指定するようにして同じステージで遊べるようにする。
- しかし、ステージ番号の指定というのは説明書がないと伝わらない。
- 1分ごとにステージが変わるようにすることで、起動のタイミングさえ合わせれば複数のパソコンで同じステージが遊べるようにした。
class Camera{ public float x; public float y; public float z = 10; public float getX(float _x){ float newX = _x - x; newX /= getZ(); // newX += width/2; return newX; } public float getY(float _y){ float newY = _y - y; newY /= getZ(); // newY += height/2; return newY; } public float getSize(float _s){ float newS = _s / getZ(); return newS; } float getZ(){ float _z = z / 10; if(_z == 0) return 1; return _z; }}
class Item{ public int index; public float x; public float y; public boolean active = true;}float WIDTH = 1500;float HEIGHT = 1500;Camera camera;ArrayList<Item> itemList = new ArrayList<Item>();float px = 100;float py = 100;float ps = 1;int index = 0;int time = 0;void setup(){ size(600, 400); camera = new Camera(); int seed = hour() * 60 + minute(); randomSeed(seed);
WIDTH = 1000 + random(0, 1000); HEIGHT = 3000 - WIDTH; for(int i=1; i<10; i++){ Item item = new Item(); item.index = i; item.x = random(20, WIDTH-40); item.y = random(20, HEIGHT-40); itemList.add(item); }}void draw(){ background(0);
if(index < 9){ time += 1; }
// 壁 renderWalls(WIDTH, HEIGHT);
// 移動(マウス追尾) PVector dir = new PVector(mouseX + camera.x - px, mouseY + camera.y - py); dir.normalize(); px += dir.x * ps; py += dir.y * ps; px = clamp(px, 20, WIDTH - 40); py = clamp(py, 20, HEIGHT - 40);
// ダッシュ ps *= 0.95; if(ps < 1) ps = 1;
// アイテムの表示 for(int i=0; i<itemList.size(); i++){ Item item = itemList.get(i); if(!item.active){ continue; } noFill(); stroke(255); rect(camera.getX(item.x), camera.getY(item.y), 20, 20); textAlign(CENTER, CENTER); textSize(18); fill(255); text(item.index, camera.getX(item.x + 10), camera.getY(item.y + 5));
if(isHit(px, py, 20, 20, item.x, item.y, 20, 20)){ if(item.index == index + 1){ // Get index = item.index; item.active = false; } } }
// プレイヤーの表示 fill(255); rect(camera.getX(px), camera.getY(py), 20, 20);
// UI noStroke(); fill(255, 255, 255, 50); rect(0, 0, width, 50); fill(255); textSize(32);
if(index == 9){ text("CLEAR!", 100, 20); }else{ text("NEXT " + (int)clamp(index + 1, 0, 9), 100, 20); } text("TIME " + (int)(time / 60f * 10) / 10f, 500, 20);
// カメラの追尾 camera.x = px - width/2; camera.y = py - height/2;}void mousePressed(){ ps = 10;}boolean isHit(float px, float py, float pw, float ph, float ex, float ey, float ew, float eh){ if(px < ex + ew && px + pw > ex){ if(py < ey + eh && py + ph > ey){ return true; } } return false;}float clamp(float v, float min, float max){ if(v < min) v = min; if(v > max) v = max; return v;}void renderWalls(float max_x, float max_y){ // 壁 fill(255); rect(camera.getX(0), camera.getY(0), max_x, 20); rect(camera.getX(0), camera.getY(0), 20, max_y); rect(camera.getX(0), camera.getY(max_y-20), max_x, 20); rect(camera.getX(max_x-20), camera.getY(0), 20, max_y);}