上記サイトを参考にしながらSTGを制作しています。
プレイヤーが死ぬと画面下から点滅しながら復帰するように
したのですが、件名の通りプレイヤーが死んだときの描画が残ったまま
下からプレイヤーが復帰してしまいます。
プレイヤーが死んだときの描画を消せる方法を分かる方がいました
教えていただきたいです。お願いします。
[player.cpp]
#include "pch.h"
#include"control.h"
PLAYER::PLAYER()
{
//画像読み込み
if(-1==LoadDivGraph("DATA/CHR/charall_2.png",12,3,4,29,40,gh)){
MSG("エラー発生");
}
width=29;
height=40;
//移動係数
move=1.0f;
//横方向と縦方向のカウント数。
xcount=0,ycount=0;
//添字用変数
ix=0,iy=0,result=0;
//初期位置
x=180;
y=400;
//生死確認
life=true;
//弾初期化
memset(shot, 0, sizeof(shot));
//弾画像読み込み
int temp = LoadGraph("DATA/BG/shot_2.png");
int w, h;
GetGraphSize(temp, &w, &h);
//フラグ全部falseにしとく
//グラッフィックハンドルと画像のサイズを代入しとく
for (int i = 0; i < PSHOT_NUM; ++i)
{
shot[i].flag = false;
shot[i].gh = temp;
shot[i].width = w;
shot[i].height = h;
}
count = 0;
dcount = 0;
damageflag = false;
}
void PLAYER::SetShotFlag(int index, bool flag)
{
shot[index].flag = flag;
}
bool PLAYER::GetShotSound()
{
return s_shot;
}
void PLAYER::GetPosition(double *x, double *y)
{
*x = this->x;
*y = this->y;
}
void PLAYER::Move()
{
if(key[KEY_INPUT_LEFT]==1 || key[KEY_INPUT_RIGHT]==1){
if(key[KEY_INPUT_UP]==1 || key[KEY_INPUT_DOWN]==1){
//移動係数を0.71に設定
move=0.71f;
}else{
//斜めじゃなければ1.0に設定
move=1.0f;
}
}else if(key[KEY_INPUT_UP]==1 || key[KEY_INPUT_DOWN]==1){
move=1.0f;
}
if(key[KEY_INPUT_LEFT]==1){
x-=(int)PLAYER_SPEED*move;
}
if(key[KEY_INPUT_RIGHT]==1){
x+=(int)PLAYER_SPEED*move;
}
if(key[KEY_INPUT_UP]==1){
y-=(int)PLAYER_SPEED*move;
}
if(key[KEY_INPUT_DOWN]==1){
y+=(int)PLAYER_SPEED*move;
}
//左キーが押されてて、かつxcountが0以上なら0にしてから1引く。
//それ以外は1引く
if(key[KEY_INPUT_LEFT]==1){
if(xcount>0)
xcount=0;
--xcount;
}
//右キーが押されてて、かつxcountが0以下なら0にしてから1足す。
//それ以外は1引く
if(key[KEY_INPUT_RIGHT]==1){
if(xcount<0)
xcount=0;
++xcount;
}
//上キーが押されてて、かつycountが0以上なら0にしてから1引く。
//それ以外は1引く
if(key[KEY_INPUT_UP]==1){
if(ycount>0)
ycount=0;
--ycount;
}
//下キーが押されてて、かつycountが0以下なら0にしてから1足す。
//それ以外は1足す
if(key[KEY_INPUT_DOWN]==1){
if(ycount<0)
ycount=0;
++ycount;
}
//カウント数から添字を求める。
ix=abs(xcount)%30/10;
iy=abs(ycount)%30/10;
//xカウントがプラスなら右向きなので2行目の先頭添字番号を足す。
if(xcount>0){
ix+=3;
result=ix;
}else if(xcount<0){
//マイナスなら左向きなので、4行目の先頭添字番号を足す。
ix+=9;
result=ix;
}
//yカウントがプラスなら下向きなので、3行目の先頭添字番号を足す。
if(ycount>0){
iy+=6;
result=iy;
}else if(ycount<0){
//1行目の先頭添字番号は0なので何もする必要なし。(分かりやすくするために書いときました)
iy+=0;
result=iy;
}
//斜め移動の場合は横顔を優先
if(move==0.71f)
result=ix;
//押されてなければカウントをゼロにする。
if(key[KEY_INPUT_LEFT]!=1 && key[KEY_INPUT_RIGHT]!=1){
xcount=0;
}
if(key[KEY_INPUT_UP]!=1 && key[KEY_INPUT_DOWN]!=1){
ycount=0;
}
//< span class="strees">
//キャラの移動制御
if (x > 400 - MARGIN)
{
x = 400 - MARGIN;
}
else if (x < MARGIN)
{
x = MARGIN;
}
if (y > 480 - height / 2 - MARGIN)
{
y = 480 - height / 2 - MARGIN;
}
else if (y < height / 2 + MARGIN)
{
y = height / 2 + MARGIN;
}
//←キーが押されてて、かつxcountが0以上なら0にしてから1引く
//それ以外は1引く
if (key[KEY_INPUT_LEFT] == 1)
{
if (xcount > 0)
xcount = 0;
--xcount;
}
//→キーが押されてて、かつxcountが0以下なら0にしてから1足す
//それ以外は1引く
if (key[KEY_INPUT_RIGHT] == 1)
{
if (xcount < 0)
xcount = 0;
++xcount;
}
//↑キーが押されてて、かつycountが0以下なら0にしてから1足す
//それいがいは1引く
if (key[KEY_INPUT_UP] == 1)
{
if (ycount > 0)
ycount = 0;
--ycount;
}
//↓キーが押されてて、かつycountが0以下なら0にしてから1足す
//それいがいは1足す
if (key[KEY_INPUT_DOWN] == 1)
{
if (ycount < 0)
ycount = 0;
++ycount;
}
//カウント数から添字を求める
ix = abs(xcount) % 30 / 10;
iy = abs(ycount) % 30 / 10;
//xカウントがプラスなら右向きなので2行目の先頭添字番号を足す
if (xcount > 0)
{
ix += 3;
result = ix;
}
else if (xcount < 0)
{
//マイナスなら左向きなので4行目の先頭添字を足す
ix += 9;
result = ix;
}
//yカウントがプラスなら下向きなので,3行目の先頭添字を足す
if (ycount > 0)
{
iy += 6;
result = iy;
}
else if (ycount < 0)
{
//1行目の先頭添字番号は0なので何も刷る必要なし
iy += 0;
result = iy;
}
//斜めの移動の場合は横顔を優先
if (move == 0.71f)
result = ix;
//描画
DrawGraph(x - width / 2, y - height / 2, gh[result], TRUE);
//押されていなければカウントをゼロにする
if (key[KEY_INPUT_LEFT] != 1 && key[KEY_INPUT_RIGHT != 1])
{
xcount = 0;
}
if (key[KEY_INPUT_UP] != 1 && key[KEY_INPUT_DOWN] != 1)
{
ycount = 0;
}
}
void PLAYER::Draw()
{
//弾描画
for (int i = 0; i < PSHOT_NUM; i++)
{
if (shot[i].flag)
{
DrawGraph(shot[i].x - shot[i].width / 2,
shot[i].y - shot[i].height / 2, shot[i].gh, TRUE);
}
}
//生きてれば描画
if(damageflag){
if (dcount > 20) {
if (dcount % 2 == 0) {
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 0);
DrawGraph(PLAYER_INITX - width / 2, PLAYER_INITY - height / 2 + 60 - (dcount - 20), gh[1], TRUE);
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
}
else {
DrawGraph(PLAYER_INITX - width / 2, PLAYER_INITY - height / 2 + 60 - (dcount - 20), gh[1], TRUE);
}
}
++dcount;
if (dcount == 80)
{
damageflag = false;
dcount = 0;
//座標を初期値に戻す
x = PLAYER_INITX;
y = PLAYER_INITY;
//上向きの画像にする
result = 1;
}
else
{
//通常描画
DrawGraph(x - width / 2, y - height / 2, gh[result], TRUE);
}
}
}
void PLAYER::Shot()
{
s_shot = false;
if (!damageflag) {
//キーが押されててかつ、6ループに一回発射
if (key[KEY_INPUT_Z] == 1 && count % 6 == 0) {
for (int i = 0; i < PSHOT_NUM; ++i) {
if (shot[i].flag == false) {
shot[i].flag = true;
shot[i].x = x;
shot[i].y = y;
break;
}
}
//ショットサウンドフラグを立てる
s_shot = true;
}
//弾を移動させる処理
for (int i = 0; i < PSHOT_NUM; ++i) {
//発射してる弾だけ
if (shot[i].flag) {
shot[i].y -= PSHOT_SPEED;
//画面の外にはみ出したらフラグを戻す
if (shot[i].y < -10) {
shot[i].flag = false;
}
}
}
}
}
bool PLAYER::GetShotPosition(int index, double *x, double *y)
{
if (shot[index].flag) {
*x = shot[index].x;
*y = shot[index].y;
return true;
}
else {
return false;
}
}
void PLAYER::SetDamageFlag()
{
damageflag = true;
}
bool PLAYER::GetDamageFlag()
{
return damageflag;
}
void PLAYER::All()
{
//消滅していないときだけ実行
if (!damageflag) {
Move();
}
Shot();
Draw();
count++;
}
[player.h]
class PLAYER{
private:
//x座標,y座標
double x,y;
//画像幅
int width,height;
//グラフィックハンドル格納用配列
int gh[12];
//移動係数
float move;
//横方向と縦方向のカウント数。
int xcount,ycount;
//添字用変数
int ix,iy,result;
//プレイヤーのライフ
int life;
bool damageflag;
bool endflag;
//ダメージ中のカウント
int dcount;
//弾
SHOT shot[PSHOT_NUM];
//カウント
int count;
bool s_shot;
private:
void Move();
void Draw();
void Shot();
public:
PLAYER();
bool GetShotSound();
bool GetShotPosition(int index, double *x, double *y);
void SetShotFlag(int index, bool flag);
void GetPosition(double *x, double *y);
void SetDamageFlag();
bool GetDamageFlag();
void All();
};
[control.cpp]
#include "pch.h"
#include "control.h"
CONTROL::CONTROL()
{
player = new PLAYER;
back = new BACK;
FILE *fp;
ENEMY_DATA data[ENEMY_NUM];
char buf[100];
int c;
int col = 1;
int row = 0;
memset(buf, 0, sizeof(buf));
fp = fopen("DATA/ENEMY/enemydata.csv", "r");
//ヘッダ読み飛ばし
while (fgetc(fp) != '\n');
while (1) {
while (1) {
c = fgetc(fp);
//末尾ならループを抜ける。
if (c == EOF)
goto out;
//カンマか改行でなければ、文字としてつなげる
if (c != ',' && c != '\n')
strcat(buf, (const char*)&c);
//カンマか改行ならループ抜ける。
else
break;
}
//ここに来たということは、1セル分の文字列が出来上がったということ
switch (col) {
//1列目は敵種類を表す。atoi関数で数値として代入。
case 1: data[row].type = atoi(buf); break;
//2列目は弾種類。以降省略。
case 2: data[row].stype = atoi(buf); break;
case 3: data[row].m_pattern = atoi(buf); break;
case 4: data[row].s_pattern = atoi(buf); break;
case 5: data[row].in_time = atoi(buf); break;
case 6: data[row].stop_time = atoi(buf); break;
case 7: data[row].shot_time = atoi(buf); break;
case 8: data[row].out_time = atoi(buf); break;
case 9: data[row].x = atoi(buf); break;
case 10: data[row].y = atoi(buf); break;
case 11: data[row].speed = atoi(buf); break;
case 12: data[row].hp = atoi(buf); break;
case 13: data[row].item = atoi(buf); break;
}
//バッファを初期化
memset(buf, 0, sizeof(buf));
//列数を足す
++col;
//もし読み込んだ文字が改行だったら列数を初期化して行数を増やす
if (c == '\n') {
col = 1;
++row;
}
}
out:
//敵クラス生成
for (int i = 0; i<ENEMY_NUM; ++i)
{
enemy[i] = new ENEMY(data[i].type, data[i].stype, data[i].m_pattern, data[i].s_pattern, data[i].in_time, data[i].stop_time, data[i].shot_time,
data[i].out_time, data[i].x, data[i].y, data[i].speed, data[i].hp, data[i].item);
}
//サウンドファイル読み込み
s_eshot = LoadSoundMem("DATA/SOUND/enemyshot.wav");
s_pshot = LoadSoundMem("DATA/SOUND/magic3.mp3");
s_edead = LoadSoundMem("DATA/SOUND/enemydead.wav");
s_pdead= LoadSoundMem("DATA/SOUND/enemydead.wav");
eshot_flag = false;
pshot_flag = false;
edead_flag = false;
pdead_flag = false;
}
bool CONTROL::CircleCollision(double c1, double c2, double cx1, double cx2, double cy1, double cy2)
{
double hlength = c1 + c2;
double xlength = cx1 - cx2;
double ylength = cy1 - cy2;
if (hlength*hlength >= xlength*xlength + ylength*ylength) {
return true;
}
else {
return false;
}
}
void CONTROL::GetPlayerPosition(double *x, double *y)
{
double tempx, tempy;
player->GetPosition(&tempx, &tempy);
*x = tempx;
*y = tempy;
}
void CONTROL::GetEnemyPosition(int index, double *x, double *y)
{
double tempx, tempy;
//指定した添字の敵の座標を取得
enemy[index]->GetPosition(&tempx, &tempy);
//代入
*x = tempx;
*y = tempy;
}
void CONTROL::All()
{
//サウンドフラグを初期化
eshot_flag = pshot_flag = edead_flag = pdead_flag = false;
//描画領域を指定
SetDrawArea(MARGIN, MARGIN, MARGIN + 380, MARGIN + 460);
back->All();
player->All();
//プレイヤーサウンドフラグチェック
if (player->GetShotSound()) {
pshot_flag = true;
}
/*if (player->GetShotSound()) {
pdead_flag = true;
}*/
for (int i = 0; i<ENEMY_NUM; i++) {
if (enemy[i] != NULL) {
//敵ショットサウンドフラグチェック
if (enemy[i]->GetShotSound()) {
eshot_flag = true;
}
if (enemy[i]->GetDeadSound()) {
edead_flag = true;
}
if (enemy[i]->All()) {
delete enemy[i];
enemy[i] = NULL;
}
}
}
//当たり判定
CollisionAll();
SoundAll();
++g_count;
}
void CONTROL::SoundAll()
{
if (pshot_flag) {
PlaySoundMem(s_pshot, DX_PLAYTYPE_BACK);
}
if (eshot_flag) {
PlaySoundMem(s_eshot, DX_PLAYTYPE_BACK);
}
if (edead_flag) {
PlaySoundMem(s_edead, DX_PLAYTYPE_BACK);
}
}
void CONTROL::CollisionAll()
{
double px, py, ex, ey;
bool tempflag = false;
//操作キャラの弾と敵との当たり判定
for (int i = 0; i<PSHOT_NUM; ++i) {
if (player->GetShotPosition(i, &px, &py)) {
for (int s = 0; s<ENEMY_NUM; ++s) {
//敵クラスのポインタがNULLじゃない、かつdeadflagがfalse(死んでない&帰還してない)
if (enemy[s] != NULL && !enemy[s]->GetDeadFlag()) {
enemy[s]->GetPosition(&ex, &ey);
//当たり判定
if (CircleCollision(PSHOT_COLLISION, ENEMY1_COLLISION, px, ex, py, ey)) {
//当たっていれば、deadflagを立てる
enemy[s]->SetDeadFlag();
//当たった弾のフラグを戻す
player->SetShotFlag(i, false);
//敵消滅音フラグセット
edead_flag = true;
}
}
}
}
}
//敵の弾と操作キャラとの当たり判定
//プレイヤーが生きていれば
if (!player->GetDamageFlag()) {
player->GetPosition(&px, &py);
for (int i = 0; i < ENEMY_NUM; i++) {
if (enemy[i] != NULL) {
for (int s = 0; s < ENEMY_SNUM; s++)
{
//弾フラグが立っていればtrueを返す
if (enemy[i]->GetShotPosition(s, &ex, &ey)) {
//弾によって当たり判定が違うのでswitch文で分岐
switch (enemy[i]->GetShotType()) {
case 0:
//当たっていれば
if (CircleCollision(PLAYER_COLLISION, ESHOT0_COLLISION, px, ex, py, ey))
{
tempflag = true;
}
break;
case 1:
if (CircleCollision(PLAYER_COLLISION, ESHOT1_COLLISION, px, ex, py, ey))
{
tempflag = true;
}
break;
case 2:
if (CircleCollision(PLAYER_COLLISION, ESHOT2_COLLISION, px, ex, py, ey))
{
tempflag = true;
}
break;
}
if (tempflag) {
//操作キャラのdamageflagを立てる
player->SetDamageFlag();
//弾を消す
enemy[i]->SetShotFlag(s,false);
//プレイヤー消滅音フラグを立てる
pdead_flag = true;
//一時フラグを戻す
tempflag = false;
}
}
}
}
}
}
}
CONTROL::~CONTROL()
{
delete player;
delete back;
for (int i = 0; i<ENEMY_NUM; ++i) {
if (enemy[i] != NULL) {
delete enemy[i];
}
}
}
[control.h]
#include "player.h"
#include"back.h"
#include"enemy.h"
#include"title.h"
class CONTROL{
private:
//プレイヤークラス
PLAYER *player;
//背景クラス
BACK *back;
//エネミークラス
ENEMY *enemy[ENEMY_NUM];
//サウンドハンドル
int s_eshot;
int s_pshot;
int s_edead;
int s_pdead;
//サウンドを鳴らすかどうかのフラグ
bool eshot_flag;
bool pshot_flag;
//敵死亡
bool edead_flag;
//プレイヤー死亡
bool pdead_flag;
private:
CONTROL();
~CONTROL();
void SoundAll();
public:
void All();
void GetPlayerPosition(double *x, double *y);
void GetEnemyPosition(int index, double *x, double *y);
static CONTROL& GetInstance() {
static CONTROL control;
return control;
}
bool CircleCollision(double c1, double c2, double cx1, double cx2, double cy1, double cy2);
void CollisionAll();
};
[define.h]
#include <windows.h>
//プレイヤーの歩くスピード
#define PLAYER_SPEED 4
#define PLAYER_INITX 180
#define PLAYER_INITY 400
//座標取得
#define MARGIN 10
//背景スクロールスピード
#define SCROLL_SPEED 2
//弾処理
#define PSHOT_NUM 20
#define PSHOT_SPEED 14
//当たり判定用半径定義
#define PLAYER_COLLISION 4
#define ENEMY1_COLLISION 14
#define PSHOT_COLLISION 3
#define ESHOT0_COLLISION 10
#define ESHOT1_COLLISION 3
#define ESHOT2_COLLISION 2
//メッセージボックス
#define MSG(m) {\
MessageBox(NULL,m,"メッセージ",MB_OK);}
//extern宣言してkey配列にどこからでもアクセスできるようにする
extern char key[256];
extern int g_count;
//プレイヤー弾
struct SHOT
{
bool flag; //弾が発射中かどうか
double x; //x座標
double y; //y座標
int gh; //グラフィックハンドル
int width, height; //画像の幅と高さ
};
//エネミー弾
struct E_SHOT
{
bool flag; //弾が発射中かどうか
double x; //x座標
double y; //y座標
double rad; //角度(ラジアン)
int gh; //グラフィックハンドル
int width, height; //画像の幅と高さ
int pattern; //ショットパターン
int speed; //弾スピード
};
#define ENEMY_SNUM 50
//エネミーデータ
struct ENEMY_DATA
{
int type; //敵種類
int stype; //弾種類
int m_pattern; //移動パターン
int s_pattern; //発射パターン
int in_time; //出現時間
int stop_time; //停止時間
int shot_time; //弾発射時間
int out_time; //帰還時間
int x; //x座標
int y; //y座標
int speed; //弾スピード
int hp; //HP
int item; //アイテム
};
#define ENEMY_NUM 5