- PR -

四角い画像を円として認識させる

投稿者投稿内容
ゴールデン
常連さん
会議室デビュー日: 2004/08/22
投稿数: 46
投稿日時: 2004-08-31 20:26
次のようなアプレットを作っています。
ピクセルの色情報を作り、それをMemoryImageSourceで画像にして、バブル大中小を10個ずつ作りました。バブルの境界線の色情報は、0x6fffffffにしてあります。境界線より外側は無色透明です。それを画面下に向かってボールが落ちるように、落ちたら跳ね、最後は下にたまるというところまではできました。ただし各バブルは重なってもそのままです。今度は、それぞれのバブルが互いに接触したら("四角い画像が接触"ではなく、その中の"バブルの境界線"が接触したらという意味)、跳ね合うようにしたいですが、一応自分でコードを書いてみてコンパイルもできましたが、実行すると、バブルが初めの位置から動かないままになってしまいました。overlap_0x6fffffff()というメソッドがおかしいのです。自分でもコードのみならず頭の中までもがぐちゃぐちゃになっています。最終的な完成目標としては、ぶつかり合ったら相手のバブルの力を受け継いで跳ねる、また、今は縦方向のみで動いていますが、横方向の動きも入れようと思っています。でもとりあえず今は縦方向のみでよいので、ぶつかったら反対方向に動くことをしたいです。この怪しげなoverlap_0x6fffffff()というメソッド(バブルの境界線がオーバーラップしたら、反対方向に動く)を本当に動くようにするにはどのようにしたらよいかを教えてください。
コード:

import java.awt.*;
import java.applet.Applet;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
/*
<applet code="BubbleWorld" width=200 height=200>
</applet>
*/
public class BubbleWorld extends Applet implements Runnable{
PixelGrabber pg[];
Image Bubble;
Image B[];//バブル大,中、小
MemoryImageSource mis;
Image offs;
Graphics og;
int b_pixels0[];//バブル大のピクセルの色情報を入れる入れ物
int b_pixels1[];
int b_pixels2[];
int b_x0[][];//バブル大一つ一つのピクセルのx座標を入れる入れ物
int b_x1[][];//バブル中一つ一つのピクセルのx座標を入れる入れ物
int b_x2[][];//バブル小一つ一つのピクセルのx座標を入れる入れ物
int b_y0[][];//バブル大一つ一つのピクセルのy座標を入れる入れ物
int b_y1[][];//バブル中一つ一つのピクセルのy座標を入れる入れ物
int b_y2[][];//バブル小一つ一つのピクセルのy座標を入れる入れ物
int t=0;//ピクセルに分解する画像枚数
int x[][];//各バブルのx座標
int y[][];//各バブルのy座標
int bx[][];//バブルが左右に動くスイッチ
int by[][];//バブルが上下に動くスイッチ
double ry[][];//バブルが上下に動くための加速分もと
Thread th;
boolean is_on;//スレッドのスイッチ
int k;
public void init(){
th=null;
offs=createImage(200,200);
pg=new PixelGrabber[3];
B=new Image[3];
make_Bubble(31);
B[0]=Bubble;
make_Bubble(25);
B[1]=Bubble;
make_Bubble(19);
B[2]=Bubble;
haiti_Bubble();
bunnkai_pixels_color_and_xy(31);
bunnkai_pixels_color_and_xy(25);
bunnkai_pixels_color_and_xy(19);
}
public void start(){
if(th==null){
th=new Thread(this);
th.start();
}
}
public void stop(){
th=null;
}
public void run(){
Thread thisThread=Thread.currentThread();
while(thisThread==th){
is_on=true;
ugoku();
repaint();
try{
th.sleep(50);
}catch(InterruptedException e){}
}
}
public void ugoku(){
for(int i=0;i<3;i++){
for(int j=0;j<10;j++){
overlap_0x6fffffff();
k=(int)(Math.pow(ry[i][j],2));
if(by[i][j]==-1){
ry[i][j]=ry[i][j]-0.3;
if(ry[i][j]<1){
by[i][j]=1;
}
if(y[i][j]<0){by[i][j]=1;}
k=-k;
}
else if(by[i][j]==1){
ry[i][j]=ry[i][j]+0.1;
if(y[i][j]>200-(31-i*6)){
by[i][j]=-1;
}
}
y[i][j]=y[i][j]+k;
}
}
}
public void update(Graphics g){
paint(g);
}
public void paint(Graphics g){
og=offs.getGraphics();
if(og!=null){
try{
og.setColor(Color.blue);
og.fillRect(0,0,200,200);
for(int i=0;i<3;i++){
for(int j=0;j<10;j++){
og.drawImage(B[i],x[i][j],y[i][j],this);
}
}
g.drawImage(offs,0,0,this);
}catch(Exception e){}
finally{og.dispose();}
}
}
public void haiti_Bubble(){
x=new int[3][10];//10はバブルの数,各バブルのx座標
y=new int[3][10];
bx=new int[3][10];
by=new int[3][10];
ry=new double[3][10];
for(int i=0;i<3;i++){
for(int j=0;j<10;j++){
bx[i][j]=1;
by[i][j]=1;
if(j<5){
x[i][j]=40*j;
y[i][j]=33*i;
}
else{
x[i][j]=40*(j-5);
y[i][j]=100+33*i;
}
}
}
}
public void overlap_0x6fffffff(){
for(int a=0;a<3;a++){
for(int b=0;b<10;b++){
for(int c=0;c<31*31;c++){
for(int d=0;d<3;d++){
for(int e=0;e<10;e++){
for(int f=0; f<25*25;f++){
for(int g=0;g<3;g++){
for(int h=0;h<10;h++){
for(int i=0;i<19*19;i++){
if(b_x0[b][c]==b_x1[e][f]||b_x0[b][c]==b_x2[h][i]||b_x1[e][f]==b_x2[h][i]){
if(b_y0[b][c]==b_y1[e][f]||b_y0[b][c]==b_y2[h][i]||b_y1[e][f]==b_y2[h][i]){
if(b_pixels0[c]==b_pixels1[f]||b_pixels0[c]==b_pixels2[i]||b_pixels1[f]==b_pixels2[i]){
if(b_pixels0[c]==0x6fffffff||b_pixels1[f]==0x6fffffff||b_pixels2[i]==0x6fffffff){
by[a][b]=-1;
by[d][e]=-1;
by[g][h]=-1;
}
else{
by[a][b]=1;
by[d][e]=1;
by[g][h]=1;
}
}
}
}
}
}
}
}
}
}
}
}
}
setxy();
}
public void setxy(){
for(int a=19;a<=31;a=a+6){
for(int h=0;h<3;h++){
for(int i=0;i<10;i++){
for(int j=0;j<a;j++){
for(int f=0;f<a;f++){
b_y0[i][j*a+f]=x[h][i]+j;
}
}
}
}
}
}
public void bunnkai_pixels_color_and_xy(int a){
if(t==0){
b_pixels0=new int[a*a];
pg[t]=new PixelGrabber(B[t],0,0,a,a,b_pixels0,0,a);
b_x0=new int[10][a*a];
b_y0=new int[10][a*a];
for(int h=0;h<10;h++){
for(int i=0;i<a;i++){
for(int j=0;j<a;j++){
b_x0[h][i*a+j]=x[0][h]+j;
b_y0[h][i*a+j]=y[0][h]+i;
}
}
}
}
else if(t==1){
b_pixels1=new int[a*a];
pg[t]=new PixelGrabber(B[t],0,0,a,a,b_pixels1,0,a);
b_x1=new int[10][a*a];
b_y1=new int[10][a*a];
for(int h=0;h<10;h++){
for(int i=0;i<a;i++){
for(int j=0;j<a;j++){
b_x1[h][i*a+j]=x[1][h]+j;
b_y1[h][i*a+j]=y[1][h]+i;
}
}
}
}
else if(t==2){
b_pixels2=new int[a*a];
pg[t]=new PixelGrabber(B[t],0,0,a,a,b_pixels2,0,a);
b_x2=new int[10][a*a];
b_y2=new int[10][a*a];
for(int h=0;h<10;h++){
for(int i=0;i<a;i++){
for(int j=0;j<a;j++){
b_x2[h][i*a+j]=x[2][h]+j;
b_y2[h][i*a+j]=y[2][h]+i;
}
}
}
}
try{
pg[t].grabPixels();
}catch(InterruptedException e){
e.printStackTrace();
}
t++;
}
public void make_Bubble(int a){
double x=0;
double y=0;
int A[]=new int[a*a];
int hankei=Math.round(a/2);//中心点も同じ
int v=200/(hankei-1);//v=Alfa値を(hankei-1)分割した値
for(int i=0;i<a*a;i++){A[i]=0x0000000000;}
for(int h=0;h<hankei-1;h++ ){
for(int k=0;k<360;k++){
for(int i=0;i<a;i++){
for(int j=0;j<a;j++){
if(j==hankei+Math.round((hankei-h)*Math.cos(Math.toRadians(k)))&&i==hankei+Math.round((hankei-h)*Math.sin(Math.toRadians(k)))){
A[i*a+j]=(200-v*h)<<24|0x00ffffff;
}
}
}
}
}
mis=new MemoryImageSource(a,a,A,0,a);
mis.setAnimated(true);
Bubble=createImage(mis);
mis.newPixels();
}
}



