14歳からはじめるC言語わくわくゲームプログラミング教室」という参考書で勉強しています。自分で新しくマップを作ったのですが、ジャンプする位置によって、壁をすり抜けてしまい、凸部分で前の壁をすり抜け、後ろの壁にあたって、落ちてゲームオーバーといいった状態になってしまいます。
#include "myhelper.h"
#include "mymain.h"
#include "stage1.h"
//ステージ切り替え用の関数ポインタ
void (*pf_initgamefunc)() = InitializeGame01;
void (*pf_drawenemyfunc)() = DrawEnemies01;
BOOL (*pf_checkclearfunc)() = CheckClearJyouken01;
//前回のキーの状態を記録する
BOOL g_akey_previous = FALSE;
BOOL g_bkey_previous = FALSE;
//自キャラのデータ
Point2D g_jikipos = {40, 340}; //自キャラの座標
Vector g_jikivector = {0, 0}; //自キャラのベクトル
BOOL g_direction = DIRECTION_RIGHT; //自キャラの向き
BOOL g_nowsit = FALSE; //現在しゃがみ中か否か
BOOL g_nowjumping = FALSE; //現在ジャンプ中か否か
//自キャラの武器
Weapon g_weapons[MAXWEAPON];
//敵キャラのデータ
int g_usedenemy_num = 0; //実際に使用する数
Enemy g_enemies[MAXENEMY];
//地面を表す線
int g_usedline_num = 1; //実際に使用している線の数
Line2D g_landlines[MAXLANDLINE];
//画像ハンドル
int g_jikiimage[11];
int g_backimage;
int g_wallimage;
int g_weaponimage;
int g_bulletimage;
int g_titleimage;
int g_clashimage[3];
int g_hitimage;
//音声ファイル
int g_backmusic; //バックで再生する音楽
//効果音
int g_clip1, g_clip2, g_clip3, g_clip4, g_clip5;
//爆発などの一時アニメーション表示
SplashAnimation g_splashes[MAXSPLASH];
//ゲーム状態の記録
GameState g_gamestate = GAME_TITLE;
//一時アニメーションの表示関数
void DrawSplash(){
for (int i=0; i<MAXSPLASH; i++ ){
if ( g_splashes[i].used == TRUE ){
DrawAnimation( g_splashes[i].position.x,
g_splashes[i].position.y,
1, 0, g_splashes[i].hanten,
g_splashes[i].imgarray,
g_splashes[i].allframe,
g_splashes[i].fps);
//表示時間を超えたら終了
if ( (GetNowCount() & INT_MAX) - g_splashes[i].starttime
> g_splashes[i].life ){
g_splashes[i].used = FALSE;
}
}
}
}
//一時アニメーションのセット
void SetSplash(SplashAnimation sp){
sp.used = TRUE; //念のため
sp.starttime = (GetNowCount() & INT_MAX); //表示開始時間設定
for (int i=0; i<MAXSPLASH; i++ ){
if ( g_splashes[i].used == FALSE ){
g_splashes[i] = sp;
}
}
}
/*地面との当たり判定
当たり判定を行うBall2Dの配列と要素数を与え、衝突していればTRUEを返す。
*/
bool CollisionLandLines( Ball2D *ballarray, int ballnum,
Line2D **pphitland, Line2D **pphitwall ){
bool result = FALSE;
Line2D *presultland = NULL;
Line2D *presultwall = NULL;
for(int i=0; i<g_usedline_num; i++){
for(int j=0; j<ballnum; j++){
//衝突チェック
if ( HitTestLineAndBall(g_landlines[i], ballarray[j]) == TRUE ){
//衝突した線が90度±20度の場合、その線は壁とみなす
if ( PIE/2.0 - fabs(g_landlines[i].katamuki) < PIE/9.0f){
result = TRUE;
if (presultwall == NULL) presultwall = &g_landlines[i];
} else {
//そうでないなら地面
//地面に対して円の中心が上側にあるかチェック
if ( IsPointAtLineFace(g_landlines[i],
ballarray[j].position) == TRUE ){
result = TRUE;
if (presultland == NULL) presultland = &g_landlines[i];
}
}
}
}
}
//Line2Dを返す
if (pphitland != NULL) *pphitland = presultland;
if (pphitwall != NULL) *pphitwall = presultwall;
return result;
}
//武器の発射処理
void ShootWeapon(){
for (int i=0; i<MAXWEAPON; i++){
if (g_weapons[i].used == FALSE){
//左右共通の初期値セット
g_weapons[i].used = TRUE;
g_weapons[i].position = g_jikipos;
g_weapons[i].movec = WEAPONSPEED;
g_weapons[i].hanten = g_direction;
//g_directionがFALSEなら右、TRUEなら左へ発射
if (g_direction==TRUE){
g_weapons[i].movec.x = -WEAPONSPEED.x;
SetSimpleTimer(0, 200);
PlaySoundMem(g_clip2, DX_PLAYTYPE_BACK);
}
break;
}
}
}
//武器の表示と移動
void DrawWeapon(){
for (int i=0; i<MAXWEAPON; i++){
if (g_weapons[i].used == TRUE){
g_weapons[i].position = AddVectorInFrameTime(
g_weapons[i].position, g_weapons[i].movec );
DrawAnimation(
g_weapons[i].position.x, g_weapons[i].position.y,
1, 0, g_weapons[i].hanten, &g_weaponimage, 1, 1.0f);
//武器が画面範囲から出たらusedをFALSEにする
if ( HitTestPointAndBox(g_framerect, g_weapons[i].position)
== FALSE ){
g_weapons[i].used = FALSE;
}
}
}
}
/*敵と武器、自キャラの当たり判定
自キャラが消滅したらTRUEを返す*/
bool CollisionCharacter(){
for (int i=0; i<g_usedenemy_num; i++){
if (g_enemies[i].used == TRUE){
Rect2D b = { {g_enemies[i].position.x - 20, g_enemies[i].position.y-50},
{g_enemies[i].position.x + 20, g_enemies[i].position.y+70},
40,120
};
//敵と武器の当たり判定
for (int j=0; j<MAXWEAPON; j++){
if (g_weapons[j].used == TRUE){
Line2D w = { {g_weapons[j].position.x - WEAPONVECTOR.x/2,
g_weapons[j].position.y - WEAPONVECTOR.y/2},
{g_weapons[j].position.x + WEAPONVECTOR.x/2,
g_weapons[j].position.y + WEAPONVECTOR.y/2}
};
if ( HitTestLineAndRect(w,b) == TRUE ){
//衝突したら敵のライフを1減らす
g_enemies[i].life--;
//敵消滅
if ( g_enemies[i].life == 0 ) {
g_enemies[i].used = FALSE;
//敵消滅時アニメーションの表示
Vector v = {15,0};
SplashAnimation clashsp = {
TRUE,
250, //0.25秒
0, //現在時間はSetSplash側で設定
AddVector(g_enemies[i].position, v),
g_clashimage,
3,
12.0f,
!(g_weapons[i].hanten)
};
SetSplash(clashsp);
PlaySoundMem(g_clip4, DX_PLAYTYPE_BACK);
}else{
if (g_enemies[i].life > 0 ){
//ヒット時アニメーションの表示
SplashAnimation hitsp = {
TRUE,
100, //0.1秒
0, //現在時間はSetSplash側で設定
g_enemies[i].position,
&g_hitimage,
1,
1.0f,
!(g_weapons[i].hanten)
};
SetSplash(hitsp);
PlaySoundMem(g_clip3, DX_PLAYTYPE_BACK);
}
//どちらの条件も満たさない(つまりlifeが最初から負の値)のときは
//敵は武器が当たってもダメージを受けない
}
g_weapons[j].used = FALSE;
//lifeが最初から負の値のときは
//敵は武器が当たってもダメージを受けない
}
}
}
//敵と自キャラの当たり判定
Rect2D m = { {g_jikipos.x - 20, g_jikipos.y-50},
{g_jikipos.x + 20, g_jikipos.y+70},
40,120
};
if(HitTestRectAndRect(b,m) == TRUE){
return TRUE;
}
}
}
return FALSE;
}
/*ゲーム状態切り替え用のグローバル変数と関数群*/
//ゲームオーバー状態に移行する
Point2D gmbodypos; //ゲームオーバー用の自キャラ座標
Vector gmbodyspd; //移動速度
void GoGameOver(){
//すでにゲームオーバー状態なら即脱出
if (g_gamestate == GAME_OVER) return;
gmbodypos = g_jikipos;
gmbodyspd = JUMPMOVEC;
if (g_direction == DIRECTION_RIGHT){
gmbodyspd.x = -40.0f;
} else {
gmbodyspd.x = 40.0f;
}
g_jikipos.y = 10000000;
g_jikivector.x = 0;
g_jikivector.y = 0;
g_gamestate = GAME_OVER;
SetSimpleTimer(31,7000);
StopSoundMem( g_backmusic );
PlaySoundMem( g_clip5, DX_PLAYTYPE_BACK );
}
//ゲームクリアー状態に移行する
void GoGameClear(){
//すでにゲームクリアー状態なら即脱出
if (g_gamestate == GAME_CLEAR) return;
g_gamestate = GAME_CLEAR;
SetSimpleTimer(31,7000);
StopSoundMem( g_backmusic );
}
//ゲームタイトル状態に移行する
void GoGameTitle(){
//すでにゲームタイトル状態なら即脱出
if (g_gamestate == GAME_TITLE) return;
g_gamestate = GAME_TITLE;
StopSoundMem( g_backmusic );
}
//ゲームスタート状態に移行する
void GoGameMain(){
//すでにゲーム中なら即脱出
if (g_gamestate == GAME_MAIN) return;
//ここにステージ切り替え?
pf_initgamefunc(); //データ初期化
g_gamestate = GAME_MAIN;
PlaySoundMem( g_clip1, DX_PLAYTYPE_BACK );
PlaySoundMem( g_backmusic, DX_PLAYTYPE_LOOP );
}
//ゲームオーバー、ゲームクリアー、ゲームタイトル画面の描画
void DrawGameOver(){
gmbodypos = AddVectorInFrameTime(gmbodypos, gmbodyspd);
gmbodyspd = AddVectorInFrameTime(gmbodyspd, GRAVITY);
DrawAnimation(gmbodypos.x, gmbodypos.y,
1, 0, g_direction, &g_jikiimage[5], 1, 1.0f);
if ( GetPassedTime(31)> -5000) {
int col = GetColor(255,0,0);
SetFontSize(100);
SetFontThickness(9);
ChangeFontType(DX_FONTTYPE_EDGE);
int x = 320 - GetDrawStringWidth("GAMEOVER",8)/2;
DrawString(x,160, "GAMEOVER", col);
}
if ( GetPassedTime(31)>0 ) GoGameTitle();
}
void DrawGameClear(){
if ( GetPassedTime(31)> -5000) {
int col = GetColor(0,255,255);
SetFontSize(100);
SetFontThickness(9);
ChangeFontType(DX_FONTTYPE_EDGE);
int x = 320 - GetDrawStringWidth("GAMECLEAR",9)/2;
DrawString(x,160, "GAMECLEAR", col);
}
if ( GetPassedTime(31)>0 ) GoGameTitle();
}
void DrawGameTitle(){
DrawRotaGraph(320,140, 1,0, g_titleimage, TRUE, FALSE);
int col = GetColor(255,0,255);
SetFontSize(32);
SetFontThickness(9);
int x = 320 - GetDrawStringWidth("PUSH Z KEY",10)/2;
DrawString(x,300, "PUSH Z KEY", col);
//キー入力チェック
int key = GetJoypadInputState(DX_INPUT_KEY_PAD1);
if (key & PAD_INPUT_A){
if (g_akey_previous == FALSE){
g_akey_previous = TRUE;
GoGameMain();
}
}else{
g_akey_previous = FALSE;
}
//ステージ切り替え
if ( CheckHitKey(KEY_INPUT_1) == 1 ){
pf_initgamefunc = InitializeGame01;
pf_drawenemyfunc = DrawEnemies01;
pf_checkclearfunc = CheckClearJyouken01;
}
}
//ゲームメイン描画
void DrawGameMain(){
//背景描画
DrawGraph(0,0, g_backimage, FALSE);
//地形を描画
DrawAnimation(g_stagesize.width/2 , g_stagesize.height/2,
1, 0, FALSE, &g_wallimage, 1, 1.0f);
#ifdef _DEBUG
for( int i=0; i<g_usedline_num; i++ ){
DrawLine2D(g_landlines[i], GetColor(128,128,128), 4);
}
#endif
//敵の処理の呼び出し
pf_drawenemyfunc();
Vector curvec1 = {0,0} ;
int key = GetJoypadInputState( DX_INPUT_KEY_PAD1 );
if (key & PAD_INPUT_LEFT) {
curvec1 = AddVector( curvec1, LEFTMOVEC );
g_direction = DIRECTION_LEFT;
}
if (key & PAD_INPUT_RIGHT){
curvec1 = AddVector( curvec1, RIGHTMOVEC );
g_direction = DIRECTION_RIGHT;
}
if(key & PAD_INPUT_DOWN){
g_nowsit = TRUE;
}else{
g_nowsit = FALSE;
}
//地面との当たり判定
BOOL ontheground = FALSE; //着地フラグ
Ball2D jikifeet[2] = {
{ {g_jikipos.x - 8, g_jikipos.y + 55} , 8},
{ {g_jikipos.x + 8, g_jikipos.y + 55} , 8}
};
Line2D *phitland, *phitwall;
bool hit = CollisionLandLines( jikifeet, 2, &phitland, &phitwall );
if (hit == TRUE){
//地面としてヒットした線があるかチェック
if ( phitland != NULL ){
//自キャラが下方向に移動しているかチェックする
g_jikivector.x = 0;
if ( (g_nowjumping == TRUE) ){
//ジャンプ中
if ( g_jikivector.y > 0 ){
g_jikivector.y = 0;
g_nowjumping = FALSE;
}
} else {
//非ジャンプ中
g_jikivector.y = 0;
}
ontheground = TRUE;
//線の傾きを反映
curvec1 = RotateVector(curvec1, phitland->katamuki);
}
//壁としてヒットした線があるかチェック
if ( phitwall != NULL ){
//もし移動方向に壁があるなら、その方向に移動できないようにする
Point2D curpos = { g_jikipos.x, g_jikipos.y+26 };
Line2D myline1 = { curpos,
AddVector(curpos, g_jikivector) };
Line2D myline2 = { curpos,
AddVector(curpos, curvec1) };
if( (HitTestLineAndLine(myline1, *phitwall) == TRUE) ||
(HitTestLineAndLine(myline2, *phitwall) == TRUE) ){
curvec1.x = 0;
curvec1.y = 0;
g_jikivector.x = 0;
}
}
}
//ジャンプ処理
if (key & PAD_INPUT_A){
if ( g_akey_previous == FALSE ){
curvec1 = AddVector( curvec1, JUMPMOVEC );
g_nowjumping = TRUE;
g_akey_previous = TRUE;
}
} else {
g_akey_previous = FALSE;
}
//弾の発射・移動
if (key & PAD_INPUT_B) {
if (g_bkey_previous == FALSE){
ShootWeapon();
//武器を発射したらその時点の移動はストップする
curvec1.x = 0;
curvec1.y = 0;
g_bkey_previous = TRUE;
}
} else {
g_bkey_previous = FALSE;
}
DrawWeapon();
//自キャラ座標の計算
if ( ontheground == TRUE ){
//接地時
g_jikivector = AddVector( g_jikivector, curvec1 );
} else {
//ジャンプ中
g_jikivector = AddVectorInFrameTime( g_jikivector, GRAVITY );
if(g_jikivector.y > 400) g_jikivector.y = 400;
}
//自キャラ座標の計算
g_jikipos = AddVectorInFrameTime( g_jikipos, g_jikivector);
//自キャラの描画
if( (key & PAD_INPUT_B) && (GetPassedTime(0) < 500) ){
//武器の発射
DrawAnimation(g_jikipos.x,g_jikipos.y, 1, 0, g_direction,
&g_jikiimage[6],2, 4.0f);
}else{
if ( g_nowsit == FALSE ){
if ( fabs(curvec1.x) > ZEROVALUE ){
//歩く
DrawAnimation( g_jikipos.x,g_jikipos.y, 1, 0, g_direction,
&g_jikiimage[1],4, 10 );
}else{
//停止状態
DrawAnimation( g_jikipos.x,g_jikipos.y, 1, 0, g_direction,
&g_jikiimage[0],1, 12 );
}
}else{
DrawAnimation(g_jikipos.x,g_jikipos.y,1,0,g_direction,
&g_jikiimage[8],1,12);
}
}
//スプラッシュアニメーションの表示
DrawSplash();
//スクロール
if (XInView(g_jikipos.x) <= SCROLL_LIMIT) ScrollToLeft(g_jikipos.x);
if (XInView(g_jikipos.x) >= 639 - SCROLL_LIMIT) ScrollToRight(g_jikipos.x);
if (YInView(g_jikipos.y) <= SCROLL_LIMIT) ScrollToUp(g_jikipos.y);
if (YInView(g_jikipos.y) >= 479 - SCROLL_LIMIT) ScrollToDown(g_jikipos.y);
//終了判定
if ( g_gamestate == GAME_MAIN ){
//敵と武器、自キャラの当たり判定
if ( CollisionCharacter() == TRUE ) GoGameOver();
//自キャラが画面外に落ちてもゲームオーバー
if ( g_jikipos.y > 1000 ) GoGameOver();
//ゲームクリアチェック
if (pf_checkclearfunc() == TRUE) GoGameClear();
}
}
//メインループ
void MyMain(){
switch(g_gamestate){
case GAME_TITLE:
DrawGameTitle();
break;
case GAME_MAIN:
DrawGameMain();
break;
case GAME_OVER:
DrawGameMain();
DrawGameOver();
break;
case GAME_CLEAR:
DrawGameMain();
DrawGameClear();
break;
}
}
//マップ用のラインデータを読み込む関数
int LoadMap(char *pfname){
int f; //ファイルハンドル
char buf[1024]; //テキスト一時読み込み一時バッファ
f = FileRead_open(pfname);
if (f==0) return -1; //読み込みエラー
g_usedline_num = 0;
while( FileRead_eof(f) == 0 ) //終端チェック
{
// 一行読み込み
FileRead_gets( buf, 1023, f ) ;
int sx,sy,ex,ey;
sscanf_s(buf, "%d,%d,%d,%d", &sx, &sy, &ex, &ey);
Line2D l = {
{(float)sx, (float)sy}, {(float)ex, (float)ey},
0, {0,0}};
SetLine2DKatamuki(&l);
g_landlines[g_usedline_num] = l;
g_usedline_num++;
}
// ファイルを閉じる
FileRead_close( f ) ;
return 0;
}
//色々なファイルの読み込み
int LoadFiles(){
//画像ファイルの読み込み
if (LoadDivGraph("media\\player.bmp",
11,6,2,113,134,g_jikiimage) == -1) return -1;
g_weaponimage = LoadGraph("media\\weapon01.bmp", 0);
if (g_weaponimage == -1) return -1;
g_titleimage = LoadGraph("media\\title01.bmp", 0);
if (g_titleimage == -1) return -1;
if (LoadDivGraph("media\\clash01.bmp",
3,3,1,64,106,g_clashimage) == -1) return -1;
g_hitimage = LoadGraph("media\\hit01.bmp", 0);
if (g_hitimage == -1) return -1;
//音楽ファイルの読み込み
g_backmusic = LoadSoundMem("media\\music02.wav");
if (g_backmusic == -1) return -1;
g_clip1 = LoadSoundMem("media\\power33.wav");
if (g_clip1 == -1) return -1;
g_clip2 = LoadSoundMem("media\\swing25_c.wav");
if (g_clip2 == -1) return -1;
g_clip3 = LoadSoundMem("media\\hit_p07.wav");
if (g_clip3 == -1) return -1;
g_clip4 = LoadSoundMem("media\\crash18_d.wav");
if (g_clip4 == -1) return -1;
g_clip5 = LoadSoundMem("media\\fall05.mp3");
if (g_clip5 == -1) return -1;
//ゲームの初期化
pf_initgamefunc();
return 1;
}