三角関数で弾幕(2)

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

三角関数で弾幕(2)

#1

投稿記事 by Ultimate » 15年前

math.hでsinとcosが出せることがわかりました。

苦しんで覚えるC言語で調べてみたら、

「[ sin ]
関数型 : double sin(double x);
引数  : ラジアン単位の角度
戻り値 : サイン値
機能  : サインを計算する」

「[ cos ]
関数型 : double cos(double x);
引数  : ラジアン単位の角度
戻り値 : コサイン値
機能  : コサインを計算する」

となっていたのですが、これをうまく利用すれば全方向ショットが再現できるようです。

http://sinkai.net/rp/4.php

カッコ内のdouble xはラジアンですよね?

ということは、角度×3.141592/180の値がdouble xですよね?

これからの参考に、cos,sinを利用した簡単なプログラムを載せていただけませんか?(探してみましたが、あまりはっきりとわからなかったので)

あと、これを利用して円を一定の角度ごとに円周上に(表現がわかりにくくてすみません)表示できたら、そのsinとcosの値を順に10倍,20倍,30倍・・・としていけば全方向ショットができますか?(こちらも表現がわかりにくくてすみません。)

よろしくお願いします。

シエル

Re:三角関数で弾幕(2)

#2

投稿記事 by シエル » 15年前

下記のページを参考にしてみてはどうでしょう?
http://dixq.net/s/26.html

Ultimate

Re:三角関数で弾幕(2)

#3

投稿記事 by Ultimate » 15年前

atan2関数は初めて知りました。

http://www.orchid.co.jp/computer/cschoo ... atan2.html

「斜辺 * cosでx座標が、斜辺 * sinでy座標が求まります。斜辺はPATTERN1SPEEDでしたね。この値を座標に増やします。」



sinとcosの値を順に10 倍,20倍,30倍・・・としていけば全方向ショットができますか?

で予想が当たっていたことがわかりました。(つまり、斜辺を10倍・・・ということなので)

全方向ショットはそのページのアルゴリズムからラジアンを2.0ずつ引く操作を抜いた感じでしょうか?

それであっていて、あとは自分でやってできるようであればこれは解決にしたいと思います。

シエル

Re:三角関数で弾幕(2)

#4

投稿記事 by シエル » 15年前

あまり質問内容がよくわかりませんが、全方向ショットであれば
下記のページをごらん下さい。
http://dixq.net/s/27.html

たいちう

Re:三角関数で弾幕(2)

#5

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

提案なんですが、三角関数を使わずに上下左右の4方向に
弾を撃つプログラムを書いてみてはどうでしょうか?
これが1段階目。

これは90度ずつ全方向に弾を撃つことと同じですので、
一段階目のプログラムを三角関数を使ったものに書き換えることができます。
これが2段階目。

最終段階は簡単で、90度ずつに弾を撃っていたのを
20度ずつに変更するだけです。

Dixq (管理人)

Re:三角関数で弾幕(2)

#6

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

シエルさん、シューティングプログラミングの館は見ている人が少なくなり次第削除しようと思っている所なので、申し訳ないですがなるべくリンクを張らないで頂けると幸いです。
早い所龍神録プログラミングの館の方に移行して、古い方は削除したいのですが、
要望があって現在残している状態です。

せっかく回答して下さっているところごめんなさい。

Ultimate

Re:三角関数で弾幕(2)

#7

投稿記事 by Ultimate » 15年前

#include "DxLib.h"
#include <math.h>

#define π 3.14159265358979323846264338327950288419

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode( TRUE ) ; // ウインドウモードに変更
if( DxLib_Init() == -1 ) return -1; // DXライブラリ初期化処理 エラーが起きたら終了

//ボール構造体
typedef struct{
int flag,x[20],y[20],z;
double angle[20];
}ch_t;

ch_t ball;

ball.z=3;

//変数作成
int i;
char key[256];
int White=GetColor(255,255,255);

//全方向ショットフラグ初期化

ball.flag=0;

//while突入

SetDrawScreen(DX_SCREEN_BACK);

while(1){
if(ProcessMessage()==-1){
break;
}
ClearDrawScreen();
GetHitKeyStateAll(key);

//Xで発射フラグを立てる
if(key[KEY_INPUT_X]){
ball.flag=1;
}


//角度決定

for(i=0;i<20;i++){
ball.angle=(18*i)*π/180;
}
for(i=0;i<20;i++){
ball.x=sin(ball.angle)+320;
ball.y=cos(ball.angle)+240;
}

//描画
while(ball.flag==1){
if(ProcessMessage()==-1){
break;
}
for(i=0;i<20;i++){
DrawCircle(ball.x,ball.y,ball.z,White,TRUE);
}


ScreenFlip();
}



}



