質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

Q&A

解決済

2回答

1513閲覧

円が衝突し、合体するプログラムを書きたいです。

KeeganP

総合スコア6

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Processing

Processingは、オープンソースプロジェクトによるCGのためのプログラミング言語です。Javaをベースにしており、グラフィック機能に特化しています。イメージの生成やアニメーションなど、視覚的なフィードバックを簡単に得ることが可能です。

0グッド

1クリップ

投稿2020/05/25 09:28

編集2020/05/26 00:25

###初めに
プログラミングの経験は浅く、ベクトルとクラスの使用に関しては完全な初学者です。
イギリス英語圏での課題ですのでColorとColourの綴りの違いには目を瞑って頂けると助かります。

プログラムの完成形の内容

①500×500の白いキャンバスに3つの動く球を描くこと。
②それぞれの球はランダムなスタート位置、ランダムな縁なしの色、20~30のランダムな半径、そしてX/Yの要素において ‐5~5のランダムな速度をもつこと。それぞれの球は壁で跳ね返ること。
球同士が初めて衝突する時に互いにくっつき、それ以降一緒に動く。合体している2つの球のうち、壁に近いほうが壁にぶつかると2球とも運動の方向が変わること。

###つまずいている点

拙いながらも②まで書きましたが③が上手く行かず、アプローチの仕方すらわかりません。
ついでに、球の色付けにも失敗いています。

該当のソースコード

Processing

