無題

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
たろう

無題

#1

投稿記事 by たろう » 15年前

何度も質問すみません。
あの、例えば原点(50,50)から円を描くようにしたいのですが、うまくいきません。どうしたらうまく円を描くようにできるのでしょうか?
void enemy_pattern3(int i)
{
    float x=enemy.x,y=enemy.y;
    if(enemy.cnt==0)
    {
        enemy.ang=0;
        enemy.vy=2;
        enemy.vx=0;
        enemy.sp=0;
        return;
    }
    if(enemy.cnt==20)
    {
        enemy.x=((enemy.x-enemy[i].gentenx)*cos(-2*PI/180)-(enemy[i].y)*sin(-2*PI/180));
        enemy[i].y=(enemy[i].x*sin(-2*PI/180)+(enemy[i].y)*cos(-2*PI/180));                
    }
}

よろしくお願いします。

Dixq (管理人)

Re:無題

#2

投稿記事 by Dixq (管理人) » 15年前

少しずつ近づけてみてはどうでしょう?
まずは原点(0,0)を中心に半径300の円を描くプログアムを作ってみてはどうでしょう。
それから中心を移動させたりしてみて下さい。

Θを角度、rを半径だとすると

x = cos(Θ) * r;
y = sin(Θ) * r;

でx,y座標が決まりますよね。
角度はenemyの持つカウンタcntで増加させてやればOKです。

Tatu

Re:無題

#3

投稿記事 by Tatu » 15年前

出現して20カウント後に円の中心(50,50)の左にいて、
そこから反時計回りにまわり、180カウントごとに一周するとき、
円の中心から敵への角度angleを考えます。

20カウント経過したときangle=PIで
それ以降は1カウントごとにPI2/180だけ小さくなる。

よって、20カウント以上のとき
angle=PI-PI2/180*(enemy.cnt-20)となります。

後は20カウント以上のときに
円の中心の座標に
円の半径と中心からの角度から計算できる円の中心に対する敵の位置を
足せば求める敵の座標になります。


あと、別のやり方で、
等速円運動は速さが変わらず、方向の変化が一定な運動だといえるので、

下に直進後、等速円運動する関数は
void enemy_pattern3(int i){
if(enemy.cnt==0){
enemy.sp=5;
enemy.ang=PI/2;
}
if(enemy.cnt==20){
enemy.sp=2;
}
if(enemy.cnt>20){
enemy.ang-=PI2/180;
}
}

のようにかくことができます。

たろう

Re:無題

#4

投稿記事 by たろう » 15年前

Dixq (管理人)Tatuさん回答ありがとうございます。
Tatuさんのおかげでできたのですが、
画像のように移動したいのですがどうすればよいでしょうか?

Tatu

Re:無題

#5

投稿記事 by Tatu » 15年前

Dixqさんの提案したプログラムを
書かずに「できた」と書きこんだということは
enemy.spとenemy.angを使うやり方に
切りかえたということでよいでしょうか?

それでは、
(1)直進が終わった直後の速さと角度はいくつにすればよいでしょうか?

(2)向きが変わるときのenemy.cntをはじめから4つ以上書いてください。
そしてこれらの値にどのような関係があるのかを考えてみてください。

(3)向きが変わるときに敵の移動する方向を逆向きにする方法、
その後の移動方向の変化はどうなるかわかりますか?

これらを考えてもわからなかったら自分で考えたものを実行してどうなるか試してみてください。

たろう

Re:無題

#6

投稿記事 by たろう » 15年前