WaitKey() ; // キーの入力待ち(『WaitKey』を使用)
DxLib_End() ; // DXライブラリ使用の終了処理
return 0 ; // ソフトの終了
}

全方向ショットを目指して、上のようにsin,cosを調べるところまでは成功しました。

ボールの数は20個、角度は18度ずつで画面中心から広がるようにしたいです。

Xを押して画面中央に表示はできました。

その後このボールが広がっていくようにするにはどうしたらいいでしょうか?

fatens

Re:三角関数で弾幕(2)

#8

投稿記事 by fatens » 15年前

まず、ch_tのxなどを配列にするのではなく、ballを配列にすべきだと思います。
それから、πもPIとでもしておくほうが無難ではないでしょうか。

x, y座標の初期値を320, 240とし、それにcos, sin×速さを毎回足していけば広がります。
ですが、そのまえにもう一度三角関数について確認しておかないと後で困ります。
画像

softya

Re:三角関数で弾幕(2)

#9

投稿記事 by softya » 15年前

sinとcosは0~1の間の値しか取らないので、移動距離を掛け算してやる必要があります。
あとは、フレーム毎に距離を加算するだけです。

double kyori = 0;

for(i=0;i<20;i++){
ball.x=sin(ball.angle)*kyori+320;
ball.y=cos(ball.angle)*kyori+240;
}

//移動する。
kyori+=1.0;

Ultimate

Re:三角関数で弾幕(2)

#10

投稿記事 by Ultimate » 15年前

ありがとうございました。

下のように変更をしました。

しかし、ball.angleは0度~360度までをつくったはずなのに、方向が下だけです。

目標は今の下1方向から360度20方向にしたいです。

何が原因で方向が下だけになってしまっているのでしょうか?

#include "DxLib.h"
#include <math.h>

#define PI 3.14159265358979323846264338327950288419

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode( TRUE ) ; // ウインドウモードに変更
if( DxLib_Init() == -1 ) return -1; // DXライブラリ初期化処理 エラーが起きたら終了

//ボール構造体
typedef struct{
int flag,x[20],y[20],z;
double angle[20];
}ch_t;

ch_t ball;

ball.z=3;

//変数作成
int i,j;
char key[256];
int White=GetColor(255,255,255);
double kyori = 0;

//全方向ショットフラグ初期化

ball.flag=0;

//while突入

SetDrawScreen(DX_SCREEN_BACK);

while(1){
if(ProcessMessage()==-1){
break;
}
ClearDrawScreen();
GetHitKeyStateAll(key);

//Xで発射フラグを立てる
if(key[KEY_INPUT_X]){
ball.flag=1;
}



//角度決定

for(i=0;i<20;i++){
ball.angle=(18*i)*PI/180;
}


//描画
while(ball.flag==1){
if(ProcessMessage()==-1){
break;
}
ClearDrawScreen();
for(i=0;i<20;i++){
DrawCircle(ball.x,ball.y,ball.z,White,TRUE);



for(i=0;i<20;i++){
ball.x=sin(ball.angle)*kyori+320;
ball.y=cos(ball.angle)*kyori+240;
}

//移動する。
kyori+=5.0;
}


ScreenFlip();
}



}



WaitKey() ; // キーの入力待ち(『WaitKey』を使用)
DxLib_End() ; // DXライブラリ使用の終了処理
return 0 ; // ソフトの終了
}

シエル

Re:三角関数で弾幕(2)

#11

投稿記事 by シエル » 15年前

すいません。下のコードは何を説明しているものなのか具体的に説明していただけますか?

for(i=0;i<20;i++){
ball.x=sin(ball.angle)*kyori+320;
ball.y=cos(ball.angle)*kyori+240;
}

Ultimate

Re:三角関数で弾幕(2)

#12

投稿記事 by Ultimate » 15年前

先ほど、回答をいただき追加したものです。

内容は、三角関数で出たものは、斜辺が1なので、sin,cosともに0~1です。

なので、その斜辺をkyoriと置いてkyoriを2倍3倍にしてsin,cosを大きくしていくというものです。

fatens

Re:三角関数で弾幕(2)