1PVector locationA, locationB, locationC; 2PVector velocityA, velocityB, velocityC; 3 4color colourA = getRandomColour(); 5color colourB = getRandomColour(); 6color colourC = getRandomColour(); 7 8color getRandomColour() { 9 return color(random(256), random(256), random(256)); 10} 11 12class BouncingBall 13{ 14 float x, y, r, dx, dy; 15 float ballColour; 16 17 BouncingBall(float xInt, float yInt, float rInt, color colourInt, float dxInt, float dyInt) 18 { 19 x = xInt; 20 y = yInt; 21 r = rInt; 22 ballColour = colourInt; 23 dx = dxInt; 24 dy = dyInt; 25 } 26 27 void render() 28 { 29 noStroke(); 30 fill(ballColour); 31 ellipse(x, y, r*2, r*2); 32 33 if(dist(ballA.x, ballA.y, ballB.x, ballB.y) <= rA + rB) 34 { 35 //This is where I have the problem 36 ballA.dx = ballB.dx; 37 ballA.dy = ballB.dy; 38 } 39 if(dist(ballB.x, ballB.y, ballC.x, ballC.y) <= rB + rC) 40 { 41 //This is where I have the problem 42 } 43 if(dist(ballC.x, ballC.y, ballA.x, ballA.y) <= rC + rA) 44 { 45 //This is where I have the problem 46 } 47 48 } 49 50 void update() 51 { 52 x += dx; 53 y += dy; 54 55 if (x - r <= 0 || x + r >= width) { 56 dx = -dx; 57 if (x - r <= 0) { 58 x = r+1; 59 } 60 if (x + r >= width-1) { 61 x = width-r-1; 62 } 63 } 64 if (y - r <= 0 || y + r >= height) { 65 dy = -dy; 66 if (y - r <= 0) { 67 y = r+1; 68 } 69 if (x + rA >= height-1) { 70 x = height-r-1; 71 } 72 } 73 } 74} 75 76final color WHITE = color(255); 77 78float rA = random(20, 30); 79float rB = random(20, 30); 80float rC = random(20, 30); 81 82float randomVelocity() { 83 return random(-5, 5); 84} 85float randomCoordinate() { 86 return random(501); 87} 88 89BouncingBall ballA, ballB, ballC; 90 91void setup() 92{ 93 size(500, 500); 94 smooth(); 95 96 locationA = new PVector(randomCoordinate(), randomCoordinate()); 97 velocityA = new PVector(randomVelocity(), randomVelocity()); 98 ballA = new BouncingBall(locationA.x, locationA.y, rA, colourA, velocityA.x, velocityA.y); 99 100 locationB = new PVector(randomCoordinate(), randomCoordinate()); 101 velocityB = new PVector(randomVelocity(), randomVelocity()); 102 ballB = new BouncingBall(locationB.x, locationB.y, rB, colourB, velocityB.x, velocityB.y); 103 104 locationC = new PVector(randomCoordinate(), randomCoordinate()); 105 velocityC = new PVector(randomVelocity(), randomVelocity()); 106 ballC = new BouncingBall(locationC.x, locationC.y, rC, colourC, velocityC.x, velocityC.y); 107} 108 109void draw() 110{ 111 //only showing 2 balls for now to make it easier to think 112 113 ballA.update(); 114 ballB.update(); 115 //ballC.update(); 116 background(WHITE); 117 ballA.render(); 118 ballB.render(); 119 //ballC.render(); 120 121}

試したこと

ベクトルの値の合成と球の合体は別々のコードが必要だと考えましたが、値の合成ではballBを変化させられず、球の合体に至っては手の付け方が思い浮かばずにいます。(頭の中ではBの座標をAに依存させようと、A座標‐2球の半径を…のように交錯していますがプログラムに起こせずにいます。)

下のコードは、既存の二つのベクトルを合成して、その値でX/Y成分を上書きしようとしました。

WhatIHaveTried

1velocityA.add(velocityB); 2--------------------------------------- 3velocityA.x = velocityA.x + velocityB.x 4velocityA.y = velocityA.y + velocityB.y 5--------------------------------------- 6velocityA.x = velocityA.x + velocityB.x 7velocityA.y = velocityA.y + velocityB.y 8velocityB.x = velocityB.x + velocityA.x 9velocityB.y = velocityB.y + velocityA.y 10--------------------------------------- 11My current attempt 12Somehow sum the 2 Vectors and make the result a new Vector and enter in the last 2 sections below 13ballA = new BouncingBall(locationA.x, locationA.y rA, colourA, , ); 14//ballA teleports when collides

補足情報

その他気になる点やアドバイスが有りましたら、とてもとても素直に聞くのでどうかお聞かせください。
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

円の集合体というクラスを規定して、そこに個々の円を所属させるという方針はいかがでしょうか。

最初は、円を1つ持った集合体を3つ生成
移動(速度)は集合体として管理します。
跳ね返りや衝突の判定は、集合体が持っている円の各要素毎に調べて、
合体は、持っている円の要素を移動させてしまい、一方の要素は空にしてしまう

どうでもいい小ネタですけど、色をランダムにするときはcolorMode(HSB)として、
Hだけを乱数、SとBを255にすると小汚い色にならず、ビビッドカラーが楽しめます。あるいは、Sを128にするとちょっと淡くて柔らかい感じの色とか。


5/26 13:13の返信③について、現状のプログラムであってもPVectorを使うのであればBouncingBallクラスはこんなふうにすべきかと思います。(もちろん、ここを変えれば他も影響をうけます)

Processing

1class BouncingBall { 2 PVector velocity; 3 PVector location; 4 float r; 5 color ballColour; 6 7 BouncingBall(PVector loc, PVector velo, float rad, color col) { 8 velocity=velo; 9 location=loc; 10 ballColour = col; 11 r=rad; 12 } 13 14 void render() { 15 //renderという名前のメソッドにrendering以外の仕事をさせてはいけない 16 noStroke(); 17 fill(ballColour); 18 ellipse(location.x, location.y, r*2, r*2); 19 } 20 21 void update() { 22 location.x += velocity.x; 23 location.y += velocity.y; 24 25 if (location.x - r <= 0 || location.x + r >= width) { 26 velocity.x=-velocity.x; 27 if (location.x - r <= 0) { 28 location.x = r+1; 29 } 30 if (location.x + r >= width-1) { 31 location.x = width-r-1; 32 } 33 } 34 if (location.y - r <= 0 || location.y + r >= height) { 35 velocity.y=-velocity.y; 36 if (location.y - r <= 0) { 37 location.y = r+1; 38 } 39 if (location.y + r >= height-1) { 40 location.y = height-r-1; 41 } 42 } 43 } 44}

5/27 追記

Processing

1//https://teratail.com/questions/264746 2class CircleInfo {//単体円 3 float x, y, dia; 4 color col; 5 CircleInfo(float _x, float _y, float _dia, color _col) { 6 x=_x; 7 y=_y; 8 dia=_dia; 9 col=_col; 10 } 11} 12 13class Colony {//円の群体 14 float x, y; 15 PVector v; 16 ArrayList<CircleInfo> cell;//個々の円 17 18 Colony(float _x, float _y, PVector _v, CircleInfo c) { 19 x=_x; 20 y=_y; 21 v=_v; 22 cell=new ArrayList<CircleInfo>(); 23 cell.add(c); 24 } 25 void addCell( CircleInfo c ) {//円の位置は群体の基準座標による 26 cell.add(c); 27 } 28 void addCellAtPos( CircleInfo c) {//円の位置はスクリーン座標による 29 cell.add(new CircleInfo(c.x-x, c.y-y, c.dia, c.col)); 30 } 31 CircleInfo[] getCell() {//含まれている円のリストを提示(合体用) 32 ArrayList<CircleInfo> cellAtPos=new ArrayList<CircleInfo>(); 33 for ( CircleInfo c : cell) { 34 cellAtPos.add(new CircleInfo(x+c.x, y+c.y, c.dia, c.col)); 35 } 36 return (CircleInfo[])cellAtPos.toArray(new CircleInfo[0]); 37 } 38 void del() { 39 cell.clear(); 40 } 41 void render() { 42 for ( CircleInfo c : cell) { 43 if (c!=null) { 44 fill(c.col); 45 circle(x+c.x, y+c.y, c.dia); 46 } 47 } 48 } 49 void update() { 50 x+=v.x; 51 y+=v.y; 52 //壁の跳ね返りはここで処理 53 //一群の最小/最大のx,y位置を求めて壁との衝突を判定 54 float minx=2*width, miny=2*height, maxx=-width, maxy=-height; 55 for (CircleInfo c : cell) { 56 if (c!=null) { 57 if (minx>x+c.x-c.dia/2) { 58 minx=x+c.x-c.dia/2; 59 } 60 if (maxx<x+c.x+c.dia/2) { 61 maxx=x+c.x+c.dia/2; 62 } 63 if (miny>y+c.y-c.dia/2) { 64 miny=y+c.y-c.dia/2; 65 } 66 if (maxy<y+c.y+c.dia/2) { 67 maxy=y+c.y+c.dia/2; 68 } 69 } 70 } 71 if (minx<=0) { 72 x+=-minx; 73 v.x=-v.x; 74 } 75 if (maxx>=width) { 76 x-=maxx-width; 77 v.x=-v.x; 78 } 79 if (miny<=0) { 80 y+=-miny; 81 v.y=-v.y; 82 } 83 if (maxy>=height) { 84 y-=maxy-height; 85 v.y=-v.y; 86 } 87 } 88} 89 90boolean collision(Colony c1, Colony c2) { 91 boolean ret=false; 92found: 93 for (CircleInfo cinfo1 : c1.getCell()) { 94 for (CircleInfo cinfo2 : c2.getCell()) { 95 if (dist(cinfo1.x, cinfo1.y, cinfo2.x, cinfo2.y)<(cinfo1.dia+cinfo2.dia)/2) { 96 ret=true; 97 break found; 98 } 99 } 100 } 101 return ret; 102} 103 104void combine(Colony c1, Colony c2) { 105 for (CircleInfo c : c2.getCell()) { 106 c1.addCellAtPos(c); 107 } 108 //合体後速度は質量比とかいろいろ考えられるけどとりあえず平均で。 109 c1.v.x=(c1.v.x+c2.v.x)/2; 110 c1.v.y=(c1.v.y+c2.v.y)/2; 111 c2.del(); 112} 113 114ArrayList<Colony> cl; 115 116void setup() { 117 size(500, 500); 118 colorMode(HSB); 119 cl=new ArrayList<Colony>(); 120 for (int i=0; i<3; i++) { 121 cl.add( 122 new Colony( random(50, width-50), random(50, height-50), 123 new PVector(random(-5, 5), random(-5, 5)), 124 new CircleInfo(0, 0, random(40, 60), color(random(256), 128, 255)) 125 )); 126 } 127 noStroke(); 128} 129void draw() { 130 background(255); 131 //移動/描画 132 for (Colony c : cl) { 133 c.update(); 134 c.render(); 135 } 136 //衝突検出/合体 137 for (int i=0; i<cl.size(); i++) { 138 for (int j=i+1; j<cl.size(); j++) { 139 if (collision(cl.get(i), cl.get(j))) { 140 combine(cl.get(i), cl.get(j)); 141 } 142 } 143 } 144}

BouncingBallを使って書けないかというのもちょっと考えてみたけど

合体している2つの球のうち、壁に近いほうが壁にぶつかると2球とも運動の方向が変わること。

が結構面倒で断念。一緒に動いている2球(以上)が同時に壁にぶつかったときどうしようかな...というのが。

投稿2020/05/26 01:08

編集2020/05/27 12:01
thkana

総合スコア7659

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KeeganP

2020/05/26 04:13

ありがとうございます!早速取り掛かりたいのですが、回答に対して質問があります。 ⓪、thkanaさんの提案は、私のコードを元に 数か所改変することが前提ですか?0から作り直したほうがいいのでしょうか? ①、円の集合体というクラスに円を所属させる、の時のクラスの役割は何でしょうか?②が私の頭の中で描かれているのですが、集合体クラスの中身がわかりません。円同士がくっつくときに要素を移動させるとのことですが、要素が空の円が枠に取り残されて…少し混乱しています。 ②、現存のBouncingBallクラスを流用して円ABCを作成した後に、集合体クラスで作成した集合体という名の3つの枠に円を個別に仕分ける。ということでしょうか? ③、PVectorで作成した速度を集合体という枠に格納し、跳ね返りや衝突を調べる。ということでしょうか? 意図を汲み切れず、申し訳ありません。
thkana

2020/05/26 04:47

⓪: 一応手元で書いてみていますが、ほとんど共通部分がないです...作り直し、ですね。 以下も、あくまで私が書いてみた方針に基づくものですが、 ①: クラスの役割は、円の集合に一体としての振る舞いをさせること、です。 「一つの円」というのは集合の中に1つの円しか含まれていないというだけのことです。個々の円が動くという概念は持っていません。 何人かの人が車に乗って移動することを考えるときに、個々人の速度を管理してそれを皆同じ値にするような考え方はしないでしょう。それと同じことです。 要素を移動、というのはちょっと正確ではなかったかな...径と色が同じ円を生成して集合中の適切な位置に追加する、ということをやっています。集合体の中での位置を考えたりすると単純な移動では難しかったので。 移動元には要素が空の「円」ではなく、要素が空の「円の集合」が残りますが、空なので(ちょっとメモリは専有しますが)無害でしょう。 ② 動くのは「円の集合体」であって円ではない、という見方をしたので、現在のBouncingBallクラスの流用は考えていません。 ③(個別の円が移動するものとして)なんのためにPVectorを使ったのでしょう? 速度や位置ベクトルってのは移動する円の属性ですよね。であれば、PVector型による位置や速度そのものがクラスのフィールドとしてあるべきじゃないかと思うのですが。 > PVectorで作成した速度 なにかクラスの扱いを根本的に勘違いしている気がします。 私が書いたプログラムを出してしまうと「プログラムを書きたい」あなたの邪魔になるかとも思いましたが、それなしで話をするのもちょっと難しいかなぁ...
KeeganP

2020/05/26 05:38

学びの手助けをして頂き、本当に助けになっています。クラスの勉強を含め、thkanaさんの方針で作ってみますね。私の頭が諦める事に支配されてしまった時はthkanaさんのお手本を拝見させて頂きたいです。それでは。
KeeganP

2020/05/27 05:40

先日から引き続きthkanaさんの方針を元に試行錯誤していましたが、私はついに折れてしまいました。手本の完成形を拝見させていただきたいです。プログラミングをするにあたって、フロートチャートを適切に作れる能力が大切だとは聞いておりますが、私はどうやらそこから学び直す必要がある気がして参りました。
KeeganP

2020/05/27 23:40

お手本拝見しました。自分の力不足を痛感するようなコードで、今後の勉強のモチベーションになります。HSBの小ネタがお気に入りです。本当にありがとうございます。
guest

0

「そういうことじゃない!」ってのは承知しています^^;
ライブラリを使うとどのくらい簡単になるか試しました。

Processing

1import fisica.*; 2 3FWorld world; 4 5void setup() { 6 size(500, 500); 7 colorMode(HSB); 8 9 Fisica.init(this); 10 world = new FWorld(); 11 world.setEdges(); 12 world.setGravity(0, 0); 13 world.setGrabbable(false); 14 15 for (int i = 0; i < 3; i++) { 16 FBody ball = createBall(); 17 ball.setPosition(random(50, width - 50), random(50, height - 50)); 18 world.add(ball); 19 } 20} 21 22void draw() { 23 background(255); 24 world.step(); 25 world.draw(); 26} 27 28void contactStarted(FContact contact) { 29 FBody b1 = contact.getBody1(); 30 FBody b2 = contact.getBody2(); 31 if (b1.isStatic() || b2.isStatic()) return; 32 if (b1.getJoints().size() != 0 && b2.getJoints().size() != 0) return; 33 34 FRevoluteJoint joint = new FRevoluteJoint(b1, b2); 35 joint.setDrawable(false); 36 world.add(joint); 37} 38 39FBody createBall() { 40 FCircle ball = new FCircle(random(40, 60)); 41 ball.setDamping(0); 42 ball.setRestitution(1); 43 ball.setVelocity(random(-300, 300), random(-300, 300)); 44 ball.setFillColor(color(random(256), 128, 255)); 45 ball.setNoStroke(); 46 return ball; 47} 48 49// ちょい寂しいのでおまけ 50void mousePressed() { 51 FBody ball = createBall(); 52 ball.setPosition(mouseX, mouseY); 53 world.add(ball); 54}

fisica

投稿2020/05/27 23:52

編集2023/07/22 07:17
TN8001

総合スコア9396

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

KeeganP

2020/05/28 04:54

非常にコンパクトですね!ライブラリを使う機会があれば参考にさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問