回答ありがとうございます。
>(1)直進が終わった直後の速さと角度はいくつにすればよいでしょうか?
角度は2度ずつで速さは2です。
プログラム組んでみたのですが、
ただenemy.xとenemy.yでやるのでできればこれをenemy.angとenemy.spでするにはどうすればよいのでしょうか?
ソースは以下です。
void enemy_pattern2(int i)
{
    float x=enemy.x,y=enemy.y;
    if(enemy.cnt==0)
    {
        enemy.ang=0;
        enemy.vy=2;
        enemy.vx=0;
        enemy[i].sp=0;
        return;
    }
    if(enemy[i].cnt==20)
    {
        enemy[i].gentenx=enemy[i].x;
        enemy[i].genteny=enemy[i].y;
        return;
    }

    if(enemy[i].cnt==40)
    {
        enemy[i].ang=0;
        enemy[i].vy=0;
        enemy[i].vx=0;
        enemy[i].knd2=1;
        enemy[i].sp=0;
    }
    if(enemy[i].cnt%80==0)
    {
        enemy[i].ang=0;
        enemy[i].vy=0;
        enemy[i].vx=0;
        enemy[i].knd2=2;
        enemy[i].sp=0;
    }
    if(enemy[i].cnt%160==0)
    {
        enemy[i].ang=0;
        enemy[i].vy=0;
        enemy[i].vx=0;
        enemy[i].knd2=1;
        enemy[i].sp=0;
    }

    
    switch(enemy[i].knd2)
    {
    case 1:
        x=((enemy[i].x-enemy[i].gentenx)*cos(PI2/180)-(enemy[i].y-enemy[i].genteny)*sin(PI2/180))
                    +enemy[i].gentenx;
        y=((enemy[i].x-enemy[i].gentenx)*sin(PI2/180)+(enemy[i].y-enemy[i].genteny)*cos(PI2/180))
                    +enemy[i].genteny;
        break;
    case 2:
        x=((enemy[i].x-enemy[i].gentenx)*cos(-PI2/180)-(enemy[i].y-enemy[i].genteny)*sin(-PI2/180))
                    +enemy[i].gentenx;
        y=((enemy[i].x-enemy[i].gentenx)*sin(-PI2/180)+(enemy[i].y-enemy[i].genteny)*cos(-PI2/180))
                    +enemy[i].genteny;
        break;
    }
    enemy[i].x=x,enemy[i].y=y;
}

たろう

Re:無題

#7

投稿記事 by たろう » 15年前

やっぱりangやspだけではできないのでしょうか?1

Tatu

Re:無題

#8

投稿記事 by Tatu » 15年前

angとspでできるかどうかですが答えは「できます。」
しかし、どのようにすればよいのかを直接は書きません。
理由はさっきの場合はangとspを用いる方法があるということを示すために関数を書きましたが
それでは、今のように自分で書くことができないからです。

さて、どうやらenemy.angとenemy.spを使うとどのように動くのかを
全く分かってなく、試してすらいなさそうな感じがするので問題を出します。
(vyをつかっているということは座標の計算をどこで行っているかはわかっていますよね?)

次のような時、enemy.angとenemy.spはどのようになるでしょうか。
これらにどのように代入すればよいのかを答えてください。
考えるとき、時計回りが正になっていることに注意してください。
enemy.vxとenemy.vyならどうなるかは今は考えないでください。

enemy.angに入る値の単位はラジアンで
1°=PI/180ラジアンの関係があります。

a)右向きに動き、速さは3

b)下向きに動き、速さは1

c)左下に動く、このとき右向きとなす角の大きさは135°、速さは4

d)右上に動く、このとき右向きとなす角の大きさは30°、速さは5

角度があっているかどうかは
void enemy_pattern2(int i){
if(enemy.cnt==0){
enemy.ang=???;
enemy.sp=???;
}
}
の???に代入して実行すればわかります。


(1)については実は速さはどうでもよいです。
しかし、移動方向は真横になります。
右向き、左向きを表す角度はそれぞれいくつでしょうか。
これらのどちらかであれば真横になります。

これらがわかるならば
2度ずつと書かれているので(2)は
角度の変化の大きさを2°として考えてみてください。
直進後、最初に向きを逆にするまでに変化する角度はいくらになるか、
向きを逆にしたのち、次に向きが逆になるまでに変化する角度はいくらになるかを考えるとよいでしょう。

たろう

Re:無題

#9

投稿記事 by たろう » 15年前

