- グローバル変数(playerx等)をできるだけ減らし、変数の取り違え等のミスの可能性を下げました。
- playerxやplayerw等関連する値はクラスにまとめ、クラスのオブジェクトして扱いました。
- void playersettei()やvoid marusettei()等の関数を各クラスの関数にして、責務をはっきりさせました。
- 組み込みの変数と名前が被らないように、定数(大文字)メンバ変数(_小文字)等命名に注意しました。
- fill(0,255,255)等ぱっと見何色かわからないので、color型で分かりやすい名前を付けました。
Processing
1// 5秒おきにランダムに変わるという仕様ですが、急に変わってイラっとしたw のと、
2// 半分の丸が無駄になるのが気になって、マウスを押すたびに交互に代わるように勝手に変えました^^;
3// 5秒おきにする場合は RANDOM_CHANGE = true; に変えてください
4final boolean RANDOM_CHANGE = false;
5
6final color CYAN = color(0, 255, 255); // 水色
7final color MAGENTA = color(255, 0, 255); // 紫
8
9Player player; // 操作する四角
10Circle[] circles = new Circle[20]; // 降ってくる丸の配列
11int score; // 点数
12
13void setup() {
14 size(800, 600);
15 noStroke();
16
17 // 四角の初期化
18 player = new Player(400, 500, 60, 30); // 初期位置と幅、高さ
19
20 // 丸たちの初期化
21 for (int i = 0; i < circles.length; i++) {
22 int x = i * 40 + 20;
23 int y = -int(random(height)); // 初期Y座標をランダムな画面外座標にすることによって、出現順をランダムにする
24 circles[i] = new Circle(x, y, 15); // 初期位置と半径
25 }
26}
27
28void draw() {
29 background(0);
30
31 player.update(); // 四角の位置をマウスX座標に更新
32 player.draw(); // 四角を描画
33
34 for (int i = 0; i < circles.length; i++) {
35 circles[i].update(); // 当該丸の位置を更新(落下)
36 if (player.isCollision(circles[i])) { // 四角と当該丸が接触していたら。。。
37 circles[i].dead(); // 丸を破壊扱いにする
38
39 if (player.getColor() == circles[i].getColor()) { // 四角と当該丸が同じ色だったら。。。
40 score += 10; // スコアをプラス
41 } else { // 四角と当該丸が違う色だったら。。。
42 score -= 100; // スコアをマイナス
43 }
44 }
45
46 circles[i].draw(); // 当該丸を描画(破壊状態だったら描画しないようにしてあるので、無条件に呼んでok)
47 }
48
49 // スコアを描画
50 fill(255); // 白
51 textSize(20); // フォントサイズ
52 text("SCORE", 10, 30);
53 text(score, 100, 30);
54
55 // 秒数を描画
56 int seconds = frameCount / 60;
57 text("TIME", 10, 60);
58 text(seconds, 100, 60);
59}
60
61// マウスを押した瞬間
62void mousePressed() {
63 if (!RANDOM_CHANGE) { // 5秒おきモードでなければ色を変える
64 player.changeColor();
65 }
66}
67
68
69// 丸に関連する処理をまとめたクラス
70class Circle {
71 private int _x; // X座標
72 private int _y; // Y座標
73 private int _radius; // 半径
74 private int _speed; // 落下速度
75 private color _color; // 色
76 private boolean _isAlive; // 生死状態
77
78 // コンストラクタ X座標, Y座標, 半径
79 Circle(int cx, int cy, int radius) {
80 _x = cx;
81 _y = cy;
82 _radius = radius;
83 _speed = int(random(1, 4)); // 落下速度 ランダム
84 _isAlive = true; // 最初は生き
85 changeColor(); // 色 ランダム
86 }
87
88 // X座標の取得
89 int getX() {
90 return _x;
91 }
92 // Y座標の取得
93 int getY() {
94 return _y;
95 }
96 // 半径の取得
97 int getRadius() {
98 return _radius;
99 }
100 // 色の取得
101 color getColor() {
102 return _color;
103 }
104 // 生死状態の取得
105 boolean isAlive() {
106 return _isAlive;
107 }
108
109 // 破壊状態に変更
110 void dead() {
111 _isAlive = false;
112 }
113
114 // 描画
115 void draw() {
116 if (_isAlive) { // 生き状態時のみ描画
117 fill(_color);
118 ellipse(_x, _y, _radius * 2, _radius * 2);
119 }
120 }
121
122 // 位置の更新
123 void update() {
124 _y += _speed;
125 if (height < _y) { // 画面外に落ちたら状態をリセット
126 _y = -_radius * 2;
127 _isAlive = true;
128 _speed =int(random(1, 4));
129 changeColor();
130 }
131 }
132
133 // 色をランダムに変える
134 void changeColor() {
135 _color = int(random(2)) == 0 ? CYAN : MAGENTA;
136 }
137}
138
139
140// 四角に関連する処理をまとめたクラス
141class Player {
142 private int _x; // X座標
143 private int _y; // Y座標
144 private int _width; // 幅
145 private int _height; // 高さ
146 private color _color; // 色
147
148 // コンストラクタ X座標, Y座標, 幅, 高さ
149 Player(int x, int y, int w, int h) {
150 _x = x;
151 _y = y;
152 _width = w;
153 _height = h;
154 _color = CYAN; // 最初は水色
155 }
156
157 // 色の取得
158 color getColor() {
159 return _color;
160 }
161
162 // 描画
163 void draw() {
164 if (mousePressed) { // マウスが押されている時だけ描画
165 fill(_color);
166 rect(_x, _y, _width, _height, 5);
167 }
168 }
169
170 // 位置の更新
171 void update() {
172 _x = mouseX - (_width / 2); // マウス位置に中心を合わす
173
174 if (RANDOM_CHANGE) { // 5秒おきモードの場合色を変える
175 // frameCountはフレームごとに1増える デフォルトでは1秒60フレーム
176 // frameCount % 2 == 0なら交互に frameCount % 10 == 0なら10フレームに1回
177 // frameCount % (60 * 5) == 0なら300フレームに1回 = 5秒に1回
178 if (frameCount % (60 * 5) == 0) {
179 changeColor();
180 }
181 }
182 }
183
184 // 色を変える
185 void changeColor() {
186 if (RANDOM_CHANGE) { // 5秒おきモードの場合。。。
187 _color = int(random(2)) == 0 ? CYAN : MAGENTA; // ランダムに変える
188 } else {
189 _color = _color == CYAN ? MAGENTA : CYAN; // 交互に変える
190 }
191 }
192
193 // 丸との当たり判定
194 boolean isCollision(Circle circle) {
195 if (!mousePressed) return false; // マウスが押されてなければ当たっていない
196 if (!circle.isAlive()) return false; // 丸が破壊されていれば当たっていない
197
198 // いろいろ計算^^;
199 boolean isCollision = circleRect(circle.getX(), circle.getY(), circle.getRadius(), _x, _y, _width, _height);
200
201 // 例えば丸を取るほど幅が広がる とか
202 //_width += isCollision ? 2 : 0;
203 return isCollision;
204 }
205
206 // 以下参考コードをちょい変更
207 // http://www.jeffreythompson.org/collision-detection/circle-rect.php
208 // CIRCLE/RECTANGLE
209 private boolean circleRect(int cx, int cy, int radius, int rx, int ry, int rw, int rh) {
210
211 // temporary variables to set edges for testing
212 int testX = cx;
213 int testY = cy;
214
215 // which edge is closest?
216 if (cx < rx) testX = rx; // test left edge
217 else if (cx > rx + rw) testX = rx + rw; // right edge
218 if (cy < ry) testY = ry; // top edge
219 else if (cy > ry + rh) testY = ry + rh; // bottom edge
220
221 // get distance from closest edges
222 // float distX = cx - testX;
223 // float distY = cy - testY;
224 // float distance = sqrt((distX * distX) + (distY * distY));
225 float distance = dist(cx, cy, testX, testY);
226
227 // if the distance is less than the radius, collision!
228 if (distance <= radius) {
229 return true;
230 }
231 return false;
232 }
233}
クラスに分けると処理があっちこっちに飛んで、わかりにくく感じるかもしれません。
しかし機能を変更や追加をしようとしたときに、
「Playerのあの関数を見ればいいんだ」
「Playerに新たに関数を追加しよう」
等、どこを変えればいいのかが明瞭になり、作っていくうちにだんだんメリットを感じてくると思います。
Processing
1final boolean RANDOM_CHANGE = false;
2final color CYAN = color(0, 255, 255);
3final color MAGENTA = color(255, 0, 255);
4final int MARU_RADIUS = 15;
5final int MARU_COUNT = 20;
6
7int playerX = 400;
8int playerY = 500;
9int playerWidth = 60;
10int playerHeight = 30;
11color playerColor = CYAN;
12
13int[] marusX = new int[MARU_COUNT];
14int[] marusY = new int[MARU_COUNT];
15color[] marusColor = new color[MARU_COUNT];
16int[] marusSpeed = new int[MARU_COUNT];
17boolean[] marusAlive = new boolean[MARU_COUNT];
18
19int score;
20
21void setup() {
22 size(800, 600);
23 noStroke();
24
25 for (int i = 0; i < MARU_COUNT; i++) {
26 marusX[i] = i * 40 + 20;
27 marusY[i] = -int(random(height));
28
29 if (int(random(2)) == 0) {
30 marusColor[i] = CYAN;
31 } else {
32 marusColor[i] = MAGENTA;
33 }
34
35 marusSpeed[i] = int(random(1, 4));
36 marusAlive[i] = true;
37 }
38}
39
40void draw() {
41 background(0);
42
43 // player更新
44 playerX = mouseX - (playerWidth / 2);
45 if (RANDOM_CHANGE) {
46 if (frameCount % (60 * 5) == 0) {
47 if (int(random(2)) == 0) {
48 playerColor = CYAN;
49 } else {
50 playerColor = MAGENTA;
51 }
52 }
53 }
54
55 // player描画
56 if (mousePressed) {
57 fill(playerColor);
58 rect(playerX, playerY, playerWidth, playerHeight, 5);
59 }
60
61
62 for (int i = 0; i < MARU_COUNT; i++) {
63 // maru更新
64 marusY[i] += marusSpeed[i];
65 if (height < marusY[i]) {
66 marusY[i] = -MARU_RADIUS * 2;
67 marusAlive[i] = true;
68 marusSpeed[i] =int(random(1, 4));
69
70 if (int(random(2)) == 0) {
71 marusColor[i] = CYAN;
72 } else {
73 marusColor[i] = MAGENTA;
74 }
75 }
76
77 // 当たり判定
78 if (mousePressed) {
79 if (marusAlive[i]) {
80 if (circleRect(marusX[i], marusY[i], MARU_RADIUS, playerX, playerY, playerWidth, playerHeight)) {
81 marusAlive[i] = false;
82
83 if (playerColor == marusColor[i]) {
84 score += 10;
85 } else {
86 score -= 100;
87 }
88 }
89 }
90 }
91
92 // maru描画
93 if (marusAlive[i]) {
94 fill(marusColor[i]);
95 ellipse(marusX[i], marusY[i], MARU_RADIUS * 2, MARU_RADIUS * 2);
96 }
97 }
98
99 fill(255);
100 textSize(20);
101 text("SCORE", 10, 30);
102 text(score, 100, 30);
103
104 int seconds = frameCount / 60;
105 text("TIME", 10, 60);
106 text(seconds, 100, 60);
107}
108
109void mousePressed() {
110 if (!RANDOM_CHANGE) {
111 if (playerColor == CYAN) {
112 playerColor = MAGENTA;
113 } else {
114 playerColor = CYAN;
115 }
116 }
117}
118
119
120// 以下参考コードをちょい変更
121// http://www.jeffreythompson.org/collision-detection/circle-rect.php
122// CIRCLE/RECTANGLE
123private boolean circleRect(int cx, int cy, int radius, int rx, int ry, int rw, int rh) {
124
125 // temporary variables to set edges for testing
126 int testX = cx;
127 int testY = cy;
128
129 // which edge is closest?
130 if (cx < rx) testX = rx; // test left edge
131 else if (cx > rx + rw) testX = rx + rw; // right edge
132 if (cy < ry) testY = ry; // top edge
133 else if (cy > ry + rh) testY = ry + rh; // bottom edge
134
135 // get distance from closest edges
136 // float distX = cx - testX;
137 // float distY = cy - testY;
138 // float distance = sqrt((distX * distX) + (distY * distY));
139 float distance = dist(cx, cy, testX, testY);
140
141 // if the distance is less than the radius, collision!
142 if (distance <= radius) {
143 return true;
144 }
145 return false;
146}