コード:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "DxLib.h"
#define WINDOWWIDTH 960
#define WINDOWHEIGHT 540
#define COLORBIT 32
#define REFRESHRATE 60
#define PCNUM 16
#define STAGESIZE 4000
#define M_PI 3
// 座標
struct VEC {
double x; // x軸
double y; // y軸
double z; // z軸
};
// 回転
struct ROT {
double v; // 垂直
double h; // 水平
double t; // 捻り
};
// 画像用ハンドル
struct GRAPHHANDLE {
int Screen; // 画面
};
// キャラ情報
struct PC {
VEC PPos; // 一つ前の位置の座標
VEC Pos; // 現在位置の座標
VEC NPos; // 移動先の座標
ROT Rot; // 角度
ROT RotTar; // 目標角度
};
// カメラ情報
struct CAMERA {
VECTOR Pos,NPos; // 現在座標
ROT Rot,RotTar; // 角度
ROT Spd; //回転速度
double Radius; //周回半径
};
// ゲーム情報
struct GAME {
int Frame;
};
// シェーダ管理用
struct SHADER {
int Gray;
};
// 構造体実体
PC Pc[PCNUM];
CAMERA Camera;
GAME Game;
SHADER Shader;
GRAPHHANDLE GraphHandle;
// その他グローバル変数
int PlayerID; // 私の操るキャラクタ(カメラはこのキャラクタを軸にして移動する
//キャラを描画
void PcDraw(void){
for(int i=0;i<PCNUM;i++){
DrawSphere3D(VGet(Pc[i].Pos.x,Pc[i].Pos.y,Pc[i].Pos.z),30,32,GetColor(0,255,0),GetColor(255,255,0),1);
}
}
//マップを描画(マップの端を示す線を引くだけ)
void MapDraw(void){
// 標準ライトの方向
SetLightDirection(VGet(0.29f,-0.58f,-0.58f));
//ステージ範囲区域を描画
DrawLine3D(VGet(-STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),VGet(STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(-STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),VGet(STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(-STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),VGet(STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(-STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),VGet(STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(-STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),VGet(-STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),VGet(STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),VGet(STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(-STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),VGet(-STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(-STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),VGet(-STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(STAGESIZE/2,-STAGESIZE/2,-STAGESIZE/2),VGet(STAGESIZE/2,-STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),VGet(STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
DrawLine3D(VGet(-STAGESIZE/2,STAGESIZE/2,-STAGESIZE/2),VGet(-STAGESIZE/2,STAGESIZE/2,STAGESIZE/2),GetColor(255,255,255));
}
// 初期化
void Init(void){
// 初期設定
SetGraphMode(WINDOWWIDTH,WINDOWHEIGHT,COLORBIT,REFRESHRATE);
ChangeWindowMode(TRUE), DxLib_Init(), SetDrawScreen(DX_SCREEN_BACK);
// Zバッファへの書き込みを有効にする
SetUseZBuffer3D(TRUE);
SetWriteZBuffer3D(TRUE);
// ピクセルシェーダバイナリコードの読み込み
Shader.Gray = LoadPixelShader("Shader/GrayScale.pso");
}
// キャラクタの初期化
void PcInit(void){
// ゲームに存在するすべてのキャラに対して
for(int i=0;i<PCNUM;i++){
// 座標
Pc[i].Pos.x=GetRand(30000)/10.0-1500.0;
Pc[i].Pos.y=GetRand(10000)/10.0-500.0;
Pc[i].Pos.z=GetRand(30000)/10.0-1500.0;
Pc[i].PPos=Pc[i].Pos;
// 向き
Pc[i].Rot.v=-atan2(-Pc[i].Pos.y,hypot(-Pc[i].Pos.z,-Pc[i].Pos.x));
Pc[i].Rot.h=atan2(-Pc[i].Pos.x,-Pc[i].Pos.z);
Pc[i].Rot.t=0.0;
}
}
// カメラの初期化
void CameraInit(void){
// 視点角度
Camera.Rot=Pc[PlayerID].Rot;
Camera.RotTar=Camera.Rot;
// 周回半径
Camera.Radius=300.0f;
// 座標
Camera.Pos.x = Pc[PlayerID].Pos.x-(Camera.Radius*sin(Camera.Rot.v+1.0f/2.0f*M_PI)*cos(1.0f/2.0f*M_PI-Camera.Rot.h))+(100.0f*sin(Camera.Rot.v)*sin(Camera.Rot.h));
Camera.Pos.z = Pc[PlayerID].Pos.z-(Camera.Radius*sin(Camera.Rot.v+1.0f/2.0f*M_PI)*sin(1.0f/2.0f*M_PI-Camera.Rot.h))+(100.0f*sin(Camera.Rot.v)*cos(Camera.Rot.h));
Camera.Pos.y = Pc[PlayerID].Pos.y-(Camera.Radius*cos(Camera.Rot.v+1.0f/2.0f*M_PI))+100.0f*cos(Camera.Rot.v);
// カメラ反映
SetupCamera_Perspective(M_PI/3);
SetCameraPositionAndAngle(VGet(Camera.Pos.x,Camera.Pos.y,Camera.Pos.z),Camera.Rot.v,Camera.Rot.h,Camera.Rot.t);
}
// ゲーム情報の初期化
void PlayInit(void){
// 初期化
PlayerID=0; // 私の操るキャラクタ(カメラはこのキャラクタを軸にして移動する
PcInit();
CameraInit();
}
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int){
static VERTEX2DSHADER Vert[6];
// 初期化
Init();
PlayInit();
// ループ処理
while(ScreenFlip()==0&&ProcessMessage()==0&&ClearDrawScreen()==0){
static VERTEX2DSHADER Vert[6];
// 頂点データの準備
if(Game.Frame==0){
// 描写可能な画像を作成
SetUseDivGraphFlag(FALSE);
SetDrawValidAlphaChannelGraphCreateFlag(TRUE);
int ScreenWidth=1;
do{ ScreenWidth*=2; }while(ScreenWidth<WINDOWWIDTH);
GraphHandle.Screen=MakeScreen(ScreenWidth,ScreenWidth,0);
SetDrawValidAlphaChannelGraphCreateFlag(FALSE);
SetUseDivGraphFlag(TRUE);
Vert[ 0 ].pos = VGet( 0.0f, 0.0f, 0.0f ) ;
Vert[ 1 ].pos = VGet( 1024.0f, 0.0f, 0.0f ) ;
Vert[ 2 ].pos = VGet( 0.0f, 1024.0f, 0.0f ) ;
Vert[ 3 ].pos = VGet( 1024.0f, 1024.0f, 0.0f ) ;
Vert[ 0 ].dif = GetColorU8( 255,255,255,255 ) ;
Vert[ 0 ].spc = GetColorU8( 0,0,0,0 ) ;
Vert[ 1 ].dif = GetColorU8( 255,255,255,255 ) ;
Vert[ 1 ].spc = GetColorU8( 0,0,0,0 ) ;
Vert[ 2 ].dif = GetColorU8( 255,255,255,255 ) ;
Vert[ 2 ].spc = GetColorU8( 0,0,0,0 ) ;
Vert[ 3 ].dif = GetColorU8( 255,255,255,255 ) ;
Vert[ 3 ].spc = GetColorU8( 0,0,0,0 ) ;
Vert[ 0 ].u = 0.0f ; Vert[ 0 ].v = 0.0f ;
Vert[ 1 ].u = 1.0f ; Vert[ 1 ].v = 0.0f ;
Vert[ 2 ].u = 0.0f ; Vert[ 2 ].v = 1.0f ;
Vert[ 3 ].u = 1.0f ; Vert[ 3 ].v = 1.0f ;
Vert[ 0 ].su = 0.0f ; Vert[ 0 ].sv = 0.0f ;
Vert[ 1 ].su = 1.0f ; Vert[ 1 ].sv = 0.0f ;
Vert[ 2 ].su = 0.0f ; Vert[ 2 ].sv = 1.0f ;
Vert[ 3 ].su = 1.0f ; Vert[ 3 ].sv = 1.0f ;
Vert[ 0 ].rhw = 1.0f ;
Vert[ 1 ].rhw = 1.0f ;
Vert[ 2 ].rhw = 1.0f ;
Vert[ 3 ].rhw = 1.0f ;
Vert[ 4 ] = Vert[ 2 ] ;
Vert[ 5 ] = Vert[ 1 ] ;
}
// グレースケール化した画像を作成
SetDrawScreen(GraphHandle.Screen);
ClearDrawScreen();
// カメラの再設定
SetupCamera_Perspective(M_PI/3);
SetCameraPositionAndAngle(VGet(Camera.Pos.x,Camera.Pos.y,Camera.Pos.z),Camera.Rot.v,Camera.Rot.h,Camera.Rot.t) ;
// 描写
MapDraw(); // マップ描画
PcDraw(); // キャラクタ描写
// 描写対象を元に戻す
SetDrawScreen(DX_SCREEN_BACK);
// カメラも元に戻す
SetupCamera_Perspective(M_PI/3);
SetCameraPositionAndAngle(VGet(Camera.Pos.x,Camera.Pos.y,Camera.Pos.z),Camera.Rot.v,Camera.Rot.h,Camera.Rot.t);
// 使用するテクスチャをセット
SetUseTextureToShader(0, GraphHandle.Screen);
// 使用するピクセルシェーダをセット
SetUsePixelShader(Shader.Gray);
// シェーダに定数セット(単に徐々に透明になる処理
int cindex = GetConstIndexToShader("Alpha", Shader.Gray);
float alpha;
alpha=((float)(300.0f-Game.Frame)/255.0f);
FLOAT4 Alpha = {1.0f, 1.0f, 1.0f, alpha};
SetPSConstF(cindex, Alpha);
// 描画
SetDrawBlendMode(DX_BLENDMODE_ALPHA,0);
DrawPrimitive2DToShader( Vert, 6, DX_PRIMTYPE_TRIANGLELIST );
SetDrawBlendMode(DX_BLENDMODE_NOBLEND,0);
// ↑の描画と↓の描画は完全に重なるはず! なのに重ならない。のが今回の質問の本質。
MapDraw(); // マップ描画
PcDraw(); // キャラクタ描写
// ゲーム内時間加算
Game.Frame++;
}
DxLib_End(); // 後処理
return 0;
}