-
Notifications
You must be signed in to change notification settings - Fork 1
/
UTyping.cpp
4773 lines (4191 loc) · 135 KB
/
UTyping.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "DxLib.h"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <deque>
#include <bitset>
#include <list>
using namespace std;
/* ============================================================ */
/* 雑多な関数 */
#include "ututil.h"
/* ============================================================ */
#include "utchallenge.h"
/* ============================================================ */
#define COLOR_EXCELLENT GetColor(255, 255, 0)
#define COLOR_GOOD GetColor(0, 255, 0)
#define COLOR_FAIR GetColor(0, 128, 255)
#define COLOR_POOR GetColor(128, 128, 128)
#define COLOR_EXCELLENT2 GetColor(255, 255, 128)
#define COLOR_GOOD2 GetColor(128, 255, 128)
#define COLOR_FAIR2 GetColor(128, 192, 255)
#define COLOR_POOR2 GetColor(192, 192, 192)
#define COLOR_TIME GetColor(64, 192, 255)
#define COLOR_TIME2 GetColor(192, 192, 192)
#define COLOR_RED_ZONE GetColor(255, 32, 0)
#define COLOR_YELLOW_ZONE GetColor(224, 255, 0)
#define COLOR_BLUE_ZONE GetColor(0, 64, 255)
#define COLOR_CLEAR_ZONE GetColor(255, 255, 255)
#define SEC_EXCELLENT 0.02
#define SEC_GOOD 0.05
#define SEC_FAIR 0.10
#define SEC_POOR 0.20
#define SCORE_EXCELLENT 1500
#define SCORE_GOOD 1000
#define SCORE_FAIR 500
#define SCORE_POOR 0
#define SCORE_COMBO 10
#define SCORE_COMBO_MAX 1000
#define SCORE_TYPING 500
/* タイピングで1文字確定させるごとに(1バイト文字、2バイト文字を問わない) */
#define GAUGE_COUNT 100
#define GAUGE_RED_ZONE 15
#define GAUGE_YELLOW_ZONE 45
#define GAUGE_CLEAR_ZONE 75
/*
failed:0
red :(0,RED]
yellow:(RED,YELLOW]
blue :(YELLOW,CLEAR]
clear :(CLEAR,COUNT]
*/
#define NAME_LEN 16
#define TYPE_BUFFER_LEN NAME_LEN
/* タイピングに用いるバッファの長さ */
/* 名前の最大長に等しい、変換のために最低4文字は必要 */
#define H_COMMENT 240
/* 【コメントの幅(高さ)はRANKING_LEN 位分を描画するときと同じ】だった */
#define H_MUSIC_INFO_SUB (6+H_COMMENT+4+H_PLAY_DATA+6)
#define MUSIC_INFO_HEIGHT 60
/* 曲情報の幅(高さ) */
/* ============================================================ */
/* 描画位置など */
#define CIRCLE_SPEED 250.0
/* 流れる円の標準の速さ(ドット/秒) */
#define X_SCORE (W_WINDOW - 25)
#define Y_SCORE 70
#define X_STAT_GAUGE (W_WINDOW - 10)
#define W_STAT_GAUGE 400
#define Y_STAT_GAUGE 10
#define H_STAT_GAUGE 40
#define X_GAUGE 90
//#define W_GAUGE 500
#define W_GAUGE_SEGMENT 5
#define W_GAUGE (W_GAUGE_SEGMENT * GAUGE_COUNT)
#define Y_GAUGE 455
#define H_GAUGE 10
#define W_GAUGE_PADDING 4
#define H_GAUGE_PADDING 2
#define X_TIME X_GAUGE
#define W_TIME W_GAUGE
#define Y_TIME 445
#define H_TIME 4
#define X_INFO 160
#define Y_INFO 10
//#define Y_INFO2 40
#define X_CIRCLE 100
#define Y_CIRCLE 180
#define R_CIRCLE 30
#define Y0_BAR (Y_CIRCLE - 60)
#define Y1_BAR (Y_CIRCLE + 50)
#define Y0_BEAT (Y_CIRCLE - 45)
#define Y1_BEAT (Y_CIRCLE + 40)
#define X_ACCURACY (X_CIRCLE - R_CIRCLE)
/* 円の左端 */
#define Y_ACCURACY 90
#define Y_LYRICS (Y_CIRCLE + R_CIRCLE + 30)
#define X_LYRICS_KANJI 100
/* これの左に"Next: ", 右に歌詞を書く */
#define Y_LYRICS_KANJI (Y_LYRICS + 35)
#define Y_LYRICS_KANJI_NEXT (Y_LYRICS + 70)
#define X_LYRICS_BIG (X_CIRCLE - R_CIRCLE)
#define Y_LYRICS_BIG 350
#define X_BUFFER (X_CIRCLE - R_CIRCLE)
#define Y_BUFFER 390
#define X_HIDDEN (X_CIRCLE + R_CIRCLE + 60)
/* Hiddenで見える左の限界 */
#define X_SUDDEN (X_HIDDEN + R_CIRCLE)
/* Suddenで見える右の限界 */
/* 両方かけたときに、ちょうど半円ぐらい見える */
#define SCALE_FUNCTION 60.0
/* 判定位置の円を原点とする座標と思うときの、長さ1に相当する画面の長さ */
#define SEC_FADEOUT 1.2
/* 終わってからスコア表示画面に移行する前にフェードアウトする時間 */
/* ============================================================ */
#define W_WINDOW 640
#define H_WINDOW 480
/* ============================================================ */
#define INFTY 1000000000
enum{
ID_EXCELLENT,
ID_GOOD,
ID_FAIR,
ID_POOR,
ID_PASS,
};
enum{
ID_FAILED_ZONE,
ID_RED_ZONE,
ID_YELLOW_ZONE,
ID_BLUE_ZONE,
ID_CLEAR_ZONE,
};
enum{
PHASE_READY, /* 開始前 */
PHASE_MAIN, /* メイン */
PHASE_FADEOUT, /* MAIN終了後フェードアウト */
PHASE_RESULT, /* スコア表示 */
PHASE_FINISHED, /* 名前入力後(ハイスコア処理完了) */
PHASE_EXIT, /* 終わったので消してもらう */
};
enum{
BEATLINE_BAR,
BEATLINE_BEAT,
};
/* ============================================================ */
/* グローバル変数とか */
int g_fontHandleDebug;
/* ============================================================ */
double myGetNowHiPerformanceCount(){
static LARGE_INTEGER Frequency = {0, 0};
static LARGE_INTEGER PerformanceCount0; /* 最初に呼び出した時の値を保存 */
LARGE_INTEGER PerformanceCount;
if(Frequency.QuadPart == 0){
if(!QueryPerformanceFrequency(&Frequency)){
throw "高分解能パフォーマンスカウンタが取得できません。";
}
QueryPerformanceCounter(&PerformanceCount0);
}
QueryPerformanceCounter(&PerformanceCount);
return (double)(PerformanceCount.QuadPart - PerformanceCount0.QuadPart)
/ Frequency.QuadPart;
}
/* ============================================================ */
#include "utcheck.h"
/* ============================================================ */
#include "utconfig.h"
/* Config */
/* ============================================================ */
static bool g_isUsingDxLib = false;
int myDxLib_Init(){
int ret;
if(!g_isUsingDxLib){
ret = DxLib_Init();
g_isUsingDxLib = true;
}else{
ret = 0;
}
/* ダブルバッファを用いる */
SetDrawScreen(DX_SCREEN_BACK);
ClearDrawScreen();
g_check.begin(GetColor(16, 16, 16));
return ret;
}
int myDxLib_End(){
int ret;
if(g_isUsingDxLib){
ret = DxLib_End();
g_isUsingDxLib = false;
}else{
ret = 0;
}
g_check.end();
return ret;
}
int myScreenFlip(){
static int count = 0;
static double fps = -1.0;
static double timeCountBegin;
if(g_config.f_showFPS){
if(count == 0){
timeCountBegin = myGetNowHiPerformanceCount();
}else if(count == 30){
double timeCountEnd = myGetNowHiPerformanceCount();
fps = 30.0 / (timeCountEnd - timeCountBegin);
/* x[us] のとき 30/(x/1000000) = 30000000/x */
/* てか、x[s]のとき30/x */
count = 0;
timeCountBegin = timeCountEnd;
}
count++;
if(fps >= 0.0){
char buf[256];
sprintf(buf, "[%4.1ffps]", fps);
int width = GetDrawStringWidthToHandle(buf, strlen(buf), g_fontHandleDebug);
DrawStringToHandle(W_WINDOW - width, 0, buf, GetColor(255, 255, 255), g_fontHandleDebug);
/* 右上にfps表示 */
}
}
if(g_config.f_debugMode){ /* デバッグモードなら左上に書いておく */
DrawStringToHandle(0, 0, "Debug Mode", GetColor(255, 0, 0), g_fontHandleDebug);
}
int ret0, ret1;
g_check.rap(GetColor(16, 16, 16));
ret0 = ScreenFlip();
g_check.end();
g_check.begin(GetColor(32, 32, 32));
ret1 = ClearDrawScreen();
g_check.rap(GetColor(16, 16, 16));
if(g_config.f_showProcessTime){
g_check.draw();
}
return (ret0 == -1 || ret1 == -1) ? -1 : 0;
}
/* ============================================================ */
#include "utkeyinput.h"
/*
char GetKeyboardInput(){
return GetInputChar(TRUE);
}
char GetKeyboardInput(double &timeCount){
return GetInputChar(TRUE);
}
//*/
/* configを参照して分岐 */
/*
char GetKeyboardInput(){
if(g_config.f_useMultiThread){
return MT_GetKeyboardInput();
}else{
return ST_GetKeyboardInput();
}
}
char GetKeyboardInput(double &timeCount){
if(g_config.f_useMultiThread){
return MT_GetKeyboardInput(timeCount);
}else{
return ST_GetKeyboardInput(timeCount);
}
}
*/
/* ============================================================ */
#include "utscore.h"
/* score,ranking */
/* ============================================================ */
#define CEFFECT1_SEC_CLEAR 0.6
#define CEFFECT1_FONT_SIZE 40
class CEffect1{
public:
CEffect1();
~CEffect1();
void clear();
void insert(int x, int y, char *str, int color, double time);
void insert(int x, int y, char ch, int color, double time);
void draw(double time);
private:
int m_fontHandle;
struct Data{
int x, y;
char str[20];
int color;
double time;
int strWidth;
};
deque<Data> m_deq;
};
CEffect1::CEffect1(){
m_fontHandle = CreateFontToHandle("MS 明朝", CEFFECT1_FONT_SIZE, 2, DX_FONTTYPE_ANTIALIASING);
}
CEffect1::~CEffect1(){
DeleteFontToHandle(m_fontHandle);
}
void CEffect1::clear(){
m_deq.clear();
}
void CEffect1::insert(int x, int y, char *str, int color, double time){
CEffect1::Data data;
data.x = x;
data.y = y;
strcpy(data.str, str);
data.color = color;
data.time = time;
data.strWidth = GetDrawStringWidthToHandle(data.str, strlen(data.str), m_fontHandle);
m_deq.push_back(data);
}
void CEffect1::insert(int x, int y, char ch, int color, double time){
/* char1文字の場合を文字列の場合に帰着 */
char buf[2];
buf[0] = ch;
buf[1] = '\0';
insert(x, y, buf, color, time);
}
void CEffect1::draw(double time){
while(!m_deq.empty() &&
time - m_deq.front().time >= CEFFECT1_SEC_CLEAR){
m_deq.pop_front();
}
for(deque<CEffect1::Data>::iterator itr = m_deq.begin(); itr != m_deq.end(); itr++){
double timeDiff = time - (*itr).time;
double ExRate; /* 文字の拡大率 */
{
double tmp = 1.0 - (timeDiff / CEFFECT1_SEC_CLEAR);
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 255 * (tmp * tmp * tmp));
/* 時間がたつにつれ透明に */
}
{ /* 時間が経つにつれ拡大 */
double tmp = timeDiff / CEFFECT1_SEC_CLEAR;
ExRate = 1.0 + 4.0 * tmp * tmp;
}
DrawExtendStringToHandle(
(*itr).x - ((*itr).strWidth * ExRate / 2), (*itr).y - (CEFFECT1_FONT_SIZE * ExRate / 2),
ExRate, ExRate, (*itr).str, (*itr).color, m_fontHandle);
}
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0); /* ブレンドしないように戻す */
}
/* ============================================================ */
#if 0
#define CEFFECT2_SEC_CLEAR 0.2
#define CEFFECT2_ALPHA 24
class CEffect2{
public:
void insert(int x, int y, int r, int color, double time);
void clear();
void draw(double time);
private:
struct Data{
int x, y, r;
int color;
double time;
};
deque<Data> m_deq;
};
void CEffect2::insert(int x, int y, int r, int color, double time){
Data d;
d.x = x; d.y = y; d.r = r;
d.color = color; d.time = time;
m_deq.push_back(d);
}
void CEffect2::clear(){
m_deq.clear();
}
void CEffect2::draw(double time){
while(!m_deq.empty() &&
time - m_deq.front().time >= CEFFECT2_SEC_CLEAR){
m_deq.pop_front();
}
for(deque<Data>::iterator itr = m_deq.begin(); itr != m_deq.end(); itr++){
double t = (time - itr->time) / CEFFECT2_SEC_CLEAR;
int alpha = (int)(CEFFECT2_ALPHA * (1-t*t));
int r = (int)(itr->r * (1.0+t*2.5*(1.0-t)*(1.0-t)));
SetDrawBlendMode(DX_BLENDMODE_ALPHA, alpha);
DrawCircle(itr->x, itr->y, r, itr->color, TRUE);
}
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
}
#endif
/* ============================================================ */
/* 後ろに文字が1文字ずつ追加され、前が消えていく文字列を対象にしたEffect */
/* 一応、文字列が長さを増やさず変化する可能性にも対応 */
#define CEFFECTSTR_SEC 0.3
/* 削除後消えるまでの時間 */
#define CEFFECTSTR_SEC2 0.08
/* 打ったエフェクトがかかる時間 */
#define CEFFECTSTR_H 10
/* 打ち切った後に落ちる距離 */
//#define CEFFECTSTR_V 15.0
/* 1秒で左向き速度が15.0文字分 */
/* これはinitのposVで設定できるようになった */
#define CEFFECTSTR_EX 2.4
/* エフェクトの文字の大きさの最初 */
class CEffectStr{
public:
void init(int fontHandle, bool flagTypeEffect, double posV, double alphaCleared);
/* 使用するフォントと、タイピングしたようなエフェクトをかけるかを最初に設定 */
/* 表示であいた左を詰める速度(文字/秒)、削除直後の不透明度も設定 */
void push(char ch, double time); /* 末尾に一文字のデータを追加 */
void push(char *str, double time); /* 末尾に数文字のデータを追加 */
void update(const char *str, int len, double time);
/* 現在のデータを設定。主に前方が消えたことを教える */
/* ここで、データの後方とstrが一致しなかったら直す */
void clear();
/* 現在のデータを単純に(消去エフェクトなしで)消す。既存のエフェクトは残す。 */
void draw(int X, int Y, double time);
/* 現在の文字列を参照しつつ表示 */
private:
void drawChar(double X, double Y, const char *buf, double t, double alpha) const;
/* 2バイト文字の関係上文字列で渡す */
void updatePos(double time);
private:
int m_fontHandle;
bool m_flagTypeEffect;
int m_fontWidth;
double m_posV;
double m_alphaCleared;
struct Data{
char ch;
double time; /* 追加された時刻 */
double timeCleared; /* 削除された時刻 */
double x; /* 削除済みの文字ついて意味を持ち、表示する位置 */
//bool isCleared;
};
deque<Data> m_deq; /* 現在のデータの文字たち */
deque<Data> m_deqCleared; /* 削除された文字たち */
double m_pos; /* 表示される位置がどれだけ左にずれるか */
double m_lastTime; /* 最後に更新した時間 */
};
void CEffectStr::init(int fontHandle, bool flagTypeEffect, double posV, double alphaCleared){
m_fontHandle = fontHandle;
{
char str[2] = " ";
m_fontWidth = GetDrawStringWidthToHandle(str, 1, m_fontHandle);
}
m_flagTypeEffect = flagTypeEffect;
m_posV = posV * m_fontWidth;
m_alphaCleared = alphaCleared;
m_deq.clear();
m_deqCleared.clear();
m_pos = 0.0;
//m_lastTime = 0.0;
}
void CEffectStr::push(char ch, double time){
Data data;
data.ch = ch;
#if 0
if(m_deq.empty() || m_deq.back().isCleared){ /* 存在しているデータがない */
data.x = 0.0;
}else{ /* 最後のデータの後ろ */
data.x = m_deq.back().x + m_fontWidth; // + 5.0;
}
#endif
data.time = time;
//data.isCleared = false;
m_deq.push_back(data);
}
void CEffectStr::push(char *str, double time){
while(*str){
push(*str, time);
str++;
}
}
void CEffectStr::update(const char *str, int len, double time){
updatePos(time);
int diff = m_deq.size() - len;
/* データのどこまでが消えたか */
if(diff < 0){
throw __LINE__;
}
/* 消えたデータを移動 */
for(int i=0; i<diff; i++){
m_deq[i].timeCleared = time;
m_deq[i].x = m_pos;
m_pos += m_fontWidth;
m_deqCleared.push_back(m_deq[i]);
//printfDx("%10c, %10d, %10f, %10f\n", m_deq[i].ch, (int)m_deq[i].x, m_deq[i].time, m_deq[i].timeCleared);
}
for(int i=0; i<diff; i++){
m_deq.pop_front();
}
if(len == 0){ /* データが空になったら、左端を0にする */
m_pos = 0.0;
}
for(int i=0; i<len; i++){
m_deq[i].ch = str[i]; /* 念のため新しいデータで上書き */
}
}
void CEffectStr::clear(){
m_deq.clear();
}
void CEffectStr::draw(int X, int Y, double time){
updatePos(time);
while(!m_deqCleared.empty() &&
time - m_deqCleared.front().timeCleared >= CEFFECTSTR_SEC){ /* 消えてから十分長い時間がたった */
m_deqCleared.pop_front();
}
char buf[3];
for(deque<Data>::iterator itr = m_deqCleared.begin(); itr != m_deqCleared.end(); itr++){
double x = itr->x;
buf[0] = itr->ch;
if(isJapanese1st(itr->ch)){
itr++;
if(itr == m_deqCleared.end()){
break;
}
buf[1] = itr->ch;
buf[2] = '\0';
}else{
buf[1] = '\0';
}
double xTime = (time - itr->timeCleared)/CEFFECTSTR_SEC;
double t = 1.0 - xTime;
if(t > 1.0) t = 1.0;
t *= t*t;
drawChar(X + x, Y + CEFFECTSTR_H * xTime * xTime,
buf, time - itr->time, m_alphaCleared * t);
}
double pos = m_pos;
for(deque<Data>::iterator itr = m_deq.begin(); itr != m_deq.end(); itr++){
double x = pos;
buf[0] = itr->ch;
if(isJapanese1st(itr->ch)){
itr++;
if(itr == m_deq.end()){
break;
}
buf[1] = itr->ch;
buf[2] = '\0';
pos += 2*m_fontWidth;
}else{
buf[1] = '\0';
pos += m_fontWidth;
}
drawChar(X + x, Y, buf, time - itr->time, 1.0);
}
}
void CEffectStr::drawChar(double X, double Y, const char *buf, double t, double alpha) const{
if(m_flagTypeEffect && t < CEFFECTSTR_SEC2){
t = 1.0 - t/CEFFECTSTR_SEC2;
if(t > 1.0) t = 1.0;
double ExRate = 1.0 + (CEFFECTSTR_EX - 1.0) * t * t;
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 64 * alpha / ExRate);
DrawExtendStringToHandle(
X - m_fontWidth * (ExRate - 1.0) / 2.0 , Y - m_fontWidth * (ExRate - 1.0),
ExRate, ExRate, buf, GetColor(255, 255, 255), m_fontHandle);
/* フォントの縦:横=1:2という仮定を使っている */
/* さらに、全角文字が来ないことが必要だが、タイピングではローマ字しか入らないのでOK */
}
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 255 * alpha);
DrawStringToHandle(X, Y, buf, GetColor(255, 255, 255), m_fontHandle);
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
/*
if(alpha!=1.0){
DrawStringToHandle(X, Y, buf, GetColor(255, 0, 0), m_fontHandle);
}
*/
}
void CEffectStr::updatePos(double time){
if(m_pos == 0.0){
m_lastTime = time;
return;
}
double timeDiff = time - m_lastTime;
if(timeDiff < 0.0){
return;
}
m_lastTime = time;
m_pos -= timeDiff * m_posV;
if(m_pos < 0.0){
m_pos = 0.0;
}
}
/* ============================================================ */
/* 良可判定のゲージ */
class CStatGauge{
public:
void init();
void draw();
void inc(int ID_accuracy);
private:
void drawBar(double val, int y, int h, int color) const;
void drawLight(double Light, int y, int h, int color) const;
private:
int m_val[4]; /* ゲージの現在描かれる長さ */
double m_drawX[4];
double m_drawV[4]; /* ゲージの現在描かれる長さの動く速度 */
double m_rate; /* ↑の長さ1に相当する画面上の長さ */
double m_light[4]; /* ゲージのそれぞれを照らす光の強さ */
int m_color[4][2];
};
void CStatGauge::init(){
for(int i=0; i<4; i++){ /* 最初の値 */
m_val[i] = 0;
m_drawX[i] = 0.0;
m_drawV[i] = 0.0;
m_light[i] = 0.0;
}
m_rate = 20.0; /* 最初の、長さ1あたりの表示する長さ */
m_color[ID_EXCELLENT][0] = COLOR_EXCELLENT;
m_color[ID_EXCELLENT][1] = COLOR_EXCELLENT2;
m_color[ID_GOOD][0] = COLOR_GOOD;
m_color[ID_GOOD][1] = COLOR_GOOD2;
m_color[ID_FAIR][0] = COLOR_FAIR;
m_color[ID_FAIR][1] = COLOR_FAIR2;
m_color[ID_POOR][0] = COLOR_POOR;
m_color[ID_POOR][1] = COLOR_POOR2;
}
void CStatGauge::draw(){ /* ゲージを表示 */
int y = Y_STAT_GAUGE;
int h = H_STAT_GAUGE / 4;
for(int i=0; i<4; i++){ /* ゲージの指すべき値に近づける */
//m_statGauge[i] += (x[i] - m_statGauge[i]) * 0.2;
m_drawV[i] += 0.12 * (m_val[i] - m_drawX[i]);
m_drawX[i] += m_drawV[i];
/* 摩擦 */
m_drawV[i] *= 0.7;
}
{
double rate = 20.0;
while(1){
bool flag = true;
for(int i=0; i<4; i++){
if(m_val[i] * rate > W_STAT_GAUGE){
flag = false;
}
}
if(flag){
break;
}
/* 超えるたびに0.75倍ずつしていき、超えなくなるまでやる */
rate *= 0.75;
}
m_rate += (rate - m_rate) * 0.2;
}
{
double x[4]; /* m_drawX[]から縮小処理してx[]に入れる */
for(int i=0; i<4; i++){
x[i] = m_drawX[i] * m_rate;
}
/* もともと濃い灰色で描画しないのは tan などへの配慮 */
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 128); /* 不透明さ1/2 */
DrawBox(X_STAT_GAUGE - W_STAT_GAUGE, y, X_STAT_GAUGE, y + 4 * h, GetColor(64, 64, 64), TRUE);
/* それぞれの長さを表示 */
for(int i=0; i<4; i++){
drawBar(x[i], y+i*h, h, m_color[i][0]);
}
}
/* 最近変更されたものを照らす */
for(int i=0; i<4; i++){
drawLight(m_light[i], y+i*h, h, m_color[i][1]);
/*
double Light = m_light[i];
SetDrawBlendMode(DX_BLENDMODE_ALPHA, (int)(192 * Light));
Light *= 4.0;
if(Light > 1.0){
Light = 1.0;
}
int dh = (int)(h * 0.5 * (1.0 - Light)*(1.0 - Light));
DrawBox(X_STAT_GAUGE - W_STAT_GAUGE, y+i*h + dh, X_STAT_GAUGE, y+(i+1)*h - dh, m_color[i][1], TRUE);
*/
m_light[i] *= 0.85;
}
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
}
void CStatGauge::inc(int ID_accuracy){
m_val[ID_accuracy]++;
m_light[ID_accuracy] = 1.0;
}
void CStatGauge::drawBar(double val, int y, int h, int color) const{
SetDrawBlendMode(DX_BLENDMODE_ALPHA, 224); /* 不透明さ7/8 */
//DrawBox((int)(X_STAT_GAUGE - val + 0.5), y, X_STAT_GAUGE, y+h, color, TRUE);
int i_val = floor(val);
double f_val = val - i_val;
DrawBox(X_STAT_GAUGE - i_val, y, X_STAT_GAUGE, y+h, color, TRUE);
SetDrawBlendMode(DX_BLENDMODE_ALPHA, (int)(224 * f_val)); /* 不透明さ(7/8)*小数部分 */
DrawBox(X_STAT_GAUGE - i_val - 1, y, X_STAT_GAUGE - i_val, y+h, color, TRUE);
SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
}
void CStatGauge::drawLight(double Light, int y, int h, int color) const{
SetDrawBlendMode(DX_BLENDMODE_ALPHA, (int)(192 * Light));
Light *= 4.0;
if(Light > 1.0){
Light = 1.0;
}
int dh = (int)(h * 0.5 * (1.0 - Light)*(1.0 - Light));
DrawBox(X_STAT_GAUGE - W_STAT_GAUGE, y + dh, X_STAT_GAUGE, y + h - dh, color, TRUE);
}
/* ============================================================ */
struct ConvertData{
public:
ConvertData(const char *buf1, const char *buf3);
bool match_front(const char *str);
bool match(const char *str);
bool get_unprocessed(char *buf);
public:
char m_str[8]; /* 日本語 → ローマ字, 全角 → 半角 の変換先は 4 文字以内だから、5以上にしておけばよい */
int m_len;
/* str には条件に使われる文字列が入っているが、そのうち確定される長さ */
/* 例: 「ん」に対して {"nb", 1}, 「っっ」に対して {"lltu", 4} など */
};
ConvertData::ConvertData(const char *buf1, const char *buf3){
strcpy(m_str, buf1);
m_len = strlen(buf1) - strlen(buf3);
/* ここでは、データを信用して、buf3がbuf1の後方と一致することを仮定する。 */
}
bool ConvertData::match_front(const char *str){ /* データの前方とstrが一致するか */
for(int i=0; str[i]!='\0'; i++){
if(str[i] != m_str[i]){
return false;
}
}
return true;
}
bool ConvertData::match(const char *str){
return (strcmp(m_str, str) == 0);
}
bool ConvertData::get_unprocessed(char *buf){
/* 未確定ローマ字部分を取得 */
strcpy(buf, m_str + m_len);
return strlen(buf) != 0;
}
/* ============================================================ */
class CTrieNode{
public:
CTrieNode();
~CTrieNode();
void insert(const char *str, const ConvertData &data); /* strでたどった先にdataを入れる */
CTrieNode *find(const char *str);
CTrieNode *find(char ch);
private:
CTrieNode *m_next[256];
public:
/* もうprivateにするの面倒 */
vector<ConvertData> m_data;
};
CTrieNode::CTrieNode(){
for(int i=0; i<256; i++){
m_next[i] = NULL;
}
}
CTrieNode::~CTrieNode(){
for(int i=0; i<256; i++){
if(m_next[i] != NULL){
delete m_next[i];
}
}
}
void CTrieNode::insert(const char *str, const ConvertData &data){
if(*str == '\0'){ /* たどり終わったのでデータを入れる */
m_data.push_back(data);
return;
}
int i = *str & 0xff; /* 0(1)~255 にする */
if(m_next[i] == NULL){ /* たどれないので新しく作る */
m_next[i] = new CTrieNode();
}
m_next[i]->insert(str+1, data); /* 次をたどる */
}
CTrieNode *CTrieNode::find(const char *str){
if(*str == '\0'){ /* ここでOK */
return this;
}
int i = *str & 0xff; /* 0(1)~255 にする */
if(m_next[i] == NULL){ /* ない */
return NULL;
}
return m_next[i]->find(str+1); /* 次をたどる */
}
CTrieNode *CTrieNode::find(char ch){
char buf[2];
buf[0] = ch;
buf[1] = '\0';
return find(buf);
}
/* ============================================================ */
struct LyricsBlock{
int lyricsNum; /* Lyricsの配列の何番目からか */
int lyricsLen; /* 一かたまりの長さ(Byte) */
double timeJust,timeUntil; /* ちょうどの時間、(ここまでのみを)打つことができる最も遅い時間 */
bool isValid; /* 有効ならtrue、そうでない(スコア対象ではない管理用のいろいろ)ならfalse */
int nTyped; /* 何バイト打たれたか */
bool isScoringTarget; /* 現在タイミング判定をする対象であるか */
int scoringCount; /* ここより前に(これ自身を含まない)スコア対象のものがあったか */
double scoringTime;
/* タイミング判定をされた時刻、!isScoringTargetのとき以外は意味はない */
//int r, g, b; /* 打ち始めのエフェクトの色(scoringTimeが有効の時、有効) */
double clearedTime; /* Blockが打ち切られた時刻、負ならまだ */
/* 区切りについては、区切りが意味を持たなくなった時刻 */
double x, y, vx, vy, vz;
/* (clearedTimeが非負の時)打ち切られた時の跳ねかた(向きはランダム)を保持 */
public:
int lyricsPos();
};
int LyricsBlock::lyricsPos(){ /* 打ってない最初のもののLyrics配列での添え字を返す */
return lyricsNum + nTyped;
}
struct Lyrics{
char ch; /* 変換された文字(あいう、。~abc123+-など)の1バイト */
int blockNum; /* LyricsBlockの配列の何番目に含まれるか */
int blockPos; /* そのなかで何バイト目か */
};
/* ============================================================ */
struct LyricsKanji{ /* 表示される歌詞 */
public:
char str[256]; /* 歌詞 */
double timeBegin; /* 表示が始まる時間 */
double timeEnd; /* 表示が終わる時間 */
public:
void draw(int x, int y, int fontHandle, double time, double timeL) const;
/* Next: に表示され始めてから、直前の歌詞が消えるまでの時間のうちどれだけ進んだか */
private:
int getDrawColor(bool flag) const;
};
void LyricsKanji::draw(int x, int y, int fontHandle, double time=-1.0, double timeL=-1.0) const{
char buf[256];
int colo[256];
int len=0;
bool flag = true; /* 普通に書く(true)か、灰色で書く(false)か */
for(const char *ptr = this->str; *ptr!='\0'; ptr++){
if(*ptr == '\\'){
ptr++;
switch(*ptr){
case '\0':
break; /* \で終了したらそれは無視 */
case '|': /* ここで、色を変更 */
flag = !flag;
break;
default:
buf[len]=*ptr;
colo[len]=getDrawColor(flag);
len++;
break;
}
}else if(isJapanese1st(*ptr)){
buf[len]=*ptr;
colo[len]=0; /* 次と同時に処理するという意味 */
len++;
ptr++;
if(*ptr == '\0'){
throw __LINE__;
}
buf[len]=*ptr;
colo[len]=getDrawColor(flag);
len++;
}else{
buf[len]=*ptr;
colo[len]=getDrawColor(flag);
len++;
}
}
buf[len]='\0';
if(len==0) return; /* 描く文字がないので終了。0除算回避 */
double drawLen;