#13

投稿記事 by fatens » 15年前

http://w3e.kanazawa-it.ac.jp/math/categ ... i-enn.html
↑のサイトをよく見てください。
私が先に書いたこと、(おそらくシエルさんの意味していることも)が分かるかと思います。

シエル

Re:三角関数で弾幕(2)

#14

投稿記事 by シエル » 15年前

ちょっと直してみました。Ultimateさんがイメージしてるのはこんな感じですか?
もしイメージどおりなら、私が貼ったコードと、fatensさんが記載して頂いているURLを熟読のうえ、
わからないところがあれば質問して下さい。

#include "DxLib.h"
#include <math.h>

#define PI 3.14159265358979323846264338327950288419
#define BALL_SPEED 4


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode( TRUE ) ; // ウインドウモードに変更
if( DxLib_Init() == -1 ) return -1; // DXライブラリ初期化処理 エラーが起きたら終了

//ボール構造体
typedef struct{
int flag,x[20],y[20],z;
double angle[20];
}ch_t;

ch_t ball;

ball.z=3;

//変数作成
int i,j;
char key[256];
int White=GetColor(255,255,255);
double kyori = 0;

//全方向ショットフラグ初期化

ball.flag=0;

//while突入

SetDrawScreen(DX_SCREEN_BACK);

while(1){
if(ProcessMessage()==-1){
break;
}
ClearDrawScreen();
GetHitKeyStateAll(key);

//Xで発射フラグを立てる
if(key[KEY_INPUT_X]){
ball.flag=1;
}



//角度決定

for(i=0;i<20;i++){
ball.angle=(18*i)*PI/180;
}

for(i=0;i<20;i++){
ball.x=320;
ball.y=240;
}



//描画
while(ball.flag==1){
if(ProcessMessage()==-1){
break;
}
ClearDrawScreen();
for(i=0;i<20;i++){
ball.x+=sin(ball.angle)*BALL_SPEED;
ball.y+=cos(ball.angle)*BALL_SPEED;
}

for(i=0;i<20;i++){
DrawCircle(ball.x,ball.y,ball.z,White,TRUE);
}



Sleep(17);

ScreenFlip();
}



}



WaitKey() ; // キーの入力待ち(『WaitKey』を使用)
DxLib_End() ; // DXライブラリ使用の終了処理
return 0 ; // ソフトの終了
}


追記:
Ulitamteさんが作成したコードはかなり不要なところでループがあったりしてたので、
色々直しています。
一度コード全体を見直すことをお勧めします。 画像

fatens

Re:三角関数で弾幕(2)

#15

投稿記事 by fatens » 15年前

typedef struct{
int flag,x[20],y[20],z;
double angle[20];
}ch_t;

これのx, yがint型なのはまずいですね。

Ultimate

Re:三角関数で弾幕(2)

#16

投稿記事 by Ultimate » 15年前

とても丁寧にありがとうございます。

目標はhttp://sinkai.net/rp/4.phpです。

出来れば円が同一円周上に表示したいです。

fatensさんのURLも読んで、その内容を理解し、ソースの内容もわかりました。

今まではball.xなどをそのまま変えてしまっていましたが、これはball.xなどに数を追加していくということですね。

softya

Re:三角関数で弾幕(2)

#17

投稿記事 by softya » 15年前

私のも説明不足だったので貼っておきます。
2つ目のループはまずいので排除しました。

include "DxLib.h"
#include <math.h>

#define π 3.14159265358979323846264338327950288419

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode( TRUE ) ; // ウインドウモードに変更
if( DxLib_Init() == -1 ) return -1; // DXライブラリ初期化処理 エラーが起きたら終了

//ボール構造体
typedef struct{
int flag,x[20],y[20],z;
double angle[20];
}ch_t;

ch_t ball;

ball.z=3;

//変数作成
int i;
char key[256];
int White=GetColor(255,255,255);
double kyori = 0;

//全方向ショットフラグ初期化

ball.flag=0;

//while突入

SetDrawScreen(DX_SCREEN_BACK);

while(1){
if(ProcessMessage()==-1){
break;
}
ClearDrawScreen();
GetHitKeyStateAll(key);

//Xで発射フラグを立てる
if(key[KEY_INPUT_X]){
ball.flag=1;
}


//角度決定

for(i=0;i<20;i++){
ball.angle=(18*i)*π/180;
}
for(i=0;i<20;i++){
ball.x=sin(ball.angle)*kyori+320;
ball.y=cos(ball.angle)*kyori+240;
}


//描画
for(i=0;i<20;i++){
DrawCircle(ball.x,ball.y,ball.z,White,TRUE);
}

if( ball.flag == 1 ) {
kyori += 1.0;
}

ScreenFlip();
}



