コンテンツにスキップ

宝探しゲーム

操作方法 / ルール

マウスのみで操作します。クリックすると少しダッシュします。

  • プレイヤーは広いフィールドからアイテムを収集します。
  • アイテムには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);
}