スクロールを作ってみた。
もちろんスクロールもタスク化。
多重スクロールは、スクロールタスクをたくさん作るだけでいいので簡単。解像度を320x240にしてみたが、やっぱり解像度は高い方がいいね。
素材はHamCorossamさんから借りました。
今回実行ファイルは無し。
ソースは以下。スクロール部分は、引数にスクロールスピード(小数点、負の数も可)、BG画像ファイル名などを指定して関数を呼び出すようにしてある。
#include "DxLib.h" #include <assert.h> // ワークエリアのサイズ、タスク数 #define WORK_SIZE 256 #define NUM_TASKS 1024 // fps調整用 #define FLAME 60 // タスクの構造体 struct TASK { // 処理関数へのポインタ void (*Func)(TASK* task); // 前後のタスクへのポインタ TASK* Prev; TASK* Next; // ワークエリア char Work[WORK_SIZE]; }; // 処理関数の型宣言 typedef void (*FUNC)(TASK* task); // タスクの連結リスト TASK* ActiveTask; TASK* FreeTask; //============================================================== // タスクリストの初期化 void InitTaskList() { // タスク用メモリの確保 TASK* task=new TASK[NUM_TASKS+2]; // アクティブタスクリストの初期化 ActiveTask=&task[0]; ActiveTask->Prev=ActiveTask->Next=ActiveTask; // フリータスクリストの初期化 FreeTask=&task[1]; for (int i=1; i<NUM_TASKS+1; i++) task[i].Next=&task[i+1]; task[NUM_TASKS+1].Next=FreeTask; } // タスクの実行 void RunTask() { for (TASK *task=ActiveTask->Next, *next; next=task->Next, task!=ActiveTask; task=next) (*task->Func)(task); } // タスクの生成 TASK* CreateTask(FUNC func) { // フリータスクリストが空ならば生成を中止する if (FreeTask->Next==FreeTask) return NULL; // フリータスクを1個取り出す TASK* task=FreeTask->Next; FreeTask->Next=task->Next; // 処理関数と前後タスクへのポインタを設定する task->Func=func; task->Prev=ActiveTask->Prev; task->Next=ActiveTask; // 前後タスクのポインタを変更する task->Prev->Next=task; task->Next->Prev=task; // 生成したタスクを返す return task; } // タスクの削除 void DeleteTask(TASK* task) { // アクティブタスクリストからタスクを削除する task->Prev->Next=task->Next; task->Next->Prev=task->Prev; // 削除したタスクをフリータスクリストに挿入する task->Next=FreeTask->Next; FreeTask->Next=task; } // プレイヤーキャラに関する構造体と関数 struct MAN_WORK { float X, Y; // 座標 int D; // 停止、移動状態 int SP; // 速さ int gh[7]; // 画像ハンドル }; // プレイヤーキャラのプロトタイプ宣言 void ManMove(TASK* task); // プレイヤーの生成 void CreateMan(float x, float y,int s) { // タスクを生成する TASK* task=CreateTask(ManMove); if (!task) return; // ワークエリアへのポインタをキャストする assert(sizeof(MAN_WORK)<=WORK_SIZE); MAN_WORK* work=(MAN_WORK*)task->Work; // 画像を読み込み int man[7]; LoadDivGraph( "running.bmp" , 7 , 7 , 1 , 24 , 32 , man );//画像を分割してimage配列に保存 // ワークエリアに初期値を設定する work->X=x; work->Y=y; work->D=0; work->SP=s; for(int i=0;i<7;i++) { work->gh[i] = man[i]; } } // プレイヤーの移動 void ManMove(TASK* task) { // ワークをキャスト MAN_WORK* work=(MAN_WORK*)task->Work; // 状態にあった画像を描画 DrawGraph( (int)work->X , (int)work->Y , work->gh[(int)(work->D / 10)+3] , TRUE ) ;//画像を描画 // 状態を変更 work->D ++; work->D %= 30; //少しずつ移動 work->X += work->SP; if(work->X>639) { work->X-=640; work->SP=GetRand(6)+1; work->Y=(float)GetRand(480); } } // fpsに関する構造体 struct FPS_WORK { int COUNT,T,AVE,COUNT0,F[FLAME]; // カウンタ、現在時間、ウェイト用基準時刻、平均値 }; // fpsのプロトタイプ宣言 void fps(TASK* task); // fpsタスクの生成 void createFps() { // タスクを生成する TASK* task=CreateTask(fps); if (!task) return; // ワークエリアへのポインタをキャストする assert(sizeof(FPS_WORK)<=WORK_SIZE); FPS_WORK* work=(FPS_WORK*)task->Work; // ワークエリアに初期値を設定する work->COUNT=0; work->T=0; work->AVE=0; } // fps表示関数 void fps(TASK* task){ // ワークをキャスト FPS_WORK* work=(FPS_WORK*)task->Work; int term; // 待ち時間 // ウェイト処理 if(work->COUNT==0) { // 60フレームの1回目なら if(work->T==0) // 完全に最初なら待たない term = 0; else //前回記録した時間をもとに計算 term = work->COUNT0 + 1000 - GetNowCount(); } else // 待つべき時間=現在あるべき時刻 - 現在の時刻 term = (int)(work->COUNT0 + work->COUNT * (1000.0/FLAME)) - GetNowCount(); if(term>0) // 待つべき時間だけ待つ Sleep(term); int gnt=GetNowCount(); if(work->COUNT==0) //60フレームに1回基準を作る work->COUNT0=gnt; work->F[work->COUNT]=gnt-work->T;//1周した時間を記録 work->T=gnt; //fpsの平均計算 if(work->COUNT%FLAME==FLAME-1){ work->AVE=0; for(int i=0;i<FLAME;i++) work->AVE+=work->F[i]; work->AVE/=FLAME; } if(work->AVE!=0){ DrawFormatString(0, 0,GetColor(255,255,255),"%.1fFPS",1000.0/(double)work->AVE); DrawFormatString(0,20,GetColor(255,255,255),"%dms" ,work->AVE); } //カウンタを増やす work->COUNT = (++work->COUNT)%FLAME; } // // スクロールに関する構造体と関数 // struct SCROLLBG_WORK { float x,y; // 表示座標 int sizex,sizey; // 画像サイズ float ssx,ssy; // スクロールスピード int gh; // 画像ハンドル }; // スクロールのプロトタイプ宣言 void scrollBg(TASK* task); // スクロールの生成 void createScrollBg(float x, float y,float sx,float sy,char *f) { int sizex,sizey; // タスクを生成する TASK* task=CreateTask(scrollBg); if (!task) return; // ワークエリアへのポインタをキャストする assert(sizeof(SCROLLBG_WORK)<=WORK_SIZE); SCROLLBG_WORK* work=(SCROLLBG_WORK*)task->Work; // 画像を読み込み int gh; gh = LoadGraph(f) ; // 画像サイズ取得 GetGraphSize( gh , &sizex , &sizey ) ; // ワークエリアに初期値を設定する work->x=x; work->y=y; work->sizex=sizex; work->sizey=sizey; work->gh=gh; work->ssx=sx; work->ssy=sy; } // スクロール void scrollBg(TASK* task) { // ワークをキャスト SCROLLBG_WORK* work=(SCROLLBG_WORK*)task->Work; // BGの部分描画 SetDrawArea( 0 , 0 , 256 , 240 ) ;//描画可能エリアを設定 DrawRectGraph( 0, 0, work->x, work->y, 256, 240, work->gh, TRUE, FALSE ) ; DrawRectGraph( 0, work->sizey - work->y , 0, 0, 256, 240, work->gh, TRUE, FALSE ) ; SetDrawArea( 0 , 0 , 320 , 240 ) ;//描画可能エリアを設定 // スクロール処理 work->x += work->ssx; if(work->x < 0) { work->x = work->sizex + work->x; } if(work->x > work->sizex-1) { work->x = work->x - work->sizex; } work->y += work->ssy; if(work->y < 0) { work->y = work->sizey + work->y; } if(work->y > work->sizey-1) { work->y = work->y - work->sizey; } } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){ char Key[256]; if( ChangeWindowMode(TRUE) != DX_CHANGESCREEN_OK || DxLib_Init() == -1 ) return -1; //ウィンドウ化と初期化処理 // 初期化フルスクリーン //if( DxLib_Init() == -1 ) return -1; // 画面モード変更 SetGraphMode( 320 , 240 , 32 ) ; //タスクリストを初期化 InitTaskList(); // 描画先を裏画面に設定 SetDrawScreen( DX_SCREEN_BACK ) ; // スクロールタスクを生成 createScrollBg(0,0,0,-1,"bg_01.bmp"); // fps表示タスクを生成 createFps(); while(!ProcessMessage() && !ClearDrawScreen() && !GetHitKeyStateAll( Key ) && !Key[KEY_INPUT_ESCAPE]){ //↑メッセージ処理 ↑画面をクリア ↑キーボード入力状態取得 ↑ESCが押されると終了 RunTask(); ScreenFlip(); } DxLib_End(); return 0; }