コード:
#include "DxLib.h"
//1種類あたり描画できる3D背景の枚数
#define TD_BASE_MAX 10
//描画できる3D背景の種類数
#define TD_CORE_MAX 10
//3D統括する構造体の種類数
#define TD_MAX 10
//π
#define PI 3.1415926535898
//フィールドの広さ
#define FMX 384
#define FMY 448
//フィールドの左上の座標
#define FX 32
#define FY 16
//描画用ベクトルの定義
VECTOR p = { 0, 0, 0 }, rot[3] = {{0,0,0},{0,0,0},{0,0,0}};
//背景用画像
int img_back[20];
int func_state=0;
// フォグ
int FogSW = 1;
//実際に描画する構造体
typedef struct{
//現在の座標
float x,y,z;
//描画点
VERTEX_3D vertex[4];
}td_base_t;
//3D描画集合体
typedef struct{
td_base_t base[TD_BASE_MAX];
//描画するかどうか、描画する枚数(縦に何枚やるか)、描画する画像のナンバー
int flag,num,img_id;
//画像の基本となる位置xyz、描画の大きさ、角度、どこからフェードインするか、どこからスタートするか、どこで描画を消すか
float sx,sy,sz,len,angle,from_y,start_y,end_y;
}td_core_t;
typedef struct{
//縦にどれだけごとに描画するか、横にどれだけごとに並べるか、セット中心、XYZ方向へ移動させるスピード
float every,set,center,spd_x,spd_y,spd_z;
//描写する絵に割り当てる構造体の数(横に何枚並べるか)、スライド方向(今のとこ1で水平方向,2は空中の水平方向)
int str_num,type,flag;
td_core_t core[TD_CORE_MAX];
}td_t;
td_t td[TD_CORE_MAX];//3D管理
int Key[256]; // キーが押されているフレーム数を格納する
// キーの入力状態を更新する
int gpUpdateKey(){
char tmpKey[256]; // 現在のキーの入力状態を格納する
GetHitKeyStateAll( tmpKey ); // 全てのキーの入力状態を得る
for( int i=0; i<256; i++ ){
if( tmpKey[i] != 0 ){ // i番のキーコードに対応するキーが押されていたら
Key[i]++; // 加算
} else { // 押されていなければ
Key[i] = 0; // 0にする
}
}
return 0;
}
//3D要素配列のxyzに値を入れていく関数、numにはtdの番号を入れる、num2にはtd.coreの番号を入れる(tdのnum)すなわちi、num3にはtd.core.baseの番号
void td_ins_first(float x,float y,float z,float every,int num,int num2,int num3,int type){
if(type==1)
{
td[num].core[num2].base[num3].x=x;
td[num].core[num2].base[num3].y=y-num3*every;
td[num].core[num2].base[num3].z=z;
}
else if(type == 2)
{
td[num].core[num2].base[num3].x=x;
td[num].core[num2].base[num3].y=y+num3*every;
td[num].core[num2].base[num3].z=z;
}
}
//スワップ関数
void SwapObChild(td_base_t *Ob1,td_base_t *Ob2){
td_base_t t = *Ob1;
*Ob1 = *Ob2;
*Ob2 = t;
}
//比較関数
void SortObject(int n){
int i,j,k;
for (i = 0; i < td[n].str_num; i++) {
if(td[n].core[i].flag==1)
{
for(j = 0; j < td[n].core[i].num;j++)
{
for (k = j + 1; k < td[n].core[i].num ; k++) {
if(td[n].type==1)//地上のとき
{
if (td[n].core[i].base[j].y < td[n].core[i].base[k].y ) {
SwapObChild( &td[n].core[i].base[j], &td[n].core[i].base[k] );
}
else if(td[n].type == 2)//上空のとき
if (td[n].core[i].base[j].y > td[n].core[i].base[k].y ) {
SwapObChild( &td[n].core[i].base[j], &td[n].core[i].base[k] );
}
}
}
}
}
}
}
//td_base内のxyz座標を更新するプログラム。numにはtd_massの配列番号を渡す
void Vector_slide(float *x,float *y,float *z,int num,int type,float from_y,float sy,float end_y)
{
*x+=td[num].spd_x;
*y+=td[num].spd_y;
*z+=td[num].spd_z;
if(type==1)
{
if(*y<=end_y)
{
*y=sy;
}
}
else if(type == 2)
{
if(*y>=end_y)
{
*y=sy;
}
}
}
//VECTOR_3Dに値を渡す関数
void Vector_ins(VERTEX_3D v[4],VECTOR &rot, float x, float y,float z, float len,float fy,float start_y, float angle,int type)
{
v[0].pos.x = x-len; v[0].pos.y = y+len ; v[0].pos.z = z;
v[0].u = 0.0F ;
v[0].v = 0.0F ;
v[1].pos.x = x-len; v[1].pos.y = y-len ; v[1].pos.z = z;
v[1].u = 0.0F ;
v[1].v = 1.0F ;
v[2].pos.x = x+len; v[2].pos.y = y+len ; v[2].pos.z = z;
v[2].u = 1.0F ;
v[2].v = 0.0F ;
v[3].pos.x = x+len; v[3].pos.y = y-len ; v[3].pos.z = z;
v[3].u = 1.0F ;
v[3].v = 1.0F ;
// 輝度は全要素100%
v[0].r = v[0].g = v[0].b = 255 ;
v[1].r = v[1].g = v[1].b = 255 ;
v[2].r = v[2].g = v[2].b = 255 ;
v[3].r = v[3].g = v[3].b = 255 ;
//指定された値より小さければフェードアウト
if(type == 1)
{
for(int i = 0; i<4;i++)
{
if( FogSW ) {
v[i].a = 255.f;
} else {
if(start_y<=v[i].pos.y)
{
v[i].a = (unsigned char)0.f;
}
else if(fy <v[i].pos.y && start_y > v[i].pos.y)
{
v[i].a =255.f*(start_y-v[i].pos.y)/(start_y-fy) ;
}
else
{
v[i].a = 255.f;
}
}
}
}
rot.x=angle;
rot.y=0;
rot.z=0;
}
// 行列計算
void CalcRotateMatrix(MATRIX *pMatResult, const VECTOR& pos, const VECTOR &rot)
{
// 移動
MATRIX m;
CreateTranslationMatrix(pMatResult, pos.x, pos.y, pos.z);
// 回転Z
CreateRotationZMatrix(&m, rot.z);
CreateMultiplyMatrix(pMatResult, &m, pMatResult);
// 回転Y
CreateRotationYMatrix(&m, rot.y);
CreateMultiplyMatrix(pMatResult, &m, pMatResult);
// 回転X
CreateRotationXMatrix(&m, rot.x);
CreateMultiplyMatrix(pMatResult, &m, pMatResult);
}
// ワールド行列を変更して表示
void DrawTransRotatePolygon1(int img, VERTEX_3D *vertex, int vertexNum, const VECTOR& pos, const VECTOR &rot)
{
// 行列計算
MATRIX matResult, matOrgWorld;
CalcRotateMatrix(&matResult, pos, rot);
GetTransformToWorldMatrix(&matOrgWorld);
// 描画
SetTransformToWorld(&matResult);
DrawPolygon3DBase(vertex, vertexNum, DX_PRIMTYPE_TRIANGLESTRIP, img, TRUE);
SetTransformToWorld(&matOrgWorld);
}
//3Dにおける中心点制御
void move_view(){
float X=640.f, Y=480.f; // ウィンドウのサイズ
float Xd=-(X/2-FMX/2-FX), Yd=0.f ; // 消失点の移動量
MATRIX mat;
CreateViewportMatrix(&mat, X/2.f+Xd, Y/2.f+Yd, X, Y);
SetTransformToViewport(&mat);
}
//カメラの初期設定
void SetDefaultCamera()
{
move_view();
MATRIX cam;
float Fx=0,Fy=0;
//カメラの位置、注視点、上方向
VECTOR vCamPos = { Fx, Fy, 100 }, vCamAt = { 0, 0, 0 }, vCamUp = { 0, 1, 0 };
CreateLookAtMatrix(&cam, &vCamPos, &vCamAt, &vCamUp);
SetTransformToView(&cam);
}
void load(){
img_back[1] = LoadGraph("test3Dgr2.png");
//カメラ位置の初期設定(元関数はgraph_back.cppに)
SetDefaultCamera();
//描画画像初期値(ステージごとや道中でも変える必要?)
//全体描画を統括する構造体の初期値
//横、縦、中心
td[0].set=50.0f;
td[0].every=50.0f;
td[0].center=19.2f;
//横枚数、速度、タイプ、フラグ
td[0].str_num=5;
td[0].spd_x=0.f;
td[0].spd_y=-1.0f;
td[0].spd_z=0.f;
td[0].type=1;
td[0].flag=1;
//地上側の描画
for(int i=0;i<td[0].str_num;i++)
{
td[0].core[i].flag=1;
td[0].core[i].img_id=1;
td[0].core[i].num=5;
td[0].core[i].angle=-13*PI/36;
//画面に平行な場合はXが基準となる
td[0].core[i].sy=80.0f;
td[0].core[i].sz=-23.f;
td[0].core[i].len=25.0f;
td[0].core[i].from_y=td[0].core[i].sy-3.0f*td[0].core[i].len;
td[0].core[i].start_y=td[0].core[i].sy-1.0f*td[0].core[i].len;
td[0].core[i].end_y=-170.f;
//横に並べる枚数に応じて、並べる方向(今回はX)ごとの中心を計算
td[0].core[i].sx=td[0].center+td[0].set*(i-td[0].str_num/2);
//以上のXYZを実際に各baseに入れていく。
for(int j=0; j< td[0].core[i].num;j++)
{
td_ins_first(td[0].core[i].sx,td[0].core[i].sy,td[0].core[i].sz,td[0].every,0,i,j,td[0].type);
}
}
}
void graph_back00(){//通常背景
SetDrawMode( DX_DRAWMODE_BILINEAR ) ;//ポリゴンが荒く見えないような描画の仕方「バイリニア法」
DrawBox(0,0,640,480,GetColor(200,255,255),TRUE);
for(int n=0;n<TD_MAX;n++)
{
if(td[n].flag==1)
{
SortObject(n);
for(int i=0;i<td[0].str_num;i++)
{
if(td[n].core[i].flag==1)
{
for(int j=0;j<td[n].core[i].num;j++)
{
Vector_ins(td[n].core[i].base[j].vertex,rot[n],td[n].core[i].base[j].x,td[n].core[i].base[j].y,td[n].core[i].base[j].z,
td[n].core[i].len,td[n].core[i].from_y,td[n].core[i].start_y,td[n].core[i].angle,td[n].type);
DrawTransRotatePolygon1(img_back[td[n].core[i].img_id], td[n].core[i].base[j].vertex, 4, p, rot[n]);
Vector_slide(&td[n].core[i].base[j].x,&td[n].core[i].base[j].y,&td[n].core[i].base[j].z,n,
td[n].type,td[n].core[i].from_y,td[n].core[i].sy,td[n].core[i].end_y);
}
}
}
}
}
SetDrawMode(DX_DRAWMODE_NEAREST);//描画方法を元に戻す
}
void graph_back_main(){
graph_back00();
}
//ゲームの初期化
void ini(){
memset(td,0,sizeof(td_t)*TD_MAX);
}
//ループで必ず行う3大処理
int ProcessLoop(){
if(ProcessMessage()!=0)return -1;//プロセス処理がエラーなら-1を返す
if(ClearDrawScreen()!=0)return -1;//画面クリア処理がエラーなら-1を返す
gpUpdateKey();
return 0;
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow){
ChangeWindowMode(TRUE);//ウィンドウモード
if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
while(ProcessLoop()==0){//メインループ
clsDx();
// 切り替え?
if( Key[ KEY_INPUT_SPACE ] == 1 ){
FogSW = !FogSW;
}
// フォグが有効?
if( FogSW ) {
// フォグを有効にする
SetFogEnable( TRUE ) ;
// フォグの色を背景に合わせる
SetFogColor( 200, 255, 255 ) ;
// フォグの開始距離と終了距離を設定する
SetFogStartEnd( 100.0f, 160.0f ) ;
} else {
// フォグを無効にする
SetFogEnable( FALSE ) ;
}
switch(func_state){
case 0://初回のみ入る処理
ini();
load(); //データロード
func_state=100;
break;
case 100://通常処理
graph_back_main();
break;
default:
printfDx("不明なfunc_state\n");
break;
}
if( FogSW ) {
printfDx("フォグが有効。半透明が無効\n");
} else {
printfDx("フォグが無効。半透明が有効\n");
}
ScreenFlip();//裏画面反映
}
DxLib_End();//DXライブラリ終了処理
return 0;
}