WaitKey() ; // キーの入力待ち(『WaitKey』を使用)
DxLib_End() ; // DXライブラリ使用の終了処理
return 0 ; // ソフトの終了
}

Ultimate

Re:三角関数で弾幕(2)

#18

投稿記事 by Ultimate » 15年前

これです。

これを目指していました。

intだったから少数が表現できていなかったのですね。

疑問が解決しました。

ありがとうございました。

fatens

Re:三角関数で弾幕(2)

#19

投稿記事 by fatens » 15年前

>fatensさんのURLも読んで、その内容を理解し、ソースの内容もわかりました。

Ultimateさんのコードではsinとcosが逆になっていることを伝えたかったのですが、
それを理解されたということでよろしいでしょうか?

まあ、解決されたようなので、私のコードも貼っておきます。
何かの参考になれば良いのですが。

#include "DxLib.h"
#include <math.h>

//度をラジアンに変換
inline float degToRad(float deg)
{
return deg * 3.1415926535f / 180;
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
ChangeWindowMode(TRUE);

if (DxLib_Init()) return 1;
if (SetDrawScreen(DX_SCREEN_BACK)) return 1;

//ボールの構造体
const int ballMax = 256;
struct {
float x, y;
float ang, spd;
int flag;
} ball[ballMax] = {0};

//ボールの初期化(20発, 円形)
for (int i = 0; i < 20; ++i) {
ball.x = 320;
ball.y = 240;
ball.ang = 360.0f / 20 * i;
ball.spd = 5.0f;
ball.flag = 1;
}

while (!ProcessMessage() && !CheckHitKey(KEY_INPUT_ESCAPE)) {
ClearDrawScreen();

//ボールの移動
for (int i = 0; i < ballMax; ++i) {
if (ball.flag == 0)
continue;
ball.x += cos(degToRad(ball.ang)) * ball.spd;
ball.y += sin(degToRad(ball[i].ang)) * ball[i].spd;
}

//ボールの描画
for (int i = 0; i < ballMax; ++i) {
if (ball[i].flag == 0)
continue;
DrawCircle(ball[i].x, ball[i].y, 3, GetColor(255, 255, 255));
}

ScreenFlip();
}

DxLib_End();

return 0;
}

シエル

Re:三角関数で弾幕(2)

#20

投稿記事 by シエル » 15年前

>intだったから少数が表現できていなかったのですね。
softyaさんの回答に対して、この返答は理解できているのか疑ってしまいますが大丈夫でしょうか?
softyaさんのコードはまだint型ですよ。

あと、softyaさんが貼っていただいているコードと私のコードとは少し方法が違います。
先ほどの私のコードはx,yをdouble型にしていなかったので、きれいに弾が広がってませんでした。
下記にdouble型に修正して、きれいに広がるようになった私のコードを一応記載しておきます。
しっかり違いを理解しておいたほうがいいですよ。


#include "DxLib.h"
#include <math.h>

#define π 3.14159265358979323846264338327950288419
#define BALL_SPEED 4.0f

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){
ChangeWindowMode( TRUE ) ; // ウインドウモードに変更
if( DxLib_Init() == -1 ) return -1; // DXライブラリ初期化処理 エラーが起きたら終了

//ボール構造体
typedef struct{
int flag;
double x[20],y[20],z;
double angle[20];
}ch_t;

ch_t ball;

ball.z=3;

//変数作成
int i;
char key[256];
int White=GetColor(255,255,255);
double kyori = 0;

//全方向ショットフラグ初期化

ball.flag=0;

//while突入

SetDrawScreen(DX_SCREEN_BACK);

for(i=0;i<20;i++){
ball.x=320;
ball.y=240;
}

while(1){
if(ProcessMessage()==-1){
break;
}
ClearDrawScreen();
GetHitKeyStateAll(key);

//Xで発射フラグを立てる
if(key[KEY_INPUT_X]){
ball.flag=1;
}


//角度決定
if(ball.flag==1){

for(i=0;i<20;i++){
ball.angle=(18*i)*π/180;
}
for(i=0;i<20;i++){
ball.x+=sin(ball.angle)*BALL_SPEED;
ball.y+=cos(ball.angle)*BALL_SPEED;
}

//描画
for(i=0;i<20;i++){
DrawCircle(ball.x,ball.y,ball.z,White,TRUE);
}

}
ScreenFlip();
}



WaitKey() ; // キーの入力待ち(『WaitKey』を使用)
DxLib_End() ; // DXライブラリ使用の終了処理
return 0 ; // ソフトの終了
}

