root/lang/d/koke/trunk/character.d @ 6347

Revision 6347, 17.5 kB (checked in by itkz, 6 years ago)

update to 7

Line 
1/********************************************************************************/
2/*      character.d                                                                                                                                     */
3/*------------------------------------------------------------------------------*/
4/*      製作              ( ゜ワ゜)ノ / 松久貫太                                                                  */
5/*      製作開始    2008/01/03                                                                                                              */
6/*      MAIL            omega@personal.email.ne.jp                                                                              */
7/*      URL             http://nagoya.cool.ne.jp/o_mega                                                                         */
8/*                                                                                                                                                              */
9/*      このソースは「やわらかライセンス」の元で配布されています。                                   */
10/*-更新履歴---------------------------------------------------------------------*/
11/*      2008/01/04                                                                                                                                      */
12/*-その他-----------------------------------------------------------------------*/
13/*      なし                                                                                                                                              */
14/********************************************************************************/
15
16private import gamecore;
17private import hell2;
18private import boot;
19private import actor;
20private import vector;
21private import keypad;
22private import map;
23
24//********************************************************************************
25// キャラクタ
26//********************************************************************************
27
28class Character : Actor{
29        enum TYPE{
30                NONE = 0,
31                SHADOW = 0,
32                NICOCHU,
33                VC_MK,
34                RAINBOW_RAY,
35                EXPLODE,
36                UP_NUSHI,
37                MAX,
38        }
39        // 名称
40        static string type_name[] =
41                ["SHADOW" , "NICOCHU" , "SOWAKA" , "RAINBOW_RAY" , "EXPLODE" , "UP_NUSHI" , "MAX"];
42        static const double type_movespeed[] =
43                [   0.0 ,  0.03 ,   0.1 ,   0.5 ,     0 ,  0.03 ];              // 移動速度
44        static const bool type_shadow[] =
45                [ false ,  true ,  true , false , false ,  true ];              // 影の有無
46        static const bool type_shake[] =
47                [ false ,  true ,  true , false , false ,  true ];              // 揺れの有無
48        static const int type_life_max[] =
49                [     0 ,    20 ,  9999 ,     0 ,     0 ,    20 ];              // ライフ上限値
50        static const bool type_blocking[] =     
51                [ false ,  true ,  true , false , false ,  true ];              // 衝突判定の有無
52        static const int type_life_dec[] =
53                [         0 ,    40 ,     0 ,     0 ,     0 ,    40 ];          // ライフ減少時間(フレーム)
54       
55        // 方向
56        enum DIRECTION{
57                DOWN = 0,
58                RIGHT,
59                LEFT,
60                UP,
61                MAX,
62        }
63        double vecx[] = [  0 ,  1 , -1 ,  0 ];  // ベクトル
64        double vecy[] = [  1 ,  0 ,  0 , -1 ];
65       
66        // 行動
67        enum MOTION{
68                NORMAL = 0,             // 通常
69                WALK,                   // 移動
70                DAMAGED,                // 非ダメージ
71                SHOOTING,               // 射撃中(ソワカちゃん向け)
72                VANISH,                 // 消失(爆発エフェクト向け)
73                DYING,                  // 死亡中
74                EATING,                 // もぐもぐ中
75                SPAWNING,               // 増殖中
76        }
77        static const int motion_interval[] = [ 0 , 999 , 20 , 2 , 24 , 40 , 20 , 40];
78       
79        DIRECTION direction;    // 方向
80        MOTION motion;                  // モーション
81        int motion_wait;                // モーション待ち時間(フレーム)
82        double move_fraction;   // 移動時の端数(0~1)
83        TYPE type;
84        int timer;
85        Keypad keypad;
86       
87        int life;
88       
89        GameMain gamemain;
90       
91        this(){
92                position = new Vec3();
93                type = TYPE.NICOCHU;
94                move_fraction = 0;
95                timer = 0;
96                direction = DIRECTION.DOWN;
97                motion = MOTION.NORMAL;
98                life = 0;
99        }
100       
101        void init(GameMain gamemain , Vec3 pos , TYPE type){
102                this.gamemain = gamemain;
103                this.position = pos;
104                this.type = type;
105                this.exist = true;
106                this.motion = MOTION.NORMAL;
107                this.move_fraction = 0;
108                this.keypad = null;
109                this.timer = 0;
110               
111                if(type == TYPE.VC_MK) this.keypad = new Keypad();
112                this.life = type_life_max[type];
113        }
114       
115        Vec3 getPosition(){return position;}
116        Vec3 getDestination(){
117                if(motion != MOTION.WALK) return position;
118                return new Vec3(position.x + vecx[direction] , position.y + vecy[direction] , 0);
119        }
120       
121        void move(){
122                timer++;
123               
124                Map map = gamemain.map;
125                int x = cast(int)position.x , y = cast(int)position.y;
126               
127                // 画面外
128                if(x < 0 || y < 0 || x >= map.width || y >= map.height){
129                        exist = false;
130                }
131               
132                // ライフ減少
133                if(type_life_dec[type] > 0 && timer % type_life_dec[type] == 0){
134                        life--;
135                }
136               
137                // モーション管理
138                motion_wait--;
139                if(motion_wait < 1){
140                        motion_wait = 0;
141                        if(motion == MOTION.VANISH || motion == MOTION.DYING) exist = false;
142                        if(motion == MOTION.DYING){
143                                if(map.getGrassLevel(x,y) < 2) map.setGrass(x,y,20);
144                        }
145                        motion = MOTION.NORMAL;
146                }
147               
148                // 死亡モーション遷移
149                if(life < 0  && motion != MOTION.VANISH && motion != MOTION.DYING && type_life_max[type] > 0){
150                        setMotion(MOTION.DYING);
151                        life = 0;
152                }
153                if(motion == MOTION.DYING) return;
154               
155                // キャラクタ固有行動
156                switch(type){
157               
158                        // ニコ厨
159                        case TYPE.NICOCHU:
160                                if(motion == MOTION.NORMAL && Hell_randInt(0,10) < 5){
161                                        if(eatGrass()){
162                                                setMotion(MOTION.EATING);
163                                                selectNewDirection();
164                                        }
165                                }
166                                if(motion == MOTION.EATING) map.setGrass(x,y,0);
167                                if(motion == MOTION.NORMAL){
168                                        int t = Hell_randInt(0,100);
169                                        if(t < configparser.getint("NICOCHU_TURN_RATIO")){
170                                                int gl = cast(int)map.getGrassLevel(x-1,y);
171                                                int gr = cast(int)map.getGrassLevel(x+1,y);
172                                                int gu = cast(int)map.getGrassLevel(x,y-1);
173                                                int gd = cast(int)map.getGrassLevel(x,y+1);
174                                               
175                                                if(gl+gr+gu+gd == 0){
176                                                        selectNewDirection();
177                                                }else{
178                                                        int r = Hell_randInt(0,gl+gr+gu+gd);
179                                                        if(r < gl){
180                                                                direction = DIRECTION.LEFT;
181                                                        }else if(r < gl + gr){
182                                                                direction = DIRECTION.RIGHT;
183                                                        }else if(r < gl + gr + gu){
184                                                                direction = DIRECTION.UP;
185                                                        }else{
186                                                                direction = DIRECTION.DOWN;
187                                                        }
188                                                }
189                                        }
190                                        setMotion(MOTION.WALK);
191                                       
192                                }
193                               
194                                if(timer % (configparser.getint("UPNUSHI_TRANSFORM_INTERVAL") * 40) == 0
195                                        && Hell_randInt(0,100) < configparser.getint("UPNUSHI_TRANSFORM_RATIO") )
196                                {
197                                        exist = false;
198                                       
199                                        Character c = gamemain.charpool.set( new Vec3(position) , TYPE.UP_NUSHI , direction );
200                                }
201                                break;
202                       
203                        // ソワカちゃん
204                        case TYPE.VC_MK:
205                                controlCharacter();
206                                life = type_life_max[type];     // 常時初期ライフ
207                                break;
208                               
209                        // びーむ
210                        case TYPE.RAINBOW_RAY:
211                                if(motion == MOTION.NORMAL) setMotion(MOTION.WALK);
212                                destroyNeigbor();
213                                break;
214                       
215                        // 爆風
216                        case TYPE.EXPLODE:
217                                break;
218                       
219                        // うp主
220                        case TYPE.UP_NUSHI:
221                                if(motion == MOTION.NORMAL){
222                                        if(Hell_randInt(0,10) < 3){
223                                                selectNewDirection();
224                                        }
225                                        setMotion(MOTION.WALK);
226                                }
227                               
228                                if(life < 1){
229                                        map.set(cast(int)position.x , cast(int)position.y , MapChip.TYPE.MOVIE);
230                                        setMotion(MOTION.DYING);
231                                }
232                               
233                                break;
234                       
235                        default:
236                                break;
237                }
238                actCharacter();
239        }
240       
241        // 移動とか汎用処理
242        void actCharacter(){
243                if(motion == MOTION.WALK){
244                        // 移動
245                        move_fraction += type_movespeed[cast(int)type];
246                        if(move_fraction >= 1.0){
247                                move_fraction = 1.0;
248                                position.x = cast(int)toMapXf();
249                                position.y = cast(int)toMapYf();
250                               
251                                move_fraction = 0;
252                                setMotion(MOTION.NORMAL);
253                        }
254                       
255                        // 移動先の確認
256                        int x = cast(int)(position.x + vecx[cast(int)direction]);
257                        int y = cast(int)(position.y + vecy[cast(int)direction]);
258                        if( !gamemain.map.isMovable(x,y) && isBlocking() ){
259                                move_fraction = 0;
260                                setMotion(MOTION.NORMAL);
261                        }
262                }
263        }
264       
265        bool isBlocking(){
266                return type_blocking[type];
267        }
268       
269        // 移動方向をランダム決定する(障害物のない方向を向く)
270        void selectNewDirection(){
271                bool chk;
272                int t = 0;
273                do{
274                        t++;
275                        direction = cast(DIRECTION) Hell_randInt(0,DIRECTION.MAX);
276                        int x = cast(int)(position.x + vecx[direction]);
277                        int y = cast(int)(position.y + vecy[direction]);
278                        chk = gamemain.map.isMovable(x,y);
279                }while(!chk && t < 32);
280        }
281       
282        // ソワカちゃん専用処理(プレーヤー操作)
283        void controlCharacter(){
284                // 七色レーザー発射
285                if(keypad.isPressEnter() && motion != MOTION.SHOOTING){
286                        Character c = gamemain.charpool.set( new Vec3(position) , TYPE.RAINBOW_RAY , direction );
287                        if(c){
288                                c.move_fraction = move_fraction;
289                                setMotion(MOTION.SHOOTING);
290                        }
291                }
292               
293                // パッド操作
294                if(motion == MOTION.NORMAL){
295                        if(move_fraction != 0){
296                                setMotion(MOTION.WALK);
297                                return;
298                        }
299                       
300                        // 移動方向決定
301                        if(keypad.isPressDown()){
302                                direction = DIRECTION.DOWN;
303                                setMotion(MOTION.WALK);
304                        }
305                       
306                        if(keypad.isPressRight()){
307                                direction = DIRECTION.RIGHT;
308                                setMotion(MOTION.WALK);
309                        }
310                       
311                        if(keypad.isPressUp()){
312                                direction = DIRECTION.UP;
313                                setMotion(MOTION.WALK);
314                        }
315                       
316                        if(keypad.isPressLeft()){
317                                direction = DIRECTION.LEFT;
318                                setMotion(MOTION.WALK);
319                        }
320                }
321        }
322       
323        // 芝を食うの図
324        bool eatGrass(){
325                int x = cast(int)position.x , y = cast(int)position.y;
326               
327                if(move_fraction != 0) return false;
328                if(gamemain.map.getGrassLevel(x,y) < 1) return false;   // レベル2以上の芝しか食べない
329               
330                // 芝を食う
331                life += gamemain.map.getGrassLevel(x,y) * 2;
332                if(life >= type_life_max[type]) {
333                        // ライフ上限を超えたらライフを半分にして増殖
334                        life /= 2;
335                       
336                        Character c = gamemain.charpool.set( new Vec3(position.x , position.y , 0) , TYPE.NICOCHU);
337                        if(c){
338                                c.life = life;
339                                while(c.direction == direction){
340                                        c.direction = cast(DIRECTION) Hell_randInt( 0 , DIRECTION.MAX );
341                                }
342                        }
343                }
344                gamemain.map.setGrass(x,y,0);
345                return true;
346        }
347       
348        // ぶっとばすぞー
349        void destroyNeigbor(){
350                for(int x=-1;x<2;x++){
351                        for(int y=-1;y<2;y++){
352                                int px = cast(int)position.x + x;
353                                int py = cast(int)position.y + y;
354                               
355                                if(!gamemain.map.isMap( px , py , MapChip.TYPE.NONE)){
356                                        Character c = gamemain.charpool.set( new Vec3(px , py , 0) , TYPE.EXPLODE);
357                                        if(c){
358                                                c.setMotion(MOTION.VANISH);
359                                        }
360                                }
361                                gamemain.map.set( px , py , MapChip.TYPE.NONE);
362                               
363                                Character ch[] = gamemain.charpool.getCharacterAtMap(px,py);
364                               
365                                foreach(inout c;ch){
366                                        // VC_MKでなく、ライフがあるキャラば爆発しろ!
367                                        if(c && c.exist && c.type != TYPE.VC_MK && type_life_max[c.type] > 0){
368                                                c.destroy();
369                                        }
370                                }
371                        }
372                }
373        }
374       
375        // 爆発しろ
376        void destroy(){
377                exist = false;
378               
379                Character c = gamemain.charpool.set( new Vec3(position) , TYPE.EXPLODE , direction );
380                if(c){
381                        c.move_fraction = move_fraction;
382                        c.setMotion(MOTION.VANISH);
383                }
384        }
385       
386        // モーションセット
387        void setMotion(MOTION m){
388                this.motion = m;
389                this.motion_wait = motion_interval[m];
390        }
391       
392        // 作画
393        void draw(DRAW_PRIORITY dp = DRAW_PRIORITY.NORMAL){
394                if(dp == DRAW_PRIORITY.NORMAL){
395                        Map map = gamemain.map;
396                        double mx = toMapXf() , my = toMapYf();
397                        // アルファブレンド
398                        int alpha = 255;
399                        if(motion == MOTION.DYING) alpha = 255 * motion_wait / motion_interval[motion];
400                       
401                        // 影
402                        if(type_shadow[cast(int)type]){
403                                /* 速度を稼ぐため、下半分だけコピーする */
404                                Hell_drawTexture("char" , map.toViewX(mx,my) , map.toViewY(mx,my) + CHIP_SIZE / 2
405                                        ,CHIP_SIZE * 0 + CHIP_SIZE * 5
406                                        ,CHIP_SIZE * TYPE.SHADOW + CHIP_SIZE / 2
407                                        ,CHIP_SIZE , CHIP_SIZE / 2 , 1 , 1
408                                        ,0,255,255,255,alpha);
409                                /* 本来のコード
410                                Hell_drawTexture("char" , map.toViewX(mx,my) , map.toViewY(mx,my)
411                                        ,CHIP_SIZE * 0 + CHIP_SIZE * 5
412                                        ,CHIP_SIZE * TYPE.SHADOW
413                                        ,CHIP_SIZE , CHIP_SIZE , 1 , 1
414                                        ,0,255,255,255,alpha);
415                                */
416                        }
417                       
418                        int shake = type_shake[cast(int)type] ? ((timer / 8) % 2) : 0 ;
419                        int reverse = (direction == DIRECTION.RIGHT || direction == DIRECTION.UP) ? -1 : 1;
420                        if(motion == MOTION.NORMAL || motion == MOTION.WALK){
421                                // 通常
422                                Hell_drawTexture("char"
423                                        , map.toViewX(mx,my) + (1 - reverse) * CHIP_SIZE / 2 , map.toViewY(mx,my) + shake
424                                        ,CHIP_SIZE * (cast(int)direction / 2) + CHIP_SIZE * 5
425                                        ,CHIP_SIZE * type
426                                        ,CHIP_SIZE , CHIP_SIZE , reverse , 1.0);
427                        }else if(motion == MOTION.DAMAGED){
428                                // ダメージ
429                                if(timer % 4 < 2)
430                                Hell_drawTexture("char"
431                                        , map.toViewX(mx,my) + (1 - reverse) * CHIP_SIZE / 2 , map.toViewY(mx,my)
432                                        ,CHIP_SIZE * (cast(int)direction / 2) + CHIP_SIZE * 5
433                                        ,CHIP_SIZE * type
434                                        ,CHIP_SIZE , CHIP_SIZE , reverse , 1.0);
435                        }else if(motion == MOTION.SHOOTING){
436                                // 射撃
437                                Hell_drawTexture("char"
438                                        , map.toViewX(mx,my) + (1 - reverse) * CHIP_SIZE / 2 , map.toViewY(mx,my)
439                                        ,CHIP_SIZE * (cast(int)direction / 2 + 2) + CHIP_SIZE * 5
440                                        ,CHIP_SIZE * type
441                                        ,CHIP_SIZE , CHIP_SIZE , reverse , 1.0);
442                        }else if(motion == MOTION.VANISH){
443                                // 消失
444                                Hell_drawTexture("char"
445                                        , map.toViewX(mx,my) , map.toViewY(mx,my)
446                                        ,CHIP_SIZE * (timer / 6) + CHIP_SIZE * 5
447                                        ,CHIP_SIZE * type
448                                        ,CHIP_SIZE , CHIP_SIZE);
449                        }else if(motion == MOTION.DYING){
450                                // 死亡
451                                int fly_y = (motion_interval[MOTION.DYING] - motion_wait);
452                                Hell_drawTexture("char"
453                                        , map.toViewX(mx,my) , map.toViewY(mx,my) - CHIP_SIZE / 4 - fly_y
454                                        ,CHIP_SIZE * 6
455                                        ,CHIP_SIZE * 0
456                                        ,CHIP_SIZE , CHIP_SIZE , 1 , 1
457                                        ,0,255,255,255,alpha);
458                                Hell_drawTexture("char"
459                                        , map.toViewX(mx,my) + (1 - reverse) * CHIP_SIZE / 2 , map.toViewY(mx,my) - fly_y
460                                        ,CHIP_SIZE * (cast(int)direction / 2) + CHIP_SIZE * 5
461                                        ,CHIP_SIZE * type
462                                        ,CHIP_SIZE , CHIP_SIZE , reverse , 1
463                                        ,0,255,255,255,alpha);
464                        }else if(motion == MOTION.EATING){
465                                // 食事中
466                                Hell_drawTexture("char"
467                                        , map.toViewX(mx,my) + (1 - reverse) * CHIP_SIZE / 2 , map.toViewY(mx,my) - ((timer / 3) % 2) * 2
468                                        ,CHIP_SIZE * (cast(int)direction / 2) + CHIP_SIZE * 5
469                                        ,CHIP_SIZE * type
470                                        ,CHIP_SIZE , CHIP_SIZE , reverse , 1.0);
471                        }
472                }else{
473                }
474        }
475       
476        // ステータス
477        void drawStatus(){
478                Map map = gamemain.map;
479                double mx = toMapXf() , my = toMapYf();
480                int vx = cast(int)map.toViewX(mx,my);
481                int vy = cast(int)map.toViewY(mx,my);
482               
483                Hell_drawRect(vx - 8 * 11  , vy - 16 , 8 * 12 , 8 * 6 , 0,0, 255,255,255,192);
484                Hell_drawFont(type_name[cast(int)type] , vx - 8 * 10  , vy - 8);
485                Hell_drawFont("LIFE:" ~ std.string.toString(life) , vx - 8 * 10 , vy + 2);
486                Hell_drawFont("TIME:" ~ std.string.toString(timer / 40) , vx - 8 * 10 , vy + 10);
487                //Hell_drawFont("MOT:" ~ std.string.toString(cast(int)motion) , vx - 8 * 10 , vy + 10);
488                //Hell_drawFont("MOW:" ~ std.string.toString(cast(int)motion_wait) , vx - 8 * 10 , vy + 18);
489        }
490       
491        double toMapXf(){
492                return position.x + move_fraction * vecx[cast(int)direction];
493        }
494        double toMapYf(){
495                return position.y + move_fraction * vecy[cast(int)direction];
496        }
497}
498
499
500//********************************************************************************
501// キャラクタプール
502//********************************************************************************
503
504class CharacterPool : ActorPool ! (Character){
505        GameMain gamemain;
506        int width;
507        int height;
508       
509        // キャラクタのバケットソート用クラス
510        class CharacterBacket{
511                const static int BACKET_MAX = 4;
512                Character char_ptr[];
513               
514                this(){
515                        char_ptr = new Character[BACKET_MAX];
516                        init();
517                }
518               
519                void init(){
520                        for(int t=0;t<BACKET_MAX;t++) char_ptr[t] = null;
521                }
522               
523                void entry(inout Character ch){
524                        for(int t=0;t<BACKET_MAX;t++){
525                                if(char_ptr[t] is null){
526                                        char_ptr[t] = ch;
527                                        return;
528                                }
529                        }
530                }
531               
532                // バケット内のキャラを描く
533                void draw(){
534                        for(int t=0;t<BACKET_MAX;t++){
535                                if(char_ptr[t]) char_ptr[t].draw();
536                        }
537                }
538        }
539        CharacterBacket charbacket[];
540       
541        this(GameMain gamemain , int n , int width , int height){
542                this.gamemain = gamemain;
543               
544                this.width = width;
545                this.height = height;
546                this.charbacket = new CharacterBacket[width * height];
547                foreach(inout c;this.charbacket) c = new CharacterBacket();
548               
549                super(n);
550        }
551       
552        // キャラクタ出現
553        Character set(Vec3 pos , Character.TYPE type , Character.DIRECTION direction = Character.DIRECTION.DOWN){
554                Character c = getInstance();
555                if(c){
556                        c.init(gamemain , pos , type);
557                        c.direction = direction;
558                        return c;
559                }else{
560                        return null;
561                }
562        }
563       
564        // キャラクタ数を数える
565        int count(Character.TYPE type = Character.TYPE.NONE){
566                int result = 0;
567                foreach(c;actors){
568                        if(c.exist == true &&(type == Character.TYPE.NONE || c.type == type)) result++;
569                }
570                return result;
571        }
572       
573        void move(){
574                // 動かす
575                super.move();
576                updateBacket();
577        }
578       
579        // バケットソートを更新する
580        void updateBacket(){
581                // バケット初期化
582                foreach(inout c;charbacket) c.init();
583               
584                // バケットソート
585                foreach(inout c;actors){
586                        if(c.exist){
587                                int x = cast(int)(c.toMapXf());
588                                int y = cast(int)(c.toMapYf());
589                                if(!inRange(x,y)) continue;
590                               
591                                charbacket[x + y * width].entry(c);
592                        }
593                }
594        }
595       
596        // ステータス作画(フラグが立っているもののみ)
597        void drawStatus(){
598                foreach(inout c;actors){
599                        if(c.exist) c.drawStatus();
600                }
601        }
602       
603        // 作画(with バケットソート)
604        void drawAtMap(int x,int y){
605                if(!inRange(x,y)) return;
606                charbacket[x + y * width].draw();
607        }
608       
609        // キャラ取得(with バケットソート)
610        Character[] getCharacterAtMap(int x,int y){
611                if(!inRange(x,y)) return null;
612                return charbacket[x + y * width].char_ptr;
613        }
614       
615        // マップ端からランダム進入
616        void entryFromMapBorder(Character.TYPE type){
617                int x,y;
618                int rndkey = Hell_randInt(0 , (width + height));
619               
620                Character c = set( new Vec3() , type);
621                if(!c) return;
622               
623                if(rndkey > width){
624                        // y軸方面から進入
625                        c.position.y = rndkey - width;
626                        if(Hell_randInt(0,10) < 5){
627                                // 左から
628                                c.position.x = 0;
629                                c.direction = Character.DIRECTION.RIGHT;
630                        }else{
631                                // 右から
632                                c.position.x = width - 1;
633                                c.direction = Character.DIRECTION.LEFT;
634                        }
635                }else{
636                        // x軸方向から進入
637                        c.position.x = rndkey;
638                        if(Hell_randInt(0,10) < 5){
639                                // 上から
640                                c.position.y = 0;
641                                c.direction = Character.DIRECTION.DOWN;
642                        }else{
643                                // 下から
644                                c.position.y = height - 1;
645                                c.direction = Character.DIRECTION.UP;
646                        }
647                }
648        }
649       
650        // キャラクタを取り除く
651        void removeCharacter(Character.TYPE type){
652                foreach(inout c;actors){
653                        if(c.exist && c.type == type) c.exist = false;
654                }
655        }
656       
657        bool inRange(int x,int y){
658                if(x < 0 || y < 0 || x >= width || y >= height) return false;
659                return true;
660        }
661}
Note: See TracBrowser for help on using the browser.