アクションゲームでプレイヤーの後を自動的についてくるキャラクター
Posted: 2012年3月12日(月) 15:48
現在、マリオブラザーズのような画面の横スクロールアクションゲームを作っています。
主人公が増殖してプレイヤーの後をついてくるというようなものなのですが、(カービィのヘルパーのような)
自動的にプレイヤーの後をついてくるキャラクターの処理がうまくいきません。
まずはプレイヤーと同じような地形との判定処理を作って、
それの前に、そのキャラクターの移動判断処理を書いています。
自分で作ってみた移動判断処理をまず箇条書きで書きますと、
(地面での処理)
・地面にいるときにプレイヤーから一定距離 左に離れたらプレイヤーに近づいて右に歩く
・地面にいるときにプレイヤーから一定距離 右に離れたらプレイヤーに近づいて左に歩く
・右に歩いているときに自分の1マス右に障害物があったらジャンプする
・左に歩いているときに自分の1マス左に障害物があったらジャンプする
・右に歩いているときに自分の1マス右の列の一番下のマスが穴だったらジャンプする
・左に歩いているときに自分の1マス左の列の一番下のマスが穴だったらジャンプする
・プレイヤーの近く一定距離まで来たら移動をやめる
(空中での処理)
・1回のジャンプで必ず1マス分はプレイヤーの方向に動かす(踏み外しは除く)
・踏み外した場合は着地まで動かない(穴の場合はジャンプしているはずなので確実に着地する)
・空中で自分の下に地面がなかったらあるところまでプレイヤーの方向に動く
・ジャンプして1マス以上動いてから自分の下に地面があったら移動をやめる
というものなのですが、
簡単なマップならこれでうまくついてきてくれるのですが、これだと分かれ道等はプレイヤーの方向を無視してしまいますし、
縦に進むマップなんて作れなくなってしまいます。
うまくついてきてくれる他の処理や、何か他に良い方法はないのでしょうか?
プレイヤーについてくるキャラのコードです
Zousyoku.cpp
主人公が増殖してプレイヤーの後をついてくるというようなものなのですが、(カービィのヘルパーのような)
自動的にプレイヤーの後をついてくるキャラクターの処理がうまくいきません。
まずはプレイヤーと同じような地形との判定処理を作って、
それの前に、そのキャラクターの移動判断処理を書いています。
自分で作ってみた移動判断処理をまず箇条書きで書きますと、
(地面での処理)
・地面にいるときにプレイヤーから一定距離 左に離れたらプレイヤーに近づいて右に歩く
・地面にいるときにプレイヤーから一定距離 右に離れたらプレイヤーに近づいて左に歩く
・右に歩いているときに自分の1マス右に障害物があったらジャンプする
・左に歩いているときに自分の1マス左に障害物があったらジャンプする
・右に歩いているときに自分の1マス右の列の一番下のマスが穴だったらジャンプする
・左に歩いているときに自分の1マス左の列の一番下のマスが穴だったらジャンプする
・プレイヤーの近く一定距離まで来たら移動をやめる
(空中での処理)
・1回のジャンプで必ず1マス分はプレイヤーの方向に動かす(踏み外しは除く)
・踏み外した場合は着地まで動かない(穴の場合はジャンプしているはずなので確実に着地する)
・空中で自分の下に地面がなかったらあるところまでプレイヤーの方向に動く
・ジャンプして1マス以上動いてから自分の下に地面があったら移動をやめる
というものなのですが、
簡単なマップならこれでうまくついてきてくれるのですが、これだと分かれ道等はプレイヤーの方向を無視してしまいますし、
縦に進むマップなんて作れなくなってしまいます。
うまくついてきてくれる他の処理や、何か他に良い方法はないのでしょうか?
プレイヤーについてくるキャラのコードです
Zousyoku.cpp
#include "DxLib.h"
#include "Keyboard.h"
#include "Player.h"
#include "Map.h"
#include "Zousyoku.h"
extern int CameraX; //現在座標から表示座標への変換用
int Enter; //Enterが1になると一人増えて0に戻る
Zousyoku_t Zousyoku[99]; //最大99人まで増殖
//マップ地形参照マクロ
#define MAP_CHIP(y,x) (MapData.Map[(y)*(MapData.Width)+(x)])
// 初期化をする
void Zousyoku_Initialize(){
Enter=0;
for (int i = 0; i < 99; ++i) //99人分の初期化
{
LoadDivGraph( "Image/Chara/Player1.png" , 16 , 4 , 4 , 32 , 32 , Zousyoku[i].DivImage );//画像の分割読み込み
Zousyoku[i].Flag = 0; //存在フラグ0
Zousyoku[i].Image = Zousyoku[i].DivImage[4]; //プレイヤーの最初の画像
Zousyoku[i].X = 0; //初期X
Zousyoku[i].Y = 0; //初期Y
Zousyoku[i].Walk=0; //歩いていない
Zousyoku[i].Muki=1; //向きが右
Zousyoku[i].WalkCount=0;//歩きカウント0
Zousyoku[i].Speed=0; //スピード0
Zousyoku[i].Accel=0.5; //加速度0.5
Zousyoku[i].Jump=0; //ジャンプしていない
Zousyoku[i].JumpPower=0; //ジャンプ力0
Zousyoku[i].JumpAccel=0.5; //重力0.5
//CPUの判断で増える入力カウント(プレイヤーでいうボタン入力)
Zousyoku[i].RIGHTcount=0;
Zousyoku[i].LEFTcount=0;
Zousyoku[i].Acount=0;
Zousyoku[i].Bcount=0;
Zousyoku[i].Count20=0; //きっちり1マス歩かせるときに使う20フレームカウント
Zousyoku[i].JumpMuki=0; //0:左に向かってジャンプしている 1:右に向かってジャンプしている
Zousyoku[i].Humihazusi=0; //現在のジャンプ状態はは自発ジャンプなのか踏み外しなのか
}
}
// 増殖キャラの動きを計算する
void Zousyoku_Move(Player_t *Player){
//Enterが1になると一人増えて0になる
if(Enter==1){
for(int i = 0; i < 99; i++)
{
if(Zousyoku[i].Flag == 0)
{
//1人の存在フラグを1に
Zousyoku[i].Flag = 1;
//初期位置設定
Zousyoku[i].X = Player->X;
Zousyoku[i].Y = Player->Y;
//プレイヤーとの距離が全員一定にならないようにランダム値を出す
Zousyoku[i].Random = GetRand( 128 );
break;
}
Enter = 0;
}
}
for(int i = 0; i < 99; i++)
{
//現在座標から表示座標への変換
Zousyoku[i].ViewX = Zousyoku[i].X-CameraX;
//存在フラグが1のキャラ全員の処理
if(Zousyoku[i].Flag==1){
//↓自分の現在の位置と地形からどう動くか判断///////////////////////////////////////////////
//(地面)プレイヤーから一定距離(ランダム値+32)左に離れたらプレイヤーに近づいて右に歩く
if(Zousyoku[i].Jump==0 && Player->X-(Zousyoku[i].Random+32) > Zousyoku[i].X){
Zousyoku[i].RIGHTcount++;
//自分の1マス右に障害物があったらジャンプする
if(MAP_CHIP((Zousyoku[i].Y)/32,(Zousyoku[i].X+32)/32)!=0 &&
MAP_CHIP((Zousyoku[i].Y+31)/32,(Zousyoku[i].X+32)/32)!=0){
Zousyoku[i].Acount = 1;
Zousyoku[i].JumpMuki = 1;
}
//自分の1マス右の列の一番下のマスが穴だったらジャンプする
if(MAP_CHIP((383)/32,(Zousyoku[i].X+32)/32)==0 &&
MAP_CHIP((383)/32,(Zousyoku[i].X+63)/32)==0){
Zousyoku[i].Acount = 1;
Zousyoku[i].JumpMuki = 1;
}
}//(地面)プレイヤーから一定距離(ランダム値+32)右に離れたらプレイヤーに近づいて左に歩く
if(Zousyoku[i].Jump==0 && Player->X+(Zousyoku[i].Random+32) < Zousyoku[i].X){
Zousyoku[i].LEFTcount++;
//自分の1マス左に障害物があったらジャンプする
if(MAP_CHIP((Zousyoku[i].Y)/32,(Zousyoku[i].X-1)/32)!=0 &&
MAP_CHIP((Zousyoku[i].Y+31)/32,(Zousyoku[i].X-1)/32)!=0){
Zousyoku[i].Acount = 1;
Zousyoku[i].JumpMuki = 0;
}
//自分の1マス左の列の一番下のマスが穴だったらジャンプする
if(MAP_CHIP((383)/32,(Zousyoku[i].X-32)/32)==0 &&
MAP_CHIP((383)/32,(Zousyoku[i].X-1)/32)==0){
Zousyoku[i].Acount = 1;
Zousyoku[i].JumpMuki = 0;
}
}
//(地面)プレイヤーの近くまで来たら移動をやめる
if(Zousyoku[i].Jump==0 && (Player->X-(Zousyoku[i].Random+32) <= Zousyoku[i].X && Player->X+(Zousyoku[i].Random+32) >= Zousyoku[i].X)){
Zousyoku[i].RIGHTcount = 0;
Zousyoku[i].LEFTcount = 0;
}
//(空中)1回のジャンプで必ず1マス分(20フレーム)は右(プレイヤーの方向)に動かす(踏み外しは除く)
if(Zousyoku[i].Jump==1 && Zousyoku[i].JumpMuki==1 && Zousyoku[i].Humihazusi==0 && Player->X > Zousyoku[i].X){
Zousyoku[i].Count20++;
if(Zousyoku[i].Count20 <= 20)
Zousyoku[i].RIGHTcount++;
}
//(空中)1回のジャンプで必ず1マス分(20フレーム)は左(プレイヤーの方向)に動かす(踏み外しは除く)
if(Zousyoku[i].Jump==1 && Zousyoku[i].JumpMuki==0 && Zousyoku[i].Humihazusi==0 && Player->X < Zousyoku[i].X){
Zousyoku[i].Count20++;
if(Zousyoku[i].Count20 <= 20)
Zousyoku[i].LEFTcount++;
}
//(空中)踏み外した場合は着地まで動かない(穴の場合はジャンプしているはずなので確実に着地する)
if(Zousyoku[i].Jump==1 && Zousyoku[i].Humihazusi==1 ){
Zousyoku[i].RIGHTcount = 0;
Zousyoku[i].LEFTcount = 0;
}
//(空中)自分の下に地面がなかったらあるところまで右(プレイヤーの方向)に動く
if(Zousyoku[i].Jump==1 && Zousyoku[i].JumpMuki==1 && Zousyoku[i].X < Player->X){
if(MAP_CHIP((383)/32,(Zousyoku[i].X)/32)==0 &&
MAP_CHIP((383)/32,(Zousyoku[i].X+31)/32)==0){
Zousyoku[i].RIGHTcount++;
}
}
//(空中)自分の下に地面がなかったらあるところまで左(プレイヤーの方向)に動く
if(Zousyoku[i].Jump==1 && Zousyoku[i].JumpMuki==0 && Zousyoku[i].X > Player->X){
if(MAP_CHIP((383)/32,(Zousyoku[i].X)/32)==0 &&
MAP_CHIP((383)/32,(Zousyoku[i].X+31)/32)==0){
Zousyoku[i].LEFTcount++;
}
}
//(空中)ジャンプして1マス以上動いてから自分の下に地面があったら移動をやめる
if(Zousyoku[i].Jump==1 && Zousyoku[i].Count20 > 20){
if(MAP_CHIP((383)/32,(Zousyoku[i].X)/32)!=0 &&
MAP_CHIP((383)/32,(Zousyoku[i].X+31)/32)!=0){
Zousyoku[i].RIGHTcount = 0;
Zousyoku[i].LEFTcount = 0;
}
}
//着地したら20フレームカウントをリセット
if(Zousyoku[i].Jump==0){
Zousyoku[i].Count20=0;
}
//↓キャラクターの移動処理///////////////////////////////////////////////////////////
//天井との補正
if(Zousyoku[i].JumpPower>0){
if(MAP_CHIP((Zousyoku[i].Y)/32,(Zousyoku[i].X)/32)!=0 ||
MAP_CHIP((Zousyoku[i].Y)/32,(Zousyoku[i].X+31)/32)!=0 ){
Zousyoku[i].Y = (Zousyoku[i].Y/32)*32+32;
}
}
//右との補正
if(MAP_CHIP((Zousyoku[i].Y)/32,(Zousyoku[i].X+31)/32)!=0 ||
MAP_CHIP((Zousyoku[i].Y+31)/32,(Zousyoku[i].X+31)/32)!=0){
Zousyoku[i].X = (Zousyoku[i].X/32)*32;
}
//左との補正
if(MAP_CHIP((Zousyoku[i].Y)/32,(Zousyoku[i].X)/32)!=0 ||
MAP_CHIP((Zousyoku[i].Y+31)/32,(Zousyoku[i].X)/32)!=0){
Zousyoku[i].X = (Zousyoku[i].X/32)*32+32;
}
//天井にぶつかったらジャンプ力を0
if(Zousyoku[i].JumpPower>0 ){
if(MAP_CHIP((Zousyoku[i].Y-1)/32,(Zousyoku[i].X)/32)!=0 ||
MAP_CHIP((Zousyoku[i].Y-1)/32,(Zousyoku[i].X+31)/32)!=0 ){
Zousyoku[i].JumpPower=0;
}
}
//右を押したときに右に壁がなかったら
if( Zousyoku[i].RIGHTcount > 0 ){
if(MAP_CHIP((Zousyoku[i].Y)/32,(Zousyoku[i].X+32)/32)==0 &&
MAP_CHIP((Zousyoku[i].Y+31)/32,(Zousyoku[i].X+32)/32)==0){
Zousyoku[i].Muki=1; //向きを右に
Zousyoku[i].WalkCount++; //歩きカウント増加
Zousyoku[i].Image = Zousyoku[i].DivImage[(Zousyoku[i].WalkCount%32)/8]; //カウントで歩くアニメーション
Zousyoku[i].X += (int)Zousyoku[i].Speed;
Zousyoku[i].Speed += Zousyoku[i].Accel ;//加速度でスピードを増加
}else{ //壁があったら
Zousyoku[i].Speed=0;//スピードを0
Zousyoku[i].Image = Zousyoku[i].DivImage[4]; //止まってる画像
}
}
//右を離したら
if(Zousyoku[i].Muki==1 && Zousyoku[i].RIGHTcount == 0){
Zousyoku[i].Image = Zousyoku[i].DivImage[4]; //止まってる画像
Zousyoku[i].WalkCount=0; //カウント停止
if(MAP_CHIP((Zousyoku[i].Y)/32,(Zousyoku[i].X+32)/32)==0 &&
MAP_CHIP((Zousyoku[i].Y+31)/32,(Zousyoku[i].X+32)/32)==0){
Zousyoku[i].X += (int)Zousyoku[i].Speed;
Zousyoku[i].Speed -= Zousyoku[i].Accel ; //壁がなかったら加速度でスピードを落とす
}else{
Zousyoku[i].Speed=0; //壁があったらスピードを0
}
}
//左を押したときに左に壁がなかったら
if( Zousyoku[i].LEFTcount > 0 ){
if(MAP_CHIP((Zousyoku[i].Y)/32,(Zousyoku[i].X-1)/32)==0 &&
MAP_CHIP((Zousyoku[i].Y+31)/32,(Zousyoku[i].X-1)/32)==0){
Zousyoku[i].Muki=0; //向きを左に
Zousyoku[i].WalkCount++; //歩きカウント増加
Zousyoku[i].Image = Zousyoku[i].DivImage[(Zousyoku[i].WalkCount%32)/8+8];//カウントでアニメーション
Zousyoku[i].X -= (int)Zousyoku[i].Speed;
Zousyoku[i].Speed += Zousyoku[i].Accel ;//加速度でスピードを増加
}else{ //壁があったら
Zousyoku[i].Speed=0;//スピードを0
Zousyoku[i].Image = Zousyoku[i].DivImage[12];
}
}
//左を離したら
if(Zousyoku[i].Muki==0 && Zousyoku[i].LEFTcount == 0){
Zousyoku[i].Image = Zousyoku[i].DivImage[12]; //止まってる画像
Zousyoku[i].WalkCount=0; //カウント停止
if(MAP_CHIP((Zousyoku[i].Y)/32,(Zousyoku[i].X-1)/32)==0 &&
MAP_CHIP((Zousyoku[i].Y+31)/32,(Zousyoku[i].X-1)/32)==0){
Zousyoku[i].X -= (int)Zousyoku[i].Speed;
Zousyoku[i].Speed -= Zousyoku[i].Accel ; //壁がなかったら加速度でスピードを落とす
}else{
Zousyoku[i].Speed=0; //壁があったらスピードを0
}
}
//プレイヤーの速さは最大値2、最小値0
if(Zousyoku[i].Speed <= 0)Zousyoku[i].Speed=0;
if(Zousyoku[i].Speed >= 2)Zousyoku[i].Speed=2;
//ジャンプする
if(Zousyoku[i].Jump==0 && Zousyoku[i].Acount > 0 ){
if(MAP_CHIP((Zousyoku[i].Y-1)/32,(Zousyoku[i].X)/32)==0 &&
MAP_CHIP((Zousyoku[i].Y-1)/32,(Zousyoku[i].X+31)/32)==0 ){
Zousyoku[i].JumpPower = 10;
Zousyoku[i].Jump = 1;
}
}
//歩いてるときに踏み外したらジャンプ状態
if(Zousyoku[i].Jump==0){
if(MAP_CHIP((Zousyoku[i].Y+32)/32,(Zousyoku[i].X)/32)==0 &&
MAP_CHIP((Zousyoku[i].Y+32)/32,(Zousyoku[i].X+31)/32)==0 )
{
Zousyoku[i].Jump=1;
Zousyoku[i].Humihazusi=1;
}
}
//右向いてるジャンプ画像
if(Zousyoku[i].Muki==1 && Zousyoku[i].Jump==1 ){
if(Zousyoku[i].JumpPower > 0){
Zousyoku[i].Image = Zousyoku[i].DivImage[4];
}
if(Zousyoku[i].JumpPower <= 0){
Zousyoku[i].Image = Zousyoku[i].DivImage[4];
}
}
//左向いてるジャンプ画像
if(Zousyoku[i].Muki==0 && Zousyoku[i].Jump==1 ){
if(Zousyoku[i].JumpPower > 0){
Zousyoku[i].Image = Zousyoku[i].DivImage[12];
}
if(Zousyoku[i].JumpPower <= 0){
Zousyoku[i].Image = Zousyoku[i].DivImage[12];
}
}
//ジャンプ中は落下させる
if(Zousyoku[i].Jump==1){
Zousyoku[i].Y-=(int)Zousyoku[i].JumpPower;
Zousyoku[i].JumpPower-=Zousyoku[i].JumpAccel;
}
//床との補正
if(MAP_CHIP((Zousyoku[i].Y+31)/32,(Zousyoku[i].X)/32)!=0 ||
MAP_CHIP((Zousyoku[i].Y+31)/32,(Zousyoku[i].X+31)/32)!=0 ){
Zousyoku[i].Y = (Zousyoku[i].Y/32)*32;
}
//地面についたらジャンプをやめる
if(Zousyoku[i].Jump==1 && Zousyoku[i].JumpPower<0 ){
if(MAP_CHIP((Zousyoku[i].Y+32)/32,(Zousyoku[i].X)/32)!=0 ||
MAP_CHIP((Zousyoku[i].Y+32)/32,(Zousyoku[i].X+31)/32)!=0 ){
Zousyoku[i].JumpPower=0;
Zousyoku[i].Jump=0;
Zousyoku[i].Acount = 0;
Zousyoku[i].Humihazusi=0;
}
}
//画面外に落ちた場合は消えて初期化(存在フラグを0にする)
if(Zousyoku[i].Y >= 384){
Zousyoku[i].Flag = 0;
Zousyoku[i].Image = Zousyoku[i].DivImage[4];
Zousyoku[i].X = 0;
Zousyoku[i].Y = 0;
Zousyoku[i].Walk=0;
Zousyoku[i].Muki=1;
Zousyoku[i].WalkCount=0;
Zousyoku[i].Speed=0;
Zousyoku[i].Accel=0.5;
Zousyoku[i].Jump=0;
Zousyoku[i].JumpPower=0;
Zousyoku[i].JumpAccel=0.5;
Zousyoku[i].RIGHTcount=0;
Zousyoku[i].LEFTcount=0;
Zousyoku[i].Acount=0;
Zousyoku[i].Bcount=0;
Zousyoku[i].Count=0;
Zousyoku[i].RandomJump=0;
Zousyoku[i].Count20=0;
Zousyoku[i].JumpMuki=0;
}
}
}
}
//キャラクター描画
void Zousyoku_Draw(){
for(int i = 0; i < 99; i++)
{
if(Zousyoku[i].Flag == 1)
DrawGraph( Zousyoku[i].ViewX, Zousyoku[i].Y , Zousyoku[i].Image, TRUE ) ;
}
}