fatens

Re:三角関数で弾幕(2)

#21

投稿記事 by fatens » 15年前

>softyaさんの回答に対して、この返答は理解できているのか疑ってしまいますが大丈夫でしょうか?

おそらくNo:54230の私の回答に対してかと。

シエル

Re:三角関数で弾幕(2)

#22

投稿記事 by シエル » 15年前

>おそらくNo:54230の私の回答に対してかと。
で、ですよね~。。つい微妙な返答だったもんで。。。 画像

Ultimate

Re:三角関数で弾幕(2)

#23

投稿記事 by Ultimate » 15年前

はい、わかりました。

さきほどfatensさんに貼り付けていただいたURLを見て、間違えているのに気がつきました。

X座標がcosでY座標がsinでしたね。

逆で覚えていました。

あと、そのソースでは、勝手に弾が発射されてしまうので、少し改造してみます。

いろいろと難しいですが、いくつか読み落としがあったので、もう一度一通りソースを読み直します。
画像

fatens

Re:三角関数で弾幕(2)

#24

投稿記事 by fatens » 15年前

>あと、そのソースでは、勝手に弾が発射されてしまうので、少し改造してみます。

そうですね。
あくまで私ならこうする、という形のサンプルですので、キー入力を必要とはしていません。

人のコードを読むのは勉強になると思うので、がんばって改造してみてください。
私のコードが良いかどうかは知りませんが...

もしわからない部分があれば遠慮なく質問してください。

Tatu

Re:三角関数で弾幕(2)

#25

投稿記事 by Tatu » 15年前

プログラムを書いてみました。

#include "DxLib.h"
#include <math.h>

#define PI 3.14159265358979
#define PI2 PI*2
//円周率の二倍は360度に等しく、よく使うと考えられるのでここで定義してしまう

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){
ChangeWindowMode(TRUE);
if(DxLib_Init() == -1) return -1;

typedef struct{
int flag;
double x,y;
double spd,angle;
}ch_t;

ch_t ball[20];
//今後メンバ変数を追加するたびに[20]をつけるのが嫌なのでこうする。
//また、自機などにもch_tを使用すると考えられるが
//自機に20個の座標は明らかに不要。

char key[256];
int White=GetColor(255,255,255);

for(int i=0;i<20;i++){
ball.flag=0;
ball.x=0;
ball.y=0;
ball.spd=0;
ball.angle=0;
}

SetDrawScreen(DX_SCREEN_BACK);

while(1){
if(ProcessMessage()==-1){
break;
}
ClearDrawScreen();
GetHitKeyStateAll(key);

//エスケープキーを押すことで終了できるようにする
if(key[KEY_INPUT_ESCAPE]){
break;
}

//弾のフラグをオンにする。
//このとき弾の情報を一緒に入れておくことにより
//毎ループ中央の座標が弾の座標として代入されることがなくなる
//なお、単位円の円周はPIではなくPI2である。
if(key[KEY_INPUT_X]){
for(int i=0;i<20;i++){
ball.flag=1;
ball.x=320;
ball.y=240;
ball.spd=4;
ball.angle=i*PI2/20;
}
}

//弾を移動させる
//曲がる弾を扱う場合でも発射時の条件から座標を求める必要はなく、
//現在の弾の情報から次を計算できる。
//念のために書いておくが
//sin,cosの取りうる値の範囲は-1から1までの間であり、
//0から1までではない。もしそうならball[i].spdが正のとき
//弾は右下にしか動けないはずである。
for(int i=0;i<20;i++){
ball[i].x+=ball[i].spd*cos(ball[i].angle);
ball[i].y+=ball[i].spd*sin(ball[i].angle);
}

//弾の描画
for(int i=0;i<20;i++){
if(ball[i].flag==1){
DrawCircle(ball[i].x,ball[i].y,3,White,TRUE);
}
}

ScreenFlip();
}

//投稿されたものにはWaitKey()がかかれていたが不要
DxLib_End();
return 0;
}

閉鎖

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