-
Notifications
You must be signed in to change notification settings - Fork 23
/
todo
1208 lines (961 loc) · 106 KB
/
todo
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
СОВЕТИКИ
Нужно начать писать советики по разработке приложений под scage. Типа Best Practices. Постараюсь постепенно пополнять
список новыми советиками
* все action'ы, render'ы итд только в объектах, но не в классах.
--
Мм, спорно же... Ну, то есть, если внутри класса определены action'ы или еще что, значит там полюбас импортирован
соответствующий ScageScreen объект (ну или еще каким извращенным способом присутствует). Таким образом, этот класс
все равно не удастся использовать в отрыве от объекта, как-то по-левому.. Или потенциальный баг в самом объекте, что
он не сможет проследить за своевременным удалением action'а и такое сложно отследить... Ну хз.
* все var с модификаторами только private
--
Не актуально, за нас уже подумали. ОКАЗЫВАЕТСЯ, поля в классах всегда имеют самый зверский модификатор private[this], и если
мы выставили для var публичный или протектед модификатор, автоматически генерятся геттер и сеттер. Это оче круто,
на самом деле. Примечательно, что во всем коде scage мне понадобилось всего в двух местах удалить лишние геттеры-сеттеры)
* в трейтах стараться не писать конструкторский код, только def'ы и val'ы
* точка входа в приложение должна наследоваться от ScageScreen (или MultiControlledScreen) с параметром
is_main_unit=true
-----------------
Порядок именования версий: a.b
a - любое изменение функциональности, добавление нового апи, изменение существующего, даже малейшее
b - фикс ошибок, рефакторинг, обновление зависимостей
----------------- версия 12 -----------------
во фреймворке Tracer отказаться от State и от def state и def changeState. Пусть там будет просто абстрактный
генерик, набор методов определяется прикладным использованием.
--
проблемка может быть когда разного типа объекты находятся на поле и им как-то надо взаимодействовать
через общий интерфейс. В данном варианте этот общий интерфейс надо будет писать.
новая функция вычисления угла, deg360, которая возвращает угол в диапазоне 0-360, угол подсчитывается всегда против часовой стрелки
(например, первый вектор на девять часов, второй на восемь - тогда угол 30 градусов;
если первый вектор на шесть часов, второй на девять часов - угол 270 градусов)
средние времена render/action за такой-то период времени (период в качестве аргумента)
----------------- версия 11 -----------------
события от клавиатуры проверять в отдельном потоке, чтобы независимо от того, насколько приложение лагает, на клавиатуру
оно отзывалось.
----------------- версия 10.6 -----------------
добавил псевдоскалярное произведение вектора на число: def */(k:Float):Vec = Vec(y*k, -x*k)
----------------- версия 10.5 -----------------
добавил оранжевый цвет для цветных строк
----------------- версия 10.3 -----------------
починил рисование некоторых цветов, в частности, оранжевого
----------------- версия 1.1 -----------------
Функция absCoord, аналог scaledCoord, которая учитывает ротацию и возвращает абсолютную координату данной точки
----------------- версия 1.0 -----------------
Функции signedDeg/signedRad в Vec/DVec, которые возвращают угод между векторами со знаком:
от 0 до 180 - второй вектор слева от первого (положительный угол откладывается против часовой стрелки)
от 0 до -180 - второй вектор справа от первого (отрицательный угол откладывается по часовой стрелке) (done)
----------------- версия 0.9.3 -----------------
Вариант окна: без параметров window_width, window_height - максимального разрешения в размер экрана
Перевод проекта на scala 2.10. переписать сетевой движок на akka. Вроде вся нужная для этого информация получена... (done)
--
сетевой движок выкинут из скаге и вынесен в отдельный проект simple-net
Доделка actions: к period добавить еще delay
Вынести в отдельный модуль сетевую часть аналогично scala-cli. Переписать все на akka. (done)
Перейти на scala-cli: избавиться от ScageProperties и логгера com.weiglewilczek.slf4s, который все равно не поддерживает
scala 2.10 (done)
Надо ли компилировать разные версии scage под разные скалки? По идее да...
----------------- версия 0.9.2 -----------------
ScageLib, мб все-таки вернуть в виде трейта и объекта: тогда в клиентском приложении можно заводить новый объект, который
наследуется от трейта ScageLib и в нем дописываются дополнительно еще всякие клиентские полезные импорты, таким образом
экономится еще одна-две строчки)
в параметрах ScageScreen: (done)
window_width -> width, window_heigt -> height, unit_name -> title
оказывается, есть баг: если не предоставить имя главному экрану, приложение не запускается, падает с ошибкой, мол не
могу найти файл шрифта!
--
хм, баг пропал...
Можно таки завести кнопку:
def windowButton(message: => String, coord:Vec, onClick:(m:Vec => Any), screen:Screen with MultiController):(Int, Int) {
val i = screen.interface {
print(message, coord, align = "center")
}
def area = {
val Vec(w, h) = messageBounds(message)
List(coord + Vec(-w/2, h/2), coord + Vec(w/2, h/2), coord + Vec(w/2, -h/2), coord + Vec(-w/2, -h/2))
}
val m = screen.leftMouseOnArea(area, onClick)
(i, m)
}
функция возвращает два числа - айдишники операций, по которым кнопку можно удалить. Также можно сделать классом и в нем
сделать метод для самоудаления и все такое. Хз, где разместить этот метод, или класс и вопрос целесообразности.
задание messagesBase, interfacesBase в ScageXML (done)
areaForMessage(), areForMessageCentered() (done)
--
в ScageMessage. Вместо centered и все такое ввести параметр align.
еще варианты *MouseOnRect*, где width, height - одним объектом Vec. Тогда туда сразу можно подставить значение messageBounds()
--
не оч актуально, так как в норм приложении почти наверняка нужна i18n, соответственно, messageBound() вычисляется динамически каждый раз (ну или как-то там),
то бишь areaForMessage() - более практичный вариант.
мб оптимизировать все эти *OnRect*, *OnRectCentered*, добавить функцию coordOnRect() - такая функция гораздо проще, чем coordOnArea(), (done)
сделать прямые вызовы mouseButton() итд
--
допилена также coordOnArea() - сначала вычисляется aabox для многоугольника и от него вычисляется coordOnRect(), и только если он true -
вычисляется coordOnArea().
добавить leftMouseOnRectCentered итд (done)
адаптировать все последние фишки для commandLineInterface (done)
надо поправить: функции msecsFrom* не учитываю паузу. Надо доработать апи, чтобы типа были и учитывающие и не (done)
учитывающие паузу.
мб в ScageLib заебенить объявления типа: (done)
type ScageScreenApp = net.scage.ScageScreenApp
итд, типа чтобы реально тока один импорт был и все. Может сработает?
---
можно использовать опыт библиотеки casbah, где так сделано
---
запилил!
Сделать ScageLib чисто объектом. В качестве трейта не используется никогда все равно. (done)
Мб Events фреймворк вынести в виде объекта или трейта и унаследовать в ScageLib. Чтобы типа это была глобальная штука, (done)
а не только в потрохах скрина. Иначе мб будет путаница если в проге несколько скринов, чей эвентс фреймворк задействован
в данном конкретном месте.
--
не унаследовать, а продублировать методы, чтобы можно было юзать отдельно объект Events, и из ScageLib
надо куда-то деть из контроллера функцию areLinesIntersect(), потому что это реально полезная функция, и она пригодится
не только там. Варианты: в Vec и DVec. Либо вообще создать новый класс Line... Правда, тогда что ли получается, надо делать
Line и DLine?.. Короче мб пока нах, и засунуть в объекты Vec/DVec.
--
Подумать, куда засунуть метод areLinesIntersect(), потому что это вообще полезный метод, и он нужен не только в контроллерах, (done)
а например, клиентским приложениям тоже пригодится. Варианты: в объекты Vec/DVec, либо завести новый класс Line, и типа в него.
Правда, похоже, придется заводить Line/DLine... Вообще, надо бы разобраться с этими двумя классами для двумерного вектора
с разной точностью, а то какая-то порнография уже получается...
Другой вариант: в ScageLib. Также я почитал сейчас еще раз про package objects в Scala, и вот мб хорошая идея превратить
ScageLib в package object net.scage.
--
засунул в ScageLib. ScageLib оставлен объектом, в качестве package object он не нужен - это ничего не упрощает.
надо разобраться с параметрами для трейсера. Предусмотреть разные варианты задания параметров:
размеры игрового поля плюс количество клеток, либо размеры плюс h_x, h_y.
придумать доработку или воркэраунд к трейсеру или к чему-нибудь, чтобы уметь рисовать непрерывную картинку на границах областей при увеличении - чтобы не было "телепортаций"
при пересечении края экрана
--
в своем простейшем виде доработка заключается в отрисовке еще восьми копий основного кадра со смещениями на один
экран вверх, вниз, в стороны и по диагоналям. Фпс при этом падает в среднем в два раза.
phys2d, который используется в качестве физ.движка в scage, не развивается с 2008 года. В целом, он ничего, но есть
небольшие проблемы, например, такой комент в методе step() класса World:
Currently anything other than 1/60f as a step leads to unpredictable results - hence the default step
fixes us to this step
из-за чего в своей обертке ScagePhysics я пилю вот такой космический костыль:
def step() {
_physicals.foreach(_.clearTouches())
for(i <- 1 to _dt) {
world.step()
for(p <- _physicals) {
p.updateCollisions(world.getContacts(p.body))
}
}
}
потому что дефолтного шага в 1/60 сильно не хватает (5/60 выглядит норм).
В общем, есть альтернативы среди физ.движков:
* JBox2D http://jbox2d.org/, http://code.google.com/p/jbox2d, в активной разработке, последние коммиты за 30 января 2012 (на текущий момент,
8 февраля). Доступен через мавен в репозитории sonatype (https://oss.sonatype.org/index.html#nexus-search;quick~jbox2d)
* JBullet http://jbullet.advel.cz/, java-порт сишного движка Bullet. В плане исходников и активности разработки менее вразумительный,
в частности, оно, кажется, не умеет в мавен. И не 2д к тому же
возможное перманентное накопление сообщений в акторах сетевой подсистемы. Подумать об этом
--
в акторах сетевой подсистемы надо запилить событие status или state - чтобы по нему отдавал всякую инфу о себе, в том числе количество сообщений в майлбоксе.
подумать над множественными начитками restitution в физическом движке
Нужно продумать стандартный механизм идентификации клиентов. А то сейчас можно хоть телнетом подключиться, и сервак думает что это клиент
и создает под него игровые сущности и шлет ему инфу. В перспективе мб даже завести некую секурность - идентификацию на основе каких-нить
криптоалгоритмов, чтобы ботов сложнее было написать.
говорят, tcp/ip это не круто, круто - udp. По крайней мере для динамичных игр с
интенсивным сетевым обменом. Надо как-то продумать это и запилить использование
udp наряду с tcp/ip (под настройку например).
Запущенный дочерний скрин может попортить ряд графических параметров, и при возврате из него, неплохо бы их автоматически
восстанавливать. Это очень легко сделать, надо запилить метод runScreen() внутри какого-нить скринового трейта, и в нем уже
вызывать метод run(), перед ним сохраняя парамы, и после возврата из него восстанавливая их. Нужно только определить этот
набор восстанавливаемых параметров. На первый взгляд: backgroundColor, currentColor
--
еще при смене разрешения все сбрасывается
Набор методов в Vec, меняющие его внутренние поля - подумать о целесообразности. Многое бы упростилось и мб ускорилось,
но и возможностей для багов больше.
--
как обычно, годное решение - завести новый класс: mutableVec
--
сделать обертки toMutable / toImmutable и все такое) Вообще, годная вещь, можно будет обойтись без пересоздания координат
трейсов в трейсере например.
--
класс MVec - наследуется от Vec и имеет дополнительные методы +=, итд и прямые методы переопределения полей. И обновить
трейсер, чтобы использовал этот класс. Подводные камни: нужно переделать всю структуру Vec, добавить уровней абстракции,
потому что типа нельзя тупо отнаследоваться от Vec: у него внутренние поля x,y - иммутабельные.
мб внедрить сортед буфер для операций из scage
проперти: еще из аргументов, которые можно в программу передать (done)
--
реализован трейт commandLineInterface
мб логировать с уровнем info начитку пропертей, просто чтобы знать какие проперти начитываются
Впилить класс Vec с числами Double, чтобы конская точность была. (done)
--
надо бы как-то так изящно придумать, чтобы вся архитектура была сразу совместима с и со старым и с новым классом, и
очень просто было выбирать какой юзать.
--
без всякого изящества запилил конвертацию из Vec в DVec и наоборот и сделал имплициты в ScageLib
--
два класса Vec, DVec, в которых полностью повторены все методы, только тип разный - это плохо.
Мб обновить методы рисования в соответствии с примером Reflections в проекте blases.tests: (done)
ellipse.toList.sliding(2).foreach {
case List(a, b) => drawLine(a, b, WHITE)
}
а то обычный drawLines как-то хреновато отрабатывает, равно как и drawPolygon. Либо добавить еще такие методы в
дополнение к имеющимся.
Был эпический факап, когда попытался написать сетевую версию Space War: код, написанный на работке не заработал дома,
потому что параллельные потоки, race conditions, конкаренси и всякая такая хуйня. Для преодоления этого был запилен трейт
SynchronizedScage, но мб это не лучший вариант решения. Код сервера наверное не следует менять, пусть он так и остается
весь акторный и асинхронный. А вот клиентский код мб можно написать еще вариант - когда запрос данных с сервера осуществляется
в фиксированные моменты и является частью главного цикла, а не вынесено в отдельный актор.
---
Ну или иметь внутреннюю дисциплину писать потокобезопасно, обмениваясь с сетевым клиентом сообщениями из основного треда... Это,
впрочем, сложновато, потому что с общей однопоточной архитектурой движка согласуется мало... Хотя в акторс фреймворк
есть же возможность тупо чекать майлбокс, когда это удобно, так что какие проблемы. Надо бы как-нить сподобиться
написать пример.
--
надо отказаться от синхронизированных классов и всего этого. вариант взаимодействия с сетевым апи надо придумать ДРУГОЙ.
--
Короче, похоже все довольно просто:
action(10) {
self.receiveWithin(10) {
// ...
}
// ...
}
И в коде сервера посылаем сообщения основному треду:
val scage_actor = self
NetServer.startServer(
onClientAccepted = (client) => {
scage_actor ! (("new client", client.id))
}
)
В общем, ЭТО РАБОТАЕТ, так что реально надо выпиливать всю синхронайзд-парашу из кода! (done)
--
увы, начиная с 2.10 scala actors объявлены deprecated и предлагается перекатываться на akka, и там не оч пока понятно,
будет ли работать это замечательно решение с посыланием сообщений основному треду. На первый взгляд синтаксис стал
запутанней и вообще параша какая-то эта akka.
функциональность контроллеров может стать депрекейтед. Потому что есть мысли, как все делать через keyPressed/mousePressed внутри
экшенов и типа это более stateless.
--
хрен-то там: гораздо меньше контроля, например, много писанины чтобы контролировать время нажатия на клавишу, гарантировать,
что при нажатии на кнопку функция отработает только один раз итд. Короче, это только в дополнение
--
Новый вариант взаимодействия с контролами:
interface {
control(KEY_A) match {
case PRESSED => print("I'm pressed", windowCenter, RED)
case UNPRESSED => print("I'm not pressed", windowCenter, GREEN)
}
}
---
Запилить таки нормальную реализацию экранных кнопок. Впилить это в функционал контроллера. Добавляем список вершин,
ограничивающих некоторый замкнутый многоугольник. При клике проверяем не попадает ли мышка в область какого-либо из
добавленных многоугольников. Если попадает - выполняем связанное с ним действие. Сигнатура функции:
def windowButton(area:Seq[Vec], on)
---
Доработка контроллера: получать информацию о состоянии контрола по его айдишнику. Требуется по сути сейчас для экранных
кнопок, но мб и для других контролов пригодится. Состояние такое: (was_pressed:Boolean, last_pressed_time:Long)
---
сделано:
добавлены методы: keyPressed, leftMousePressed, rightMousePressed, mouseOnArea. Этого в целом хватает, чтобы заебенить
оконный интерфейс и все такое
--
но все-таки методы, возвращающие инфу: (нажато/не нажато, сколько времени нажато, последний момент нажатия) - нужны..
Доработка сетевого апи: вариант шифрования, вариант сжатия, вариант идентификации клиентов/сервера. Попробовать еще раз
реализовать сетевые переменные.
--
кстати, внезапно осознал что эта концепция "сетевых переменных" это ж по сути велосипедная реализация какой-нить базы данных.
Во всяком случае все ТЗ можно организовать например в виде внешнего инстанса mongodb и драйвера доступа к нему из сервера
и из клиентов. Типа обновляют одну и ту же общую коллекцию, да и все. Так что нафиг это все.
----------------- версия 0.9.1 -----------------
Надо бы зафиксировать версию, и в следующей версии разработать таки удобную систему построения сетевых
приложений. Проект "сетевые переменные" немножко провалился, но можно его попробовать доработать и таки дожать.
мб перейти к использованию либы lift-json: в сетевом апи или вообще везде вместо State
еще функции центрирования: (done)
* центрировать только по оси x
* left align
* right align
net api: реализовать функцию ask(question:State):State - типа мы посылаем "вопрос" серверу или клиенту, и блочимся,
пока не придет ответ. (done)
впиливаю много всяких изменений, которые неизвестным образом сказываются на производительности. Наоборот, есть также идеи
допилить какие-то оптимизации, но неизвестно, нужны ли они, и скажется ли это как-то на производительности.
Короче, я остро нуждаюсь в бенчмарке, остро!!!
фреймворк tracers тоже надо сделать синхронизированным
--
нахуй, всю синхронизированность убираю наоборот.
Вариант контрола: работает только в режиме паузы (сейчас есть: работает только если не на паузе, работает всегда) (done)
--
тут кстати может быть подводный камень с onKeyUp если в onKeyDown сменился on_pause. (done)
Впрочем, в клавишах смены вроде onKeyUp не юзается, да я его и вообще почти нигде не юзаю...
--
NoPause -> IgnorePause, Pause -> OnPause. Итого три возможности:
без суффикса: работать, если не на паузе
IgnorePause: работать в любом случае
OnPause: работать, если на паузе
что необходимо доделать:
* поддержка апплетов (done: решение мб не сверхэлегантное но по кр мере работает)
* работа из нескольких потоков
* с архетипом проблемы: системные либы lwjgl присутствуют внутри jar-файлов
* использовать мавеновские плагины shade и proguard - для получения одного джарника вместо кучи и уменьшения его
размера за счет выпиливания неиспользуемых классов.
--
proguard плохо шринкает, так что потом джарник не запускается, shade работает ок, но похоже системные либы lwjgl
впихнуть внуть общего джарника не получится. JarSplice умеет такое, но он не работает с мавеном, а имеет гуевый
интерфейс.
* приделать профиль -Papplet со сборкой апплета
--
для апплета пригодился бы один джарник на все. Так удобнее. Для jnlp в целом тоже, да и вообще
* андроид
* 3D
net api: sendToAllExcept, sendToAllExceptSync (done)
надо бы вернуть возможность менять framerate (done)
сделать ScageProperties уметь воспринимать проперти, переданные в командной строке по -D (done)
delOperationIfExists, delOperationsIfExist, delOperationsIfExistExcept (done)
--
NoWarn вместо IfExists
дополнительные таймеры: с момента старта приложения, с момента старта экрана, с момента последнего рестарта... (done)
Еще надо подумать про паузу и периодические экшены: после того как сняли с паузы, если держали достаточно долго, у всех
периодических экшенов сразу сработает условие и они все выполнятся. Мб на период паузы обновлять им last_action_time
--
фигня
нужно разработать механизм, чтобы периодические экшены вообще не вызывались, если сейчас они гарантированно не выстрелят.
Например можно хранить экшены как мап: время срабатывания -> список функций. Причем пусть это будет TreeMap!
И тогда мы по msecsFrom сразу получаем список ключей, экшоны на которых надо выполнить.
ColoredString - попробовать сделать принимать Any, геттеры (text, originalText, colorSwitches) записывать без скобок
передавать в drawRect* в качестве ширины и высоты вектор (одно значение вместо двух)
trace.state("pewpew", 15) вместо trace.state.valueOrDefault("pewpew", 15)
операции: clearOnce, initOnce, actionOnce, delayedAction
--
забил пока
Подумать над ускорением удалялок операций - если контейнеры функций переделать из аррайбаферов в хешмапы, как для events,
то удалять по id станет быстрее. Еще SortedBuffer можно сделать на основе Vector - быстрее будет вставка.
--
Vector - иммутабельная структура. Хешмапы к ускорению тоже не оч помогают.
Версионирование. Непонятно, что делать с версиями дальше. Переваливать через 1.0 неохота, и упираться в него,
повышая минорные версии, в общем-то, тоже. Плюс, непонятно, когда наступает момент повышения версии: ориентироваться на
периоды разработки или на количество новых добавленных фич? Мб перейти на другую систему присваивания версий. Как вариант:
месяц-год. 052012, 062012 итд. Повышать, соответственно, раз в месяц. Хотя лучше все-таки как-то учитывать и количество фич,
чтобы версии по наполненности были более-менее равномерные...
пути дальнейшего развития:
* порт для андроида
* 3D (поботвить подробнее opengl)
нужны методы printCentered, по аналогии с drawRectCentered итд. Нужно вычислять прямоугольник, в который вписана строка,
которую хотим нарисовать и при ее рисовании соответствующим образом смещать точку ее рисования так чтобы переданная в
аргументах координата размещалась по центру строки.
это уже пахнет задротством, но мб предусмотреть еще одну стадию жизненного цикла экрана:
заход в экран в САМЫЙ ПЕРВЫЙ раз. типа prepreinit. Выполняется за все время работы приложения вообще один единственный раз,
в дальнейшем если и есть перезапуски экрана, то выполняется preinit, а эта стадия пропускается. Аналогично в конце: postdispose,
выполняется при самом-самом последнем выходе из экрана, то есть когда stopApp() вызвано. Подумать о возможных юзкейсах для этого.
прочитал что в андроиде похожая идея с экранами, есть жизненные циклы экранов, которые выполняются когда
экран останавливается/запускается. Только там вроде как не втупую вызов следующего экрана где-то в коде
логики предыдущего и соответственно возврат в точку вызова при его остановке, а нечто более интеллектуальное,
наподобие использования гипервизора: стек экранов и все такое. Надо подумать, можно ли у меня запилить такой
стек, и имеет ли это смысл? На первый взгляд не очень-то имеет, потому что бывает не нужна полная остановка текущего треда,
либо придется усложнять логику чтобы при его восстановлении все там какие-нить данные восстанавливались.
Я вроде наконец сообразил для чего мог бы пригодиться events-framework. В общем, бывает такое, что переменная заведена
где-нибудь, но менять ее позарез требуется из разных классов, так что полностью приватной ее не сделаешь. Можно конечно,
сделать из нее проперти, но если в ее сеттере будет просто присваивание переменной нового значения, то с тем же успехом
снимаешь модификатор private и не ебешь мозг. Но тогда этот сеттер может теоретически вызываться кем угодно, и проблема
мутабельных изменяемых состояний предстает во всей красе (конечно, если все же завести сеттер, то можно в нем поставить
брейкпоинт и отследить, какой пидор нам портит переменную, но если обращений к ней много, это может быть сложно).
И тут-то на помощь нам и приходит events framework! Там где мы объявили переменную, мы также задаем, в ответ на какие
события и что именно с ней следует сделать. Синтаксис нужно предусмотреть как в акторах, чтобы можно было передавать
произвольный набор дополнительных параметров. Ну и потом все заинтересованные лица просто вызывают нужный эвент, и все,
что нужно, на этот эвент реагирует. Переменную при этом с чистой совестью можно заводить private и делать ей один геттер.
Например, в игре Blases когда шипы лопают пузырь, они уменьшают счет за уровень на 100 очков. Вместо этого можно дергать
event типа "Пузырь лопнул" и по этому эвенту будут нужные изменения со счетом происходить уже в основном классе.
Впрочем, меня немного пугает производительность этого всего и опять же нужность...
расставить sealed где-нибудь, говорят это помогает от оптимизации
посмотреть, где можно заменить сигнатуры def foo(a:Any) на более кошерные def foo[A](a:A)
посмотреть, где можно заменить наборы параметров, по умолчанию начитывающиеся из пропертей, на имплицитные параметры
подумать над оптимизацией передачи параметров трейсерам: мб передавать только h_x, h_y...
IntersectablePolygon из проекта Blases содержит отличные наработки для эпичного апгрейда фреймворка tracers: по аналогии можно сделать
трейсы иметь форму и определять пересечения! Сейчас трейсы по сути - просто точки. В клиентском приложении можно определять для
них какой-нибудь размер, то есть считать их кругами. По умолчанию это все надо ставить, но еще добавить возможность
задавать им вершины и считать их полноценными полигонами. location будет центральной точкой, вершины будут окружать ее
--
Есть конечно же некоторые проблемы. Изначальная парадигма разбивать все поле на прямоугольную сетку. Весь фреймворк tracers
ориентирован на то, что объекты будут размерами примерно как ячейки сетки
StaticPolygon надо бы научиться двигать
мб донести в ScageLib всякие фабрики классов, чтобы и их импортить не надо было. (done)
надо бы переделать апи по удалению событий от клавиатуры/мыши. В текущем виде оно не очень юзабельно: во первых, я его (done)
никогда вроде и не юзал, во вторых, оно и первоначально годилось только для SingleController, а теперь, когда допилен
MultiController и активно используется, оно неюзабельно тем более. Но похоже наворачивать там придется столько, что с
наскока я это не осилю. Что мне хочется:
как в Scage, одну функцию delKeys... мм, я только что мысленно кончил =)
в общем, это даже можно оформить в качестве delOperations, чтобы она принимала и распознавала типы операций - события
от клавиатуры и мыши, как сделано для Рендерера. Проблема заключается в том, что контейнеры событий имеют очень разнотипную структуру, и многие
из них и так уже хашмапы. То есть придется что-то типа наворачивать хашмап над хашмапами, и мне как-то страшно...
мб сделать везде единообразно и где "scage.properties" - переписать на "scageproperties" (пушо наоборот из-за особенностей (done)
вебстарта сделать не выйдет).
--
сделал понимать все варианты
Вощем, нужно придумать стандартный механизм уметь программно показывать версию приложения из pom.xml. Похоже, самый простой путь для этого - (done)
завести в ресурсах новый файл, например maven.properties с содержимым типа:
version = ${project.version}
и добавить этот файл в pom.xml в список ресурсов для фильтрации. Тогда на самом раннем этапе сборки, еще до компиляции в этот файл попадет версия,
и впоследствии этот файл окажется в джарнике, то есть будет доступен ровно также и в собранном приложении. Можно парсить этот файл, используя
стандартный явашный класс Properties.
Проблема здесь такая, что все эти замечательные действия нужно будет проделать над клиентским приложением и, например, внести maven.properties в архетип.
А апи соответственно, рамзместится в библиотеке (в ScageProperties). Если проект будет создан не из архетипа, апи работать не будет. Вощем, как-то неконсистентно.
--
сделал, переебашив ScageProperties. Теперь оно умеет принимать произвольное количество файлов с пропертями
(задаются через запятую: -Dscage.properties=prop1.properties,prop2.properties,...) и искать последовательно в них всех. Принудительно подсовывается файл maven.properties
и в этом файле ключам присваиваются значения свойств из pom.xml. Файл maven.properties фильтруется на этапе генерации ресурсов, и так туда все нужное попадает.
Бедненько но стильненько.
сделать ScageXML уметь менять локаль на ходу и переначитывать мессаджи. Это очень крутая фича, типа переключалка языков (done)
будет по кнопке
Похоже, все функции в RendererInintializer теперь достаточно универсальны и опираются только на приходящие аргументы, (done)
и на функции из RendererLib, то есть RendererInintializer вообще не нужен больше как отдельный трейт, и все функции
из него можно перенести в RendererLib. Подумать об этом.
--
профит от этого такой, что можно будет импортить только net.scage.ScageLib и менять разрешение и всякое такое, без
дополнительного импорта основного класса приложения (потомка ScageScreenApp)
--
удолил. Испытываю сплошое удовольствие теперь)
ВНИМАНИЕ: UnicodeFont козлит, если в качестве координат на отрисовку сообщений отдавать нецелые числа. Следует иметь
в виду этот невъебенски важный факт!
вроде прикольно получилось в Blases запилить Button. Мб завести новый пакет ui (в пакете support), где сложить всякие
стандартные элементы интерфейса. Только тогда нужно еще продумать возможность их кастомизации, и сделать какие-нибудь еще
элементы, а то пока один Button и есть. Можно в принципе оставить их реализацию клиентским разработчикам, просто сделав
руководство по их созданию (на примере того же Blases).
подумать про вызов restart() из одного из экшенов. Типа мб лучше сделать чтобы restart() вызывался после всех экшенов (done)
--
кажется не должно быть проблем. Экшены спроектированы так, что не сохраняют и не гарантируют порядок исполнения, то есть
подразумевается, что порядок исполнения не важен. То есть, если в одном из экшенов произошел вызов restart() и исполнение
продолжилось следующим экшеном, как бы с середины - должно быть пох... Типа, нет разницы, с середины или с начала. Наверное.
--
все так, единственные подводные камни: сообщения в логе типа такой-то трейс или такой-то физикал или такая-то операция нот фаунд.
Типа довыполняется остаток экшенов, а все объекты, которые там крутятся уже удалены, и сами эти экшены на самом деле мб тоже удалены.
Но это все ограничивается ворнингами в логе только если используется стандартное апи. Если какие-то хаки, можно и nullpointer словить.
--
переделал с использованием приватной переменной restart_toggled. Теперь, если в одном из экшенов произошел рестарт, все следующие
не выполняются.
сделать для ScageScreen тоже возможность задавать тайтл в качестве параметра....
--
мб использовать в качестве title - unit_name от ScageScreenApp с возможностью менять его при переходе на другой скрин
мб завести что-то типа onPhysicsCoordChanged() - чтобы не приходилось в трейсере обновлять координату физического объекта на каждом шаге
--
смысла особого нет, потому что координату физический движок все равно и так меняет на каждом шаге обычно.
запилить функции в NetServer: sendToAllExcept(), sendToAllExceptSync() (done)
продумать механизм опертиавного дисконнекта отвалившихся клиентов. очевидный путь: уменьшить пинг_таймаут, но тогда без (done)
конца будут мусорные пинги, которые ни к чему в тех типах сетевых приложений, которые и сами постоянно что-то шлют.
Мб нужно какое-нибудь апи, чтобы клиентские приложения сами могли офлайнов отслеживать и давать команду на очистку в нужное время.
--
еще можно таймаут очистки от офлайнов запилить под отдельную настройку (net.offline_check_timeout) и уменьшать только ее, а пинг. например, вообще
отключить. еще можно поиметь некий стандартный механизм общения клиента и сервера в начале и в конце. Сейчас сервер вначале присылает accepted, а
в конце disconnect, а клиент у нас весь такой молчаливый. Это и к вопросу об идентификации клиента.
пишут
http://stackoverflow.com/questions/5740906/how-to-check-for-null-in-a-single-statement-in-scala
что это scala-way избавляться везде от null и заменять на Option. Надо просмотреть код scage на предмет такого (например,
net api)
запилить функцию drawTraceLocations() (done!)
перепилить Trace: (done!)
trait Trace -> trait TraceTrait
добавить отдельный класс Trace, где changerType = Trace
лоигрование загрузки картинок по аналогии со шрифтами итд
фиксируем версию 0.8 и съебываем на гитхаб! (поросенок Петр, почти (с))
похоже, идея с сортировкой функций рисования при всей своей винрарности не очень применима на практике и нуждается в доработке - потому что в реальных проектах
по сути, видимо будет требоваться всего одна функция отрисовки, выполняющаяся безусловно, и она уже в свою очередь будет решать, что нарисовать, а что нет - таким образом,
порядок рисования нужно будет вычислять другими средствами, предложенный механизм не годится. Есть несколько путей решения проблемы:
* впиливать динамически заполняемый мап allow_render
* разобраться с опенгльным depth-buffer. Я как-то уже пробовал, у меня не заработало, и я забил разбираться. Мб надо дожать это. На первый неискушенный взгляд это решение
кажется лучше, потому что встроено в потроха opengl, типа ничего и делать не надо (а все есть).
переделать контроллер (^^) с использованием partialFunction:
controls {
case "KEY_W" => (wanna_go_up = true; wanna_go_up = false)
}
пока просто подумать об этом, концепт типа
мб все проперти которые начитывает движок, поместить в lazy val в ScageProperties, и брать их оттуда.
--
по моему, не нужно
придумать как вписывать версию в джарник в манифест и как ее забирать оттуда. Чтобы не вписывать номер версии в 100500 местах (в pom.xml и в файле пропертей - для отображения в заголовке окна),
а только в одном (в pom.xml)
--
аналогично можно попробовать поступить с именем
попробовать вытащить из phys2d алгоритм такого-то крутого collision detection'а
уметь задавать window_width, window_height в коде (по умолчанию берутся из пропертей) (done, вынесены в качестве параметров в ScreenApp, по умолчанию по прежнему берутся из пропертей)
net api, рассмотреть юзкейсы:
* ввести с клавиатуры порт и стартовать на нем сервер. Остановить сервер по событию с клавиатуры, потом начать снова на новом (заданном) порту (done, теперь вроде должно уметь так)
* ввести с клавиатуры брл и порт для подключения и стартовать клиент. По событию с клавиатуры отключиться, затем подключиться к новому хосту. (done)
Все-таки попробовать уменьшить количество импортов (done! впилил таки ScageLib, уряяя!!!))
сделать NetServer уметь сообщать что он закончил работу для корректного выхода (чтобы можно было подождать, пока все
треды завершатся). (done, сделал дополнительные методы sendSync() - синхронные посылалки, а также сделал метод disconnect() тоже синхронным,
то есть основном поток будет ждать сигнала его завершения и только после этого продолжать). (done)
сделать Renderer, который object и Renderer, который trait - одной структурой, сделать в ней метод initgl с модификатором
private[scage], запускать его из main в ScageScreenApp... (хм, короче я разобрался с этим, done)
или все-все трейтами переделать... Ладно, если только понадобится.
Несколько статей про сетевой фреймворк Netty и технологию NIO, на которой он основан
http://habrahabr.ru/blogs/java/136456/
http://habrahabr.ru/blogs/gdev/136765/
критикуется архитектура сервера, когда на каждое подключение создается по потоку (а я еще и по два хотел, на ввод и вывод) -
поскольку переключение между потоками в яве удовольствие дорогое, нужно стараться обходиться как можно меньшим их количеством.
В общем, мб сетевое апи надо на этом Netty переписать
--
допилил через акторы, должно быть годно, стопицот тредов не создается, так что нахуй нетти пока что.
Доработка интерфейсов: контролы. Тег <control>. Область в виде многоугольника (задается координатами).
При клике на него генерится событие, и по этому событию можно что-нибудь сделать. Пока концепция.
В net api может быть надо еще делать по потоку (актор) на отправку сообщений. То есть на сервере на каждого клиента два
потока: на прием и на отправку, и на клиенте два аналогичных потоков. А то отправка немного тормозит.
Еще надо сделать сервер и клиент не быть синглтонами. В принципе все легко, можно сделать аналогично трейсерам. Параметров реально мало,
четыре штуки всего, проблем никаких не вижу. Разве что отдельно запилить возможность динамически выбирать незанятый порт -
вот это будет чуть посложнее. Но это можно на потом оставить.
--
В идеале, конечно, лучше бы доделать совсем ынтерпрайзно: когда отправляем/принимаем очередное сообщение, забираем из пула
новый тред, и он продолжает слушать. Когда тред закончил отправлять/принимать - возвращаем в пул. Количество тредов в пуле можно задавать настройкой.
Будет такой крутой доморощенный томкат =)
--
эта ынтерпрайзность впилена в Scala, "акторы" называется =) Переделал под них сетевое апи.
Перепилить все подсистемы, чтобы наряду с начиткой из ScageProperties умели принимать настройки напрямую в виде параметров.
Чтобы типа альтернатива была. Это в частности касается Renderer, ScagePhysics и net api. (хм, вроде везде done)
ScageProperties: придумать что-нибудь, чтобы источником пропертей был не только файл, а что угодно (например, принимать проперти по сети).
Это пока типа концепции.
проперти: парсить Vec, ScageColor и State. Уметь в формулы плюс запоминание констант (последнее касается также ScageXML). (done)
State не умеет в Int, парсит из json во float, с этим можно что-то сделать, по идее. Алсо надо бы перепилить формат, чтобы умел:
{blabla:"pewpew"}, наряду с {"blabla":"pewpew"} (типа строковый ключ в json необязательно заключать в кавычки)
--
ключ в формате json всегд надо в кавычки брать. Насчет парсинга в int пока забил - а что если очередное значение оказалось целым,
а на другом конце ждем float? Типа не угадаешь, так что пусть будет что-то одно (float)
доработка ScageId:
сделать объектом (забить на класс), в нем два метода:
def nextDisplayListId:Int
def nextId:Long
проблема с дисплей_листами, что opengl принимает для них int и не желает long, но остальным участкам кода лучше бы long,
он гораздо больше чисел содержит, а переполнение количества операций свыше двух миллиардов вполне возможно. Хотя в довершение
надо бы сообразить корректную ротацию айдишников при переполнении или хотя бы эффективный fast-fail - чтобы приложение
сразу обсиралось при превышении. А так это все все равно ненадежно.
--
эта проблема остро не стоит, ну и хрен с ней
мб написать свою парсилку пропертей, чтобы она парсила их в объект State
--
да, но зачем? (с)
Снова появилась идея завести один глобальный импорт, чтобы не импортить каждый раз кучу всего. Если коротко, и без
деталей реализации, это может быть объект ScageApp, от которого надо унаследовать трейты:
import net.scage.handlers.Renderer._
import net.scage.support.ScageColors._
import org.lwjgl.input.Keyboard._
import net.scage.support.messages.ScageMessage._
import net.scage.support.messages.ScageXML._
import net.scage.support.ScageProperties._
ScageId._
Но трейты надо сначала аккуратно написать... В общем, есть о чем подумать (done! ScageLib!)
Включить в Scage:
http://code.google.com/p/http-bot/source/browse/trunk/src/su/msk/dunno/httpbot/support/Conn.java
http://code.google.com/p/http-bot/source/browse/trunk/src/su/msk/dunno/httpbot/support/parsers/HtmlParser.java
http://code.google.com/p/http-bot/source/browse/trunk/src/su/msk/dunno/httpbot/support/parsers/FormParser.java
для взаимодействия с http. Парсеры, конечно, лучше накарябать свои, но встроенный в Scala xml-фреймворк,
к сожалению, скорее всего не подойдет для html(
сжатие сетевого трафика. В перспективе - шифрование (опциональное, ессно). Причем, сжатие придется писать самостоятельно, потому что
встроенный в жабу gzip немножко не так работает как нам нужно (требует закрывать канал)
--
Есть такая гугловая либа snappy: http://code.google.com/p/snappy-java/, думаю заюзать ее, но пока не до конца разобрался:
http://groups.google.com/group/xerial/browse_thread/thread/8bc9d36c810eda72?hl=en
ШкагеПропертиш НЕОБХОДИМО сделать трейтом!!
--
идея все-таки фейл, потому что бессмысленно это. Ну да, ScageApp теперь носитель настроек, и клиентский код может брать настройки у главного
окна приложения. Круто. Но неклиентский а библиотечный мой код срать же хотел на ScageApp, ведь это класс, а не объект. А настройки моему
библиотечному коду точно также нужны. Так что искать он их будет продолжать в объекте ScageProperties, и никуда от этого не деться.
Ментальный онанизм последней пары дней привел меня к тому что теперь есть один объект ScageProperties, который начитывает имя файла с
настройками из системной проперти -Dscage.properties. Если она отсутствует, используется имя scage.properties. В таком варианте мы полностью
гарантируем наличие уникальность и иммутабельность объекта с настройками для приложения: нет никаких препятствий к его инициализации, и никто
его никогда не перезапишет.
Минусы: если в джарнике есть на самом деле несколько программ, и каждая использует свой файл с настройками, чтобы все правильно
запустить, теперь нужно в строке запуска указывать еще и -Dscage.properties, а раньше достаточно было просто другое имя запускающего
класса указать - имя нужной ему проперти было вписано в параметры конструктора. Может можно как-то научить либу понимать какой файл
какому классу нужен? Например, уметь начитывать имя класса, из которого взята текущая точка входа
и искать файл <имя_класса>.toLowerCase+".properties". Но зато теперь можно удобно подкладывать разные файлы настроек проге, просто меняя
строку запуска, без перекомпиляции. Хз, правда опять же, нужно ли это.
попробовать все же еще разок сделать main unit единственно возможным в системе, и чтобы с него начинался запуск приложения (в нем точка входа) и отложенно вызывался run(), чтобы
самостоятельно его вызывать не надо было (посмотреть, как это сделано в трейте App).
еще апдейт контроллера: вынести отслеживание событий по нажатию кнопок клавиатуры и мыши (was_pressed, last_pressed_time) в объект, чтобы эта инфа была независима от текущего
запущенного экрана и была общей для них всех. В текущей реализации, если, например, по нажатию на какую-либо кнопку осуществляется переход в новый экран, и в нем, в свою очередь по этой же
кнопке осуществляется выход - мы сразу выйдем обратно. Данная доработка должна поправить этот баг.
апдейт контроллера: события по нажатию нескольких клавиш (ctrl-Z, shift-C итд)
мб избавить от ScageMessage и все методы перетащить в Renderer? Хотя нах надо...
--
обратное предложение: сделать трейтом! мм, тоже фейл же...
мб вынести ScageColor в отдельный файл, и все три файла (ScageColor, ScageColors, ScageColorTest) отправить в отдельный пакет colors
Придумать стандартный способ останавливать приложения на основе Scage (без графического интерфейса). Я голосую за какой-нибудь веб-интерфейс или типа того.
--
а вот можно еще так:
val sc = new Scanner(System.in)
и на каждом шаге:
if(sc.hasNextLine) {
val line = sc.nextLine().trim()
line match {
case "exit" | "quit" => Scage.stopApp()
// more cases here...
case _ =>
}
}
правда, Scanner и всякие там hasNextLine() на первый взгляд не выглядят легкими и дешевыми, так что мб лучше эту технику оставлять опциональной на совести приложений, которым такое
действительно надо (например, графическим такое нах не надо, имхо).
добавить в ScageProperties парсилку арифеметики, дописывать ей в константы все вводимые ключи, чтобы их тоже можно было использовать.
реализовать ввод значений Vec и ScageColor
Переписать ColoredString через комбинатор парсеров (главным образом, чтобы поучиться его использовать).
--
Хотя наверное не получится: текущая реализация не context-free (если стоит слеш - не делать color switch) и отказываться от этой фичи не хочется
сетевая часть: перепилить с синглтонов на классы, чтобы была возможность стартовать в одном приложении несколько
серверов/клиентов. Реализовать companion objects - в них запилить текущий порт - увеличивать его на 1 при старте
очередного сервера/клиента, либо при эксепшоне
сетевая часть: запилить крутой парсер json (готовый, из стандартной библиотеки или сторонний, в крайнем случае самому
написать, прочитав главу Parcers из "Programming in Scala, 2nd edition"), чтобы был такой же удобный, как для xml.
сетевая часть: периодические сообщения keepAlive с заданным интервалом (меньше checkTimeout), чтобы не зависеть от
клиентского кода в плане посылки сообщений. Тогда можно поощрять checkTimeout (сделать ненулевым по умолчанию)
удаление клавиш
продумать:
* гарантии инициализации пропертей (проперти в виде трейта?)
* независимость рендера от пропертей (передача нужных вещей в виде параметров в функцию инициализации)
* независимость ScageMessage от пропертей
* логирование запуска юнитов
* трейты Renderer и ScageController получились неотделимы от Scage, отдельно их не получится использовать. Подумать, насколько
это плохо.
* реально ли делать рестарт приложения просто вызовом init (без exit) - тогда можно было бы избавиться от
дополнительного dispose. если же это нереально - запилить функцию restart:
def restart() {
exit()
init()
}
надо придумать и написать PerformanceTest
сделать профиль noscagelogo, и в нем собирать либу без логотипа Scage. По умолчанию собирать с логотипом. От
настройки scage.logo в Renderer избавиться.
всегда явно писать тип возвращаемого значения
проставить в нужных местах final и sealed
полностью делать интерфейс экранов в xml, как в андроиде. Продумать язык описания интерфейса.
--
пример xml:
<interfaces>
<interface id="player.stats" x="20" y = "300" xinterval="5" yinterval="20">
<row id="player.health" x="20" y="300">
HP: $0
</row>
<row id="player.energy" x="20" y="300">
Energy: $0
</row>
<row />
<row id="player.defence">
Def: $0
</row>
<row id="player.infection">
Infection Level: $0
</row>
</interface>
</interfaces>
в строчках вместо message_id будут подставляться соответствующие строки из файлов со строками
Вызов из кода:
interface {
ScageMessage.printStrings(ScageXML.xmlInterface("player.stats", 100, 50, 50, 0), 300, 400, 20)
}
100, 50, 50, 0 - значения, которые следует подставить в строчки вместо знаков вопроса. Здесь такой
момент, что строчки вообще говоря могут иметь произвольное количество знаков вопроса и надо скармливать каждой строке
из этого набора параметров только то, что имеет отношение к ней.
20 - межстрочное расстояние. xmlInterface() возвращает массив строк, они печатаются одна под другой функцией
printStrings(), которая принимает массив строк
--
мб передавать в тегах row также аттрибут message:
<row message_id="player.defence" message="Defence: ?" />
и использовать эту строку согласно какому-нибудь критерию (типа если по айдишнику найти не удалось/айдишника нет)
--
придумать как задавать в xml значения координат через функции от размеров окна (типа резиновый интерфейс) и относительно
положения других интерфейсов
--
в файлах строк мб тоже запилить поддержку аттрибутов координат и цвета
--
насчет задания в пропертях и xml всякого через функции от размеров окна итд - можно впилить самописные парсеры с помощью
встооенного в скакалку генератора парсеров (глава 33 "Programming in Scala, 2nd edition")
перепилить функции-удалялки через няшное collections api (done, перепилено вроде. Во всяком случае, все эти места уже основательно
переебашены и не один раз)
в трейсерах:
getState -> state (done)
traces_in_point -> traces_points (done)
point_matrix -> изменить тип: Array[ArrayBuffer[T]]
--
не годится, придется делать toList в методах, отдающих куски из point_matrix (прям ArrayBuffer-то стремновато отдавать)
http://www.scala-lang.org/node/10473
По ссылке скакалочные изменения в версии 2.9.1
Это надо внимательно прочитать и по возможности впилить в scage, куда надо.
Например, паралелльные коллекции. Это ведь круто?
The App Trait, The DelayedInit Trait - вот мне очень хочется избавиться от обязательного def main(args:Array[String]) {run()}
в объекте-главном экране. В идеале это должно быть что-то такое, что мы пишем весь инициализированный код в нашем
клиенстком объекте, а при запуске, будет вызван он и потом run(). И еще надо чтобы учитывалось, что наследник
ScageScreen может не обязательно быть объектом и тогда чтобы в нем не было ни main, ничего такого.
New methods in collections:
collectFirst, maxBy, minBy, span, inits, tails, permutations, combinations, subsets
можно запилить в init нечто вроде проверки: после отработки всех init-функций мы подсчитываем количество экшонов,
рендеров и интерфейсов. Если количество чего-нибудь увеличилось с последнего запуска инит, отдаем ворнинг с
информацией, чего стало больше. По идее, повторные вызовы init означают перезапуск приложения, то есть по идее все
в нем должно вернуться к исходному состоянию. Если чего-то стало больше - где-то прога не удаляет за собой, и это
может привести к переполнению, тормозам итд.
Я прочитал в книжке про ковариантность и контравариантность, и теперь можно подумать, надо ли запиливать что-то
такое в трейсерах
Круто! Оказывается, текущая архитектура контроллера не позволяет добавлять несколько событий на одну клавишу, например,
как-нибудь так:
key(KEY_1, onKeyDown = println("1!"))
key(KEY_1, onKeyDown = println("one!"))
отработает только последнее!
С кнопками мыши и другими ее событиями ситуация немного отличается, но работает тоже нестабильно.
---
мб пойти в обратную сторону и запилить возможность на каждую кнопку клавиатуры/мыши, на мышиные
движения/перетаскивания и колесико вешать ровно одну функцию. Повторное добавление перезаписывает текущую
Сделать, чтобы окошко по центру экрана запускалось (done, хотя возможны траблы на мультимониторной системе)
Одноразовые самоудаляющиеся экшоны. Экшоны запускающиеся с задержкой (типа синтаксический сахар такой. И то и то сейчас
может быть реализовано средствами движка).
--
пока неактуально
Сделать объект-компаньон-фабрику для ScagePhysics. Пусть будет апи, похожее на те, что предоставляют объекты коллекций:
val physics = ScagePhysics(ball, floor, left_wall, right_wall, roof, table)
типа оно нам сделает physics и сразу туда добавит нужное. Подумать аналогично про трейсеры.
Доработать апи в ScagePhysics в части касающейся регистрации касаний-столкновений. Вроде phys2d умеет определять точку
касания, надо ее отдавать. Важно же знать не просто, что тела коснулись, а каким они местом коснулись (например,
ударились об стенку в процессе падения, или таки уже ебнулись об пол и пора умирать).
physicals в ScagePhysics - сделать ArrayList
--
или ArrayBuffer, а чо
Renderer: мб scale тоже сделать функцией?.. Подумать о производительности функций center() и window_center()
window_center() особо не используется, кажется он использовался в Blamer только..
Мб предусмотреть два режима: когда эти штуки - изменяемые переменные, и когда функции...
--
этак и backgroundColor и color можно запилить функциями... В общем, серьезно подумать о целесообразности
--
гыгы, нее, низя scale сделать функцией. Иначе будет обсираться более простой юзкейс:
key(KEY_ADD, onKeyDown = {scale += 1})
типа по нажатию на плюсик увеличить масштаб. Если scale будет функцией, то эта функция:
{scale + 1}
будет вызываться каждый такт, в результате после нажатия на плюс картинка начнет непрерывно приближаться.
Воркэраунд от этого выглядит более херово:
private var my_scale = 1
scale = my_scale
key(KEY_ADD, onKeyDown = {my_scale += 1})
три строчки вместо одной. Аналогичные возможные траблы с color и backgroundColor. С другой стороны, с текущим апи,
если нам надо, чтобы масштаб изменялся в зависимости от чего-то, мы пилим что-то такое (пример из проекта Uke):
action {
scale = if(Uke.coord.y - fartherst_coord.y > screen_height/2) screen_height/2/(Uke.coord.y - fartherst_coord.y) else 1
}
примерно такое же было бы написано, если scale - функция:
scale = {
if(Uke.coord.y - fartherst_coord.y > screen_height/2) screen_height/2/(Uke.coord.y - fartherst_coord.y) else 1
}
как-то так, кароч
ScagePhysics: изменяемый dt (done)
GRAY и DARK_GRAY надо бы местами поменять (done)
подумать над усложнением схемы работы: предусмотреть возможность перезапуска. Изначально подразумевалось, что код в списке
exits будет вызываться только при окончании работы приложения. Но конечно же суперудобно сделать возможность перезапуска
игры без выхода из приложения, тем более что это достигается практически нахаляву связкой exit(); init();
Проблема в том, что в exits может содержаться код, освобождающий ресурсы насовсем, так что последующие init() и run() обосрутся.
Конечно, не до конца понятно, нужен ли такой код под ява-машиной, все равно, при выходе jvm освободит все...
Вощем как вариант можно запилить еще один список функций, только название для него пока не придумал
Вообще кастомиазция процесса старта приложения и его завершения - отдельная тема, но пока не актуальная. Пока:
слово Loading..., потом логотип движка, потом логотип игры, если есть или вступительная фраза (имя разработчика например),
дальше собственно игра. Показ логотипов и фраз все по 1 секунде, фразы пишутся слева сверху зеленым цветом главным шрифтом.
После игры - слово Exiting...
апгрейд парсилки xml:
пусть принимает еще произвольные аттрибуты, например цвет сообщения, позиция, пауза перед выводом итд. Пусть функция xml()
возвращает json со всеми этими данными и из него уже можно будет нужно вытаскивать
написать функция color:String -> ScageColor (done)
настройка id.start не нужна, потому что нет никакого смысла ее менять, и даже сейчас к этому есть препятствия:
она должна быть не меньше 10000. Пусть она просто будет 10000 (done)
drawRect и drawFilledRect принимают координату и считает ее центральной! Надо еще чтобы был левый верхний угол, как обычно. (done)
--
старые функции переименованы с добавлением префикса Centered. Обратную совместимость я в гробу видал, притом что проектов
все равно никаких нет пока :3
баг с отрисовкой физических полигонов закрашенными мнгоугольниками (функция drawFilledPolygon)
action'ы, которые не тормозятся паузой. Сейчас есть настройка pause.global: если она true, все экшены останавливаются (done)
на паузе, если false - никакие не останавливаются, и можно там дальше в коде нужных экшонов предусмотреть, влияет ли на
исполнение пауза или нет. Мб вынести эту логику на уровень движка, чтобы были actionNoPause и обычные. Тогда можно
настройку pause.global выкинуть.
--
Аналогично можно предусмотреть влияние паузы на рендеры и на нажатие клавиш.
drawPolygon не имеет параметра color, ай-я-яй (done)
--
орлы? тащем-та просто не было метода, принимающего List в качестве аргумента. Аналогично допилил для drawFilledPolygon
принудительный показ ололологотипа движка (done)
аналогично drawPoints - drawLines (done)
написать апи для проигрывания анимации
--
надо сначала подумать, как бы такое апи могло выглядеть. Хотя можно, как я обычно делаю: написать под определенные нужды,
и если в следующем приложении написанного не хватат, допиливать под него итд.
--
предварительно соснул хуйцов. предложенный вариант апи менее гибкий, чем текущий, через переменную current_frame,
один экшон и один рендер. Надо этот юзкейс как-то весь годно формализовать в один периодический метод.
мелкие оптимизации:
метод removeTrace/removeTraceById (один типа, чтобы не было лишнего foreach), итд
--
тогда и для экшонов что ли такое пилить? я ебанусь же.
подумать на досуге о возможности переполнения айдишников и возможном замедлении работы при логировании
их генерации (в режиме дебаг, при добавлении новых трейсов, например)
начать ботать Java Web Start. В перспективе это должно стать профилем в pom.xml (done)
--
крутота!
новый метод в трейсере: removeTraceByPoint/removeTraceByCoord
--
необходимость пока под вопросом
сообщение в логе при постановке/снятии с паузы (done)
--
нужно например за тем, чтобы иметь возможность все же отслеживать состояние "на паузе/не на паузе", даже
если в интерфейсе это нигде не отображается никак (клиентский разработчик может в программе нигде не помечать состояние паузы)
outsidePoint(...) -> point(...)
--
нее: метод point из CoordTracer перенести в ScageTracer (done)
мб переписать методы типа drawPolygon итд, принимающие произвольное количество координат: сначала цвет,
потом координаты. Это избавит от дополнительного метода (вроде)
допилить drawPoint чтобы принимал список точек (done)
--
метод drawPoints
В ScageMessage добавить методы принимающие Vec вместо float, float
--
дописать в ScageMessage методы print*, принимающие Vec