コード:
#include "DxLib.h"
#define SCREEN_WIDTH (640) // 画面の横幅
#define SCREEN_HEIGHT (480) // 画面の縦幅
#define CHIP_SIZE (32) // 一つのチップのサイズ
#define MAP_WIDTH (1920 / CHIP_SIZE) // マップの横幅
#define MAP_HEIGHT (SCREEN_HEIGHT / CHIP_SIZE) // マップの縦幅
#define G (0.3F) // キャラに掛かる重力加速度
#define JUMP_POWER (9.0F) // キャラのジャンプ力
#define SPEED (2.0F) // キャラの移動スピード
#define CHAR_SIZE (60) // プレイヤーのサイズ
typedef struct{
int img,muki;
}ch_t;
struct shot{
int x2,y2; //座標
int flag;
};
// マップデータ
char MapData[MAP_HEIGHT][MAP_WIDTH] =
{
0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0,
1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
1,0,0,1,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,1,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,1,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
1,0,0,1,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 0,0,0,1,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 0,0,0,1,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,1,
1,0,0,1,1, 1,1,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 0,0,0,1,1, 1,1,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 0,0,0,1,1, 1,1,0,0,0, 0,0,0,0,0, 0,0,1,0,1,
1,0,0,0,0, 0,0,0,1,1, 0,0,0,0,0, 0,0,1,0,0, 0,0,0,0,0, 0,0,0,1,1, 0,0,0,0,0, 0,0,1,0,0, 1,0,0,0,0, 0,0,0,1,1, 0,0,0,0,0, 0,0,1,0,1,
1,0,0,0,0, 0,0,0,0,0, 0,0,1,1,0, 0,0,1,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,1,1,0, 0,0,1,0,0, 1,0,0,0,0, 0,0,0,0,0, 0,0,1,1,0, 0,0,1,0,1,
1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,0, 1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,1,0,1,
1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
1,0,0,0,0, 0,0,1,1,0, 0,0,0,0,0, 1,0,0,0,0, 0,0,0,0,0, 0,0,1,1,0, 0,0,0,0,0, 1,0,0,0,0, 0,0,0,0,0, 0,0,1,1,0, 0,0,0,0,0, 1,0,0,0,1,
1,0,0,0,0, 1,1,1,1,1, 0,0,0,0,1, 1,0,0,0,0, 0,0,0,0,0, 1,1,1,1,1, 0,0,0,0,1, 1,0,0,0,0, 0,0,0,0,0, 1,1,1,1,1, 0,0,0,0,1, 1,0,0,0,1,
1,1,1,0,0, 1,1,1,1,1, 0,0,0,1,1, 1,0,0,0,0, 0,1,1,0,0, 1,1,1,1,1, 0,0,0,1,1, 1,0,0,0,0, 0,1,1,0,0, 1,1,1,1,1, 0,0,0,1,1, 1,0,0,0,1,
1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
1,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,1,
1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1, 1,1,1,1,1,
} ;
float PlX, PlY ; // プレイヤーの座標(中心座標)
float ElX, ElY ;
float PlDownSp ; // プレイヤーの落下速度
float ElDownSp ;
char PlJumpFlag ; // プレイヤーがジャンプ中か、のフラグ
char walking_flag ;
int Input, EdgeInput ; // 入力状態
int FrameStartTime ; // 60FPS固定用、時間保存用変数
int camerax=0,cameray=0; //カメラ
// マップチップの値を取得する関数
int GetChipParam( float X, float Y ) ;
// キャラクタをマップとの当たり判定を考慮しながら移動する関数
int CharMove( float *X, float *Y, float *DownSP,
float MoveX, float MoveY, float Size, char *JumpFlag ) ;
// アクションサンプルプログラムメイン関数
int ActMain( void ) ;
// マップとの当たり判定( 戻り値 0:当たらなかった 1:左辺に当たった 2:右辺に当たった
// 3:上辺に当たった 4:下辺に当たった
int MapHitCheck( float X, float Y, float *MoveX, float *MoveY ) ;
// WinMain関数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow )
{
//ChangeWindowMode( TRUE ) ;
if( DxLib_Init() == -1 ) // DXライブラリ初期化処理
{
return -1; // エラーが起きたら直ちに終了
}
// アクションゲームのメイン関数を呼ぶ
ActMain() ;
// DXライブラリの後始末
DxLib_End() ;
// 終了
return 0 ;
}
// アクションプログラムメイン
int ActMain( void )
{
ch_t ch;
int Color;
Color=GetColor(255,255,255);
int image[16],image2[16],image1[1],image3[1],image4[1];
char Key[256];
int i=0,counter=0,tmuki=2;
struct shot tama[10];
int HP=5,emo=1;
if( DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1;
for(i=0;i<10;i++){ //初期化処理
tama[i].x2=(int)PlX; tama[i].y2=(int)PlY; //座標代入
tama[i].flag=0; //飛んでいない事を示すフラグ=0
}
// 描画先を裏画面にセット
SetDrawScreen( DX_SCREEN_BACK ) ;
walking_flag=FALSE;
ch.muki=2;
LoadDivGraph( "chara.png" , 16 , 4 , 4 , 60 , 60 , image );
LoadDivGraph( "Mesh.bmp" , 1 , 1 , 1 , 32, 32 , image1);
LoadDivGraph( "hg.png" , 16 , 4 , 4 , 32, 32 , image2);
LoadDivGraph( "blo.png" , 1 , 1 , 1 , 32, 32 , image3);
LoadDivGraph( "sima.png" , 1 , 1 , 1 , 32, 32 , image4);
// 垂直同期信号を待たない
SetWaitVSyncFlag( FALSE ) ;
// プレイヤーの座標を初期化
PlX = 320.0F ; PlY = 240.0F ;
ElX = 300.0F ; ElY = 410.0F ;
// プレイヤーの落下速度を初期化
PlDownSp = 0.0F ;
ElDownSp = 0.0F ;
// ジャンプ中フラグを倒す
PlJumpFlag = FALSE ;
// 入力状態の初期化
Input = 0 ;
EdgeInput = 0 ;
// 60FPS固定用、時間保存用変数を現在のカウント値にセット
FrameStartTime = GetNowCount() ;
// メインループ開始、ESCキーで外に出る
while( ProcessMessage() == 0 && !ClearDrawScreen() && CheckHitKey( KEY_INPUT_ESCAPE ) == 0 && !GetHitKeyStateAll( Key ))
{
DrawFormatString(0,0,Color,"ch.muki=%d",ch.muki);
DrawFormatString(100,0,Color,"tama.muki=%d",tmuki);
// 1/60秒立つまで待つ
while( GetNowCount() - FrameStartTime < 1000 / 60 ){}
// 現在のカウント値を保存
FrameStartTime = GetNowCount() ;
if( (int)PlX%1==0 && (int)PlY%1==0){ //座標が1で割り切れたら入力可能
walking_flag=FALSE;
if ( CheckHitKey( KEY_INPUT_UP ) == 1 ) //上ボタンが押されたら
ch.muki=0; //上向きフラグを立てる
else if( CheckHitKey( KEY_INPUT_LEFT ) == 1 ) //左ボタンが押されたら
ch.muki=1; //左向きフラグを立てる
else if( CheckHitKey( KEY_INPUT_RIGHT ) == 1 ) //右ボタンが押されたら
ch.muki=2; //右向きフラグを立てる
else walking_flag=TRUE;
}
// プレイヤーの移動処理
{
float MoveX, MoveY ;
// 移動量の初期化
MoveX = 0.0F ;
MoveY = 0.0F ;
// 左右の移動を見る
if(walking_flag==FALSE){
if( Key[ KEY_INPUT_LEFT ] == 1 ) MoveX -= SPEED ;
if( Key[ KEY_INPUT_RIGHT ] == 1 ){
if(camerax>350)
MoveX;
else
MoveX += SPEED ;
}
}
// 地に足が着いている場合のみジャンプボタン(ボタン1 or Zキー)を見る
if( PlJumpFlag == FALSE && Key[ KEY_INPUT_SPACE ] == 1 )
{
PlDownSp = -JUMP_POWER ;
PlJumpFlag = TRUE ;
}
// 落下処理
PlDownSp += G ;
// 落下速度を移動量に加える
MoveY = PlDownSp ;
// 移動量に基づいてキャラクタの座標を移動
CharMove( &PlX, &PlY, &PlDownSp, MoveX, MoveY, CHAR_SIZE, &PlJumpFlag ) ;
}
{
if(counter<5) //前にzを押してから5カウント未満なら
counter++; //カウントアップ
else if( Key[ KEY_INPUT_Z ] == 1 ){//5カウント以上たってい
counter=0; //カウンターを戻す
tmuki=ch.muki;
for(i=0;i<10;i++){
if(tama[i].flag==0){ //発射していない玉を探し、
tama[i].flag=1; //発射フラグを立てる
tama[i].x2=(int)PlX;
tama[i].y2=(int)PlY;
break;
}
}
}
if(tmuki==2){
for(i=0;i<10;i++){
if(tama[i].flag==1){ //発射している玉なら
tama[i].x2+=8;
DrawGraph( tama[i].x2 , tama[i].y2 , image2[15] , TRUE );//玉を描画
if(tama[i].x2 > 640){ //もし画面外まで来たら
tama[i].x2=(int)PlX; //初期値に戻し、
tama[i].y2=(int)PlY;
tama[i].flag=0; //発射フラグを戻す
}
if(tama[i].x2 < ElX+12 && tama[i].x2 > ElX-12 &&
tama[i].y2 < ElY+12 && tama[i].y2 > ElY-12 && HP>0){
tama[i].x2=(int)PlX;
tama[i].y2=(int)PlY;
tama[i].flag=0;
HP--;
}
}
}
}
if(tmuki==1){
for(i=0;i<10;i++){
if(tama[i].flag==1){ //発射している玉なら
tama[i].x2-=8;
DrawGraph( tama[i].x2-30 , tama[i].y2 , image2[6] , TRUE );//玉を描画
if(tama[i].x2 < 0){ //もし画面外まで来たら
tama[i].x2=(int)PlX; //初期値に戻し、
tama[i].y2=(int)PlY;
tama[i].flag=0; //発射フラグを戻す
}
if(tama[i].x2-30 < ElX+12 && tama[i].x2-30 > ElX-12 &&
tama[i].y2 < ElY+12 && tama[i].y2 > ElY-12 && HP>0){
tama[i].x2=(int)PlX;
tama[i].y2=(int)PlY;
tama[i].flag=0;
HP--;
}
}
}
}
if(tmuki==0){
for(i=0;i<10;i++){
if(tama[i].flag==1){ //発射している玉なら
tama[i].y2-=8;
DrawGraph( tama[i].x2 , tama[i].y2 , image2[2] , TRUE );//玉を描画
if(tama[i].y2 > 480){ //もし画面外まで来たら
tama[i].x2=(int)PlX; //初期値に戻し、
tama[i].y2=(int)PlY;
tama[i].flag=0; //発射フラグを戻す
}
if(tama[i].x2 < ElX+12 && tama[i].x2 > ElX-12 &&
tama[i].y2 < ElY+12 && tama[i].y2 > ElY-12 && HP>0){
tama[i].x2=(int)PlX;
tama[i].y2=(int)PlY;
tama[i].flag=0;
HP--;
}
}
}
}
}
camerax=(int)PlX;
if(camerax<0) camerax=0;
if(camerax>1920) camerax=1920;
// マップの描画
{
int i, j ;
for( i = 0 ; i < MAP_HEIGHT ; i ++ )
{
for( j = 0 ; j < MAP_WIDTH ; j ++ )
{
// 1は当たり判定チップを表しているので1のところだけ描画
if( MapData[i][j] == 1 )
{
if(camerax>350){
DrawGraph( (int)(j * CHIP_SIZE )-camerax , (int) (i * CHIP_SIZE ) , image1[0] , TRUE ) ;
}
else
DrawGraph( (int)(j * CHIP_SIZE ) , (int) (i * CHIP_SIZE ) , image1[0] , TRUE ) ;
}
}
}
}
if(ch.muki==2)
ch.img=image[( (int)PlX%32)/8];
if(ch.muki==1)
ch.img=image[( (int)PlX%32)/8+4];
// キャラクタの描画
DrawGraph( (int) (PlX - CHAR_SIZE * 0.5F) , (int) (PlY - CHAR_SIZE * 0.5F) , ch.img , TRUE ) ;
{
if(emo==1)
ElX--;
if(emo==0)
ElX++;
if(ElX==400)
emo=1;
if(ElX==50)
emo=0;
}
if(HP>0)
DrawGraph( (int) ElX , (int) ElY , image4[0] , TRUE ) ;
if(PlX>ElX-10 && PlX<ElX+10 && PlY>ElY-10 && PlY<ElY+10 && HP>0)
DxLib_End() ;
// 画面の更新
ScreenFlip() ;
}
// 終了
return 0 ;
}
// キャラクタをマップとの当たり判定を考慮しながら移動する
int CharMove( float *X, float *Y, float *DownSP,
float MoveX, float MoveY, float Size, char *JumpFlag )
{
float Dummy = 0.0F ;
float hsize ;
// キャラクタの左上、右上、左下、右下部分が当たり判定のある
// マップに衝突しているか調べ、衝突していたら補正する
// 半分のサイズを算出
hsize = Size * 0.5F ;
// 先ず上下移動成分だけでチェック
{
// 左下のチェック、もしブロックの上辺に着いていたら落下を止める
if( MapHitCheck( *X - hsize, *Y + hsize, &Dummy, &MoveY ) == 3 ) *DownSP = 0.0F ;
// 右下のチェック、もしブロックの上辺に着いていたら落下を止める
if( MapHitCheck( *X + hsize, *Y + hsize, &Dummy, &MoveY ) == 3 ) *DownSP = 0.0F ;
// 左上のチェック、もしブロックの下辺に当たっていたら落下させる
if( MapHitCheck( *X - hsize, *Y - hsize, &Dummy, &MoveY ) == 4 ) *DownSP *= -1.0F ;
// 右上のチェック、もしブロックの下辺に当たっていたら落下させる
if( MapHitCheck( *X + hsize, *Y - hsize, &Dummy, &MoveY ) == 4 ) *DownSP *= -1.0F ;
if( MapHitCheck( *X , *Y + hsize, &Dummy, &MoveY ) == 3 ) *DownSP = 0.0F ;
// 上下移動成分を加算
*Y += MoveY ;
}
// 後に左右移動成分だけでチェック
{
// 左下のチェック
MapHitCheck( *X - hsize, *Y + hsize, &MoveX, &Dummy ) ;
// 右下のチェック
MapHitCheck( *X + hsize, *Y + hsize, &MoveX, &Dummy ) ;
// 左上のチェック
MapHitCheck( *X - hsize, *Y - hsize, &MoveX, &Dummy ) ;
// 右上のチェック
MapHitCheck( *X + hsize, *Y - hsize, &MoveX, &Dummy ) ;
// 左右移動成分を加算
*X += MoveX ;
}
// 接地判定
{
// キャラクタの左下と右下の下に地面があるか調べる
if( GetChipParam( *X - Size * 0.5F, *Y + Size * 0.5F + 1.0F ) == 0 &&
GetChipParam( *X + Size * 0.5F, *Y + Size * 0.5F + 1.0F ) == 0 )
{
// 足場が無かったらジャンプ中にする
*JumpFlag = TRUE ;
}
else
{
// 足場が在ったら接地中にする
*JumpFlag = FALSE ;
}
}
// 終了
return 0 ;
}
// マップとの当たり判定( 戻り値 0:当たらなかった 1:左辺に当たった 2:右辺に当たった
// 3:上辺に当たった 4:下辺に当たった
// 注意:MoveX と MoveY 、どっちか片方が0じゃないとまともに動作しません(爆)
int MapHitCheck( float X, float Y,
float *MoveX, float *MoveY )
{
float afX, afY ;
// 移動量を足す
afX = X + *MoveX ;
afY = Y + *MoveY ;
// 当たり判定のあるブロックに当たっているかチェック
if( GetChipParam( afX, afY ) != 0 )
{
float blx, bty, brx, bby ;
// 当たっていたら壁から離す処理を行う
// ブロックの上下左右の座標を算出
blx = (float)( (int)afX / CHIP_SIZE ) * CHIP_SIZE ; // 左辺の X 座標
brx = (float)( (int)afX / CHIP_SIZE + 1 ) * CHIP_SIZE ; // 右辺の X 座標
bty = (float)( (int)afY / CHIP_SIZE ) * CHIP_SIZE ; // 上辺の Y 座標
bby = (float)( (int)afY / CHIP_SIZE + 1 ) * CHIP_SIZE ; // 下辺の Y 座標
// 上辺に当たっていた場合
if( *MoveY > 0.0F )
{
// 移動量を補正する
*MoveY = bty - Y - 1.0F ;
// 上辺に当たったと返す
return 3 ;
}
// 下辺に当たっていた場合
if( *MoveY < 0.0F )
{
// 移動量を補正する
*MoveY = bby - Y + 1.0F ;
// 下辺に当たったと返す
return 4 ;
}
// 左辺に当たっていた場合
if( *MoveX > 0.0F )
{
// 移動量を補正する
*MoveX = blx - X - 1.0F ;
// 左辺に当たったと返す
return 1 ;
}
// 右辺に当たっていた場合
if( *MoveX < 0.0F )
{
// 移動量を補正する
*MoveX = brx - X + 1.0F ;
// 右辺に当たったと返す
return 2 ;
}
// ここに来たら適当な値を返す
return 4 ;
}
// どこにも当たらなかったと返す
return 0 ;
}
// マップチップの値を取得する関数
int GetChipParam( float X, float Y )
{
int x, y ;
// 整数値へ変換
x = (int)X / CHIP_SIZE ;
y = (int)Y / CHIP_SIZE ;
// マップからはみ出ていたら 0 を返す
if( x >= MAP_WIDTH || y >= MAP_HEIGHT || x < 0 || y < 0 ) return 0 ;
// 指定の座標に該当するマップの情報を返す
return MapData[ y ][ x ] ;
}