[ メッセージ編集済み 編集者: ゴールデン 編集日時 2004-08-31 21:52 ]
H2
ぬし
会議室デビュー日: 2001/09/06
投稿数: 586
お住まい・勤務地: 港
投稿日時: 2004-08-31 21:27
[url=http://www.atmarkit.co.jp/bbs/phpBB/faq-japanese.php#bbcode]codeタグ[/code]を使ってコードを見やすくしていただけるとうれしいのですが・・・。

下記のようなBubbleクラスを作って、Appletの中で全部のBubble配列を持ったほうが分かりやすくなりますよ。すべてをApplet内で処理をしようとすると分かりにくくなります。
コード:
public class Bubble {
  private int x, y;       //バブルの座標
  private int xDir, yDir; //バブルの動きの方向
  private int speed;      //バブルのスピード
  private int diameter;   //バブルの直径
  private Color color;    //バブルの色

  public boolean isColliding(Bubble b); //thisがbと衝突したか調べる
  public void paint(Graphics g); //gにthisを描く
  ・・・ そのほかのメソッド
}

ゴールデン
常連さん
会議室デビュー日: 2004/08/22
投稿数: 46
投稿日時: 2004-08-31 22:29
H2さん、お返事ありがとうございます。そうですね。変数の種類が多すぎてごちゃごちゃしているので、すっきりさせるためにクラスを作るといいですね。最終的にはそのように書き換えます。
説明不足な点を書き加えます。

ugoku()…各バブルを縦方向に動かす。
haiti_Bubble()…大中小のバブルを10個ずつ配置する。
overlap_0x6fffffff()…バブルどおしの半透明白の線が重なったら、縦反対方向に動く。
setxy()…バブルの位置情報(x,y)に合わせて、バブル内の各ピクセルの位置情報を関係付ける。
bunnkai_pixels_color_and_xy(int a)…画像として作った一辺aのバブルをピクセルに分解し、@それぞれの色情報を配列に入れ、Aそれぞれの位置情報をb_x0、b_y0(これはバブル大の場合)の配列に入れる。
make_Bubble(int a)…ピクセルの色情報を設定し、直径aのバブルが入った一辺aの画像を作る。バブルの色の境界線は0x6fffffffで、その外側は無色透明。

特にoverlap_0x6fffffff()についてよろしくお願いします。

[ メッセージ編集済み 編集者: ゴールデン 編集日時 2004-08-31 22:40 ]

[ メッセージ編集済み 編集者: ゴールデン 編集日時 2004-08-31 22:53 ]
a-san
ベテラン
会議室デビュー日: 2004/06/01
投稿数: 53
投稿日時: 2004-09-01 01:47
プログラムがよくわからないです。
動きは違いますが、別のプログラムを作ったのでよければ参考にしてください。
import java.awt.*;
import javax.swing.*;

/*
* 質量同じ、半径同じ、初速同じ。初期の位置は等間隔。初速の向きのみランダム
* 重力加速度なし。壁なし。完全鋼体。
*/
public class BubbleFrame extends JFrame implements Runnable {
Bubble[] bubbles;
BubbleView view;

BubbleFrame() {
bubbles = new Bubble[100];
for (int i=0; i<bubbles.length; i++) {
double th = Math.random() * 2.0 * Math.PI; // 0..2π
double speed = 10.0;
bubbles[i] = new Bubble(100*(i%10), 100*(i/10), 20, speed*Math.cos(th), speed*Math.sin(th));
}
view = new BubbleView(this);
getContentPane().add(view);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(640, 480);
setVisible(true);
new Thread(this).start();
}
public void run() {
for(; {
for (int i=0; i<bubbles.length; i++) {
bubbles[i].move(0.1);
}
collision();
repaint();
try { Thread.sleep(100); } catch (InterruptedException e) { }
}
}
void collision() {
for (int i=0; i<bubbles.length-1; i++) {
for (int j=i+1; j<bubbles.length; j++) {
// 2つのバブルの距離が半径の和以下なら衝突!
double dx = bubbles[i].x - bubbles[j].x;
double dy = bubbles[i].y - bubbles[j].y;
if (Math.sqrt(dx*dx + dy*dy) < (bubbles[i].radius + bubbles[j].radius)) {
// お互いが近づいているときだけ、向きを変える。
double vdx = bubbles[i].dx - bubbles[j].dx;
double vdy = bubbles[i].dy - bubbles[j].dy;
if (dx*vdx+dy*vdy<0) {
// 物理法則を忘れたので速度ベクトルを交換するだけ
double tmpx = bubbles[i].dx;
double tmpy = bubbles[i].dy;
bubbles[i].dx = bubbles[j].dx;
bubbles[i].dy = bubbles[j].dy;
bubbles[j].dx = tmpx;
bubbles[j].dy = tmpy;
}
}
}
}
}
public static void main(String[] args) {
new BubbleFrame();
}
}

class Bubble {
double x;
double y;
double radius;
double dx;
double dy;
Bubble(double x, double y, double radius, double dx, double dy) {
this.x = x;
this.y = y;
this.radius = radius;
this.dx = dx;
this.dy = dy;
}
void move(double dt) {
x += dx * dt;
y += dy * dt;
}
void draw(Graphics g) {
g.drawOval((int)(x-radius), (int)(y-radius), (int)radius*2, (int)radius*2);
}
}

class BubbleView extends JComponent {
BubbleFrame frame;
BubbleView(BubbleFrame frame) {
this.frame = frame;
}
public void paintComponent(Graphics g) {
for (int i=0; i<frame.bubbles.length; i++) {
frame.bubbles[i].draw(g);
}
}
}
H2
ぬし
会議室デビュー日: 2001/09/06
投稿数: 586
お住まい・勤務地: 港
投稿日時: 2004-09-01 10:09
forが9つもある・・・。申し訳ないのですが、これはさすがに理解しようにもできません。ここは「急がば回れ」でa-sanさんのプログラムをサンプルに分かりやすいプログラムに書きかえたほうが早いと思いますよ。
あいつー
ベテラン
会議室デビュー日: 2004/05/20
投稿数: 89
投稿日時: 2004-09-01 11:16
戯れに計算してみました。

3*10*31*31*10*25*25*3*10*19*19 = 1,951,430,625,000

さすがにこれはお勧めできないです…。
ゴールデン
常連さん
会議室デビュー日: 2004/08/22
投稿数: 46
投稿日時: 2004-09-01 11:20
a-san,H2さんありがとうございます。
a-san、わざわざプログラムを作って頂いてありがとうございます。a-sanのプログラムを動かしてみました。だけど、円は表示されますが円が動かないままです。できればまたアドバイスを頂きたいです。でも、私の場合、ピクセルごとの色情報をMemoryImageSourceで画像にしてから、0x6fffffffの位置を知るために、PixelGrabberで、画像を分解して位置情報を得ている、ということをしているため2度手間をしてややこしくしていることに気づきました。すべてdrawOvalメソッドから位置情報を得ることができれば、ややこしい部分を省くことができることにa-sanのプログラムを見て気づきました。できるかどうか分かりませんが、今晩やってみようと思います。またよろしくお願いします。
びしばし
大ベテラン
会議室デビュー日: 2002/03/13
投稿数: 181
投稿日時: 2004-09-01 15:34
要するにオブジェクトどうしの衝突判定をしたいわけですよね ?

今回は円なのでa-sanが書かれているように半径と距離で計算できるので判定はラクですが、オブジェクト数が増えると判定の計算量が指数関数的に爆発します。
もっと簡便な式で近似計算をしたり、「近くにありそうなオブジェクトだけ判定する」ような工夫をすると、高速にたくさんのオブジェクトを動かせるようになると思います。
そういうときには 3D ゲームの手法を調べられるといいでしょう。

...そこまでは必要ないのかもしれませんけれど。余談ですみません。

スキルアップ/キャリアアップ(JOB@IT)