返信ありがとうございます。
>右向き、左向きを表す角度はそれぞれいくつでしょうか。
右向きは0度で左の向きは180度ですよね?
enemy.angを2度ずつとやって逆を-2度ずつとやったのですが、S字を描くように移動します。
どうしたらよいのでしょうか?ソース載せます。
void enemy_pattern3(int i){ 
    if(enemy.cnt==0){ 
        enemy.sp=2; 
       // enemy.ang=PI/2;
        return;
    } 
    if(enemy.cnt==20){ 
        enemy.sp=2; 
    } 
    if(enemy.cnt==40){ 
        enemy.sp=1; 
        enemy.knd2=1;
    } 
    if(enemy.cnt%80==0)
    {
        enemy[i].sp=2;
        enemy[i].knd2=1;    
    }
    if(enemy[i].cnt%160==0)
    {
        enemy[i].sp=-2;
        enemy[i].knd2=2;
    }

    switch(enemy[i].knd2)
    {
    case 1:
        enemy[i].ang-=PI2/180;
        break;
    case 2:
        enemy[i].ang+=PI2/180;
        break;
    }
}

たろう

Re:無題

#10

投稿記事 by たろう » 15年前

すみません。enemy.ang-=PI2/180;
でなぜ円を描くように動くのでしょうか?
enemy.ang=-PI2/180ではなぜ円を描かない動きになってしまうのでしょうか?
enemy.ang=-PI2/180で円を描くなら納得するのですが。どうもしっくりきません。

たいちう

Re:無題

#11

投稿記事 by たいちう » 15年前

"-="と"=-"の違いには気付いているのですよね?
それぞれ、次の意味です。

enemy.ang = enemy.ang - PI2/180;
enemy.ang = -PI2/180;

前者は角度が-2度ずつ変わっていきますが、
後者は常に-2度を代入しています。
回転するのはどっちですか?

たろう

Re:無題

#12

投稿記事 by たろう » 15年前

>"-="と"=-"の違いには気付いているのですよね?
>それぞれ、次の意味です。

>enemy.ang = enemy.ang - PI2/180;
>enemy.ang = -PI2/180;
前者それはわかるのですが、
あっわかりました。すみませんでした。なんか勘違いしていました。
enemy.ang = enemy.ang - PI2/180;
で毎回拡大して回転しているのかと思っていましたが、
enemy.ang = -PI2/180;だと2度固定されると言うことですね。ということで回転はしない。
わかっていませんでした。変な質問してすみませんでした。

たろう

Re:無題

#13

投稿記事 by たろう » 15年前

ソースを変更しました。
void enemy_pattern3(int i){ 
    if(enemy.cnt==0){ 
        enemy.sp=5; 
        
        return;
    } 
    if(enemy.cnt==20){ 
        enemy.sp=5; 
        enemy.ang=PI2;
    } 

    if(enemy.cnt%80==0)
    {
        enemy.sp=1;
        enemy.knd2=1;    
    }
    if(enemy.cnt%160==0)
    {
        enemy.sp=1;
        enemy[i].knd2=2;
    }

    switch(enemy[i].knd2)
    {
    case 1:
        enemy[i].ang-=PI2/180;
        break;
    case 2:
        enemy[i].ang+=PI2/180;
        break;
    }
}

enemy[i].ang=PI2;
何ですけど、縦90度に移動するにはenemy[i].ang=PI/2だとはわかっているんですが、
enemy[i].ang=PI2;にしないと縦に動いてくれないのでこれにしました。原因は不明です。
enemy[i].angはこのほかには代入計算をしていないのはずなんですが・・・

このプログラムで実行すると横にSを描いたような動きになってしまいます。
画像のような動きについて、ヒントでもよいので、ご教授よろしくお願いします。

たろう

Re:無題

#14

投稿記事 by たろう » 15年前

Tatuさんの問題やっていませんでした。
a)右向きに動き、速さは3
enemy.ang=0;
enemy.sp=3
b)下向きに動き、速さは1
enemy.ang=PI/2;
enemy.sp=1;
c)左下に動く、このとき右向きとなす角の大きさは135°、速さは4
enemy.ang=PI*3/4;
enemy.sp=4
d)右上に動く、このとき右向きとなす角の大きさは30°、速さは5
enemy.ang=PI/6;
enemy.sp=5;
です。

Tatu

Re:無題

#15

投稿記事 by Tatu » 15年前

