トップビューとは、真上からの視点のことで、
向きと位置が空間的に分かりやすいというか、
そのまま(関数の)グラフに当てはめられるので、
私としては最も作りやすいと思う視点です。
ですが、ゲームとしての見栄えは良くなく、
せいぜいターン制戦略SLGに使われるくらいでしょうか、
ゲームとして使われるのは稀です。
では、見栄えのよい視点とは何かと言えば、
おそらく、クォータービューではないでしょうか。
クォータービューとは、斜め上方から見た視点です。
ですから、ある意味見た目は3Dと似ています。
いまは大体が3Dで作られているゲームなので、
視点など特に造作もなく変えられると思いますが、
2Dの場合は中々大変なものです。
なんにせよ、クォータービューの視点を前提に、
座標やベクトルを管理するのは難しいのです。
ですから、管理・更新はトップビューを前提にしたもので行い、
描画の際だけ、クォータービューのそれに変換するのが良いんじゃないか、
というのが、まあ、私が突発的に考えた方法です。
長い説明になりましたが、結局のところ、
中身のデータをトップビューで管理して、
描画の際だけクォータービューに変換するような
プログラムを書いたよ、というのが今回の趣旨です。
#include
#include "DxLib.h"
const int WIDTH = 200;
const int HEIGHT = 200;
struct Vec
{
double x,y;
Vec():x(0.0),y(0.0){}
Vec(double x_, double y_)
:x(x_),y(y_){}
};
//ベクトルの内積・実数倍・減算
double Dot(Vec A, Vec B){ return A.x*B.x+A.y*B.y; }
Vec VecMul(Vec V, double D){ return Vec(V.x*D, V.y*D); }
Vec VecSub(Vec T, Vec S){ return Vec(T.x-S.x,T.y-S.y); }
Vec VecSum(Vec T, Vec S){ return Vec(T.x+S.x,T.y+S.y); }
struct MovingBall
{
MovingBall()
{
Pos = Vec(
(double)GetRand(WIDTH),
(double)GetRand(HEIGHT)
);
double angle
= GetRand(314*2)/100.0;
Velocity =
Vec( cos(angle)*4,
sin(angle)*4 );
}
// 位置
Vec Pos;
// 速度
Vec Velocity;
// 位置の更新
void Moving();
// 各種方式で描画
void Render_In_TopView();
void Render_In_QuarterView();
};
//トップビュー視点での座標・ベクトルを
//クォータービュー視点でのそれに変換
Vec ConvertVec_TopView_into_QuarterView
(Vec Tvec)
{
// 一次変換
const double ang = 45.0/180.0*PHI;
//回転行列
const double a1=cos(ang), a2=-sin(ang)
, a3=sin(ang), a4=cos(ang) ;
//拡大縮小行列
const double s1=1.0, s2=0.0
, s3=0.0, s4=0.5 ;
Vec Qvec;
Vec Bvec = Tvec;
Qvec.x = a1*Bvec.x + a2*Bvec.y;
Qvec.y = a3*Bvec.x + a4*Bvec.y;
Bvec = Qvec;
Qvec.x = s1*Bvec.x + s2*Bvec.y;
Qvec.y = s3*Bvec.x + s4*Bvec.y;
//最後に平行移動
Qvec = VecSum(Qvec, Vec(WIDTH*cos(ang),0));
return Qvec;
}
//上の逆
Vec ConvertVec_QuarterView_into_TopView
(Vec Qvec)
{
return Vec();
}
void MovingBall::Moving()
{
//---壁との衝突
if( Pos.x WIDTH )
{
//右端の法線
Vec vN(-1.0,0.0);
Velocity = VecSub(Velocity, VecMul(vN, 2*Dot(vN,Velocity)));
}
if( Pos.y HEIGHT )
{
//下端の法線
Vec vN(0.0,-1.0);
Velocity = VecSub(Velocity, VecMul(vN, 2*Dot(vN,Velocity)));
}
//---
Pos.x += Velocity.x;
Pos.y += Velocity.y;
}
void MovingBall::Render_In_TopView()
{
DrawCircle( (int)Pos.x,
(int)Pos.y,
4,
GetColor(255,0,0) );
}
void MovingBall::Render_In_QuarterView()
{
Vec Ren_Pos = ConvertVec_TopView_into_QuarterView(Pos);
//描画に際して位置をずらす(+200,+50)
DrawOval( (int)Ren_Pos.x + 200,
(int)Ren_Pos.y + 50,
4,
2,
GetColor(255,0,0),
1 );
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
ChangeWindowMode(true);
DxLib_Init();
SetDrawScreen(DX_SCREEN_BACK);
SetDrawMode( DX_DRAWMODE_BILINEAR ) ;
//4つのボールが動きまわる
const int NUM = 4;
MovingBall Balls[NUM];
while(ProcessMessage() == 0 && !CheckHitKey(KEY_INPUT_ESCAPE))
{
ClsDrawScreen();
//各枠を描画
DrawBox(0,0,WIDTH,HEIGHT,GetColor(255,255,255),false);
Vec A(0,0), B(200,0), C(0, 200), D(200, 200);
A=ConvertVec_TopView_into_QuarterView(A);
B=ConvertVec_TopView_into_QuarterView(B);
C=ConvertVec_TopView_into_QuarterView(C);
D=ConvertVec_TopView_into_QuarterView(D);
DrawLine(A.x+WIDTH,A.y+50,B.x+WIDTH,B.y+50,65535);
DrawLine(A.x+WIDTH,A.y+50,C.x+WIDTH,C.y+50,65535);
DrawLine(B.x+WIDTH,B.y+50,D.x+WIDTH,D.y+50,65535);
DrawLine(C.x+WIDTH,C.y+50,D.x+WIDTH,D.y+50,65535);
for(int i = 0; i < NUM; ++i)
{
Balls[i].Moving();
Balls[i].Render_In_TopView();
Balls[i].Render_In_QuarterView();
}
ScreenFlip();
}
DxLib_End();
};
その様子をトップビューとクォータービューで描画します。
見た目はこんな感じです。 動きのあるプログラムって、
本当にSSの見栄えは最悪ですね…。
一応プログラムも添付しておきます。 貼っておいて何ですが、
こんなべらぼうにアップロードしてしまって大丈夫なんでしょうか…
編集1 : インデント修正
編集2 : 出来ていませんでしたので再び…
編集3 : code を code=c に変更