角度とスピードの問題については
d)の角度は右上に進むとしているのでPI/6ではなく、-PI/6であるということ以外はあっているので
ほぼ角度とスピードについては理解しているとわかりました。
今はS字を描くように動いているということなので行ったり来たりする動きはそろそろできるでしょう。
また、S字を描くように動かすにはどうすればよいかがこれでわかりましたね?

さて、プログラムの一部を取り出すと

if(enemy.cnt%80==0)
{
enemy.sp=1;
enemy.knd2=1;
}
if(enemy.cnt%160==0)
{
enemy.sp=1;
enemy.knd2=2;
}

となっていますが
この書き方ではenemy.cntが0,160,320,...のときに
二つのif文の条件を両方とも満たしてしまい、
両方の処理が行われます。

両方の処理が行われるということがないようにするには
どうすればよいでしょうか?
この場合、enemy.cntが80,240,400,...の時に
一つ目のif文の条件を満たすようにすればよさそうですね。

if文の条件を変えたら今度は
動きを変えるときに逆向きにするにはそのときに角度をどう変化させればよいかを考えてください。
この時、ある向きとそれに対して逆の向きの間にはどのような関係があるかを考えてください。

たろう

Re:無題

#16

投稿記事 by たろう » 15年前

返信ありがとうございます。
>動きを変えるときに逆向きにするにはそのときに角度をどう変化させればよいかを考えてください。
逆向きにするのはenemy.angを+=から-=にした時、逆向きになるんですよね?

>この時、ある向きとそれに対して逆の向きの間にはどのような関係があるかを考えてください。
ある向きに対して逆向きには角度が違う?
すみません。わかりません。

たろう

Re:無題

#17

投稿記事 by たろう » 15年前

>両方の処理が行われるということがないようにするには
>どうすればよいでしょうか?
>この場合、enemy.cntが80,240,400,...の時に
>一つ目のif文の条件を満たすようにすればよさそうですね。
if(enemy.cnt%80==0 && enemy.cnt%160!=0)
{}
でしょうか?

たろう

Re:無題

#18

投稿記事 by たろう » 15年前

ソース変えたので載せます。
void enemy_pattern3(int i){ 
    if(enemy.cnt==0){ 
        enemy.sp=5; 
        enemy.ang=PI/2;
        return;
    } 
    if(enemy.cnt==20){ 
        enemy.sp=5; 
        
    } 

    if(enemy.cnt%80==0 && enemy.cnt%160!=0)
    {
        enemy.sp=1;
        enemy.knd2=1;    
    }
    if(enemy.cnt%160==0)
    {
        enemy[i].sp=-1;
        enemy[i].knd2=2;
    }

    switch(enemy[i].knd2)
    {
    case 1:
        enemy[i].ang+=PI2/180;
        break;
    case 2:
        enemy[i].ang-=PI2/180;
        break;
    }
}

これで画像に近い動きができたのですが、
ただ、画像のように動くのではなく、直進した後すぐに「J」みたいに移動します。

Tatu

Re:無題

#19

投稿記事 by Tatu » 15年前

>>ある向きに対して逆向きには角度が違う?
では、その違いはどういうものでしょうか?

右向き(0)の反対は左向き(PI)で
下向き(PI/2)の反対は上向き(PI*3/2)で
上向き(PI*3/2)の反対は下向きだけど
ある角度にPI2の整数倍を足した角度は同じ方向を指すから
下向きはPI/2だけではなく、PI*5/2でもあらわすことができる。

これらからどのように変化させればよいかわからないでしょうか?

速さに-をかけるのも一つの手段ではあります。


if文の条件
それでもよいですが、
if(enemy.cnt%160==80)と書くと考えてました。


>>jの字の形に動く。
ここでenemy.cntがいくつの時に向きとenemy.knd2がどうなるのかが
問題になるのですが

まず、直進が終わってから何カウントのとき向きが変化するでしょうか。
いちばん最初が40カウントだとすれば、最初からその次までは40カウントの二倍かかるから120カウントになります。
それ以降は200,280,....のときに向きが変わります。

これと最初の20カウントが直進であることを考えると
enemy.cntが60,140,220,300,...のときに向きが変わる(enemy.sp *= -1 もしくは enemy.ang += PI)ことになります。

enemy.cntが20のときenemy.sp=1, enemy.ang=0, enemy.knd2=2(反時計回り)とすれば
enemy[i].cntが60,220,380,...のときにenemy[i].knd2が1(時計回り)になり、
enemy[i].cntが140,300,460,...のときにenemy[i].knd2が2(反時計回り)になります。

たろう

Re:無題

#20

投稿記事 by たろう » 15年前

回答ありがとうございます。おかげでできました。
本当にありがとうございました。

Tatu

Re:無題

#21

投稿記事 by Tatu » 15年前

解決したようでよかったです。

最後に私が書いたプログラムです。

void enemy_patternT1(int i){
if(enemy.cnt==0){
enemy.sp=5;
enemy.ang=PI/2;
}
if(enemy.cnt==20){
enemy.sp=2;
enemy.ang=0;
}
if(enemy.cnt>20){
if( (enemy.cnt+25)%90==0 ){
enemy.ang+=PI;
}
if( (enemy.cnt+25)%180<90){
enemy[i].ang-=PI2/180;
}
else{
enemy[i].ang+=PI2/180;
}
}
}

たろう

Re:無題

#22

投稿記事 by たろう » 15年前

そのソースで
if((enemy.cnt+25)%180<90)
{
    enemy.ang-=PI/180;
}else{
    enemy.ang+=PI/180;
}

とやってみたんですが、時計周りに90度回転してそして反時計回りに90度回転すると思ったのですが、
ちゃんと180度回転します。なぜなのでしょうか?

Tatu

Re:無題

#23

投稿記事 by Tatu » 15年前

角度の変化は たろう さんが考えているとおり、90度しか変わっていません。
これは向きを変える前後の向きを見ればわかります。

同じ弧を同じ速さで90度回転させたいのならば向きを変えるタイミングを変えることになるので
if文の条件が変わります。


説明しませんでしたが
条件をif((enemy.cnt+25)%180<90)としている理由は以下の通りです。

まず往復の周期を180としたく、その半分の間だけ条件を満たすようにしたいので
if(???%180<90)
と考えました。

そして、最初に向きを変えるのが20+45=65カウントで
これに25を足すと90カウントになるため、
if((enemy.cnt+25)%180<90)とし、
enemy.cntが20から65の間にあるときにこの条件を満たすので
この条件でよいことがわかりました。

もし、このとき逆だったら
処理を変えるか、
if((enemy.cnt+25)%180>=90)
と書き換えればよいだけです。


また、向きを変える条件を
if((enemy.cnt+25)%90==0)としていますが

これはif((enemy.cnt+25)%180==0 || (enemy.cnt+25)%180==90)が
if((enemy.cnt+25)%90==0)と同じ条件になるからです。

たろう

Re:無題

#24

投稿記事 by たろう » 15年前

回答ありがとうございます。
enemy.spを上げてもenemy.ang-=PI/180は結局90度回転するという認識でよいのでしょうか?

Tatu

Re:無題

#25

投稿記事 by Tatu » 15年前

enemy.spをあげて試したらどうなりましたか?
それを見てわからなければenemy.ang-=PI2/180のとき
enemy.spを変えたらどうなりましたか?

たろう

Re:無題

#26

投稿記事 by たろう » 15年前

>enemy.spをあげて試したらどうなりましたか?
>それを見てわからなければenemy.ang-=PI2/180のとき
>enemy.spを変えたらどうなりましたか?


弧を描く長さが長くなりました。
PI/180の時1度90回繰り返されて結局90度回転しているという認識でよいのでしょうか?
何か勘違いしているのでしょうか?

Tatu

Re:無題

#27

投稿記事 by Tatu » 15年前

PI/180 * 90 = PI/2 という考え方でいいですよ。

enemy.spを変えて弧の長さが変わっても回転する角度は変わらないということを確認してほしかっただけです。

たろう

Re:無題

#28

投稿記事 by たろう » 15年前

そうだったんですか。本当に回答ありがとうございました!

閉鎖

“C言語何でも質問掲示板” へ戻る